-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
652 additions
and
112 deletions.
There are no files selected for viewing
16 changes: 16 additions & 0 deletions
16
java-api/src/java10/java/xyz/wagyourtail/jvmdg/j10/stub/java_base/J_L_M_RuntimeMXBean.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package xyz.wagyourtail.jvmdg.j10.stub.java_base; | ||
|
||
import xyz.wagyourtail.jvmdg.version.Stub; | ||
|
||
import java.lang.management.RuntimeMXBean; | ||
|
||
public class J_L_M_RuntimeMXBean { | ||
|
||
@Stub | ||
public static long getPid(RuntimeMXBean bean) { | ||
String name = bean.getName(); | ||
name = name.substring(0, name.indexOf('@')); | ||
return Long.parseLong(name); | ||
} | ||
|
||
} |
250 changes: 250 additions & 0 deletions
250
java-api/src/java9/java/xyz/wagyourtail/jvmdg/j9/intl/UnixProcessHandle.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
package xyz.wagyourtail.jvmdg.j9.intl; | ||
|
||
import org.jetbrains.annotations.NotNull; | ||
import sun.misc.Unsafe; | ||
import xyz.wagyourtail.jvmdg.exc.MissingStubError; | ||
import xyz.wagyourtail.jvmdg.j9.stub.java_base.J_L_ProcessHandle; | ||
import xyz.wagyourtail.jvmdg.util.Utils; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.UncheckedIOException; | ||
import java.lang.invoke.MethodHandle; | ||
import java.lang.invoke.MethodHandles; | ||
import java.lang.invoke.MethodType; | ||
import java.nio.file.FileSystems; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.nio.file.StandardWatchEventKinds; | ||
import java.nio.file.WatchService; | ||
import java.time.Duration; | ||
import java.time.Instant; | ||
import java.util.Arrays; | ||
import java.util.Optional; | ||
import java.util.concurrent.CompletableFuture; | ||
import java.util.stream.Stream; | ||
|
||
public class UnixProcessHandle implements J_L_ProcessHandle { | ||
private static final Unsafe unsafe = Utils.getUnsafe(); | ||
private static final MethodHandles.Lookup IMPL_LOOKUP = Utils.getImplLookup(); | ||
private static final MethodHandle waitForProcessExit; | ||
|
||
static { | ||
MethodHandle waitForProcessExit1; | ||
try { | ||
Class<?> unixProcess = Class.forName("java.lang.UNIXProcess"); | ||
waitForProcessExit1 = IMPL_LOOKUP.findVirtual(unixProcess, "waitForProcessExit", MethodType.methodType(int.class, int.class)).bindTo(unsafe.allocateInstance(unixProcess)); | ||
} catch (NoSuchMethodException | IllegalAccessException | ClassNotFoundException e) { | ||
// we are probably on j9+, fallback on actual processHandle impl stuff | ||
try { | ||
waitForProcessExit1 = MethodHandles.insertArguments(IMPL_LOOKUP.findStatic(Class.forName("java.lang.ProcessHandleImpl"), "waitForProcessExit0", MethodType.methodType(int.class, long.class, boolean.class)), 1, false).asType(MethodType.methodType(int.class, int.class)); | ||
} catch (NoSuchMethodException | IllegalAccessException | ClassNotFoundException ex) { | ||
throw new RuntimeException(ex); | ||
} | ||
} catch (InstantiationException e) { | ||
throw new RuntimeException(e); | ||
} | ||
|
||
waitForProcessExit = waitForProcessExit1; | ||
} | ||
|
||
private final long pid; | ||
private String[] pidInfo; | ||
private final String[] cmdline; | ||
|
||
public UnixProcessHandle(long pid) { | ||
this.pid = pid; | ||
pidInfo = readPidInfo(); | ||
cmdline = readCmdLine(); | ||
} | ||
|
||
public static boolean isUnix() { | ||
return File.pathSeparatorChar == ':'; | ||
} | ||
|
||
/** | ||
* <a href="https://man7.org/linux/man-pages/man5/proc_pid_stat.5.html">/proc/<pid>/stat</a> | ||
*/ | ||
private String[] readPidInfo() { | ||
Path pth = Paths.get("/proc/" + pid + "/stat"); | ||
if (Files.isReadable(pth)) { | ||
try { | ||
pidInfo = new String(Files.readAllBytes(pth)).split(" "); | ||
} catch (IOException e) { | ||
pidInfo = null; | ||
} | ||
} | ||
return pidInfo; | ||
} | ||
|
||
/** | ||
* <a href="https://man7.org/linux/man-pages/man5/proc_pid_cmdline.5.html">/proc/<pid>/cmdline</a> | ||
*/ | ||
private String[] readCmdLine() { | ||
Path pth = Paths.get("/proc/" + pid + "/cmdline"); | ||
if (Files.isReadable(pth)) { | ||
try { | ||
String args = new String(Files.readAllBytes(pth)); | ||
if (args.isEmpty()) { | ||
return null; | ||
} | ||
return args.split("\0"); | ||
} catch (IOException e) { | ||
return null; | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
@Override | ||
public long pid() { | ||
return pid; | ||
} | ||
|
||
@Override | ||
public Optional<J_L_ProcessHandle> parent() { | ||
String[] info = readPidInfo(); | ||
if (info != null) { | ||
return Optional.of(new UnixProcessHandle(Long.parseLong(info[3]))); | ||
} | ||
return Optional.empty(); | ||
} | ||
|
||
@Override | ||
public Stream<J_L_ProcessHandle> children() { | ||
Path pth = Paths.get("/proc/" + pid + "/task"); | ||
try(Stream<Path> stream = Files.list(pth)) { | ||
return Stream.of(stream.toArray(Path[]::new)).flatMap(e -> { | ||
try { | ||
String s = new String(Files.readAllBytes(e.resolve("children"))); | ||
if (s.isEmpty()) { | ||
return Stream.empty(); | ||
} | ||
return Arrays.stream(s.split(" ")); | ||
} catch (IOException ex) { | ||
return Stream.empty(); | ||
} | ||
}).mapToLong(Long::parseLong).mapToObj(UnixProcessHandle::new); | ||
} catch (IOException e) { | ||
throw new UncheckedIOException(e); | ||
} | ||
} | ||
|
||
@Override | ||
public Stream<J_L_ProcessHandle> descendants() { | ||
return children().flatMap(e -> Stream.concat(Stream.of(e), e.descendants())); | ||
} | ||
|
||
@Override | ||
public Info info() { | ||
return new Info() { | ||
@Override | ||
public Optional<String> command() { | ||
if (cmdline != null) { | ||
return Optional.ofNullable(cmdline[0]); | ||
} | ||
return Optional.empty(); | ||
} | ||
|
||
@Override | ||
public Optional<String> commandLine() { | ||
if (cmdline != null) { | ||
return Optional.of(String.join(" ", cmdline)); | ||
} | ||
return Optional.empty(); | ||
} | ||
|
||
@Override | ||
public Optional<String[]> arguments() { | ||
if (cmdline != null) { | ||
String[] args = new String[cmdline.length - 1]; | ||
System.arraycopy(cmdline, 1, args, 0, cmdline.length - 1); | ||
return Optional.of(args); | ||
} | ||
return Optional.empty(); | ||
} | ||
|
||
@Override | ||
public Optional<Instant> startInstant() { | ||
String[] info = readPidInfo(); | ||
if (info != null) { | ||
return Optional.of(Instant.ofEpochMilli(Long.parseLong(info[22]))); | ||
} | ||
return Optional.empty(); | ||
} | ||
|
||
@Override | ||
public Optional<Duration> totalCpuDuration() { | ||
String[] info = readPidInfo(); | ||
if (info != null) { | ||
return Optional.of(Duration.ofMillis(Long.parseLong(info[14]))); | ||
} | ||
return Optional.empty(); | ||
} | ||
|
||
@Override | ||
public Optional<String> user() { | ||
try { | ||
return Optional.of(Files.getOwner(Paths.get("/proc/" + pid + "/cmdline")).getName()); | ||
} catch (IOException e) { | ||
return Optional.empty(); | ||
} | ||
} | ||
}; | ||
} | ||
|
||
@Override | ||
public CompletableFuture<J_L_ProcessHandle> onExit() { | ||
return CompletableFuture.supplyAsync(() -> { | ||
if (pid > Integer.MAX_VALUE) { | ||
throw MissingStubError.create(); | ||
} | ||
try { | ||
int exitCode = (int) waitForProcessExit.invokeExact((int) pid); | ||
} catch (Throwable e) { | ||
throw new RuntimeException(e); | ||
} | ||
return new UnixProcessHandle(pid); | ||
}); | ||
} | ||
|
||
@Override | ||
public boolean supportsNormalTermination() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public boolean destroy() { | ||
ProcessBuilder pb = new ProcessBuilder("kill", Long.toString(pid)); | ||
try { | ||
Process p = pb.start(); | ||
p.waitFor(); | ||
return p.exitValue() == 0; | ||
} catch (IOException | InterruptedException e) { | ||
return false; | ||
} | ||
} | ||
|
||
@Override | ||
public boolean destroyForcibly() { | ||
ProcessBuilder pb = new ProcessBuilder("kill", "-9", Long.toString(pid)); | ||
try { | ||
Process p = pb.start(); | ||
p.waitFor(); | ||
return p.exitValue() == 0; | ||
} catch (IOException | InterruptedException e) { | ||
return false; | ||
} | ||
} | ||
|
||
@Override | ||
public boolean isAlive() { | ||
return Files.exists(Paths.get("/proc/" + pid + "/status")); | ||
} | ||
|
||
@Override | ||
public int compareTo(@NotNull J_L_ProcessHandle other) { | ||
return Long.compare(pid, other.pid()); | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
java-api/src/java9/java/xyz/wagyourtail/jvmdg/j9/stub/java_base/J_L_Process.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package xyz.wagyourtail.jvmdg.j9.stub.java_base; | ||
|
||
import xyz.wagyourtail.jvmdg.util.Utils; | ||
import xyz.wagyourtail.jvmdg.version.Stub; | ||
|
||
import java.lang.invoke.MethodHandles; | ||
import java.util.stream.Stream; | ||
|
||
public class J_L_Process { | ||
private static final MethodHandles.Lookup IMPL_LOOKUP = Utils.getImplLookup(); | ||
|
||
@Stub | ||
public static J_L_ProcessHandle toHandle(Process process) throws Throwable { | ||
long pid = (long) IMPL_LOOKUP.findGetter(process.getClass(), "pid", int.class).invoke(process); | ||
return J_L_ProcessHandle.of(pid).get(); | ||
} | ||
|
||
@Stub | ||
public static J_L_ProcessHandle.Info info(Process process) throws Throwable { | ||
return toHandle(process).info(); | ||
} | ||
|
||
@Stub | ||
public static Stream<J_L_ProcessHandle> children(Process process) throws Throwable { | ||
return toHandle(process).children(); | ||
} | ||
|
||
@Stub | ||
public static Stream<J_L_ProcessHandle> descendants(Process process) throws Throwable { | ||
return toHandle(process).descendants(); | ||
} | ||
|
||
} |
Oops, something went wrong.