Skip to content

Commit

Permalink
Enhance reflective pid-getting for Windows Java 8+
Browse files Browse the repository at this point in the history
This is a modified version of a patch proposed in jruby#7515 (comment)
that uses a third mechanism for getting the PID: the `pid` method
added to ProcessImpl in 8 and made public in Process in 9.

For JRuby 10, which will target Java 17 or 21, we can just call
`pid` directly.

Fixes jruby#7515
  • Loading branch information
headius committed Jul 1, 2024
1 parent 6655bb6 commit e690825
Showing 1 changed file with 76 additions and 49 deletions.
125 changes: 76 additions & 49 deletions core/src/main/java/org/jruby/util/ShellLauncher.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
Expand Down Expand Up @@ -659,6 +660,7 @@ public static long getPidFromProcess(Process process) {
private static final Field UNIXProcess_pid;
private static final Class ProcessImpl;
private static final Field ProcessImpl_handle;
private static final Method ProcessImpl_pid;
private interface PidGetter { long getPid(Process process); }
private static final PidGetter PID_GETTER;

Expand All @@ -681,7 +683,7 @@ private interface PidGetter { long getPid(Process process); }
if (up != null) {
try {
pid = up.getDeclaredField("pid");
Java.trySetAccessible(pid);
if (!Java.trySetAccessible(pid)) pid = null;
} catch (NoSuchFieldException | SecurityException e) {
// ignore and try windows version
}
Expand All @@ -694,69 +696,43 @@ private interface PidGetter { long getPid(Process process); }
try {
pi = Class.forName("java.lang.ProcessImpl");
handle = pi.getDeclaredField("handle");
Java.trySetAccessible(handle);
if (!Java.trySetAccessible(handle)) {
handle = null;
}
} catch (Exception e) {
// ignore and use hashcode
}

Method pi_pid = null;
if (pi != null) {
try {
pi_pid = pi.getMethod("pid");
if (!Java.trySetAccessible(pi_pid)) {
pi_pid = null;
if (handle == null) pi = null;
}
} catch (Exception e) {
// ignore and use hashcode
}
}
ProcessImpl = pi;
ProcessImpl_handle = handle;
ProcessImpl_pid = pi_pid;

if (UNIXProcess_pid != null) {
if (ProcessImpl_handle != null) {
// try both
pidGetter = new PidGetter() {
public long getPid(Process process) {
try {
if (UNIXProcess.isInstance(process)) {
return (Integer)UNIXProcess_pid.get(process);
} else if (ProcessImpl.isInstance(process)) {
Long hproc = (Long) ProcessImpl_handle.get(process);
return WindowsFFI.getKernel32().GetProcessId(hproc);
}
} catch (Exception e) {
// ignore and use hashcode
}
return process.hashCode();
}
};
pidGetter = ShellLauncher::getPidBoth;
} else {
// just unix
pidGetter = new PidGetter() {
public long getPid(Process process) {
try {
if (UNIXProcess.isInstance(process)) {
return (Integer)UNIXProcess_pid.get(process);
}
} catch (Exception e) {
// ignore and use hashcode
}
return process.hashCode();
}
};
pidGetter = ShellLauncher::getPidUnix;
}
} else if (ProcessImpl_handle != null) {
} else if (ProcessImpl_handle != null || ProcessImpl_pid != null) {
// just windows
pidGetter = new PidGetter() {
public long getPid(Process process) {
try {
if (ProcessImpl.isInstance(process)) {
Long hproc = (Long) ProcessImpl_handle.get(process);
return WindowsFFI.getKernel32().GetProcessId(hproc);
}

} catch (Exception e) {
// ignore and use hashcode
}
return process.hashCode();
}
};
pidGetter = ShellLauncher::getPidWindows;
} else {
// neither - default PidGetter
pidGetter = new PidGetter() {
public long getPid(Process process) {
return process.hashCode();
}
};
pidGetter = Object::hashCode;
}
PID_GETTER = pidGetter;
}
Expand All @@ -765,6 +741,57 @@ public static long reflectPidFromProcess(Process process) {
return PID_GETTER.getPid(process);
}

private static long getPidBoth(Process process) {
try {
if (UNIXProcess.isInstance(process)) {
return getPidUnix(process);
} else if (ProcessImpl.isInstance(process)) {
return getPidWindows(process);
}
} catch (Exception e) {
// fall back on hashcode
}

return process.hashCode();
}

private static long getPidWindows(Process process) {
long pid = -1;
if (ProcessImpl_handle != null) {
try {
if (ProcessImpl.isInstance(process)) {
Long hproc = (Long) ProcessImpl_handle.get(process);
return WindowsFFI.getKernel32().GetProcessId(hproc);
}
} catch (Exception e) {
// fall back on pid logic
}
}

if (pid == -1 && ProcessImpl_pid != null) {
// JDK > 8 has a new way to look it up and also can't use "handle" field anymore
try {
return (long) ProcessImpl_pid.invoke(process);
} catch (Exception e2) {
// fall back on hashcode
}
}

return process.hashCode();
}

private static long getPidUnix(Process process) {
try {
if (UNIXProcess.isInstance(process)) {
return (Integer) UNIXProcess_pid.get(process);
}
} catch (Exception e) {
// fall back on hashcode
}

return process.hashCode();
}

public static Process run(Ruby runtime, IRubyObject string) throws IOException {
return run(runtime, new IRubyObject[] {string}, false);
}
Expand Down

0 comments on commit e690825

Please sign in to comment.