< prev index next >
src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c
Print this page
rev 12467 : 8131168: Refactor ProcessHandleImpl_*.c and add implememtation for AIX
*** 26,197 ****
#include "jni.h"
#include "jni_util.h"
#include "java_lang_ProcessHandleImpl.h"
#include "java_lang_ProcessHandleImpl_Info.h"
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/sysctl.h>
/**
! * Implementations of ProcessHandleImpl functions for MAC OS X;
! * are NOT common to all Unix variants.
! */
!
! static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t pid);
! static void getCmdlineInfo(JNIEnv *env, jobject jinfo, pid_t pid);
!
! /*
! * Common Unix function to lookup the uid and return the user name.
! */
! extern jstring uidToUser(JNIEnv* env, uid_t uid);
!
! /* Field id for jString 'command' in java.lang.ProcessHandle.Info */
! static jfieldID ProcessHandleImpl_Info_commandID;
!
! /* Field id for jString[] 'arguments' in java.lang.ProcessHandle.Info */
! static jfieldID ProcessHandleImpl_Info_argumentsID;
!
! /* Field id for jlong 'totalTime' in java.lang.ProcessHandle.Info */
! static jfieldID ProcessHandleImpl_Info_totalTimeID;
!
! /* Field id for jlong 'startTime' in java.lang.ProcessHandle.Info */
! static jfieldID ProcessHandleImpl_Info_startTimeID;
!
! /* Field id for jString 'user' in java.lang.ProcessHandleImpl.Info */
! static jfieldID ProcessHandleImpl_Info_userID;
!
! /* static value for clock ticks per second. */
! static long clock_ticks_per_second;
!
! /**************************************************************
! * Static method to initialize field IDs and the ticks per second rate.
! *
! * Class: java_lang_ProcessHandleImpl_Info
! * Method: initIDs
! * Signature: ()V
! */
! 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, clazz, "arguments", "[Ljava/lang/String;"));
! CHECK_NULL(ProcessHandleImpl_Info_totalTimeID =
! (*env)->GetFieldID(env, clazz, "totalTime", "J"));
! CHECK_NULL(ProcessHandleImpl_Info_startTimeID =
! (*env)->GetFieldID(env, 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;
! 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);
! }
! }
!
! /*
! * 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,
! jlong startTime) {
! pid_t pid = (pid_t) jpid;
! pid_t ppid = -1;
!
! if (pid == getpid()) {
! ppid = getppid();
! } else {
! const 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) {
! JNU_ThrowByNameWithLastError(env,
! "java/lang/RuntimeException", "sysctl failed");
! return -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;
! }
/*
* Returns the children of the requested pid and optionally each parent.
*
- * Class: java_lang_ProcessHandleImpl
- * Method: getProcessPids0
- * Signature: (J[J[J)I
- *
* Use sysctl to accumulate any process whose parent pid is zero or matches.
* The resulting pids are stored into the array of longs.
* The number of pids is returned if they all fit.
* If the parentArray is non-null, store the parent pid.
* 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,
! jlongArray jstimesArray) {
jlong* pids = NULL;
jlong* ppids = NULL;
jlong* stimes = NULL;
jsize parentArraySize = 0;
jsize arraySize = 0;
--- 26,65 ----
#include "jni.h"
#include "jni_util.h"
#include "java_lang_ProcessHandleImpl.h"
#include "java_lang_ProcessHandleImpl_Info.h"
+ #include "ProcessHandleImpl_unix.h"
+
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/sysctl.h>
/**
! * Implementation of native ProcessHandleImpl functions for MAC OS X.
! * See ProcessHandleImpl_unix.c for more details.
*/
! void os_initNative(JNIEnv *env, jclass clazz) {}
/*
* Returns the children of the requested pid and optionally each parent.
*
* Use sysctl to accumulate any process whose parent pid is zero or matches.
* The resulting pids are stored into the array of longs.
* The number of pids is returned if they all fit.
* If the parentArray is non-null, store the parent pid.
* If the array is too short, excess pids are not stored and
* the desired length is returned.
*/
! jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray,
! jlongArray jparentArray, jlongArray jstimesArray) {
jlong* pids = NULL;
jlong* ppids = NULL;
jlong* stimes = NULL;
jsize parentArraySize = 0;
jsize arraySize = 0;
*** 301,425 ****
free(buffer);
// If more pids than array had size for; count will be greater than array size
return count;
}
- /**************************************************************
- * Implementation of ProcessHandleImpl_Info native methods.
- */
-
- /*
- * Fill in the Info object from the OS information about the process.
- *
- * Class: java_lang_ProcessHandleImpl
- * Method: info0
- * Signature: (J)I
- */
- 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);
- }
-
/**
! * 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.
*/
! static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t jpid) {
! jlong totalTime; // nanoseconds
! unsigned long long startTime; // milliseconds
const 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) {
- if (errno == EINVAL) {
- return;
- } else {
JNU_ThrowByNameWithLastError(env,
"java/lang/RuntimeException", "sysctl failed");
}
- return;
- }
-
- // Convert the UID to the username
- jstring name = NULL;
- CHECK_NULL((name = uidToUser(env, kp.kp_eproc.e_ucred.cr_uid)));
- (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, name);
- JNU_CHECK_EXCEPTION(env);
! startTime = kp.kp_proc.p_starttime.tv_sec * 1000 +
kp.kp_proc.p_starttime.tv_usec / 1000;
!
! (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
! JNU_CHECK_EXCEPTION(env);
// Get cputime if for current process
if (pid == getpid()) {
struct rusage usage;
! if (getrusage(RUSAGE_SELF, &usage) != 0) {
! return;
! }
jlong microsecs =
usage.ru_utime.tv_sec * 1000 * 1000 + usage.ru_utime.tv_usec +
usage.ru_stime.tv_sec * 1000 * 1000 + usage.ru_stime.tv_usec;
! totalTime = microsecs * 1000;
! (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, totalTime);
! JNU_CHECK_EXCEPTION(env);
}
}
/**
! * Construct the argument array by parsing the arguments from the sequence of arguments.
*/
! static int fillArgArray(JNIEnv *env, jobject jinfo, int nargs,
! const char *cp, const char *argsEnd) {
! jstring str = NULL;
! jobject argsArray;
! int i;
!
! if (nargs < 1) {
! return 0;
! }
! // Create a String array for nargs-1 elements
! CHECK_NULL_RETURN((argsArray = (*env)->NewObjectArray(env,
! nargs - 1, JNU_ClassString(env), NULL)), -1);
! for (i = 0; i < nargs - 1; i++) {
! // skip to the next argument; omits arg[0]
! cp += strnlen(cp, (argsEnd - cp)) + 1;
! if (cp > argsEnd || *cp == '\0') {
! return -2; // Off the end pointer or an empty argument is an error
}
-
- CHECK_NULL_RETURN((str = JNU_NewStringPlatform(env, cp)), -1);
-
- (*env)->SetObjectArrayElement(env, argsArray, i, str);
- JNU_CHECK_EXCEPTION_RETURN(env, -3);
}
! (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_argumentsID, argsArray);
! JNU_CHECK_EXCEPTION_RETURN(env, -4);
! return 0;
}
/**
* Retrieve the command and arguments for the process and store them
* into the Info object.
*/
! static void getCmdlineInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
int mib[3], maxargs, nargs, i;
size_t size;
char *args, *cp, *sp, *np;
// Get the maximum size of the arguments
mib[0] = CTL_KERN;
mib[1] = KERN_ARGMAX;
size = sizeof(maxargs);
if (sysctl(mib, 2, &maxargs, &size, NULL, 0) == -1) {
--- 169,254 ----
free(buffer);
// If more pids than array had size for; count will be greater than array size
return count;
}
/**
! * Use sysctl and return the ppid, total cputime and start time.
! * Return: -1 is fail; zero is unknown; > 0 is parent pid
! * 'total' will contain the running time of 'pid' in nanoseconds.
! * 'start' will contain the start time of 'pid' in milliseconds since epoch.
*/
! pid_t os_getParentPidAndTimings(JNIEnv *env, pid_t jpid,
! jlong *totalTime, jlong *startTime) {
const pid_t pid = (pid_t) jpid;
+ pid_t ppid = -1;
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) {
JNU_ThrowByNameWithLastError(env,
"java/lang/RuntimeException", "sysctl failed");
+ return -1;
}
! if (bufSize > 0 && kp.kp_proc.p_pid == pid) {
! *startTime = kp.kp_proc.p_starttime.tv_sec * 1000 +
kp.kp_proc.p_starttime.tv_usec / 1000;
! ppid = kp.kp_eproc.e_ppid;
! }
// Get cputime if for current process
if (pid == getpid()) {
struct rusage usage;
! if (getrusage(RUSAGE_SELF, &usage) == 0) {
jlong microsecs =
usage.ru_utime.tv_sec * 1000 * 1000 + usage.ru_utime.tv_usec +
usage.ru_stime.tv_sec * 1000 * 1000 + usage.ru_stime.tv_usec;
! *totalTime = microsecs * 1000;
}
+ }
+
+ return ppid;
+
}
/**
! * Return the uid of a process or -1 on error
*/
! static uid_t getUID(pid_t pid) {
! 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) {
! if (bufSize > 0 && kp.kp_proc.p_pid == pid) {
! return kp.kp_eproc.e_ucred.cr_uid;
}
}
! return (uid_t)-1;
}
/**
* Retrieve the command and arguments for the process and store them
* into the Info object.
*/
! void os_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
int mib[3], maxargs, nargs, i;
size_t size;
char *args, *cp, *sp, *np;
+ // Get the UID first. This is done here because it is cheap to do it here
+ // on other platforms like Linux/Solaris/AIX where the uid comes from the
+ // same source like the command line info.
+ unix_getUserInfo(env, jinfo, getUID(pid));
+
// Get the maximum size of the arguments
mib[0] = CTL_KERN;
mib[1] = KERN_ARGMAX;
size = sizeof(maxargs);
if (sysctl(mib, 2, &maxargs, &size, NULL, 0) == -1) {
*** 435,445 ****
return;
}
do { // a block to break out of on error
char *argsEnd;
! jstring str = NULL;
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS2;
mib[2] = pid;
size = (size_t) maxargs;
--- 264,274 ----
return;
}
do { // a block to break out of on error
char *argsEnd;
! jstring cmdexe = NULL;
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS2;
mib[2] = pid;
size = (size_t) maxargs;
*** 454,479 ****
cp = &args[sizeof(nargs)]; // Strings start after nargs
argsEnd = &args[size];
// Store the command executable path
! if ((str = JNU_NewStringPlatform(env, cp)) == NULL) {
! break;
! }
! (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_commandID, str);
! if ((*env)->ExceptionCheck(env)) {
break;
}
// Skip trailing nulls after the executable path
for (cp = cp + strnlen(cp, argsEnd - cp); cp < argsEnd; cp++) {
if (*cp != '\0') {
break;
}
}
! fillArgArray(env, jinfo, nargs, cp, argsEnd);
} while (0);
// Free the arg buffer
free(args);
}
--- 283,304 ----
cp = &args[sizeof(nargs)]; // Strings start after nargs
argsEnd = &args[size];
// Store the command executable path
! if ((cmdexe = JNU_NewStringPlatform(env, cp)) == NULL) {
break;
}
// Skip trailing nulls after the executable path
for (cp = cp + strnlen(cp, argsEnd - cp); cp < argsEnd; cp++) {
if (*cp != '\0') {
break;
}
}
! unix_fillArgArray(env, jinfo, nargs, cp, argsEnd, cmdexe);
} while (0);
// Free the arg buffer
free(args);
}
< prev index next >