jdk/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c
changeset 31682 c19dcf5e0b6d
parent 30899 d2408e757489
child 32209 24bb680a1609
equal deleted inserted replaced
31681:e9a9d5b369bc 31682:c19dcf5e0b6d
    51  * - waitForProcessExit0(pid, reap)
    51  * - waitForProcessExit0(pid, reap)
    52  * - getCurrentPid0()
    52  * - getCurrentPid0()
    53  * - destroy0(pid, force)
    53  * - destroy0(pid, force)
    54  */
    54  */
    55 
    55 
    56 
       
    57 #ifndef WIFEXITED
    56 #ifndef WIFEXITED
    58 #define WIFEXITED(status) (((status)&0xFF) == 0)
    57 #define WIFEXITED(status) (((status)&0xFF) == 0)
    59 #endif
    58 #endif
    60 
    59 
    61 #ifndef WEXITSTATUS
    60 #ifndef WEXITSTATUS
    80   do { \
    79   do { \
    81     _result = _cmd; \
    80     _result = _cmd; \
    82   } while((_result == NULL) && (errno == EINTR)); \
    81   } while((_result == NULL) && (errno == EINTR)); \
    83 } while(0)
    82 } while(0)
    84 
    83 
       
    84 #ifdef __solaris__
       
    85     #define STAT_FILE "/proc/%d/status"
       
    86 #else
       
    87     #define STAT_FILE "/proc/%d/stat"
       
    88 #endif
    85 
    89 
    86 /* Block until a child process exits and return its exit code.
    90 /* Block until a child process exits and return its exit code.
    87  * Note, can only be called once for any given pid if reapStatus = true.
    91  * Note, can only be called once for any given pid if reapStatus = true.
    88  */
    92  */
    89 JNIEXPORT jint JNICALL
    93 JNIEXPORT jint JNICALL
    90 Java_java_lang_ProcessHandleImpl_waitForProcessExit0(JNIEnv* env,
    94 Java_java_lang_ProcessHandleImpl_waitForProcessExit0(JNIEnv* env,
    91                                               jclass junk,
    95                                                      jclass junk,
    92                                               jlong jpid,
    96                                                      jlong jpid,
    93                                               jboolean reapStatus)
    97                                                      jboolean reapStatus)
    94 {
    98 {
    95     pid_t pid = (pid_t)jpid;
    99     pid_t pid = (pid_t)jpid;
    96     errno = 0;
   100     errno = 0;
    97 
   101 
    98     if (reapStatus != JNI_FALSE) {
   102     if (reapStatus != JNI_FALSE) {
   176 /*
   180 /*
   177  * Class:     java_lang_ProcessHandleImpl
   181  * Class:     java_lang_ProcessHandleImpl
   178  * Method:    getCurrentPid0
   182  * Method:    getCurrentPid0
   179  * Signature: ()J
   183  * Signature: ()J
   180  */
   184  */
   181 JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_getCurrentPid0
   185 JNIEXPORT jlong JNICALL
   182 (JNIEnv *env, jclass clazz) {
   186 Java_java_lang_ProcessHandleImpl_getCurrentPid0(JNIEnv *env, jclass clazz) {
   183     pid_t pid = getpid();
   187     pid_t pid = getpid();
   184     return (jlong) pid;
   188     return (jlong) pid;
   185 }
       
   186 
       
   187 /*
       
   188  * Class:     java_lang_ProcessHandleImpl
       
   189  * Method:    isAlive0
       
   190  * Signature: (J)Z
       
   191  */
       
   192 JNIEXPORT jboolean JNICALL Java_java_lang_ProcessHandleImpl_isAlive0
       
   193 (JNIEnv *env, jobject obj, jlong jpid) {
       
   194     pid_t pid = (pid_t) jpid;
       
   195     return (kill(pid, 0) < 0) ? JNI_FALSE : JNI_TRUE;
       
   196 }
   189 }
   197 
   190 
   198 /*
   191 /*
   199  * Class:     java_lang_ProcessHandleImpl
   192  * Class:     java_lang_ProcessHandleImpl
   200  * Method:    destroy0
   193  * Method:    destroy0
   201  * Signature: (Z)Z
   194  * Signature: (Z)Z
   202  */
   195  */
   203 JNIEXPORT jboolean JNICALL Java_java_lang_ProcessHandleImpl_destroy0
   196 JNIEXPORT jboolean JNICALL
   204 (JNIEnv *env, jobject obj, jlong jpid, jboolean force) {
   197 Java_java_lang_ProcessHandleImpl_destroy0(JNIEnv *env,
       
   198                                           jobject obj,
       
   199                                           jlong jpid,
       
   200                                           jlong startTime,
       
   201                                           jboolean force) {
   205     pid_t pid = (pid_t) jpid;
   202     pid_t pid = (pid_t) jpid;
   206     int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;
   203     int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;
   207     return (kill(pid, sig) >= 0);
   204     jlong start = Java_java_lang_ProcessHandleImpl_isAlive0(env, obj, jpid);
   208 
   205 
       
   206     if (start == startTime || start == 0 || startTime == 0) {
       
   207         return (kill(pid, sig) < 0) ? JNI_FALSE : JNI_TRUE;
       
   208     } else {
       
   209         return JNI_FALSE;
       
   210     }
   209 }
   211 }
   210 
   212 
   211 /**
   213 /**
   212  * Size of password or group entry when not available via sysconf
   214  * Size of password or group entry when not available via sysconf
   213  */
   215  */
   258 #if defined(__linux__) || defined(__AIX__)
   260 #if defined(__linux__) || defined(__AIX__)
   259 
   261 
   260 /*
   262 /*
   261  * Signatures for internal OS specific functions.
   263  * Signatures for internal OS specific functions.
   262  */
   264  */
   263 static pid_t parentPid(JNIEnv *env, pid_t pid);
   265 static pid_t getStatInfo(JNIEnv *env, pid_t pid,
   264 static jint getChildren(JNIEnv *env, jlong jpid,
   266                                      jlong *totalTime, jlong* startTime);
   265                         jlongArray array, jlongArray jparentArray);
       
   266 
       
   267 static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t pid);
       
   268 static void getCmdlineInfo(JNIEnv *env, pid_t pid, jobject jinfo);
   267 static void getCmdlineInfo(JNIEnv *env, pid_t pid, jobject jinfo);
   269 static long long getBoottime(JNIEnv *env);
   268 static long long getBoottime(JNIEnv *env);
   270 
   269 
   271 jstring uidToUser(JNIEnv* env, uid_t uid);
   270 jstring uidToUser(JNIEnv* env, uid_t uid);
   272 
   271 
   296  *
   295  *
   297  * Class:     java_lang_ProcessHandleImpl_Info
   296  * Class:     java_lang_ProcessHandleImpl_Info
   298  * Method:    initIDs
   297  * Method:    initIDs
   299  * Signature: ()V
   298  * Signature: ()V
   300  */
   299  */
   301 JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_initIDs
   300 JNIEXPORT void JNICALL
   302   (JNIEnv *env, jclass clazz) {
   301 Java_java_lang_ProcessHandleImpl_00024Info_initIDs(JNIEnv *env, jclass clazz) {
   303 
   302 
   304     CHECK_NULL(ProcessHandleImpl_Info_commandID = (*env)->GetFieldID(env,
   303     CHECK_NULL(ProcessHandleImpl_Info_commandID = (*env)->GetFieldID(env,
   305         clazz, "command", "Ljava/lang/String;"));
   304         clazz, "command", "Ljava/lang/String;"));
   306     CHECK_NULL(ProcessHandleImpl_Info_argumentsID = (*env)->GetFieldID(env,
   305     CHECK_NULL(ProcessHandleImpl_Info_argumentsID = (*env)->GetFieldID(env,
   307         clazz, "arguments", "[Ljava/lang/String;"));
   306         clazz, "arguments", "[Ljava/lang/String;"));
   309         clazz, "totalTime", "J"));
   308         clazz, "totalTime", "J"));
   310     CHECK_NULL(ProcessHandleImpl_Info_startTimeID = (*env)->GetFieldID(env,
   309     CHECK_NULL(ProcessHandleImpl_Info_startTimeID = (*env)->GetFieldID(env,
   311         clazz, "startTime", "J"));
   310         clazz, "startTime", "J"));
   312     CHECK_NULL(ProcessHandleImpl_Info_userID = (*env)->GetFieldID(env,
   311     CHECK_NULL(ProcessHandleImpl_Info_userID = (*env)->GetFieldID(env,
   313         clazz, "user", "Ljava/lang/String;"));
   312         clazz, "user", "Ljava/lang/String;"));
       
   313 }
       
   314 
       
   315 /**************************************************************
       
   316  * Static method to initialize the ticks per second rate.
       
   317  *
       
   318  * Class:     java_lang_ProcessHandleImpl
       
   319  * Method:    initNative
       
   320  * Signature: ()V
       
   321  */
       
   322 JNIEXPORT void JNICALL
       
   323 Java_java_lang_ProcessHandleImpl_initNative(JNIEnv *env, jclass clazz) {
   314     clock_ticks_per_second = sysconf(_SC_CLK_TCK);
   324     clock_ticks_per_second = sysconf(_SC_CLK_TCK);
   315     bootTime_ms = getBoottime(env);
   325     bootTime_ms = getBoottime(env);
   316 }
   326 }
   317 
   327 
   318 /*
   328 /*
       
   329  * Check if a process is alive.
       
   330  * Return the start time (ms since 1970) if it is available.
       
   331  * If the start time is not available return 0.
       
   332  * If the pid is invalid, return -1.
       
   333  *
       
   334  * Class:     java_lang_ProcessHandleImpl
       
   335  * Method:    isAlive0
       
   336  * Signature: (J)J
       
   337  */
       
   338 JNIEXPORT jlong JNICALL
       
   339 Java_java_lang_ProcessHandleImpl_isAlive0(JNIEnv *env, jobject obj, jlong jpid) {
       
   340     pid_t pid = (pid_t) jpid;
       
   341     jlong startTime = 0L;
       
   342     jlong totalTime = 0L;
       
   343     pid_t ppid = getStatInfo(env, pid, &totalTime, &startTime);
       
   344     return (ppid <= 0) ? -1 : startTime;
       
   345 }
       
   346 
       
   347 /*
   319  * Returns the parent pid of the requested pid.
   348  * Returns the parent pid of the requested pid.
       
   349  * The start time of the process must match (or be ANY).
   320  *
   350  *
   321  * Class:     java_lang_ProcessHandleImpl
   351  * Class:     java_lang_ProcessHandleImpl
   322  * Method:    parent0
   352  * Method:    parent0
   323  * Signature: (J)J
   353  * Signature: (J)J
   324  */
   354  */
   325 JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_parent0
   355 JNIEXPORT jlong JNICALL
   326 (JNIEnv *env, jobject obj, jlong jpid) {
   356 Java_java_lang_ProcessHandleImpl_parent0(JNIEnv *env,
       
   357                                         jobject obj,
       
   358                                         jlong jpid,
       
   359                                         jlong startTime) {
   327     pid_t pid = (pid_t) jpid;
   360     pid_t pid = (pid_t) jpid;
   328     pid_t ppid = -1;
   361     pid_t ppid;
   329 
   362 
   330     pid_t mypid = getpid();
   363     pid_t mypid = getpid();
   331     if (pid == mypid) {
   364     if (pid == mypid) {
   332         ppid = getppid();
   365         ppid = getppid();
   333     } else {
   366     } else {
   334         ppid = parentPid(env, pid);
   367         jlong start = 0L;;
       
   368         jlong total = 0L;        // unused
       
   369         ppid = getStatInfo(env, pid, &total, &start);
       
   370         if (start != startTime && start != 0 && startTime != 0) {
       
   371             ppid = -1;
       
   372         }
   335     }
   373     }
   336     return (jlong) ppid;
   374     return (jlong) ppid;
   337 }
   375 }
   338 
   376 
   339 /*
   377 /*
   340  * Returns the children of the requested pid and optionally each parent.
   378  * Returns the children of the requested pid and optionally each parent.
   341  *
   379  * Reads /proc and accumulates any process who parent pid matches.
       
   380  * The resulting pids are stored into the array of longs.
       
   381  * The number of pids is returned if they all fit.
       
   382  * If the array is too short, the negative of the desired length is returned. *
   342  * Class:     java_lang_ProcessHandleImpl
   383  * Class:     java_lang_ProcessHandleImpl
   343  * Method:    getChildPids
   384  * Method:    getChildPids
   344  * Signature: (J[J[J)I
   385  * Signature: (J[J[J)I
   345  */
   386  */
   346 JNIEXPORT jint JNICALL Java_java_lang_ProcessHandleImpl_getProcessPids0
   387 JNIEXPORT jint JNICALL
   347 (JNIEnv *env, jclass clazz, jlong jpid,
   388 Java_java_lang_ProcessHandleImpl_getProcessPids0(JNIEnv *env,
   348     jlongArray jarray, jlongArray jparentArray) {
   389                                                  jclass clazz,
   349     return getChildren(env, jpid, jarray, jparentArray);
   390                                                  jlong jpid,
   350 }
   391                                                  jlongArray jarray,
   351 
   392                                                  jlongArray jparentArray,
   352 /*
   393                                                  jlongArray jstimesArray) {
   353  * Reads /proc and accumulates any process who parent pid matches.
   394 
   354  * The resulting pids are stored into the array of longs.
       
   355  * The number of pids is returned if they all fit.
       
   356  * If the array is too short, the negative of the desired length is returned.
       
   357  */
       
   358 static jint getChildren(JNIEnv *env, jlong jpid,
       
   359     jlongArray jarray, jlongArray jparentArray) {
       
   360     DIR* dir;
   395     DIR* dir;
   361     struct dirent* ptr;
   396     struct dirent* ptr;
   362     pid_t pid = (pid_t) jpid;
   397     pid_t pid = (pid_t) jpid;
   363     pid_t ppid = 0;
       
   364     size_t count = 0;
       
   365     jlong* pids = NULL;
   398     jlong* pids = NULL;
   366     jlong* ppids = NULL;
   399     jlong* ppids = NULL;
   367     size_t parentArraySize = 0;
   400     jlong* stimes = NULL;
   368     size_t arraySize = 0;
   401     jsize parentArraySize = 0;
       
   402     jsize arraySize = 0;
       
   403     jsize stimesSize = 0;
       
   404     jsize count = 0;
   369 
   405 
   370     arraySize = (*env)->GetArrayLength(env, jarray);
   406     arraySize = (*env)->GetArrayLength(env, jarray);
   371     JNU_CHECK_EXCEPTION_RETURN(env, -1);
   407     JNU_CHECK_EXCEPTION_RETURN(env, -1);
   372     if (jparentArray != NULL) {
   408     if (jparentArray != NULL) {
   373         parentArraySize = (*env)->GetArrayLength(env, jparentArray);
   409         parentArraySize = (*env)->GetArrayLength(env, jparentArray);
   374         JNU_CHECK_EXCEPTION_RETURN(env, -1);
   410         JNU_CHECK_EXCEPTION_RETURN(env, -1);
   375 
   411 
   376         if (arraySize != parentArraySize) {
   412         if (arraySize != parentArraySize) {
       
   413             JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
       
   414             return 0;
       
   415         }
       
   416     }
       
   417     if (jstimesArray != NULL) {
       
   418         stimesSize = (*env)->GetArrayLength(env, jstimesArray);
       
   419         JNU_CHECK_EXCEPTION_RETURN(env, -1);
       
   420 
       
   421         if (arraySize != stimesSize) {
   377             JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
   422             JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
   378             return 0;
   423             return 0;
   379         }
   424         }
   380     }
   425     }
   381 
   426 
   383      * To locate the children we scan /proc looking for files that have a
   428      * To locate the children we scan /proc looking for files that have a
   384      * position integer as a filename.
   429      * position integer as a filename.
   385      */
   430      */
   386     if ((dir = opendir("/proc")) == NULL) {
   431     if ((dir = opendir("/proc")) == NULL) {
   387         JNU_ThrowByNameWithLastError(env,
   432         JNU_ThrowByNameWithLastError(env,
   388             "java/lang/Runtime", "Unable to open /proc");
   433             "java/lang/RuntimeException", "Unable to open /proc");
   389         return -1;
   434         return -1;
   390     }
   435     }
   391 
   436 
   392     do { // Block to break out of on Exception
   437     do { // Block to break out of on Exception
   393         pids = (*env)->GetLongArrayElements(env, jarray, NULL);
   438         pids = (*env)->GetLongArrayElements(env, jarray, NULL);
   398             ppids  = (*env)->GetLongArrayElements(env, jparentArray, NULL);
   443             ppids  = (*env)->GetLongArrayElements(env, jparentArray, NULL);
   399             if (ppids == NULL) {
   444             if (ppids == NULL) {
   400                 break;
   445                 break;
   401             }
   446             }
   402         }
   447         }
       
   448         if (jstimesArray != NULL) {
       
   449             stimes  = (*env)->GetLongArrayElements(env, jstimesArray, NULL);
       
   450             if (stimes == NULL) {
       
   451                 break;
       
   452             }
       
   453         }
   403 
   454 
   404         while ((ptr = readdir(dir)) != NULL) {
   455         while ((ptr = readdir(dir)) != NULL) {
       
   456             pid_t ppid = 0;
       
   457             jlong totalTime = 0L;
       
   458             jlong startTime = 0L;
       
   459 
   405             /* skip files that aren't numbers */
   460             /* skip files that aren't numbers */
   406             pid_t childpid = (pid_t) atoi(ptr->d_name);
   461             pid_t childpid = (pid_t) atoi(ptr->d_name);
   407             if ((int) childpid <= 0) {
   462             if ((int) childpid <= 0) {
   408                 continue;
   463                 continue;
   409             }
   464             }
   410 
   465             // Read /proc/pid/stat and get the parent pid, and start time
   411             ppid = 0;
   466             ppid = getStatInfo(env, childpid, &totalTime, &startTime);
   412             if (pid != 0 || jparentArray != NULL) {
   467             if (ppid > 0 && (pid == 0 || ppid == pid)) {
   413                 // parentPid opens and reads /proc/pid/stat
       
   414                 ppid = parentPid(env, childpid);
       
   415             }
       
   416             if (pid == 0 || ppid == pid) {
       
   417                 if (count < arraySize) {
   468                 if (count < arraySize) {
   418                     // Only store if it fits
   469                     // Only store if it fits
   419                     pids[count] = (jlong) childpid;
   470                     pids[count] = (jlong) childpid;
   420 
   471 
   421                     if (ppids != NULL) {
   472                     if (ppids != NULL) {
   422                         // Store the parentPid
   473                         // Store the parentPid
   423                         ppids[count] = (jlong) ppid;
   474                         ppids[count] = (jlong) ppid;
   424                     }
   475                     }
       
   476                     if (stimes != NULL) {
       
   477                         // Store the process start time
       
   478                         stimes[count] = startTime;
       
   479                     }
   425                 }
   480                 }
   426                 count++; // Count to tabulate size needed
   481                 count++; // Count to tabulate size needed
   427             }
   482             }
   428         }
   483         }
   429     } while (0);
   484     } while (0);
   432         (*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
   487         (*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
   433     }
   488     }
   434     if (ppids != NULL) {
   489     if (ppids != NULL) {
   435         (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
   490         (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
   436     }
   491     }
       
   492     if (stimes != NULL) {
       
   493         (*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0);
       
   494     }
   437 
   495 
   438     closedir(dir);
   496     closedir(dir);
   439     // If more pids than array had size for; count will be greater than array size
   497     // If more pids than array had size for; count will be greater than array size
   440     return count;
   498     return count;
   441 }
   499 }
   442 
   500 
   443 /*
       
   444  * Returns the parent pid of a given pid, or -1 if not found
       
   445  */
       
   446 static pid_t parentPid(JNIEnv *env, pid_t pid) {
       
   447     char state;
       
   448     FILE* fp;
       
   449     char stat[2048];
       
   450     int statlen;
       
   451     char fn[32];
       
   452     int i, p;
       
   453     char* s;
       
   454 
       
   455     /*
       
   456      * try to open /proc/%d/stat
       
   457      */
       
   458     snprintf(fn, sizeof fn, "/proc/%d/stat", pid);
       
   459     fp = fopen(fn, "r");
       
   460     if (fp == NULL) {
       
   461         return -1;
       
   462     }
       
   463 
       
   464     /*
       
   465      * The format is: pid (command) state ppid ...
       
   466      * As the command could be anything we must find the right most
       
   467      * ")" and then skip the white spaces that follow it.
       
   468      */
       
   469     statlen = fread(stat, 1, (sizeof stat - 1), fp);
       
   470     fclose(fp);
       
   471     if (statlen < 0) {
       
   472         return -1;
       
   473     }
       
   474 
       
   475     stat[statlen] = '\0';
       
   476     s = strrchr(stat, ')');
       
   477     if (s == NULL) {
       
   478         return -1;
       
   479     }
       
   480     do s++; while (isspace(*s));
       
   481     i = sscanf(s, "%c %d", &state, &p);
       
   482     if (i != 2) {
       
   483         return (pid_t)-1;
       
   484     }
       
   485     return (pid_t) p;
       
   486 }
       
   487 
   501 
   488 /**************************************************************
   502 /**************************************************************
   489  * Implementation of ProcessHandleImpl_Info native methods.
   503  * Implementation of ProcessHandleImpl_Info native methods.
   490  */
   504  */
   491 
   505 
   494  *
   508  *
   495  * Class:     java_lang_ProcessHandleImpl_Info
   509  * Class:     java_lang_ProcessHandleImpl_Info
   496  * Method:    info0
   510  * Method:    info0
   497  * Signature: (JLjava/lang/ProcessHandle/Info;)I
   511  * Signature: (JLjava/lang/ProcessHandle/Info;)I
   498  */
   512  */
   499 JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_info0
   513 JNIEXPORT void JNICALL
   500   (JNIEnv *env, jobject jinfo, jlong jpid) {
   514 Java_java_lang_ProcessHandleImpl_00024Info_info0(JNIEnv *env,
       
   515                                                  jobject jinfo,
       
   516                                                  jlong jpid) {
   501     pid_t pid = (pid_t) jpid;
   517     pid_t pid = (pid_t) jpid;
   502     getStatInfo(env, jinfo, (pid_t)pid);
   518     pid_t ppid;
   503     getCmdlineInfo(env, pid, jinfo);
   519     jlong totalTime = 0L;
       
   520     jlong startTime = -1L;
       
   521 
       
   522     ppid = getStatInfo(env, pid,  &totalTime, &startTime);
       
   523     if (ppid > 0) {
       
   524         (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, totalTime);
       
   525         JNU_CHECK_EXCEPTION(env);
       
   526 
       
   527         (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
       
   528         JNU_CHECK_EXCEPTION(env);
       
   529 
       
   530         getCmdlineInfo(env, pid, jinfo);
       
   531     }
   504 }
   532 }
   505 
   533 
   506 /**
   534 /**
   507  * Read /proc/<pid>/stat and fill in the fields of the Info object.
   535  * Read /proc/<pid>/stat and return the ppid, total cputime and start time.
   508  * The executable name, plus the user, system, and start times are gathered.
   536  * -1 is fail;  zero is unknown; >  0 is parent pid
   509  */
   537  */
   510 static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
   538 static pid_t getStatInfo(JNIEnv *env, pid_t pid,
   511     char state;
   539                                      jlong *totalTime, jlong* startTime) {
   512     FILE* fp;
   540     FILE* fp;
   513     char buffer[2048];
   541     char buffer[2048];
   514     struct stat stat_buf;
       
   515     int statlen;
   542     int statlen;
   516     char fn[32];
   543     char fn[32];
   517     int i, ppid = -2;
       
   518     char* s;
   544     char* s;
   519     char *cmd;
   545     int parentPid;
   520     jstring name = NULL;
   546     long unsigned int utime = 0;      // clock tics
   521     unsigned long userTime = 0;             // clock tics
   547     long unsigned int stime = 0;      // clock tics
   522     unsigned long totalTime = 0;            // clock tics
   548     long long unsigned int start = 0; // microseconds
   523     jlong total = 0;                        // nano seconds
       
   524     unsigned long long startTime = 0;       // microseconds
       
   525 
   549 
   526     /*
   550     /*
   527      * Try to stat and then open /proc/%d/stat
   551      * Try to stat and then open /proc/%d/stat
   528      */
   552      */
   529     snprintf(fn, sizeof fn, "/proc/%d/stat", pid);
   553     snprintf(fn, sizeof fn, STAT_FILE, pid);
   530 
       
   531     if (stat(fn, &stat_buf) < 0) {
       
   532         return;
       
   533     }
       
   534 
       
   535     CHECK_NULL((name = uidToUser(env, stat_buf.st_uid)));
       
   536     (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, name);
       
   537     JNU_CHECK_EXCEPTION(env);
       
   538 
   554 
   539     fp = fopen(fn, "r");
   555     fp = fopen(fn, "r");
   540     if (fp == NULL) {
   556     if (fp == NULL) {
   541         return;
   557         return -1;              // fail, no such /proc/pid/stat
   542     }
   558     }
   543 
   559 
   544     /*
   560     /*
   545      * The format is: pid (command) state ppid ...
   561      * The format is: pid (command) state ppid ...
   546      * As the command could be anything we must find the right most
   562      * As the command could be anything we must find the right most
   547      * ")" and then skip the white spaces that follow it.
   563      * ")" and then skip the white spaces that follow it.
   548      */
   564      */
   549     statlen = fread(buffer, 1, (sizeof buffer - 1), fp);
   565     statlen = fread(buffer, 1, (sizeof buffer - 1), fp);
   550     fclose(fp);
   566     fclose(fp);
   551     if (statlen < 0) {
   567     if (statlen < 0) {
   552         return;
   568         return 0;               // parent pid is not available
   553     }
   569     }
   554 
   570 
   555     buffer[statlen] = '\0';
   571     buffer[statlen] = '\0';
   556     s = strchr(buffer, '(');
   572     s = strchr(buffer, '(');
   557     if (s == NULL) {
   573     if (s == NULL) {
   558         return;
   574         return 0;               // parent pid is not available
   559     }
   575     }
   560     // Found start of command, skip to end
   576     // Found start of command, skip to end
   561     s++;
   577     s++;
   562     s = strrchr(s, ')');
   578     s = strrchr(s, ')');
   563     if (s == NULL) {
   579     if (s == NULL) {
   564         return;
   580         return 0;               // parent pid is not available
   565     }
   581     }
   566     s++;
   582     s++;
   567 
   583 
   568     // Scan the needed fields from status, retaining only ppid(4),
   584     // Scan the needed fields from status, retaining only ppid(4),
   569     // utime (14), stime(15), starttime(22)
   585     // utime (14), stime(15), starttime(22)
   570     i = sscanf(s, " %c %d %*d %*d %*d %*d %*d %*u %*u %*u %*u %lu %lu %*d %*d %*d %*d %*d %*d %llu",
   586     if (4 != sscanf(s, " %*c %d %*d %*d %*d %*d %*d %*u %*u %*u %*u %lu %lu %*d %*d %*d %*d %*d %*d %llu",
   571             &state, &ppid, &userTime, &totalTime, &startTime);
   587             &parentPid, &utime, &stime, &start)) {
   572     if (i != 5) {
   588         return 0;              // not all values parsed; return error
   573         return;              // not all values parsed; return error
   589     }
   574     }
   590 
   575 
   591     *totalTime = (utime + stime) * (jlong)(1000000000 / clock_ticks_per_second);
   576     total = (userTime + totalTime) * (jlong)(1000000000 / clock_ticks_per_second);
   592 
   577 
   593     *startTime = bootTime_ms + ((start * 1000) / clock_ticks_per_second);
   578     startTime = bootTime_ms + ((startTime * 1000) / clock_ticks_per_second);
   594 
   579 
   595     return parentPid;
   580     (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, total);
       
   581     JNU_CHECK_EXCEPTION(env);
       
   582     (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
       
   583     JNU_CHECK_EXCEPTION(env);
       
   584 }
   596 }
   585 
   597 
   586 /**
   598 /**
   587  * Construct the argument array by parsing the arguments from the sequence
   599  * Construct the argument array by parsing the arguments from the sequence
   588  * of arguments. The zero'th arg is the command executable
   600  * of arguments. The zero'th arg is the command executable
   630     int fd;
   642     int fd;
   631     int cmdlen = 0;
   643     int cmdlen = 0;
   632     char *cmdline = NULL, *cmdEnd;  // used for command line args and exe
   644     char *cmdline = NULL, *cmdEnd;  // used for command line args and exe
   633     jstring cmdexe = NULL;
   645     jstring cmdexe = NULL;
   634     char fn[32];
   646     char fn[32];
       
   647     struct stat stat_buf;
   635 
   648 
   636     /*
   649     /*
   637      * Try to open /proc/%d/cmdline
   650      * Try to open /proc/%d/cmdline
   638      */
   651      */
   639     snprintf(fn, sizeof fn, "/proc/%d/cmdline", pid);
   652     snprintf(fn, sizeof fn, "/proc/%d/cmdline", pid);
   676             s += strnlen(s, (cmdEnd - s)) + 1;
   689             s += strnlen(s, (cmdEnd - s)) + 1;
   677         }
   690         }
   678 
   691 
   679         if (fillArgArray(env, jinfo, i, cmdline, cmdEnd, cmdexe) < 0) {
   692         if (fillArgArray(env, jinfo, i, cmdline, cmdEnd, cmdexe) < 0) {
   680             break;
   693             break;
       
   694         }
       
   695 
       
   696         // Get and store the user name
       
   697         if (fstat(fd, &stat_buf) == 0) {
       
   698             jstring name = uidToUser(env, stat_buf.st_uid);
       
   699             if (name != NULL) {
       
   700                 (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, name);
       
   701             }
   681         }
   702         }
   682     } while (0);
   703     } while (0);
   683 
   704 
   684     if (cmdline != NULL) {
   705     if (cmdline != NULL) {
   685         free(cmdline);
   706         free(cmdline);