--- old/./src/share/classes/java/lang/Process.java 2012-09-07 14:37:47.899436606 -0400 +++ new/./src/share/classes/java/lang/Process.java 2012-09-07 14:37:47.775436610 -0400 @@ -26,6 +26,9 @@ package java.lang; import java.io.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.concurrent.TimeUnit; /** @@ -75,6 +78,7 @@ * @since JDK1.0 */ public abstract class Process { + /** * Returns the output stream connected to the normal input of the * subprocess. Output to the stream is piped into the standard @@ -262,4 +266,44 @@ return true; } } + + /** + * Returns the process id of the subprocess + * + * @return the process id or -1 if the process is not alive + * @since 1.8 + */ + public abstract int getPid(); + + /** + * Returns the process id of the current process. + * + * @return the process id of the current process. + * @since 1.8 + * + **/ + public static native int getCurrentPid(); + + public abstract String getProcessName(int pid); + + /** + * @return the process name of the current process. + * @since 1.8 + */ + public String getCurrentProcessName() { + return getProcessName( getCurrentPid() ); + } + + /** + * @return the process name of this process or null if no longer live + * @since 1.8 + */ + public String getProcessName() { + int pid = getPid(); + if (pid >=0) { + return getProcessName( getPid() ); + } else { + return null; + } + } } --- old/./src/solaris/classes/java/lang/UNIXProcess.java.bsd 2012-09-07 14:37:48.391436591 -0400 +++ new/./src/solaris/classes/java/lang/UNIXProcess.java.bsd 2012-09-07 14:37:48.259436595 -0400 @@ -34,9 +34,14 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Arrays; -import java.util.concurrent.Executors; import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.security.AccessController; @@ -139,7 +144,7 @@ dir, fds, redirectErrorStream); - + try { doPrivileged(new PrivilegedExceptionAction() { public Void run() throws IOException { @@ -270,6 +275,33 @@ return !hasExited; } + @Override + public int getPid() { + if (!isAlive()) { + return -1; + } else { + return pid; + } + } + + @Override + public String getProcessName(int pid) { + // look at /proc//comm + if (pid < 0) { + throw new IllegalArgumentException( "pid == " + pid ); + } + Path p = Paths.get( "/proc/" + pid + "/comm" ); + if (!Files.exists(p, LinkOption.NOFOLLOW_LINKS )) { + return null; + } + + try { + return Files.readAllLines( p, Charset.defaultCharset() ).get(0); + } catch (IOException ioex) { + throw new RuntimeException( ioex ); + } + } + /* This routine initializes JNI field offsets for the class */ private static native void initIDs(); @@ -349,4 +381,6 @@ } } } + + } --- old/./src/solaris/classes/java/lang/UNIXProcess.java.linux 2012-09-07 14:37:48.951436575 -0400 +++ new/./src/solaris/classes/java/lang/UNIXProcess.java.linux 2012-09-07 14:37:48.799436579 -0400 @@ -34,6 +34,11 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Arrays; import java.util.concurrent.Executors; import java.util.concurrent.Executor; @@ -270,6 +275,33 @@ return !hasExited; } + @Override + public int getPid() { + if (!isAlive()) { + return -1; + } else { + return pid; + } + } + + @Override + public String getProcessName(int pid) { + // look at /proc//comm + if (pid < 0) { + throw new IllegalArgumentException( "pid == " + pid ); + } + Path p = Paths.get( "/proc/" + pid + "/comm" ); + if (!Files.exists(p, LinkOption.NOFOLLOW_LINKS )) { + return null; + } + + try { + return Files.readAllLines( p, Charset.defaultCharset() ).get(0); + } catch (IOException ioex) { + throw new RuntimeException( ioex ); + } + } + /* This routine initializes JNI field offsets for the class */ private static native void initIDs(); --- old/./src/solaris/classes/java/lang/UNIXProcess.java.solaris 2012-09-07 14:37:49.499436559 -0400 +++ new/./src/solaris/classes/java/lang/UNIXProcess.java.solaris 2012-09-07 14:37:49.371436563 -0400 @@ -25,7 +25,20 @@ package java.lang; -import java.io.*; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.concurrent.TimeUnit; /* java.lang.Process subclass in the UNIX environment. @@ -83,7 +96,7 @@ dir, std_fds, redirectErrorStream); - + java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { if (std_fds[0] == -1) @@ -221,6 +234,33 @@ return !hasExited; } + @Override + public int getPid() { + if (!isAlive()) { + return -1; + } else { + return pid; + } + } + + @Override + public String getProcessName(int pid) { + // look at /proc//comm + if (pid < 0) { + throw new IllegalArgumentException( "pid == " + pid ); + } + Path p = Paths.get( "/proc/" + pid + "/comm" ); + if (!Files.exists(p, LinkOption.NOFOLLOW_LINKS )) { + return null; + } + + try { + return Files.readAllLines( p, Charset.defaultCharset() ).get(0); + } catch (IOException ioex) { + throw new RuntimeException( ioex ); + } + } + // A FileInputStream that supports the deferment of the actual close // operation until the last pending I/O operation on the stream has // finished. This is required on Solaris because we must close the stdin --- old/./src/windows/classes/java/lang/ProcessImpl.java 2012-09-07 14:37:50.003436544 -0400 +++ new/./src/windows/classes/java/lang/ProcessImpl.java 2012-09-07 14:37:49.867436548 -0400 @@ -330,4 +330,22 @@ throws IOException; private static native boolean closeHandle(long handle); + + private static native int getProcessId(long handle); + private static native String getModuleBaseName(int pid); + + @Override + public int getPid() { + if (!isAlive()) { + return -1; + } else { + return getProcessId(handle); + } + } + + @Override + public String getProcessName(int pid) { + return getModuleBaseName(pid); + } + } --- old/./src/windows/native/java/lang/ProcessImpl_md.c 2012-09-07 14:37:50.475436530 -0400 +++ new/./src/windows/native/java/lang/ProcessImpl_md.c 2012-09-07 14:37:50.335436534 -0400 @@ -32,6 +32,8 @@ #include "io_util.h" #include #include +#include +#include /* We try to make sure that we can read and write 4095 bytes (the * fixed limit on Linux) to the pipe on all operating systems without @@ -390,3 +392,43 @@ } return ptr_to_jlong(h); } + +JNIEXPORT jint JNICALL +Java_java_lang_ProcessImpl_getProcessId(JNIEnv *env, jclass ignored, jlong handle) +{ + return GetProcessId((HANDLE) handle); +} + +JNIEXPORT jint JNICALL +Java_java_lang_ProcessImpl_getCurrentPid(JNIEnv *env, jobject this) +{ + return GetCurrentProcessId(); +} + + +JNIEXPORT jstring JNICALL +Java_java_lang_ProcessImpl_getModuleBaseName(JNIEnv *env, jclass ignored, jint pid) +{ + char szProcessName[MAX_PATH]; + + // Get a handle to the process. + + HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | + PROCESS_VM_READ, + FALSE, pid ); + + // Get the process name. + + if (hProcess != NULL ) + { + HMODULE hMod; + DWORD cbNeeded; + + if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), + &cbNeeded) ) { + GetModuleBaseName( hProcess, hMod, szProcessName, + sizeof(szProcessName) ); + } + } + return szProcessName; +} --- old/./test/Makefile 2012-09-07 14:37:51.023436514 -0400 +++ new/./test/Makefile 2012-09-07 14:37:50.895436517 -0400 @@ -480,6 +480,11 @@ jdk_lang: $(call TestDirs, java/lang) $(call RunAgentvmBatch) +ifdef DIRS +TD: $(call TestDirs, $(DIRS)) + $(call RunAgentvmBatch) +endif + # Stable othervm testruns (minus items from PROBLEM_LIST) # Using agentvm has serious problems with these tests JDK_ALL_TARGETS += jdk_management1 --- old/./test/java/lang/ProcessBuilder/Basic.java 2012-09-07 14:37:51.611436496 -0400 +++ new/./test/java/lang/ProcessBuilder/Basic.java 2012-09-07 14:37:51.463436501 -0400 @@ -673,6 +673,16 @@ public InputStream getErrorStream() { return p.getErrorStream(); } + + @Override + public int getPid() { + return p.getPid(); + } + + @Override + public String getProcessName( int pid ) { + return p.getProcessName( pid ); + } } private static boolean matches(String str, String regex) { @@ -2132,15 +2142,54 @@ //---------------------------------------------------------------- // Check that Process.isAlive() & // Process.waitFor(0, TimeUnit.MILLISECONDS) work as expected. + // Also, check that Process.getPid() works properly //---------------------------------------------------------------- try { List childArgs = new ArrayList(javaChildArgs); childArgs.add("sleep"); + List pidsBefore = new ArrayList(Process.getPids()); + System.out.println( java.util.Arrays.toString(pidsBefore.toArray()) ); final Process p = new ProcessBuilder(childArgs).start(); long start = System.nanoTime(); if (!p.isAlive() || p.waitFor(0, TimeUnit.MILLISECONDS)) { fail("Test failed: Process exited prematurely"); } + int pid = p.getPid(); + System.out.println( "pid = " + pid ); + if (pid < 0) { + fail("Test failed: PID of running process should be >= 0"); + } + // check for valid process name (should be 'java') + String pName = p.getProcessName( pid ); + System.out.println( "Process name = " + pName ); + if (pName == null || pName.equals("") || !pName.equals("java")) { + fail("Test failed: Process.getProcessName(" + pid + ") returned '" + pName + "' instead of 'java'" ); + } + + // Now test that getPids() contains this pid + List pidsAfter = new ArrayList(Process.getPids()); + System.out.println( java.util.Arrays.toString(pidsAfter.toArray())); + if (!pidsAfter.contains(new Integer(pid))) { + fail("Test failed: Process.getPids() (after) does not contain pid of process that was started"); + } + if (pidsBefore.contains(new Integer(pid))) { + fail("Test failed: Process.getPids() (before) contains pid of process that was started"); + } + // should just be one matching the process we just created + if (pidsAfter.size() != (pidsBefore.size() + 1)) { + fail("Test failed: Process.getPids().size() returned " + pidsAfter.size() + " instead of " + + (pidsBefore.size() + 1) ); + } + // display all process names we've created + for (Integer aPid:pidsAfter) { + try { + pName = p.getProcessName(aPid); + } catch (IllegalArgumentException iae) { + pName = ""; + } + System.out.println( aPid + " " + pName ); + } + long end = System.nanoTime(); // give waitFor(timeout) a wide berth (100ms) if ((end - start) > 100000000) @@ -2155,6 +2204,11 @@ fail("Test failed: Process still alive - please terminate " + p.toString() + " manually"); } + pid = p.getPid(); + System.out.println( "pid = " + pid ); + if (pid >=0) { + fail("Test failed: PID of dead process is " + pid); + } } catch (Throwable t) { unexpected(t); } //---------------------------------------------------------------- --- /dev/null 2012-09-06 08:53:01.422600655 -0400 +++ new/./test/java/lang/Process/GetProcessInfo.java 2012-09-07 14:37:52.011436485 -0400 @@ -0,0 +1,16 @@ +public class GetProcessInfo { + + public static void main(String... args) { + int pid = Process.getCurrentPid(); + System.out.println( " PID = " + pid ); + if (pid <= 0) { + throw new Exception("Test Failed: Invalid current PID: " + pid); + } + + String currentProcessName = new Process().getCurrentProcessName(); + String currentProcessNameByPid = new Process().getProcessName( pid ); + if (!currentProcessName.equals(currentProcessNameByPid)) { + throw new Exception("Test Failed: current process name ( " + currentProcessName + " ) does not match process name by pid ( " + currentProcessNameByPid + " )"); + } + } +}