Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/java.base/aix/native/libjava/ProcessHandleImpl_aix.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray,
pid_t ppid = (pid_t) ProcessBuffer[i].pi_ppid;

// Get the parent pid, and start time
if (pid == 0 || ppid == pid) {
if (pid == java_lang_ProcessHandleImpl_ALL_CHILDREN_PID || ppid == pid) {
if (count < arraySize) {
// Only store if it fits
pids[count] = (jlong) childpid;
Expand Down
4 changes: 2 additions & 2 deletions src/java.base/linux/native/libjava/ProcessHandleImpl_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void os_initNative(JNIEnv *env, jclass clazz) {
* Return pids of active processes, and optionally parent pids and
* start times for each process.
* For a specific non-zero pid, only the direct children are returned.
* If the pid is zero, all active processes are returned.
* If the pid is ALL_CHILDREN_PID, all active processes are returned.
* Reads /proc and accumulates any process following the rules above.
* The resulting pids are stored into an array of longs named jarray.
* The number of pids is returned if they all fit.
Expand Down Expand Up @@ -153,7 +153,7 @@ jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray,

// Get the parent pid, and start time
ppid = os_getParentPidAndTimings(env, childpid, &totalTime, &startTime);
if (ppid >= 0 && (pid == 0 || ppid == pid)) {
if (ppid >= 0 && (pid == java_lang_ProcessHandleImpl_ALL_CHILDREN_PID || ppid == pid)) {
if (count < arraySize) {
// Only store if it fits
pids[count] = (jlong) childpid;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ void os_initNative(JNIEnv *env, jclass clazz) {}
* Return pids of active processes, and optionally parent pids and
* start times for each process.
* For a specific non-zero pid jpid, only the direct children are returned.
* If the pid jpid is zero, all active processes are returned.
* If the pid jpid is ALL_CHILDREN_PID, all active processes are returned.
* Uses sysctl to accumulates any process following the rules above.
* The resulting pids are stored into an array of longs named jarray.
* The number of pids is returned if they all fit.
Expand Down Expand Up @@ -153,8 +153,10 @@ jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray,
}

// Process each entry in the buffer
// Pid 0 has itself as a parent, return only the other children
for (i = nentries; --i >= 0; ++kp) {
if (pid == 0 || kp->kp_eproc.e_ppid == pid) {
if (pid == java_lang_ProcessHandleImpl_ALL_CHILDREN_PID ||
(kp->kp_eproc.e_ppid == pid && kp->kp_eproc.e_ppid != (jlong) kp->kp_proc.p_pid)) {
if (count < arraySize) {
// Only store if it fits
pids[count] = (jlong) kp->kp_proc.p_pid;
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/lang/ProcessHandle.java
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ static ProcessHandle current() {
* does not support this operation
*/
static Stream<ProcessHandle> allProcesses() {
return ProcessHandleImpl.children(0);
return ProcessHandleImpl.allProcesses();
}

/**
Expand Down
42 changes: 37 additions & 5 deletions src/java.base/share/classes/java/lang/ProcessHandleImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,26 @@ public CompletableFuture<ProcessHandle> onExit() {
/* The start time of a Process that does not exist. */
private static final long STARTTIME_PROCESS_UNKNOWN = -1;

/* Sentinel pid to return all processes. */
private static final long ALL_CHILDREN_PID = -1L;

/**
* Returns a snapshot of all processes visible to the current process.
* <p>
* <em>Note that processes are created and terminate asynchronously. There
* is no guarantee that a process in the stream is alive or that no other
* processes may have been created since the inception of the snapshot.
* </em>
*
* @return a Stream of ProcessHandles for all processes
* @throws UnsupportedOperationException if the implementation
* does not support this operation
*/
static Stream<ProcessHandle> allProcesses() {

return children(ProcessHandleImpl.ALL_CHILDREN_PID);
}

/**
* Private constructor. Instances are created by the {@code get(long)} factory.
* @param pid the pid for this instance
Expand Down Expand Up @@ -311,7 +331,7 @@ public Optional<ProcessHandle> parent() {

/**
* Returns the number of pids filled in to the array.
* @param pid if {@code pid} equals zero, then all known processes are returned;
* @param pid if {@code pid} equals ALL_CHILDREN_PID, then all known processes are returned;
* 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
Expand Down Expand Up @@ -431,17 +451,22 @@ public Stream<ProcessHandle> descendants() {
pids = new long[size];
ppids = new long[size];
starttimes = new long[size];
size = getProcessPids0(0, pids, ppids, starttimes);
size = getProcessPids0(ALL_CHILDREN_PID, pids, ppids, starttimes);
}

int next = 0; // index of next process to check
int count = -1; // count of subprocesses scanned
int count = 0; // count of subprocesses scanned
long ppid = pid; // start looking for this parent
long ppStart = 0;
// Find the start time of the parent
for (int i = 0; i < size; i++) {
if (pids[i] == ppid) {
// Found the parent, swap it to the end and do not look at it again
ppStart = starttimes[i];
swap(pids, i, size - 1);
swap(ppids, i, size - 1);
swap(starttimes, i, size - 1);
size--;
break;
}
}
Expand All @@ -458,9 +483,13 @@ public Stream<ProcessHandle> descendants() {
next++;
}
}
ppid = pids[++count]; // pick up the next pid to scan for
if (count >= next) {
break;
}
ppid = pids[count]; // pick up the next pid to scan for
ppStart = starttimes[count]; // and its start time
} while (count < next);
count++;
} while (true);

final long[] cpids = pids;
final long[] stimes = starttimes;
Expand Down Expand Up @@ -499,6 +528,9 @@ public boolean equals(Object obj) {
if (this == obj) {
return true;
}
//ProcessHandleImpl that = (ProcessHandleImpl)obj;
//System.out.printf("this.pid: %d that.pid: %d this.startTime: %d that.startTime: %d\n",
//this.pid, that.pid, this.startTime, that.startTime);
return (obj instanceof ProcessHandleImpl other)
&& (pid == other.pid)
&& (startTime == other.startTime || startTime == 0 || other.startTime == 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ Java_java_lang_ProcessHandleImpl_getProcessPids0(JNIEnv *env,
// Now walk the snapshot of processes, and
// save information about each process in turn
do {
if (ppid == 0 ||
if (ppid == java_lang_ProcessHandleImpl_ALL_CHILDREN_PID ||
(pe32.th32ParentProcessID > 0
&& (pe32.th32ParentProcessID == ppid))) {
if (count < arraySize) {
Expand Down
20 changes: 20 additions & 0 deletions test/jdk/java/lang/ProcessHandle/TreeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,14 @@
import jdk.test.lib.Utils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;

/*
* @test
* @summary Test counting and JavaChild.spawning and counting of Processes.
* @requires vm.flagless
* @bug 8381567
* @library /test/lib
* @modules java.base/jdk.internal.misc
* jdk.management
Expand Down Expand Up @@ -469,4 +472,21 @@ public void test5() {
}
}

@Test
@EnabledOnOs(OS.MAC)
void pidZeroTest() {
ProcessHandle pZero = ProcessHandle.of(0).orElseThrow();
Assertions.assertFalse(pZero.children().toList().contains(pZero),
"pid 0 should not be a child of pid 0");

Assertions.assertDoesNotThrow(() -> pZero.descendants().toList());

Assertions.assertFalse(pZero.descendants().toList().contains(pZero),
"pid 0 should not be a descendant of pid 0");

// Verify that (on MacOS) pid 0 is listed as one of allProcesses()
Stream<ProcessHandle> allProcesses = ProcessHandle.allProcesses();
long pZeroCount = allProcesses.filter(p -> p.equals(pZero)).count();
Assertions.assertEquals(1, pZeroCount, "pid 0 should appear exactly once in a list of all processes");
}
}