8078099: (process) ProcessHandle should uniquely identify processes
authorrriggs
Tue, 14 Jul 2015 15:35:37 -0400
changeset 31682 c19dcf5e0b6d
parent 31681 e9a9d5b369bc
child 31683 ac6d7a188995
8078099: (process) ProcessHandle should uniquely identify processes 8078108: (process) ProcessHandle.isAlive should be robust Summary: isAlive should check and confirm the start time Reviewed-by: simonis, plevart
jdk/make/mapfiles/libjava/mapfile-vers
jdk/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c
jdk/src/java.base/share/classes/java/lang/ProcessHandleImpl.java
jdk/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c
jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java
jdk/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c
jdk/src/java.base/windows/classes/java/lang/ProcessImpl.java
jdk/src/java.base/windows/native/libjava/ProcessHandleImpl_win.c
--- a/jdk/make/mapfiles/libjava/mapfile-vers	Tue Jul 14 15:29:16 2015 -0400
+++ b/jdk/make/mapfiles/libjava/mapfile-vers	Tue Jul 14 15:35:37 2015 -0400
@@ -166,11 +166,12 @@
 		Java_java_lang_Package_getSystemPackage0;
 		Java_java_lang_Package_getSystemPackages0;
 		Java_java_lang_ProcessEnvironment_environ;
+		Java_java_lang_ProcessHandleImpl_destroy0;
 		Java_java_lang_ProcessHandleImpl_getCurrentPid0;
-		Java_java_lang_ProcessHandleImpl_parent0;
+		Java_java_lang_ProcessHandleImpl_getProcessPids0;
+		Java_java_lang_ProcessHandleImpl_initNative;
 		Java_java_lang_ProcessHandleImpl_isAlive0;
-		Java_java_lang_ProcessHandleImpl_getProcessPids0;
-		Java_java_lang_ProcessHandleImpl_destroy0;
+		Java_java_lang_ProcessHandleImpl_parent0;
 		Java_java_lang_ProcessHandleImpl_waitForProcessExit0;
 		Java_java_lang_ProcessHandleImpl_00024Info_initIDs;
 		Java_java_lang_ProcessHandleImpl_00024Info_info0;
--- a/jdk/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c	Tue Jul 14 15:29:16 2015 -0400
+++ b/jdk/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c	Tue Jul 14 15:35:37 2015 -0400
@@ -75,9 +75,8 @@
  * Method:    initIDs
  * Signature: ()V
  */
-JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_initIDs
-  (JNIEnv *env, jclass clazz) {
-
+JNIEXPORT void JNICALL
+Java_java_lang_ProcessHandleImpl_00024Info_initIDs(JNIEnv *env, jclass clazz) {
     CHECK_NULL(ProcessHandleImpl_Info_commandID =
             (*env)->GetFieldID(env, clazz, "command", "Ljava/lang/String;"));
     CHECK_NULL(ProcessHandleImpl_Info_argumentsID =
@@ -88,7 +87,45 @@
             (*env)->GetFieldID(env, clazz, "startTime", "J"));
     CHECK_NULL(ProcessHandleImpl_Info_userID =
             (*env)->GetFieldID(env, clazz, "user", "Ljava/lang/String;"));
-    clock_ticks_per_second = sysconf(_SC_CLK_TCK);
+}
+/**************************************************************
+ * Static method to initialize the ticks per second rate.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    initNative
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_java_lang_ProcessHandleImpl_initNative(JNIEnv *env, jclass clazz) {
+      clock_ticks_per_second = sysconf(_SC_CLK_TCK);
+}
+
+/*
+ * Check if a process is alive.
+ * Return the start time (ms since 1970) if it is available.
+ * If the start time is not available return 0.
+ * If the pid is invalid, return -1.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    isAlive0
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL
+Java_java_lang_ProcessHandleImpl_isAlive0(JNIEnv *env, jobject obj, jlong jpid) {
+    pid_t pid = (pid_t) jpid;
+    struct kinfo_proc kp;
+    size_t bufSize = sizeof kp;
+
+    // Read the process info for the specific pid
+    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
+
+    if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) < 0) {
+        return  (errno == EINVAL) ? -1 : 0;
+    } else {
+        return (bufSize == 0) ?  -1 :
+                                 (jlong) (kp.kp_proc.p_starttime.tv_sec * 1000
+                                        + kp.kp_proc.p_starttime.tv_usec / 1000);
+    }
 }
 
 /*
@@ -98,8 +135,11 @@
  * Method:    parent0
  * Signature: (J)J
  */
-JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_parent0
-(JNIEnv *env, jobject obj, jlong jpid) {
+JNIEXPORT jlong JNICALL
+Java_java_lang_ProcessHandleImpl_parent0(JNIEnv *env,
+                                         jobject obj,
+                                         jlong jpid,
+                                         jlong startTime) {
     pid_t pid = (pid_t) jpid;
     pid_t ppid = -1;
 
@@ -117,7 +157,14 @@
                 "java/lang/RuntimeException", "sysctl failed");
             return -1;
         }
-        ppid = (bufSize > 0 && kp.kp_proc.p_pid == pid) ? kp.kp_eproc.e_ppid : -1;
+        // If the buffer is full and for the pid requested then check the start
+        if (bufSize > 0 && kp.kp_proc.p_pid == pid) {
+            jlong start = (jlong) (kp.kp_proc.p_starttime.tv_sec * 1000
+                                   + kp.kp_proc.p_starttime.tv_usec / 1000);
+            if (start == startTime || start == 0 || startTime == 0) {
+                ppid = kp.kp_eproc.e_ppid;
+            }
+        }
     }
     return (jlong) ppid;
 }
@@ -136,15 +183,20 @@
  * If the array is too short, excess pids are not stored and
  * the desired length is returned.
  */
-JNIEXPORT jint JNICALL Java_java_lang_ProcessHandleImpl_getProcessPids0
-(JNIEnv *env, jclass clazz, jlong jpid,
-    jlongArray jarray, jlongArray jparentArray)
-{
-    size_t count = 0;
+JNIEXPORT jint JNICALL
+Java_java_lang_ProcessHandleImpl_getProcessPids0(JNIEnv *env,
+                                                 jclass clazz,
+                                                 jlong jpid,
+                                                 jlongArray jarray,
+                                                 jlongArray jparentArray,
+                                                 jlongArray jstimesArray) {
     jlong* pids = NULL;
     jlong* ppids = NULL;
-    size_t parentArraySize = 0;
-    size_t arraySize = 0;
+    jlong* stimes = NULL;
+    jsize parentArraySize = 0;
+    jsize arraySize = 0;
+    jsize stimesSize = 0;
+    jsize count = 0;
     size_t bufSize = 0;
     pid_t pid = (pid_t) jpid;
 
@@ -159,6 +211,15 @@
             return 0;
         }
     }
+    if (jstimesArray != NULL) {
+        stimesSize = (*env)->GetArrayLength(env, jstimesArray);
+        JNU_CHECK_EXCEPTION_RETURN(env, -1);
+
+        if (arraySize != stimesSize) {
+            JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
+            return 0;
+        }
+    }
 
     // Get buffer size needed to read all processes
     int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
@@ -198,6 +259,12 @@
                 break;
             }
         }
+        if (jstimesArray != NULL) {
+            stimes  = (*env)->GetLongArrayElements(env, jstimesArray, NULL);
+            if (stimes == NULL) {
+                break;
+            }
+        }
 
         // Process each entry in the buffer
         for (i = nentries; --i >= 0; ++kp) {
@@ -209,6 +276,12 @@
                         // Store the parentPid
                         ppids[count] = (jlong) kp->kp_eproc.e_ppid;
                     }
+                    if (stimes != NULL) {
+                        // Store the process start time
+                        jlong startTime = kp->kp_proc.p_starttime.tv_sec * 1000 +
+                                          kp->kp_proc.p_starttime.tv_usec / 1000;
+                        stimes[count] = startTime;
+                    }
                 }
                 count++; // Count to tabulate size needed
             }
@@ -221,6 +294,9 @@
     if (ppids != NULL) {
         (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
     }
+    if (stimes != NULL) {
+        (*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0);
+    }
 
     free(buffer);
     // If more pids than array had size for; count will be greater than array size
@@ -238,8 +314,10 @@
  * Method:    info0
  * Signature: (J)I
  */
-JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_info0
-  (JNIEnv *env, jobject jinfo, jlong jpid) {
+JNIEXPORT void JNICALL
+Java_java_lang_ProcessHandleImpl_00024Info_info0(JNIEnv *env,
+                                                 jobject jinfo,
+                                                 jlong jpid) {
     pid_t pid = (pid_t) jpid;
     getStatInfo(env, jinfo, pid);
     getCmdlineInfo(env, jinfo, pid);
@@ -251,7 +329,7 @@
  */
 static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t jpid) {
     jlong totalTime;                    // nanoseconds
-    unsigned long long startTime;       // microseconds
+    unsigned long long startTime;       // milliseconds
 
     const pid_t pid = (pid_t) jpid;
     struct kinfo_proc kp;
--- a/jdk/src/java.base/share/classes/java/lang/ProcessHandleImpl.java	Tue Jul 14 15:29:16 2015 -0400
+++ b/jdk/src/java.base/share/classes/java/lang/ProcessHandleImpl.java	Tue Jul 14 15:35:37 2015 -0400
@@ -39,6 +39,7 @@
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.IntStream;
 import java.util.stream.Stream;
 
 import sun.misc.InnocuousThread;
@@ -52,6 +53,24 @@
  * @since 1.9
  */
 final class ProcessHandleImpl implements ProcessHandle {
+    /**
+     * Cache the ProcessHandle of this process.
+     */
+    private static final ProcessHandleImpl current;
+
+    /**
+     * Map of pids to ExitCompletions.
+     */
+    private static final ConcurrentMap<Long, ExitCompletion>
+            completions = new ConcurrentHashMap<>();
+
+    static {
+        initNative();
+        long pid = getCurrentPid0();
+        current = new ProcessHandleImpl(pid, isAlive0(pid));
+    }
+
+    private static native void initNative();
 
     /**
      * The thread pool of "process reaper" daemon threads.
@@ -84,9 +103,6 @@
         }
     }
 
-    private static final ConcurrentMap<Long, ExitCompletion>
-        completions = new ConcurrentHashMap<>();
-
     /**
      * Returns a CompletableFuture that completes with process exit status when
      * the process completes.
@@ -142,22 +158,33 @@
     private static native int waitForProcessExit0(long pid, boolean reapvalue);
 
     /**
-     * Cache the ProcessHandle of this process.
-     */
-    private static final ProcessHandleImpl current =
-            new ProcessHandleImpl(getCurrentPid0());
-
-    /**
      * The pid of this ProcessHandle.
      */
     private final long pid;
 
     /**
+     * The start time of this process.
+     * If STARTTIME_ANY, the start time of the process is not available from the os.
+     * If greater than zero, the start time of the process.
+     */
+    private final long startTime;
+
+    /* The start time should match any value.
+     * Typically, this is because the OS can not supply it.
+     * The process is known to exist but not the exact start time.
+     */
+    private final long STARTTIME_ANY = 0L;
+
+    /* The start time of a Process that does not exist. */
+    private final long STARTTIME_PROCESS_UNKNOWN = -1;
+
+    /**
      * Private constructor.  Instances are created by the {@code get(long)} factory.
      * @param pid the pid for this instance
      */
-    private ProcessHandleImpl(long pid) {
+    private ProcessHandleImpl(long pid, long startTime) {
         this.pid = pid;
+        this.startTime = startTime;
     }
 
     /**
@@ -173,17 +200,21 @@
         if (sm != null) {
             sm.checkPermission(new RuntimePermission("manageProcess"));
         }
-        return Optional.ofNullable(isAlive0(pid) ? new ProcessHandleImpl(pid) : null);
+        long start = isAlive0(pid);
+        return (start >= 0)
+                ? Optional.of(new ProcessHandleImpl(pid, start))
+                : Optional.empty();
     }
 
     /**
-     * Returns a ProcessHandle corresponding known to exist pid.
-     * Called from ProcessImpl, it does not perform a security check or check if the process is alive.
+     * Returns a ProcessHandle for an existing native process known to be alive.
+     * The startTime of the process is retrieved and stored in the ProcessHandle.
+     * It does not perform a security check since it is called from ProcessImpl.
      * @param pid of the known to exist process
      * @return a ProcessHandle corresponding to an existing Process instance
      */
-    static ProcessHandle getUnchecked(long pid) {
-        return new ProcessHandleImpl(pid);
+    static ProcessHandleImpl getInternal(long pid) {
+        return new ProcessHandleImpl(pid, isAlive0(pid));
     }
 
     /**
@@ -227,12 +258,12 @@
      * @throws SecurityException           if permission is not granted by the
      *                                     security policy
      */
-    static Optional<ProcessHandle> parent(long pid) {
+    public Optional<ProcessHandle> parent() {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             sm.checkPermission(new RuntimePermission("manageProcess"));
         }
-        long ppid = parent0(pid);
+        long ppid = parent0(pid, startTime);
         if (ppid <= 0) {
             return Optional.empty();
         }
@@ -242,9 +273,11 @@
     /**
      * Returns the parent of the native pid argument.
      *
+     * @param pid the process id
+     * @param startTime the startTime of the process
      * @return the parent of the native pid; if any, otherwise -1
      */
-    private static native long parent0(long pid);
+    private static native long parent0(long pid, long startTime);
 
     /**
      * Returns the number of pids filled in to the array.
@@ -252,37 +285,46 @@
      *      otherwise only direct child process pids are returned
      * @param pids an allocated long array to receive the pids
      * @param ppids an allocated long array to receive the parent pids; may be null
+     * @param starttimes an allocated long array to receive the child start times; may be null
      * @return if greater than or equals to zero is the number of pids in the array;
      *      if greater than the length of the arrays, the arrays are too small
      */
-    private static native int getProcessPids0(long pid, long[] pids, long[] ppids);
+    private static native int getProcessPids0(long pid, long[] pids,
+                                              long[] ppids, long[] starttimes);
 
     /**
      * Destroy the process for this ProcessHandle.
-     * @param pid the processs ID to destroy
+     * The native code checks the start time before sending the termination request.
+     *
      * @param force {@code true} if the process should be terminated forcibly;
      *     else {@code false} for a normal termination
      */
-    static void destroyProcess(long pid, boolean force) {
-        destroy0(pid, force);
+    boolean destroyProcess(boolean force) {
+        if (this.equals(current)) {
+            throw new IllegalStateException("destroy of current process not allowed");
+        }
+        return destroy0(pid, startTime, force);
     }
 
-    private static native boolean destroy0(long pid, boolean forcibly);
+    /**
+      * Signal the process to terminate.
+      * The process is signaled only if its start time matches the known start time.
+      *
+      * @param pid  process id to kill
+      * @param startTime the start time of the process
+      * @param forcibly true to forcibly terminate (SIGKILL vs SIGTERM)
+      * @return true if the process was signaled without error; false otherwise
+      */
+    private static native boolean destroy0(long pid, long startTime, boolean forcibly);
 
     @Override
     public boolean destroy() {
-        if (this.equals(current)) {
-            throw new IllegalStateException("destroy of current process not allowed");
-        }
-        return destroy0(getPid(), false);
+        return destroyProcess(false);
     }
 
     @Override
     public boolean destroyForcibly() {
-        if (this.equals(current)) {
-            throw new IllegalStateException("destroy of current process not allowed");
-        }
-        return destroy0(getPid(), true);
+        return destroyProcess(true);
     }
 
 
@@ -300,22 +342,20 @@
      */
     @Override
     public boolean isAlive() {
-        return isAlive0(pid);
+        long start = isAlive0(pid);
+        return (start >= 0 && (start == startTime || start == 0 || startTime == 0));
     }
 
     /**
-     * Returns true or false depending on whether the pid is alive.
-     * This must not reap the exitValue like the isAlive method above.
+     * Returns the process start time depending on whether the pid is alive.
+     * This must not reap the exitValue.
      *
      * @param pid the pid to check
-     * @return true or false
+     * @return the start time in milliseconds since 1970,
+     *         0 if the start time cannot be determined,
+     *         -1 if the pid does not exist.
      */
-    private static native boolean isAlive0(long pid);
-
-    @Override
-    public Optional<ProcessHandle> parent() {
-        return parent(pid);
-    }
+    private static native long isAlive0(long pid);
 
     @Override
     public Stream<ProcessHandle> children() {
@@ -336,11 +376,16 @@
         }
         int size = 100;
         long[] childpids = null;
+        long[] starttimes = null;
         while (childpids == null || size > childpids.length) {
             childpids = new long[size];
-            size = getProcessPids0(pid, childpids, null);
+            starttimes = new long[size];
+            size = getProcessPids0(pid, childpids, null, starttimes);
         }
-        return Arrays.stream(childpids, 0, size).mapToObj((id) -> new ProcessHandleImpl(id));
+
+        final long[] cpids = childpids;
+        final long[] stimes = starttimes;
+        return IntStream.range(0, size).mapToObj(i -> new ProcessHandleImpl(cpids[i], stimes[i]));
     }
 
     @Override
@@ -352,10 +397,12 @@
         int size = 100;
         long[] pids = null;
         long[] ppids = null;
+        long[] starttimes = null;
         while (pids == null || size > pids.length) {
             pids = new long[size];
             ppids = new long[size];
-            size = getProcessPids0(0, pids, ppids);
+            starttimes = new long[size];
+            size = getProcessPids0(0, pids, ppids, starttimes);
         }
 
         int next = 0;       // index of next process to check
@@ -368,13 +415,16 @@
                 if (ppids[i] == ppid) {
                     swap(pids, i, next);
                     swap(ppids, i, next);
+                    swap(starttimes, i, next);
                     next++;
                 }
             }
             ppid = pids[++count];   // pick up the next pid to scan for
         } while (count < next);
 
-        return Arrays.stream(pids, 0, count).mapToObj((id) -> new ProcessHandleImpl(id));
+        final long[] cpids = pids;
+        final long[] stimes = starttimes;
+        return IntStream.range(0, count).mapToObj(i -> new ProcessHandleImpl(cpids[i], stimes[i]));
     }
 
     // Swap two elements in an array
@@ -386,7 +436,7 @@
 
     @Override
     public ProcessHandle.Info info() {
-        return ProcessHandleImpl.Info.info(pid);
+        return ProcessHandleImpl.Info.info(pid, startTime);
     }
 
     @Override
@@ -406,8 +456,17 @@
 
     @Override
     public boolean equals(Object obj) {
-        return (obj instanceof ProcessHandleImpl) &&
-            (pid == ((ProcessHandleImpl) obj).pid);
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ProcessHandleImpl) {
+            ProcessHandleImpl other = (ProcessHandleImpl) obj;
+            return (pid == other.pid) &&
+                    (startTime == other.startTime
+                        || startTime == 0
+                        || other.startTime == 0);
+        }
+        return false;
     }
 
     /**
@@ -453,14 +512,24 @@
         /**
          * Returns the Info object with the fields from the process.
          * Whatever fields are provided by native are returned.
+         * If the startTime of the process does not match the provided
+         * startTime then an empty Info is returned.
          *
          * @param pid the native process identifier
+         * @param startTime the startTime of the process being queried
          * @return ProcessHandle.Info non-null; individual fields may be null
          *          or -1 if not available.
          */
-        public static ProcessHandle.Info info(long pid) {
+        public static ProcessHandle.Info info(long pid, long startTime) {
             Info info = new Info();
             info.info0(pid);
+            if (startTime != info.startTime) {
+                info.command = null;
+                info.arguments = null;
+                info.startTime = -1L;
+                info.totalTime = -1L;
+                info.user = null;
+            }
             return info;
         }
 
@@ -511,7 +580,7 @@
                 sb.append("args: ");
                 sb.append(Arrays.toString(arguments));
             }
-            if (startTime != -1) {
+            if (startTime > 0) {
                 if (sb.length() != 0) sb.append(", ");
                 sb.append("startTime: ");
                 sb.append(startInstant());
--- a/jdk/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c	Tue Jul 14 15:29:16 2015 -0400
+++ b/jdk/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c	Tue Jul 14 15:35:37 2015 -0400
@@ -38,6 +38,7 @@
 #include <signal.h>
 #include <stdlib.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 #include <limits.h>
 
@@ -55,8 +56,9 @@
 /*
  * Signatures for internal OS specific functions.
  */
-static pid_t parentPid(JNIEnv *env, pid_t pid);
-static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t pid);
+static pid_t getStatInfo(JNIEnv *env, pid_t pid,
+                                     jlong *totalTime, jlong* startTime,
+                                     uid_t *uid);
 static void getCmdlineInfo(JNIEnv *env, jobject jinfo, pid_t pid);
 
 extern jstring uidToUser(JNIEnv* env, uid_t uid);
@@ -86,9 +88,8 @@
  * Method:    initIDs
  * Signature: ()V
  */
-JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_initIDs
-  (JNIEnv *env, jclass clazz) {
-
+JNIEXPORT void JNICALL
+Java_java_lang_ProcessHandleImpl_00024Info_initIDs(JNIEnv *env, jclass clazz) {
     CHECK_NULL(ProcessHandleImpl_Info_commandID = (*env)->GetFieldID(env,
         clazz, "command", "Ljava/lang/String;"));
     CHECK_NULL(ProcessHandleImpl_Info_argumentsID = (*env)->GetFieldID(env,
@@ -99,25 +100,68 @@
         clazz, "startTime", "J"));
     CHECK_NULL(ProcessHandleImpl_Info_userID = (*env)->GetFieldID(env,
         clazz, "user", "Ljava/lang/String;"));
+}
+
+/**************************************************************
+ * Static method to initialize the ticks per second rate.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    initNative
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_java_lang_ProcessHandleImpl_initNative(JNIEnv *env, jclass clazz) {
     clock_ticks_per_second = sysconf(_SC_CLK_TCK);
 }
 
 /*
+ * Check if a process is alive.
+ * Return the start time (ms since 1970) if it is available.
+ * If the start time is not available return 0.
+ * If the pid is invalid, return -1.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    isAlive0
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL
+Java_java_lang_ProcessHandleImpl_isAlive0(JNIEnv *env, jobject obj, jlong jpid) {
+    pid_t pid = (pid_t) jpid;
+    jlong startTime = 0L;
+    jlong totalTime = 0L;
+    uid_t uid = -1;
+    pid_t ppid = getStatInfo(env, pid, &totalTime, &startTime, &uid);
+    return (ppid < 0) ? -1 : startTime;
+}
+
+/*
  * Returns the parent pid of the requested pid.
  *
  * Class:     java_lang_ProcessHandleImpl
  * Method:    parent0
  * Signature: (J)J
  */
-JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_parent0
-(JNIEnv *env, jobject obj, jlong jpid) {
+JNIEXPORT jlong JNICALL
+Java_java_lang_ProcessHandleImpl_parent0(JNIEnv *env,
+                                         jobject obj,
+                                         jlong jpid,
+                                         jlong startTime) {
     pid_t pid = (pid_t) jpid;
     pid_t ppid = -1;
 
     if (pid == getpid()) {
         ppid = getppid();
     } else {
-        ppid = parentPid(env, pid);
+        jlong start = 0L;
+        jlong total = 0L;
+        uid_t uid = -1;
+
+        pid_t ppid = getStatInfo(env, pid, &total, &start, &uid);
+        if (start != startTime
+            && start != 0
+            && startTime != 0) {
+            ppid = -1;
+        }
     }
     return (jlong) ppid;
 }
@@ -134,18 +178,24 @@
  * The number of pids is returned if they all fit.
  * If the array is too short, the desired length is returned.
  */
-JNIEXPORT jint JNICALL Java_java_lang_ProcessHandleImpl_getProcessPids0
-(JNIEnv *env, jclass clazz, jlong jpid,
-    jlongArray jarray, jlongArray jparentArray)
-{
+JNIEXPORT jint JNICALL
+Java_java_lang_ProcessHandleImpl_getProcessPids0(JNIEnv *env,
+                                                 jclass clazz,
+                                                 jlong jpid,
+                                                 jlongArray jarray,
+                                                 jlongArray jparentArray,
+                                                 jlongArray jstimesArray) {
     DIR* dir;
     struct dirent* ptr;
     pid_t pid = (pid_t) jpid;
-    size_t count = 0;
     jlong* pids = NULL;
     jlong* ppids = NULL;
-    size_t parentArraySize = 0;
-    size_t arraySize = 0;
+    jlong* stimes = NULL;
+    jsize parentArraySize = 0;
+    jsize arraySize = 0;
+    jsize stimesSize = 0;
+    jsize count = 0;
+    char procname[32];
 
     arraySize = (*env)->GetArrayLength(env, jarray);
     JNU_CHECK_EXCEPTION_RETURN(env, 0);
@@ -158,6 +208,15 @@
             return 0;
         }
     }
+    if (jstimesArray != NULL) {
+        stimesSize = (*env)->GetArrayLength(env, jstimesArray);
+        JNU_CHECK_EXCEPTION_RETURN(env, -1);
+
+        if (arraySize != stimesSize) {
+            JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
+            return 0;
+        }
+    }
 
     /*
      * To locate the children we scan /proc looking for files that have a
@@ -180,9 +239,18 @@
                 break;
             }
         }
+        if (jstimesArray != NULL) {
+            stimes  = (*env)->GetLongArrayElements(env, jstimesArray, NULL);
+            if (stimes == NULL) {
+                break;
+            }
+        }
 
         while ((ptr = readdir(dir)) != NULL) {
-            pid_t ppid;
+            pid_t ppid = 0;
+            jlong totalTime = 0L;
+            jlong startTime = 0L;
+            uid_t uid; // value unused
 
             /* skip files that aren't numbers */
             pid_t childpid = (pid_t) atoi(ptr->d_name);
@@ -190,20 +258,21 @@
                 continue;
             }
 
-            ppid = 0;
-            if (pid != 0 || jparentArray != NULL) {
-                // parentPid opens and reads /proc/pid/stat
-                ppid = parentPid(env, childpid);
-            }
-            if (pid == 0 || ppid == pid) {
+            // Read /proc/pid/stat and get the parent pid, and start time
+            ppid = getStatInfo(env, childpid, &totalTime, &startTime, &uid);
+            if (ppid >= 0 && (pid == 0 || ppid == pid)) {
                 if (count < arraySize) {
                     // Only store if it fits
                     pids[count] = (jlong) childpid;
 
                     if (ppids != NULL) {
-                        // Store the parentPid
+                        // Store the parent Pid
                         ppids[count] = (jlong) ppid;
                     }
+                    if (stimes != NULL) {
+                        // Store the process start time
+                        stimes[count] = startTime;
+                    }
                 }
                 count++; // Count to tabulate size needed
             }
@@ -216,45 +285,15 @@
     if (ppids != NULL) {
         (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
     }
+    if (stimes != NULL) {
+        (*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0);
+    }
 
     closedir(dir);
     // If more pids than array had size for; count will be greater than array size
     return count;
 }
 
-/*
- * Returns the parent pid of a given pid, or -1 if not found
- */
-static pid_t parentPid(JNIEnv *env, pid_t pid) {
-    FILE* fp;
-    pstatus_t pstatus;
-    int statlen;
-    char fn[32];
-    int i, p;
-    char* s;
-
-    /*
-     * Try to open /proc/%d/status
-     */
-    snprintf(fn, sizeof fn, "/proc/%d/status", pid);
-    fp = fopen(fn, "r");
-    if (fp == NULL) {
-        return -1;
-    }
-
-    /*
-     * The format is: pid (command) state ppid ...
-     * As the command could be anything we must find the right most
-     * ")" and then skip the white spaces that follow it.
-     */
-    statlen = fread(&pstatus, 1, (sizeof pstatus), fp);
-    fclose(fp);
-    if (statlen < 0) {
-        return -1;
-    }
-    return (pid_t) pstatus.pr_ppid;
-}
-
 /**************************************************************
  * Implementation of ProcessHandleImpl_Info native methods.
  */
@@ -266,93 +305,74 @@
  * Method:    info0
  * Signature: (J)V
  */
-JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_info0
-  (JNIEnv *env, jobject jinfo, jlong jpid) {
+JNIEXPORT void JNICALL
+Java_java_lang_ProcessHandleImpl_00024Info_info0(JNIEnv *env,
+                                                 jobject jinfo,
+                                                  jlong jpid) {
     pid_t pid = (pid_t) jpid;
-    getStatInfo(env, jinfo, pid);
+    jlong startTime = 0L;
+    jlong totalTime = 0L;
+    uid_t uid = -1;
+    pid_t ppid = getStatInfo(env, pid, &totalTime, &startTime, &uid);
+
     getCmdlineInfo(env, jinfo, pid);
+
+    if (ppid > 0) {
+        jstring str;
+        (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
+        JNU_CHECK_EXCEPTION(env);
+
+        (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, totalTime);
+        JNU_CHECK_EXCEPTION(env);
+
+        CHECK_NULL((str = uidToUser(env, uid)));
+        (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, str);
+        JNU_CHECK_EXCEPTION(env);
+    }
 }
 
 /**
- * Read /proc/<pid>/stat and fill in the fields of the Info object.
- * Gather the user and system times.
+ * Read /proc/<pid>/status and return the ppid, total cputime and start time.
+ * Return: -1 is fail;  zero is unknown; >  0 is parent pid
  */
-static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
+static pid_t getStatInfo(JNIEnv *env, pid_t pid,
+                                      jlong *totalTime, jlong* startTime,
+                                      uid_t* uid) {
     FILE* fp;
-    pstatus_t pstatus;
-    struct stat stat_buf;
-    int ret;
+    psinfo_t psinfo;
     char fn[32];
-    int i, p;
-    char* s;
-    jlong totalTime;
+    int ret;
 
     /*
      * Try to open /proc/%d/status
      */
-    snprintf(fn, sizeof fn, "/proc/%d/status", pid);
-
-    if (stat(fn, &stat_buf) < 0) {
-        return;
-    }
-
+    snprintf(fn, sizeof fn, "/proc/%d/psinfo", pid);
     fp = fopen(fn, "r");
     if (fp == NULL) {
-        return;
+        return -1;
     }
 
-    ret = fread(&pstatus, 1, (sizeof pstatus), fp);
+    ret = fread(&psinfo, 1, (sizeof psinfo), fp);
     fclose(fp);
-    if (ret < 0) {
-        return;
+    if (ret < (sizeof psinfo)) {
+        return -1;
     }
 
-    totalTime = pstatus.pr_utime.tv_sec * 1000000000L + pstatus.pr_utime.tv_nsec +
-                pstatus.pr_stime.tv_sec * 1000000000L + pstatus.pr_stime.tv_nsec;
+    *totalTime = psinfo.pr_time.tv_sec * 1000000000L + psinfo.pr_time.tv_nsec;
 
-    (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, totalTime);
-    JNU_CHECK_EXCEPTION(env);
+    *startTime = psinfo.pr_start.tv_sec * (jlong)1000 +
+                 psinfo.pr_start.tv_nsec / 1000000;
+
+    *uid = psinfo.pr_uid;
+
+    return (pid_t) psinfo.pr_ppid;
 }
 
 static void getCmdlineInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
-    FILE* fp;
-    psinfo_t psinfo;
-    int ret;
     char fn[32];
     char exePath[PATH_MAX];
-    int i, p;
-    jlong startTime;
-    jobjectArray cmdArray;
     jstring str = NULL;
-
-    /*
-     * try to open /proc/%d/psinfo
-     */
-    snprintf(fn, sizeof fn, "/proc/%d/psinfo", pid);
-    fp = fopen(fn, "r");
-    if (fp == NULL) {
-        return;
-    }
-
-    /*
-     * The format is: pid (command) state ppid ...
-     * As the command could be anything we must find the right most
-     * ")" and then skip the white spaces that follow it.
-     */
-    ret = fread(&psinfo, 1, (sizeof psinfo), fp);
-    fclose(fp);
-    if (ret < 0) {
-        return;
-    }
-
-    CHECK_NULL((str = uidToUser(env, psinfo.pr_uid)));
-    (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, str);
-    JNU_CHECK_EXCEPTION(env);
-
-    startTime = (jlong)psinfo.pr_start.tv_sec * (jlong)1000 +
-                (jlong)psinfo.pr_start.tv_nsec / 1000000;
-    (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
-    JNU_CHECK_EXCEPTION(env);
+    int ret;
 
     /*
      * The path to the executable command is the link in /proc/<pid>/paths/a.out.
--- a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java	Tue Jul 14 15:29:16 2015 -0400
+++ b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java	Tue Jul 14 15:35:37 2015 -0400
@@ -64,7 +64,7 @@
     static final boolean SUPPORTS_NORMAL_TERMINATION = true;
 
     private final int pid;
-    private final ProcessHandle processHandle;
+    private final ProcessHandleImpl processHandle;
     private int exitcode;
     private boolean hasExited;
 
@@ -320,7 +320,7 @@
                           dir,
                           fds,
                           redirectErrorStream);
-        processHandle = ProcessHandleImpl.getUnchecked(pid);
+        processHandle = ProcessHandleImpl.getInternal(pid);
 
         try {
             doPrivileged((PrivilegedExceptionAction<Void>) () -> {
@@ -505,7 +505,7 @@
                 // soon, so this is quite safe.
                 synchronized (this) {
                     if (!hasExited)
-                        ProcessHandleImpl.destroyProcess(pid, force);
+                        processHandle.destroyProcess(force);
                 }
                 try { stdin.close();  } catch (IOException ignored) {}
                 try { stdout.close(); } catch (IOException ignored) {}
@@ -521,7 +521,7 @@
                 // soon, so this is quite safe.
                 synchronized (this) {
                     if (!hasExited)
-                        ProcessHandleImpl.destroyProcess(pid, force);
+                        processHandle.destroyProcess(force);
                     try {
                         stdin.close();
                         if (stdout_inner_stream != null)
@@ -542,7 +542,7 @@
     @Override
     public CompletableFuture<Process> onExit() {
         return ProcessHandleImpl.completion(pid, false)
-                .handleAsync((exitStatus, unusedThrowable) -> {
+                .handleAsync((unusedExitStatus, unusedThrowable) -> {
                     boolean interrupted = false;
                     while (true) {
                         // Ensure that the concurrent task setting the exit status has completed
--- a/jdk/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c	Tue Jul 14 15:29:16 2015 -0400
+++ b/jdk/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c	Tue Jul 14 15:35:37 2015 -0400
@@ -53,7 +53,6 @@
  * - destroy0(pid, force)
  */
 
-
 #ifndef WIFEXITED
 #define WIFEXITED(status) (((status)&0xFF) == 0)
 #endif
@@ -82,15 +81,20 @@
   } while((_result == NULL) && (errno == EINTR)); \
 } while(0)
 
+#ifdef __solaris__
+    #define STAT_FILE "/proc/%d/status"
+#else
+    #define STAT_FILE "/proc/%d/stat"
+#endif
 
 /* Block until a child process exits and return its exit code.
  * Note, can only be called once for any given pid if reapStatus = true.
  */
 JNIEXPORT jint JNICALL
 Java_java_lang_ProcessHandleImpl_waitForProcessExit0(JNIEnv* env,
-                                              jclass junk,
-                                              jlong jpid,
-                                              jboolean reapStatus)
+                                                     jclass junk,
+                                                     jlong jpid,
+                                                     jboolean reapStatus)
 {
     pid_t pid = (pid_t)jpid;
     errno = 0;
@@ -178,34 +182,32 @@
  * Method:    getCurrentPid0
  * Signature: ()J
  */
-JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_getCurrentPid0
-(JNIEnv *env, jclass clazz) {
+JNIEXPORT jlong JNICALL
+Java_java_lang_ProcessHandleImpl_getCurrentPid0(JNIEnv *env, jclass clazz) {
     pid_t pid = getpid();
     return (jlong) pid;
 }
 
 /*
  * Class:     java_lang_ProcessHandleImpl
- * Method:    isAlive0
- * Signature: (J)Z
- */
-JNIEXPORT jboolean JNICALL Java_java_lang_ProcessHandleImpl_isAlive0
-(JNIEnv *env, jobject obj, jlong jpid) {
-    pid_t pid = (pid_t) jpid;
-    return (kill(pid, 0) < 0) ? JNI_FALSE : JNI_TRUE;
-}
-
-/*
- * Class:     java_lang_ProcessHandleImpl
  * Method:    destroy0
  * Signature: (Z)Z
  */
-JNIEXPORT jboolean JNICALL Java_java_lang_ProcessHandleImpl_destroy0
-(JNIEnv *env, jobject obj, jlong jpid, jboolean force) {
+JNIEXPORT jboolean JNICALL
+Java_java_lang_ProcessHandleImpl_destroy0(JNIEnv *env,
+                                          jobject obj,
+                                          jlong jpid,
+                                          jlong startTime,
+                                          jboolean force) {
     pid_t pid = (pid_t) jpid;
     int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;
-    return (kill(pid, sig) >= 0);
+    jlong start = Java_java_lang_ProcessHandleImpl_isAlive0(env, obj, jpid);
 
+    if (start == startTime || start == 0 || startTime == 0) {
+        return (kill(pid, sig) < 0) ? JNI_FALSE : JNI_TRUE;
+    } else {
+        return JNI_FALSE;
+    }
 }
 
 /**
@@ -260,11 +262,8 @@
 /*
  * Signatures for internal OS specific functions.
  */
-static pid_t parentPid(JNIEnv *env, pid_t pid);
-static jint getChildren(JNIEnv *env, jlong jpid,
-                        jlongArray array, jlongArray jparentArray);
-
-static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t pid);
+static pid_t getStatInfo(JNIEnv *env, pid_t pid,
+                                     jlong *totalTime, jlong* startTime);
 static void getCmdlineInfo(JNIEnv *env, pid_t pid, jobject jinfo);
 static long long getBoottime(JNIEnv *env);
 
@@ -298,8 +297,8 @@
  * Method:    initIDs
  * Signature: ()V
  */
-JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_initIDs
-  (JNIEnv *env, jclass clazz) {
+JNIEXPORT void JNICALL
+Java_java_lang_ProcessHandleImpl_00024Info_initIDs(JNIEnv *env, jclass clazz) {
 
     CHECK_NULL(ProcessHandleImpl_Info_commandID = (*env)->GetFieldID(env,
         clazz, "command", "Ljava/lang/String;"));
@@ -311,61 +310,98 @@
         clazz, "startTime", "J"));
     CHECK_NULL(ProcessHandleImpl_Info_userID = (*env)->GetFieldID(env,
         clazz, "user", "Ljava/lang/String;"));
+}
+
+/**************************************************************
+ * Static method to initialize the ticks per second rate.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    initNative
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_java_lang_ProcessHandleImpl_initNative(JNIEnv *env, jclass clazz) {
     clock_ticks_per_second = sysconf(_SC_CLK_TCK);
     bootTime_ms = getBoottime(env);
 }
 
 /*
+ * Check if a process is alive.
+ * Return the start time (ms since 1970) if it is available.
+ * If the start time is not available return 0.
+ * If the pid is invalid, return -1.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    isAlive0
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL
+Java_java_lang_ProcessHandleImpl_isAlive0(JNIEnv *env, jobject obj, jlong jpid) {
+    pid_t pid = (pid_t) jpid;
+    jlong startTime = 0L;
+    jlong totalTime = 0L;
+    pid_t ppid = getStatInfo(env, pid, &totalTime, &startTime);
+    return (ppid <= 0) ? -1 : startTime;
+}
+
+/*
  * Returns the parent pid of the requested pid.
+ * The start time of the process must match (or be ANY).
  *
  * Class:     java_lang_ProcessHandleImpl
  * Method:    parent0
  * Signature: (J)J
  */
-JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_parent0
-(JNIEnv *env, jobject obj, jlong jpid) {
+JNIEXPORT jlong JNICALL
+Java_java_lang_ProcessHandleImpl_parent0(JNIEnv *env,
+                                        jobject obj,
+                                        jlong jpid,
+                                        jlong startTime) {
     pid_t pid = (pid_t) jpid;
-    pid_t ppid = -1;
+    pid_t ppid;
 
     pid_t mypid = getpid();
     if (pid == mypid) {
         ppid = getppid();
     } else {
-        ppid = parentPid(env, pid);
+        jlong start = 0L;;
+        jlong total = 0L;        // unused
+        ppid = getStatInfo(env, pid, &total, &start);
+        if (start != startTime && start != 0 && startTime != 0) {
+            ppid = -1;
+        }
     }
     return (jlong) ppid;
 }
 
 /*
  * Returns the children of the requested pid and optionally each parent.
- *
+ * Reads /proc and accumulates any process who parent pid matches.
+ * The resulting pids are stored into the array of longs.
+ * The number of pids is returned if they all fit.
+ * If the array is too short, the negative of the desired length is returned. *
  * Class:     java_lang_ProcessHandleImpl
  * Method:    getChildPids
  * Signature: (J[J[J)I
  */
-JNIEXPORT jint JNICALL Java_java_lang_ProcessHandleImpl_getProcessPids0
-(JNIEnv *env, jclass clazz, jlong jpid,
-    jlongArray jarray, jlongArray jparentArray) {
-    return getChildren(env, jpid, jarray, jparentArray);
-}
+JNIEXPORT jint JNICALL
+Java_java_lang_ProcessHandleImpl_getProcessPids0(JNIEnv *env,
+                                                 jclass clazz,
+                                                 jlong jpid,
+                                                 jlongArray jarray,
+                                                 jlongArray jparentArray,
+                                                 jlongArray jstimesArray) {
 
-/*
- * Reads /proc and accumulates any process who parent pid matches.
- * The resulting pids are stored into the array of longs.
- * The number of pids is returned if they all fit.
- * If the array is too short, the negative of the desired length is returned.
- */
-static jint getChildren(JNIEnv *env, jlong jpid,
-    jlongArray jarray, jlongArray jparentArray) {
     DIR* dir;
     struct dirent* ptr;
     pid_t pid = (pid_t) jpid;
-    pid_t ppid = 0;
-    size_t count = 0;
     jlong* pids = NULL;
     jlong* ppids = NULL;
-    size_t parentArraySize = 0;
-    size_t arraySize = 0;
+    jlong* stimes = NULL;
+    jsize parentArraySize = 0;
+    jsize arraySize = 0;
+    jsize stimesSize = 0;
+    jsize count = 0;
 
     arraySize = (*env)->GetArrayLength(env, jarray);
     JNU_CHECK_EXCEPTION_RETURN(env, -1);
@@ -378,6 +414,15 @@
             return 0;
         }
     }
+    if (jstimesArray != NULL) {
+        stimesSize = (*env)->GetArrayLength(env, jstimesArray);
+        JNU_CHECK_EXCEPTION_RETURN(env, -1);
+
+        if (arraySize != stimesSize) {
+            JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
+            return 0;
+        }
+    }
 
     /*
      * To locate the children we scan /proc looking for files that have a
@@ -385,7 +430,7 @@
      */
     if ((dir = opendir("/proc")) == NULL) {
         JNU_ThrowByNameWithLastError(env,
-            "java/lang/Runtime", "Unable to open /proc");
+            "java/lang/RuntimeException", "Unable to open /proc");
         return -1;
     }
 
@@ -400,20 +445,26 @@
                 break;
             }
         }
+        if (jstimesArray != NULL) {
+            stimes  = (*env)->GetLongArrayElements(env, jstimesArray, NULL);
+            if (stimes == NULL) {
+                break;
+            }
+        }
 
         while ((ptr = readdir(dir)) != NULL) {
+            pid_t ppid = 0;
+            jlong totalTime = 0L;
+            jlong startTime = 0L;
+
             /* skip files that aren't numbers */
             pid_t childpid = (pid_t) atoi(ptr->d_name);
             if ((int) childpid <= 0) {
                 continue;
             }
-
-            ppid = 0;
-            if (pid != 0 || jparentArray != NULL) {
-                // parentPid opens and reads /proc/pid/stat
-                ppid = parentPid(env, childpid);
-            }
-            if (pid == 0 || ppid == pid) {
+            // Read /proc/pid/stat and get the parent pid, and start time
+            ppid = getStatInfo(env, childpid, &totalTime, &startTime);
+            if (ppid > 0 && (pid == 0 || ppid == pid)) {
                 if (count < arraySize) {
                     // Only store if it fits
                     pids[count] = (jlong) childpid;
@@ -422,6 +473,10 @@
                         // Store the parentPid
                         ppids[count] = (jlong) ppid;
                     }
+                    if (stimes != NULL) {
+                        // Store the process start time
+                        stimes[count] = startTime;
+                    }
                 }
                 count++; // Count to tabulate size needed
             }
@@ -434,56 +489,15 @@
     if (ppids != NULL) {
         (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
     }
+    if (stimes != NULL) {
+        (*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0);
+    }
 
     closedir(dir);
     // If more pids than array had size for; count will be greater than array size
     return count;
 }
 
-/*
- * Returns the parent pid of a given pid, or -1 if not found
- */
-static pid_t parentPid(JNIEnv *env, pid_t pid) {
-    char state;
-    FILE* fp;
-    char stat[2048];
-    int statlen;
-    char fn[32];
-    int i, p;
-    char* s;
-
-    /*
-     * try to open /proc/%d/stat
-     */
-    snprintf(fn, sizeof fn, "/proc/%d/stat", pid);
-    fp = fopen(fn, "r");
-    if (fp == NULL) {
-        return -1;
-    }
-
-    /*
-     * The format is: pid (command) state ppid ...
-     * As the command could be anything we must find the right most
-     * ")" and then skip the white spaces that follow it.
-     */
-    statlen = fread(stat, 1, (sizeof stat - 1), fp);
-    fclose(fp);
-    if (statlen < 0) {
-        return -1;
-    }
-
-    stat[statlen] = '\0';
-    s = strrchr(stat, ')');
-    if (s == NULL) {
-        return -1;
-    }
-    do s++; while (isspace(*s));
-    i = sscanf(s, "%c %d", &state, &p);
-    if (i != 2) {
-        return (pid_t)-1;
-    }
-    return (pid_t) p;
-}
 
 /**************************************************************
  * Implementation of ProcessHandleImpl_Info native methods.
@@ -496,49 +510,51 @@
  * Method:    info0
  * Signature: (JLjava/lang/ProcessHandle/Info;)I
  */
-JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_info0
-  (JNIEnv *env, jobject jinfo, jlong jpid) {
+JNIEXPORT void JNICALL
+Java_java_lang_ProcessHandleImpl_00024Info_info0(JNIEnv *env,
+                                                 jobject jinfo,
+                                                 jlong jpid) {
     pid_t pid = (pid_t) jpid;
-    getStatInfo(env, jinfo, (pid_t)pid);
-    getCmdlineInfo(env, pid, jinfo);
+    pid_t ppid;
+    jlong totalTime = 0L;
+    jlong startTime = -1L;
+
+    ppid = getStatInfo(env, pid,  &totalTime, &startTime);
+    if (ppid > 0) {
+        (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, totalTime);
+        JNU_CHECK_EXCEPTION(env);
+
+        (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
+        JNU_CHECK_EXCEPTION(env);
+
+        getCmdlineInfo(env, pid, jinfo);
+    }
 }
 
 /**
- * Read /proc/<pid>/stat and fill in the fields of the Info object.
- * The executable name, plus the user, system, and start times are gathered.
+ * Read /proc/<pid>/stat and return the ppid, total cputime and start time.
+ * -1 is fail;  zero is unknown; >  0 is parent pid
  */
-static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
-    char state;
+static pid_t getStatInfo(JNIEnv *env, pid_t pid,
+                                     jlong *totalTime, jlong* startTime) {
     FILE* fp;
     char buffer[2048];
-    struct stat stat_buf;
     int statlen;
     char fn[32];
-    int i, ppid = -2;
     char* s;
-    char *cmd;
-    jstring name = NULL;
-    unsigned long userTime = 0;             // clock tics
-    unsigned long totalTime = 0;            // clock tics
-    jlong total = 0;                        // nano seconds
-    unsigned long long startTime = 0;       // microseconds
+    int parentPid;
+    long unsigned int utime = 0;      // clock tics
+    long unsigned int stime = 0;      // clock tics
+    long long unsigned int start = 0; // microseconds
 
     /*
      * Try to stat and then open /proc/%d/stat
      */
-    snprintf(fn, sizeof fn, "/proc/%d/stat", pid);
-
-    if (stat(fn, &stat_buf) < 0) {
-        return;
-    }
-
-    CHECK_NULL((name = uidToUser(env, stat_buf.st_uid)));
-    (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, name);
-    JNU_CHECK_EXCEPTION(env);
+    snprintf(fn, sizeof fn, STAT_FILE, pid);
 
     fp = fopen(fn, "r");
     if (fp == NULL) {
-        return;
+        return -1;              // fail, no such /proc/pid/stat
     }
 
     /*
@@ -549,38 +565,34 @@
     statlen = fread(buffer, 1, (sizeof buffer - 1), fp);
     fclose(fp);
     if (statlen < 0) {
-        return;
+        return 0;               // parent pid is not available
     }
 
     buffer[statlen] = '\0';
     s = strchr(buffer, '(');
     if (s == NULL) {
-        return;
+        return 0;               // parent pid is not available
     }
     // Found start of command, skip to end
     s++;
     s = strrchr(s, ')');
     if (s == NULL) {
-        return;
+        return 0;               // parent pid is not available
     }
     s++;
 
     // Scan the needed fields from status, retaining only ppid(4),
     // utime (14), stime(15), starttime(22)
-    i = sscanf(s, " %c %d %*d %*d %*d %*d %*d %*u %*u %*u %*u %lu %lu %*d %*d %*d %*d %*d %*d %llu",
-            &state, &ppid, &userTime, &totalTime, &startTime);
-    if (i != 5) {
-        return;              // not all values parsed; return error
+    if (4 != sscanf(s, " %*c %d %*d %*d %*d %*d %*d %*u %*u %*u %*u %lu %lu %*d %*d %*d %*d %*d %*d %llu",
+            &parentPid, &utime, &stime, &start)) {
+        return 0;              // not all values parsed; return error
     }
 
-    total = (userTime + totalTime) * (jlong)(1000000000 / clock_ticks_per_second);
-
-    startTime = bootTime_ms + ((startTime * 1000) / clock_ticks_per_second);
+    *totalTime = (utime + stime) * (jlong)(1000000000 / clock_ticks_per_second);
 
-    (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, total);
-    JNU_CHECK_EXCEPTION(env);
-    (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
-    JNU_CHECK_EXCEPTION(env);
+    *startTime = bootTime_ms + ((start * 1000) / clock_ticks_per_second);
+
+    return parentPid;
 }
 
 /**
@@ -632,6 +644,7 @@
     char *cmdline = NULL, *cmdEnd;  // used for command line args and exe
     jstring cmdexe = NULL;
     char fn[32];
+    struct stat stat_buf;
 
     /*
      * Try to open /proc/%d/cmdline
@@ -679,6 +692,14 @@
         if (fillArgArray(env, jinfo, i, cmdline, cmdEnd, cmdexe) < 0) {
             break;
         }
+
+        // Get and store the user name
+        if (fstat(fd, &stat_buf) == 0) {
+            jstring name = uidToUser(env, stat_buf.st_uid);
+            if (name != NULL) {
+                (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, name);
+            }
+        }
     } while (0);
 
     if (cmdline != NULL) {
--- a/jdk/src/java.base/windows/classes/java/lang/ProcessImpl.java	Tue Jul 14 15:29:16 2015 -0400
+++ b/jdk/src/java.base/windows/classes/java/lang/ProcessImpl.java	Tue Jul 14 15:35:37 2015 -0400
@@ -34,7 +34,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.lang.Override;
 import java.lang.ProcessBuilder.Redirect;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
@@ -391,7 +390,7 @@
 
         handle = create(cmdstr, envblock, path,
                         stdHandles, redirectErrorStream);
-        processHandle = ProcessHandleImpl.getUnchecked(getProcessId0(handle));
+        processHandle = ProcessHandleImpl.getInternal(getProcessId0(handle));
 
         java.security.AccessController.doPrivileged(
         new java.security.PrivilegedAction<Void>() {
--- a/jdk/src/java.base/windows/native/libjava/ProcessHandleImpl_win.c	Tue Jul 14 15:29:16 2015 -0400
+++ b/jdk/src/java.base/windows/native/libjava/ProcessHandleImpl_win.c	Tue Jul 14 15:35:37 2015 -0400
@@ -64,8 +64,8 @@
  * Method:    initIDs
  * Signature: ()V
  */
-JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_initIDs
-  (JNIEnv *env, jclass clazz) {
+JNIEXPORT void JNICALL
+Java_java_lang_ProcessHandleImpl_00024Info_initIDs(JNIEnv *env, jclass clazz) {
 
     CHECK_NULL(ProcessHandleImpl_Info_commandID = (*env)->GetFieldID(env,
         clazz, "command", "Ljava/lang/String;"));
@@ -78,15 +78,25 @@
     CHECK_NULL(ProcessHandleImpl_Info_userID = (*env)->GetFieldID(env,
         clazz, "user", "Ljava/lang/String;"));
 }
+/**************************************************************
+ * Static method to initialize native.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    initNative
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_java_lang_ProcessHandleImpl_initNative(JNIEnv *env, jclass clazz) {
+}
 
 /*
  * Block until a child process exits and return its exit code.
  */
 JNIEXPORT jint JNICALL
 Java_java_lang_ProcessHandleImpl_waitForProcessExit0(JNIEnv* env,
-                                              jclass junk,
-                                              jlong jpid,
-                                              jboolean reapStatus) {
+                                                     jclass junk,
+                                                     jlong jpid,
+                                                     jboolean reapStatus) {
     DWORD pid = (DWORD)jpid;
     DWORD exitValue = -1;
     HANDLE handle = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION,
@@ -97,7 +107,7 @@
     do {
         if (!GetExitCodeProcess(handle, &exitValue)) {
             JNU_ThrowByNameWithLastError(env,
-                "java/lang/Runtime", "GetExitCodeProcess");
+                "java/lang/RuntimeException", "GetExitCodeProcess");
             break;
         }
         if (exitValue == STILL_ACTIVE) {
@@ -110,7 +120,7 @@
                                        INFINITE) /* Wait forever */
                 == WAIT_FAILED) {
                 JNU_ThrowByNameWithLastError(env,
-                    "java/lang/Runtime", "WaitForMultipleObjects");
+                    "java/lang/RuntimeException", "WaitForMultipleObjects");
                 break;
             }
         }
@@ -126,8 +136,8 @@
  * Method:    getCurrentPid0
  * Signature: ()J
  */
-JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_getCurrentPid0
-(JNIEnv *env, jclass clazz) {
+JNIEXPORT jlong JNICALL
+Java_java_lang_ProcessHandleImpl_getCurrentPid0(JNIEnv *env, jclass clazz) {
     DWORD  pid = GetCurrentProcessId();
     return (jlong)pid;
 }
@@ -139,13 +149,21 @@
  * Method:    parent0
  * Signature: (J)J
  */
-JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_parent0
-(JNIEnv *env, jclass clazz, jlong jpid) {
-
-    DWORD ppid = -1;
+JNIEXPORT jlong JNICALL
+Java_java_lang_ProcessHandleImpl_parent0(JNIEnv *env,
+                                         jclass clazz,
+                                         jlong jpid,
+                                         jlong startTime) {
+    DWORD ppid = 0;
     DWORD wpid = (DWORD)jpid;
     PROCESSENTRY32 pe32;
     HANDLE hProcessSnap;
+    jlong start;
+
+    start = Java_java_lang_ProcessHandleImpl_isAlive0(env, clazz, jpid);
+    if (start != startTime && start != 0 && startTime != 0) {
+        return -1;
+    }
 
     // Take a snapshot of all processes in the system.
     hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
@@ -181,18 +199,23 @@
  * Method:    getChildPids
  * Signature: (J[J[J)I
  */
-JNIEXPORT jint JNICALL Java_java_lang_ProcessHandleImpl_getProcessPids0
-(JNIEnv *env, jclass clazz, jlong jpid,
-    jlongArray jarray, jlongArray jparentArray) {
-
+JNIEXPORT jint JNICALL
+Java_java_lang_ProcessHandleImpl_getProcessPids0(JNIEnv *env,
+                                                 jclass clazz,
+                                                 jlong jpid,
+                                                 jlongArray jarray,
+                                                 jlongArray jparentArray,
+                                                 jlongArray jstimesArray) {
     HANDLE hProcessSnap;
     PROCESSENTRY32 pe32;
     DWORD ppid = (DWORD)jpid;
-    size_t count = 0;
     jlong* pids = NULL;
     jlong* ppids = NULL;
-    size_t parentArraySize = 0;
-    size_t arraySize = 0;
+    jlong* stimes = NULL;
+    jsize parentArraySize = 0;
+    jsize arraySize = 0;
+    jsize stimesSize = 0;
+    jsize count = 0;
 
     arraySize = (*env)->GetArrayLength(env, jarray);
     JNU_CHECK_EXCEPTION_RETURN(env, -1);
@@ -205,6 +228,15 @@
             return 0;
         }
     }
+    if (jstimesArray != NULL) {
+        stimesSize = (*env)->GetArrayLength(env, jstimesArray);
+        JNU_CHECK_EXCEPTION_RETURN(env, -1);
+
+        if (arraySize != stimesSize) {
+            JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
+            return 0;
+        }
+    }
 
     // Take a snapshot of all processes in the system.
     hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
@@ -228,6 +260,12 @@
                     break;
                 }
             }
+            if (jstimesArray != NULL) {
+                stimes  = (*env)->GetLongArrayElements(env, jstimesArray, NULL);
+                if (stimes == NULL) {
+                    break;
+                }
+            }
             // Now walk the snapshot of processes, and
             // save information about each process in turn
             do {
@@ -236,11 +274,17 @@
                     && (pe32.th32ParentProcessID == ppid))) {
                     if (count < arraySize) {
                         // Only store if it fits
-                        pids[count] = (jlong)pe32.th32ProcessID;
+                        pids[count] = (jlong) pe32.th32ProcessID;
                         if (ppids != NULL) {
                             // Store the parentPid
                             ppids[count] = (jlong) pe32.th32ParentProcessID;
                         }
+                        if (stimes != NULL) {
+                            // Store the process start time
+                            stimes[count] =
+                                    Java_java_lang_ProcessHandleImpl_isAlive0(env,
+                                            clazz, (jlong) pe32.th32ProcessID);
+                        }
                     }
                     count++;    // Count to tabulate size needed
                 }
@@ -253,6 +297,9 @@
         if (ppids != NULL) {
             (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
         }
+        if (stimes != NULL) {
+            (*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0);
+        }
     } else {
         JNU_ThrowByName(env,
             "java/lang/RuntimeException", "snapshot not available");
@@ -263,48 +310,6 @@
     return (jint)count;
 }
 
-/*
- * Destroy the process.
- *
- * Class:     java_lang_ProcessHandleImpl
- * Method:    destroy0
- * Signature: (Z)V
- */
-JNIEXPORT jboolean JNICALL Java_java_lang_ProcessHandleImpl_destroy0
-(JNIEnv *env, jclass clazz, jlong jpid, jboolean force) {
-    DWORD pid = (DWORD)jpid;
-    HANDLE handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
-    if (handle != NULL) {
-        TerminateProcess(handle, 1);
-        CloseHandle(handle);         // Ignore return code
-        return JNI_TRUE;
-    }
-    return JNI_FALSE;
-}
-
-/*
- * Class:     java_lang_ProcessHandleImpl
- * Method:    isAlive0
- * Signature: (J)Z
- */
-JNIEXPORT jboolean JNICALL Java_java_lang_ProcessHandleImpl_isAlive0
-(JNIEnv *env, jclass clazz, jlong jpid) {
-    DWORD pid = (DWORD)jpid;
-
-    jboolean ret = JNI_FALSE;
-    HANDLE handle =
-        OpenProcess(THREAD_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION,
-                    FALSE, pid);
-    if (handle != NULL) {
-        DWORD dwExitStatus;
-
-        GetExitCodeProcess(handle, &dwExitStatus);
-        CloseHandle(handle); // Ignore return code
-        ret = (dwExitStatus == STILL_ACTIVE);
-    }
-    return ret;
-}
-
 /**
  * Assemble a 64 bit value from two 32 bit values.
  */
@@ -315,14 +320,90 @@
 }
 
 /*
+ * Get the start time in ms from 1970 from the handle.
+ */
+static jlong getStartTime(HANDLE handle) {
+    FILETIME CreationTime, ExitTime, KernelTime, UserTime;
+    if (GetProcessTimes(handle, &CreationTime, &ExitTime, &KernelTime, &UserTime)) {
+        jlong start = jlong_from(CreationTime.dwHighDateTime,
+                                 CreationTime.dwLowDateTime) / 10000;
+        start -= 11644473600000L; // Rebase Epoch from 1601 to 1970
+        return start;
+    } else {
+        return 0;
+    }
+}
+
+/*
+ * Destroy the process.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    destroy0
+ * Signature: (Z)V
+ */
+JNIEXPORT jboolean JNICALL
+Java_java_lang_ProcessHandleImpl_destroy0(JNIEnv *env,
+                                          jclass clazz,
+                                          jlong jpid,
+                                          jlong startTime,
+                                          jboolean force) {
+    DWORD pid = (DWORD)jpid;
+    jboolean ret = JNI_FALSE;
+    HANDLE handle = OpenProcess(PROCESS_TERMINATE | THREAD_QUERY_INFORMATION
+                                | PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
+    if (handle != NULL) {
+        jlong start = getStartTime(handle);
+        if (start == startTime || startTime == 0) {
+            ret = TerminateProcess(handle, 1) ? JNI_TRUE : JNI_FALSE;
+        }
+        CloseHandle(handle);         // Ignore return code
+    }
+    return ret;
+}
+
+ /*
+ * Check if a process is alive.
+ * Return the start time (ms since 1970) if it is available.
+ * If the start time is not available return 0.
+ * If the pid is invalid, return -1.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    isAlive0
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL
+Java_java_lang_ProcessHandleImpl_isAlive0(JNIEnv *env, jclass clazz, jlong jpid) {
+    DWORD pid = (DWORD)jpid;
+
+    jlong ret = -1;
+    HANDLE handle =
+        OpenProcess(THREAD_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION,
+                    FALSE, pid);
+    if (handle != NULL) {
+        DWORD dwExitStatus;
+
+        GetExitCodeProcess(handle, &dwExitStatus);
+        if (dwExitStatus == STILL_ACTIVE) {
+            ret = getStartTime(handle);
+        } else {
+            ret = -1;
+        }
+        CloseHandle(handle); // Ignore return code
+   }
+   return ret;
+}
+
+/*
  * Fill in the Info object from the OS information about the process.
  *
  * Class:     java_lang_ProcessHandleImpl
  * Method:    info0
  * Signature: (J)V
  */
-JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_info0
-  (JNIEnv *env, jobject jinfo, jlong jpid) {
+JNIEXPORT void JNICALL
+Java_java_lang_ProcessHandleImpl_00024Info_info0(JNIEnv *env,
+                                                 jobject jinfo,
+                                                 jlong jpid) {
     DWORD pid = (DWORD)jpid;
     int ret = 0;
     HANDLE handle =