From fa9f8a58e129549145a7f0fcb9bed3c370ced079 Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Tue, 20 Aug 2024 12:41:34 -0500 Subject: [PATCH] some cursed wait for exit --- .../jvmdg/j9/intl/UnixProcessHandle.java | 48 ++++++++++++++++--- .../downgradetest/TestProcessHandle.java | 7 +-- .../test/integration/DowngradeTests.java | 6 +-- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/java-api/src/java9/java/xyz/wagyourtail/jvmdg/j9/intl/UnixProcessHandle.java b/java-api/src/java9/java/xyz/wagyourtail/jvmdg/j9/intl/UnixProcessHandle.java index 4d4c6bb4..1ea52269 100644 --- a/java-api/src/java9/java/xyz/wagyourtail/jvmdg/j9/intl/UnixProcessHandle.java +++ b/java-api/src/java9/java/xyz/wagyourtail/jvmdg/j9/intl/UnixProcessHandle.java @@ -1,11 +1,17 @@ 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; @@ -20,6 +26,29 @@ 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; @@ -56,7 +85,11 @@ private String[] readCmdLine() { Path pth = Paths.get("/proc/" + pid + "/cmdline"); if (Files.isReadable(pth)) { try { - return new String(Files.readAllBytes(pth)).split("\0"); + String args = new String(Files.readAllBytes(pth)); + if (args.isEmpty()) { + return null; + } + return args.split("\0"); } catch (IOException e) { return null; } @@ -164,14 +197,15 @@ public Optional user() { @Override public CompletableFuture onExit() { return CompletableFuture.supplyAsync(() -> { - try (WatchService ws = FileSystems.getDefault().newWatchService()) { - Path pth = Paths.get("/proc/" + pid + "/status"); - pth.register(ws, StandardWatchEventKinds.ENTRY_DELETE); - ws.take(); - return this; - } catch (IOException | InterruptedException e) { + 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); }); } diff --git a/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestProcessHandle.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestProcessHandle.java index 5845cf11..6889fe1a 100644 --- a/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestProcessHandle.java +++ b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestProcessHandle.java @@ -4,10 +4,12 @@ import java.lang.management.ManagementFactory; import java.util.Arrays; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Semaphore; public class TestProcessHandle { - public static void main(String[] args) throws IOException { + public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { ProcessHandle currentProcessHandle = ProcessHandle.current(); System.out.println(currentProcessHandle.pid() == ManagementFactory.getRuntimeMXBean().getPid()); List lst = Arrays.asList(currentProcessHandle.info().arguments().get()); @@ -22,7 +24,6 @@ public static void main(String[] args) throws IOException { } Process p = pb.start(); currentProcessHandle.children().map(e -> String.join(" ", e.info().arguments().get())).forEach(System.out::println); - p.toHandle().onExit().thenAccept(e -> System.out.println(e.info().commandLine())); -// Thread.sleep(1); + System.out.println(p.toHandle().onExit().get().info().commandLine().orElse("missing")); } } diff --git a/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/DowngradeTests.java b/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/DowngradeTests.java index 8975c234..6cdb1096 100644 --- a/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/DowngradeTests.java +++ b/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/DowngradeTests.java @@ -44,15 +44,15 @@ private static Stream flags() { return Stream.of( new FlagsAndRunner(JavaRunner.JavaVersion.V1_8, flags.copy(e -> { e.classVersion = JavaRunner.JavaVersion.V1_8.toOpcode(); - e.multiReleaseVersions = Set.of(JavaRunner.JavaVersion.V11.toOpcode(), JavaRunner.JavaVersion.V17.toOpcode()); +// e.multiReleaseVersions = Set.of(JavaRunner.JavaVersion.V11.toOpcode(), JavaRunner.JavaVersion.V17.toOpcode()); })), new FlagsAndRunner(JavaRunner.JavaVersion.V11, flags.copy(e -> { e.classVersion = JavaRunner.JavaVersion.V1_8.toOpcode(); - e.multiReleaseVersions = Set.of(JavaRunner.JavaVersion.V11.toOpcode(), JavaRunner.JavaVersion.V17.toOpcode()); +// e.multiReleaseVersions = Set.of(JavaRunner.JavaVersion.V11.toOpcode(), JavaRunner.JavaVersion.V17.toOpcode()); })), new FlagsAndRunner(JavaRunner.JavaVersion.V17, flags.copy(e -> { e.classVersion = JavaRunner.JavaVersion.V1_8.toOpcode(); - e.multiReleaseVersions = Set.of(JavaRunner.JavaVersion.V11.toOpcode(), JavaRunner.JavaVersion.V17.toOpcode()); +// e.multiReleaseVersions = Set.of(JavaRunner.JavaVersion.V11.toOpcode(), JavaRunner.JavaVersion.V17.toOpcode()); })) // new FlagsAndRunner(flags.copy(e -> { // e.classVersion = JavaRunner.JavaVersion.V1_7.toOpcode();