< prev index next >

src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c

Print this page
rev 12414 : 8131168: Refactor ProcessHandleImpl_*.c and add implememtation for AIX


  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "jni.h"
  27 #include "jni_util.h"
  28 #include "java_lang_ProcessHandleImpl.h"
  29 #include "java_lang_ProcessHandleImpl_Info.h"
  30 


  31 #include <stdio.h>
  32 #include <errno.h>
  33 #include <signal.h>
  34 #include <stdlib.h>
  35 #include <unistd.h>
  36 #include <string.h>
  37 
  38 #include <sys/sysctl.h>
  39 
  40 /**
  41  * Implementations of ProcessHandleImpl functions for MAC OS X;
  42  * are NOT common to all Unix variants.
  43  */
  44 
  45 static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t pid);
  46 static void getCmdlineInfo(JNIEnv *env, jobject jinfo, pid_t pid);
  47 
  48 /*
  49  * Common Unix function to lookup the uid and return the user name.
  50  */
  51 extern jstring uidToUser(JNIEnv* env, uid_t uid);
  52 
  53 /* Field id for jString 'command' in java.lang.ProcessHandle.Info */
  54 static jfieldID ProcessHandleImpl_Info_commandID;
  55 
  56 /* Field id for jString[] 'arguments' in java.lang.ProcessHandle.Info */
  57 static jfieldID ProcessHandleImpl_Info_argumentsID;
  58 
  59 /* Field id for jlong 'totalTime' in java.lang.ProcessHandle.Info */
  60 static jfieldID ProcessHandleImpl_Info_totalTimeID;
  61 
  62 /* Field id for jlong 'startTime' in java.lang.ProcessHandle.Info */
  63 static jfieldID ProcessHandleImpl_Info_startTimeID;
  64 
  65 /* Field id for jString 'user' in java.lang.ProcessHandleImpl.Info */
  66 static jfieldID ProcessHandleImpl_Info_userID;
  67 
  68 /* static value for clock ticks per second. */
  69 static long clock_ticks_per_second;
  70 
  71 /**************************************************************
  72  * Static method to initialize field IDs and the ticks per second rate.
  73  *
  74  * Class:     java_lang_ProcessHandleImpl_Info
  75  * Method:    initIDs
  76  * Signature: ()V
  77  */
  78 JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_initIDs
  79   (JNIEnv *env, jclass clazz) {
  80 
  81     CHECK_NULL(ProcessHandleImpl_Info_commandID =
  82             (*env)->GetFieldID(env, clazz, "command", "Ljava/lang/String;"));
  83     CHECK_NULL(ProcessHandleImpl_Info_argumentsID =
  84             (*env)->GetFieldID(env, clazz, "arguments", "[Ljava/lang/String;"));
  85     CHECK_NULL(ProcessHandleImpl_Info_totalTimeID =
  86             (*env)->GetFieldID(env, clazz, "totalTime", "J"));
  87     CHECK_NULL(ProcessHandleImpl_Info_startTimeID =
  88             (*env)->GetFieldID(env, clazz, "startTime", "J"));
  89     CHECK_NULL(ProcessHandleImpl_Info_userID =
  90             (*env)->GetFieldID(env, clazz, "user", "Ljava/lang/String;"));
  91     clock_ticks_per_second = sysconf(_SC_CLK_TCK);
  92 }
  93 
  94 /*
  95  * Returns the parent pid of the requested pid.
  96  *
  97  * Class:     java_lang_ProcessHandleImpl
  98  * Method:    parent0
  99  * Signature: (J)J
 100  */
 101 JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_parent0
 102 (JNIEnv *env, jobject obj, jlong jpid) {
 103     pid_t pid = (pid_t) jpid;
 104     pid_t ppid = -1;
 105 
 106     if (pid == getpid()) {
 107         ppid = getppid();
 108     } else {
 109         const pid_t pid = (pid_t) jpid;
 110         struct kinfo_proc kp;
 111         size_t bufSize = sizeof kp;
 112 
 113         // Read the process info for the specific pid
 114         int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
 115         if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) < 0) {
 116             JNU_ThrowByNameWithLastError(env,
 117                 "java/lang/RuntimeException", "sysctl failed");
 118             return -1;
 119         }
 120         ppid = (bufSize > 0 && kp.kp_proc.p_pid == pid) ? kp.kp_eproc.e_ppid : -1;
 121     }
 122     return (jlong) ppid;
 123 }
 124 
 125 /*
 126  * Returns the children of the requested pid and optionally each parent.
 127  *
 128  * Class:     java_lang_ProcessHandleImpl
 129  * Method:    getProcessPids0
 130  * Signature: (J[J[J)I
 131  *
 132  * Use sysctl to accumulate any process whose parent pid is zero or matches.
 133  * The resulting pids are stored into the array of longs.
 134  * The number of pids is returned if they all fit.
 135  * If the parentArray is non-null, store the parent pid.
 136  * If the array is too short, excess pids are not stored and
 137  * the desired length is returned.
 138  */
 139 JNIEXPORT jint JNICALL Java_java_lang_ProcessHandleImpl_getProcessPids0
 140 (JNIEnv *env, jclass clazz, jlong jpid,
 141     jlongArray jarray, jlongArray jparentArray)
 142 {
 143     size_t count = 0;
 144     jlong* pids = NULL;
 145     jlong* ppids = NULL;
 146     size_t parentArraySize = 0;
 147     size_t arraySize = 0;
 148     size_t bufSize = 0;
 149     pid_t pid = (pid_t) jpid;
 150 
 151     arraySize = (*env)->GetArrayLength(env, jarray);
 152     JNU_CHECK_EXCEPTION_RETURN(env, -1);
 153     if (jparentArray != NULL) {
 154         parentArraySize = (*env)->GetArrayLength(env, jparentArray);
 155         JNU_CHECK_EXCEPTION_RETURN(env, -1);
 156 
 157         if (arraySize != parentArraySize) {
 158             JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
 159             return 0;
 160         }
 161     }
 162 


 210                         ppids[count] = (jlong) kp->kp_eproc.e_ppid;
 211                     }
 212                 }
 213                 count++; // Count to tabulate size needed
 214             }
 215         }
 216     } while (0);
 217 
 218     if (pids != NULL) {
 219         (*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
 220     }
 221     if (ppids != NULL) {
 222         (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
 223     }
 224 
 225     free(buffer);
 226     // If more pids than array had size for; count will be greater than array size
 227     return count;
 228 }
 229 
 230 /**************************************************************
 231  * Implementation of ProcessHandleImpl_Info native methods.
 232  */
 233 
 234 /*
 235  * Fill in the Info object from the OS information about the process.
 236  *
 237  * Class:     java_lang_ProcessHandleImpl
 238  * Method:    info0
 239  * Signature: (J)I
 240  */
 241 JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_info0
 242   (JNIEnv *env, jobject jinfo, jlong jpid) {
 243     pid_t pid = (pid_t) jpid;
 244     getStatInfo(env, jinfo, pid);
 245     getCmdlineInfo(env, jinfo, pid);







 246 }
 247 
 248 /**
 249  * Read /proc/<pid>/stat and fill in the fields of the Info object.
 250  * The executable name, plus the user, system, and start times are gathered.
 251  */
 252 static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t jpid) {
 253     jlong totalTime;                    // nanoseconds
 254     unsigned long long startTime;       // microseconds
 255 
 256     const pid_t pid = (pid_t) jpid;
 257     struct kinfo_proc kp;
 258     size_t bufSize = sizeof kp;
 259 
 260     // Read the process info for the specific pid
 261     int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
 262 
 263     if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) < 0) {
 264         if (errno == EINVAL) {
 265             return;
 266         } else {
 267             JNU_ThrowByNameWithLastError(env,
 268                 "java/lang/RuntimeException", "sysctl failed");
 269         }
 270         return;
 271     }
 272 
 273     // Convert the UID to the username
 274     jstring name = NULL;
 275     CHECK_NULL((name = uidToUser(env, kp.kp_eproc.e_ucred.cr_uid)));
 276     (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, name);
 277     JNU_CHECK_EXCEPTION(env);
 278 
 279     startTime = kp.kp_proc.p_starttime.tv_sec * 1000 +
 280                 kp.kp_proc.p_starttime.tv_usec / 1000;
 281 
 282     (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
 283     JNU_CHECK_EXCEPTION(env);
 284 
 285     // Get cputime if for current process
 286     if (pid == getpid()) {
 287         struct rusage usage;
 288         if (getrusage(RUSAGE_SELF, &usage) != 0) {
 289             return;
 290         }
 291         jlong microsecs =
 292             usage.ru_utime.tv_sec * 1000 * 1000 + usage.ru_utime.tv_usec +
 293             usage.ru_stime.tv_sec * 1000 * 1000 + usage.ru_stime.tv_usec;
 294         totalTime = microsecs * 1000;
 295         (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, totalTime);
 296         JNU_CHECK_EXCEPTION(env);
 297     }
 298 }
 299 
 300 /**
 301  * Construct the argument array by parsing the arguments from the sequence of arguments.
 302  */
 303 static int fillArgArray(JNIEnv *env, jobject jinfo, int nargs,
 304                         const char *cp, const char *argsEnd) {
 305     jstring str = NULL;
 306     jobject argsArray;
 307     int i;
 308 
 309     if (nargs < 1) {
 310         return 0;
 311     }
 312     // Create a String array for nargs-1 elements
 313     CHECK_NULL_RETURN((argsArray = (*env)->NewObjectArray(env,
 314             nargs - 1, JNU_ClassString(env), NULL)), -1);
 315 
 316     for (i = 0; i < nargs - 1; i++) {
 317         // skip to the next argument; omits arg[0]
 318         cp += strnlen(cp, (argsEnd - cp)) + 1;
 319 
 320         if (cp > argsEnd || *cp == '\0') {
 321             return -2;  // Off the end pointer or an empty argument is an error
 322         }
 323 
 324         CHECK_NULL_RETURN((str = JNU_NewStringPlatform(env, cp)), -1);
 325 
 326         (*env)->SetObjectArrayElement(env, argsArray, i, str);
 327         JNU_CHECK_EXCEPTION_RETURN(env, -3);
 328     }
 329     (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_argumentsID, argsArray);
 330     JNU_CHECK_EXCEPTION_RETURN(env, -4);
 331     return 0;
 332 }
 333 
 334 /**
 335  * Retrieve the command and arguments for the process and store them
 336  * into the Info object.
 337  */
 338 static void getCmdlineInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
 339     int mib[3], maxargs, nargs, i;
 340     size_t size;
 341     char *args, *cp, *sp, *np;
 342 
 343     // Get the maximum size of the arguments
 344     mib[0] = CTL_KERN;
 345     mib[1] = KERN_ARGMAX;
 346     size = sizeof(maxargs);
 347     if (sysctl(mib, 2, &maxargs, &size, NULL, 0) == -1) {
 348             JNU_ThrowByNameWithLastError(env,
 349                     "java/lang/RuntimeException", "sysctl failed");
 350         return;
 351     }
 352 
 353     // Allocate an args buffer and get the arguments
 354     args = (char *)malloc(maxargs);
 355     if (args == NULL) {
 356         JNU_ThrowOutOfMemoryError(env, "malloc failed");
 357         return;
 358     }
 359 
 360     do {            // a block to break out of on error
 361         char *argsEnd;
 362         jstring str = NULL;
 363 
 364         mib[0] = CTL_KERN;
 365         mib[1] = KERN_PROCARGS2;
 366         mib[2] = pid;
 367         size = (size_t) maxargs;
 368         if (sysctl(mib, 3, args, &size, NULL, 0) == -1) {
 369             if (errno != EINVAL) {
 370             JNU_ThrowByNameWithLastError(env,
 371                     "java/lang/RuntimeException", "sysctl failed");
 372             }
 373             break;
 374         }
 375         memcpy(&nargs, args, sizeof(nargs));
 376 
 377         cp = &args[sizeof(nargs)];      // Strings start after nargs
 378         argsEnd = &args[size];
 379 
 380         // Store the command executable path
 381         if ((str = JNU_NewStringPlatform(env, cp)) == NULL) {
 382             break;
 383         }
 384         (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_commandID, str);
 385         if ((*env)->ExceptionCheck(env)) {
 386             break;
 387         }
 388 
 389         // Skip trailing nulls after the executable path
 390         for (cp = cp + strnlen(cp, argsEnd - cp); cp < argsEnd; cp++) {
 391             if (*cp != '\0') {
 392                 break;
 393             }
 394         }
 395 
 396         fillArgArray(env, jinfo, nargs, cp, argsEnd);
 397     } while (0);
 398     // Free the arg buffer
 399     free(args);
 400 }
 401 


  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "jni.h"
  27 #include "jni_util.h"
  28 #include "java_lang_ProcessHandleImpl.h"
  29 #include "java_lang_ProcessHandleImpl_Info.h"
  30 
  31 #include "ProcessHandleImpl_unix.h"
  32 
  33 #include <stdio.h>
  34 #include <errno.h>
  35 #include <signal.h>
  36 #include <stdlib.h>
  37 #include <unistd.h>
  38 #include <string.h>
  39 
  40 #include <sys/sysctl.h>
  41 
  42 /**
  43  * Implementation of native ProcessHandleImpl functions for MAC OS X.
  44  * See ProcessHandleImpl_unix.c for more details.
  45  */
  46 
  47 void os_init(JNIEnv *env, jclass clazz) {}














































































  48 
  49 /*
  50  * Returns the children of the requested pid and optionally each parent.
  51  *




  52  * Use sysctl to accumulate any process whose parent pid is zero or matches.
  53  * The resulting pids are stored into the array of longs.
  54  * The number of pids is returned if they all fit.
  55  * If the parentArray is non-null, store the parent pid.
  56  * If the array is too short, excess pids are not stored and
  57  * the desired length is returned.
  58  */
  59 jint os_getChildren(JNIEnv *env, jlong jpid,
  60     jlongArray jarray, jlongArray jparentArray) {


  61     size_t count = 0;
  62     jlong* pids = NULL;
  63     jlong* ppids = NULL;
  64     size_t parentArraySize = 0;
  65     size_t arraySize = 0;
  66     size_t bufSize = 0;
  67     pid_t pid = (pid_t) jpid;
  68 
  69     arraySize = (*env)->GetArrayLength(env, jarray);
  70     JNU_CHECK_EXCEPTION_RETURN(env, -1);
  71     if (jparentArray != NULL) {
  72         parentArraySize = (*env)->GetArrayLength(env, jparentArray);
  73         JNU_CHECK_EXCEPTION_RETURN(env, -1);
  74 
  75         if (arraySize != parentArraySize) {
  76             JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
  77             return 0;
  78         }
  79     }
  80 


 128                         ppids[count] = (jlong) kp->kp_eproc.e_ppid;
 129                     }
 130                 }
 131                 count++; // Count to tabulate size needed
 132             }
 133         }
 134     } while (0);
 135 
 136     if (pids != NULL) {
 137         (*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
 138     }
 139     if (ppids != NULL) {
 140         (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
 141     }
 142 
 143     free(buffer);
 144     // If more pids than array had size for; count will be greater than array size
 145     return count;
 146 }
 147 




 148 /*
 149  * Returns the parent pid of a given pid, or -1 if not found




 150  */
 151 pid_t os_parentPid(JNIEnv *env, pid_t pid) {
 152     struct kinfo_proc kp;
 153     size_t bufSize = sizeof kp;
 154 
 155     // Read the process info for the specific pid
 156     int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
 157     if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) < 0) {
 158         JNU_ThrowByNameWithLastError(env,
 159             "java/lang/RuntimeException", "sysctl failed");
 160         return -1;
 161     }
 162     return (bufSize > 0 && kp.kp_proc.p_pid == pid) ? kp.kp_eproc.e_ppid : (pid_t)-1;
 163 }
 164 
 165 /**
 166  * Use sysctl to fill in the user name and cpu time fields of the Info object.

 167  */
 168 void os_getStatInfo(JNIEnv *env, jobject jinfo, pid_t jpid) {
 169     jlong totalTime;                    // nanoseconds
 170     unsigned long long startTime;       // microseconds
 171 
 172     const pid_t pid = (pid_t) jpid;
 173     struct kinfo_proc kp;
 174     size_t bufSize = sizeof kp;
 175 
 176     // Read the process info for the specific pid
 177     int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
 178 
 179     if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) < 0) {
 180         if (errno == EINVAL) {
 181             return;
 182         } else {
 183             JNU_ThrowByNameWithLastError(env,
 184                 "java/lang/RuntimeException", "sysctl failed");
 185         }
 186         return;
 187     }
 188 
 189     // Convert the UID to the username
 190     jstring name = NULL;
 191     CHECK_NULL((name = unix_uidToUser(env, kp.kp_eproc.e_ucred.cr_uid)));
 192     (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, name);
 193     JNU_CHECK_EXCEPTION(env);
 194 
 195     startTime = kp.kp_proc.p_starttime.tv_sec * 1000 +
 196                 kp.kp_proc.p_starttime.tv_usec / 1000;
 197 
 198     (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
 199     JNU_CHECK_EXCEPTION(env);
 200 
 201     // Get cputime if for current process
 202     if (pid == getpid()) {
 203         struct rusage usage;
 204         if (getrusage(RUSAGE_SELF, &usage) != 0) {
 205             return;
 206         }
 207         jlong microsecs =
 208             usage.ru_utime.tv_sec * 1000 * 1000 + usage.ru_utime.tv_usec +
 209             usage.ru_stime.tv_sec * 1000 * 1000 + usage.ru_stime.tv_usec;
 210         totalTime = microsecs * 1000;
 211         (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, totalTime);
 212         JNU_CHECK_EXCEPTION(env);
 213     }
 214 }
 215 
 216 /**


































 217  * Retrieve the command and arguments for the process and store them
 218  * into the Info object.
 219  */
 220 void os_getCmdlineInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
 221     int mib[3], maxargs, nargs, i;
 222     size_t size;
 223     char *args, *cp, *sp, *np;
 224 
 225     // Get the maximum size of the arguments
 226     mib[0] = CTL_KERN;
 227     mib[1] = KERN_ARGMAX;
 228     size = sizeof(maxargs);
 229     if (sysctl(mib, 2, &maxargs, &size, NULL, 0) == -1) {
 230             JNU_ThrowByNameWithLastError(env,
 231                     "java/lang/RuntimeException", "sysctl failed");
 232         return;
 233     }
 234 
 235     // Allocate an args buffer and get the arguments
 236     args = (char *)malloc(maxargs);
 237     if (args == NULL) {
 238         JNU_ThrowOutOfMemoryError(env, "malloc failed");
 239         return;
 240     }
 241 
 242     do {            // a block to break out of on error
 243         char *argsEnd;
 244         jstring cmdexe = NULL;
 245 
 246         mib[0] = CTL_KERN;
 247         mib[1] = KERN_PROCARGS2;
 248         mib[2] = pid;
 249         size = (size_t) maxargs;
 250         if (sysctl(mib, 3, args, &size, NULL, 0) == -1) {
 251             if (errno != EINVAL) {
 252             JNU_ThrowByNameWithLastError(env,
 253                     "java/lang/RuntimeException", "sysctl failed");
 254             }
 255             break;
 256         }
 257         memcpy(&nargs, args, sizeof(nargs));
 258 
 259         cp = &args[sizeof(nargs)];      // Strings start after nargs
 260         argsEnd = &args[size];
 261 
 262         // Store the command executable path
 263         if ((cmdexe = JNU_NewStringPlatform(env, cp)) == NULL) {




 264             break;
 265         }
 266 
 267         // Skip trailing nulls after the executable path
 268         for (cp = cp + strnlen(cp, argsEnd - cp); cp < argsEnd; cp++) {
 269             if (*cp != '\0') {
 270                 break;
 271             }
 272         }
 273 
 274         unix_fillArgArray(env, jinfo, nargs, cp, argsEnd, cmdexe);
 275     } while (0);
 276     // Free the arg buffer
 277     free(args);
 278 }
 279 
< prev index next >