diff --git a/src/jvm.ts b/src/jvm.ts index 589c381..fb01ec6 100644 --- a/src/jvm.ts +++ b/src/jvm.ts @@ -1360,6 +1360,8 @@ export class JVM { // nothing left to report to } } + // Main must be joinable before DestroyJavaVM waits for other threads. + yield* this.exitThread(t); // DestroyJavaVM: wait for the other non-daemon threads, then shut down. while (this.nonDaemonAlive(t)) { yield t.block(new Promise((r) => { @@ -1367,7 +1369,6 @@ export class JVM { check(); })); } - yield* this.exitThread(t); yield t.call(boot("java/lang/Shutdown").methodMap.get("shutdown()V")!); this.halt(code); } diff --git a/test/java/MainThreadExit.java b/test/java/MainThreadExit.java new file mode 100644 index 0000000..d7ae3ab --- /dev/null +++ b/test/java/MainThreadExit.java @@ -0,0 +1,15 @@ +public class MainThreadExit { + public static void main(String[] args) { + Thread main = Thread.currentThread(); + main.setUncaughtExceptionHandler((thread, error) -> System.out.println("uncaught: " + error.getMessage())); + new Thread(() -> { + try { + main.join(); + System.out.println("main alive: " + main.isAlive()); + } catch (InterruptedException e) { + throw new AssertionError(e); + } + }).start(); + throw new RuntimeException("main failed"); + } +} diff --git a/test/jtreg/passing.txt b/test/jtreg/passing.txt index 1266d2a..91bfd46 100644 --- a/test/jtreg/passing.txt +++ b/test/jtreg/passing.txt @@ -1053,6 +1053,7 @@ java/lang/Thread/SleepSanity.java java/lang/Thread/SleepWithDuration.java java/lang/Thread/ThreadStateTest.java java/lang/Thread/ThreadStopTest.java +java/lang/Thread/UncaughtExceptionsTest.java java/lang/Thread/virtual/Collectable.java java/lang/Thread/virtual/Locking.java java/lang/Thread/virtual/Reflection.java