From jai.forums2013 at gmail.com Mon Mar 8 16:51:37 2021 From: jai.forums2013 at gmail.com (Jaikiran Pai) Date: Mon, 8 Mar 2021 22:21:37 +0530 Subject: jtreg main/othervm "completes" even when there's a non-daemon thread currently active? Message-ID: Please consider this trivial Java program: public class FooTest { ??? public static void main(final String[] args) throws Exception { ??? ??? Thread t = new Thread(new Task()); ??? ??? t.setName("Thread-A"); ??? ??? t.start(); ??? ??? System.out.println("Main done"); ??? } ??? public static class Task implements Runnable { ??? ??? @Override ??? ??? public void run() { ??? ??? ??? // wait forever ??? ??? ??? System.out.println("Initiating a wait"); ??? ??? ??? try { ??? ??? ??? ??? new java.util.concurrent.CountDownLatch(1).await(); ??? ??? ??? } catch (Throwable t) { ??? ??? ??? ??? t.printStackTrace(); ??? ??? ??? } ??? ??? } ??? } } All it does is launches a (non-daemon) thread and the thread just waits (forever). When you run this as a normal Java program, as expected it waits forever, even after the "main" thread is completed, due to the other non-daemon thread. Now let's consider the exact same program converted into a jtreg, by adding just the javadoc annotations: /** ?* @test ?* @summary Test jtreg ?* @run main/othervm FooTest ?*/ public class FooTest { ??? public static void main(final String[] args) throws Exception { ??? ??? Thread t = new Thread(new Task()); ??? ??? t.setName("Thread-A"); ??? ??? t.start(); ??? ??? System.out.println("Main done"); ??? } ??? public static class Task implements Runnable { ??? ??? @Override ??? ??? public void run() { ??? ??? ??? // wait forever ??? ??? ??? System.out.println("Initiating a wait"); ??? ??? ??? try { ??? ??? ??? ??? new java.util.concurrent.CountDownLatch(1).await(); ??? ??? ??? } catch (Throwable t) { ??? ??? ??? ??? t.printStackTrace(); ??? ??? ??? } ??? ??? } ??? } } (no change to the code, just the jtreg annotations/markers have been added). Now run this from within the JDK testsuite (for example), using jtreg: jtreg -jdk:build/macosx-x86_64-server-release/images/jdk test/jdk/java/lang/FooTest.java This "passes" (immediately). i.e. the jtreg launched program/test doesn't wait for the non-daemon thread to complete and instead just exits successfully when the main thread is done. I have verified the logs to make sure it indeed exits cleanly without errors or timeouts and does the run the code in that test. Is this expected? I haven't found this mentioned in the user guide (as far as I can see) and a quick glance in the jtreg source code (the MainWrapper specifically) doesn't tell me how this change in behaviour of the JVM exit semantics would be possible (since it ultimately uses ProcessBuilder to launch the program). -Jaikiran From jai.forums2013 at gmail.com Mon Mar 8 16:58:16 2021 From: jai.forums2013 at gmail.com (Jaikiran Pai) Date: Mon, 8 Mar 2021 22:28:16 +0530 Subject: jtreg main/othervm "completes" even when there's a non-daemon thread currently active? In-Reply-To: References: Message-ID: <27b11ff6-fb6d-1ae5-5184-0748de82dfb3@gmail.com> Sorry, never mind. Just after I sent this mail, I went back to the jtreg FAQ and used a different search term this time to see if this has been explained there and indeed I see it now https://openjdk.java.net/jtreg/faq.html#what-happens-if-my-test-returns-when-there-are-still-threads-running. Sorry about this. -Jaikiran On 08/03/21 10:21 pm, Jaikiran Pai wrote: > Please consider this trivial Java program: > > public class FooTest { > ??? public static void main(final String[] args) throws Exception { > ??? ??? Thread t = new Thread(new Task()); > ??? ??? t.setName("Thread-A"); > ??? ??? t.start(); > ??? ??? System.out.println("Main done"); > ??? } > > ??? public static class Task implements Runnable { > ??? ??? @Override > ??? ??? public void run() { > ??? ??? ??? // wait forever > ??? ??? ??? System.out.println("Initiating a wait"); > ??? ??? ??? try { > ??? ??? ??? ??? new java.util.concurrent.CountDownLatch(1).await(); > ??? ??? ??? } catch (Throwable t) { > ??? ??? ??? ??? t.printStackTrace(); > ??? ??? ??? } > ??? ??? } > ??? } > } > > > All it does is launches a (non-daemon) thread and the thread just > waits (forever). When you run this as a normal Java program, as > expected it waits forever, even after the "main" thread is completed, > due to the other non-daemon thread. > > Now let's consider the exact same program converted into a jtreg, by > adding just the javadoc annotations: > > > /** > ?* @test > ?* @summary Test jtreg > ?* @run main/othervm FooTest > ?*/ > public class FooTest { > ??? public static void main(final String[] args) throws Exception { > ??? ??? Thread t = new Thread(new Task()); > ??? ??? t.setName("Thread-A"); > ??? ??? t.start(); > ??? ??? System.out.println("Main done"); > ??? } > > ??? public static class Task implements Runnable { > ??? ??? @Override > ??? ??? public void run() { > ??? ??? ??? // wait forever > ??? ??? ??? System.out.println("Initiating a wait"); > ??? ??? ??? try { > ??? ??? ??? ??? new java.util.concurrent.CountDownLatch(1).await(); > ??? ??? ??? } catch (Throwable t) { > ??? ??? ??? ??? t.printStackTrace(); > ??? ??? ??? } > ??? ??? } > ??? } > } > > (no change to the code, just the jtreg annotations/markers have been > added). > > > Now run this from within the JDK testsuite (for example), using jtreg: > > jtreg -jdk:build/macosx-x86_64-server-release/images/jdk > test/jdk/java/lang/FooTest.java > > This "passes" (immediately). i.e. the jtreg launched program/test > doesn't wait for the non-daemon thread to complete and instead just > exits successfully when the main thread is done. I have verified the > logs to make sure it indeed exits cleanly without errors or timeouts > and does the run the code in that test. > > Is this expected? I haven't found this mentioned in the user guide (as > far as I can see) and a quick glance in the jtreg source code (the > MainWrapper specifically) doesn't tell me how this change in behaviour > of the JVM exit semantics would be possible (since it ultimately uses > ProcessBuilder to launch the program). > > -Jaikiran > > > From jonathan.gibbons at oracle.com Mon Mar 8 17:26:41 2021 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Mon, 8 Mar 2021 09:26:41 -0800 Subject: jtreg main/othervm "completes" even when there's a non-daemon thread currently active? In-Reply-To: <27b11ff6-fb6d-1ae5-5184-0748de82dfb3@gmail.com> References: <27b11ff6-fb6d-1ae5-5184-0748de82dfb3@gmail.com> Message-ID: <262057af-0c79-237a-1e98-a734f8505a52@oracle.com> Thanks for the update. -- Jon On 3/8/21 8:58 AM, Jaikiran Pai wrote: > Sorry, never mind. Just after I sent this mail, I went back to the > jtreg FAQ and used a different search term this time to see if this > has been explained there and indeed I see it now > https://openjdk.java.net/jtreg/faq.html#what-happens-if-my-test-returns-when-there-are-still-threads-running. > > Sorry about this. > > -Jaikiran > > On 08/03/21 10:21 pm, Jaikiran Pai wrote: >> Please consider this trivial Java program: >> >> public class FooTest { >> ??? public static void main(final String[] args) throws Exception { >> ??? ??? Thread t = new Thread(new Task()); >> ??? ??? t.setName("Thread-A"); >> ??? ??? t.start(); >> ??? ??? System.out.println("Main done"); >> ??? } >> >> ??? public static class Task implements Runnable { >> ??? ??? @Override >> ??? ??? public void run() { >> ??? ??? ??? // wait forever >> ??? ??? ??? System.out.println("Initiating a wait"); >> ??? ??? ??? try { >> ??? ??? ??? ??? new java.util.concurrent.CountDownLatch(1).await(); >> ??? ??? ??? } catch (Throwable t) { >> ??? ??? ??? ??? t.printStackTrace(); >> ??? ??? ??? } >> ??? ??? } >> ??? } >> } >> >> >> All it does is launches a (non-daemon) thread and the thread just >> waits (forever). When you run this as a normal Java program, as >> expected it waits forever, even after the "main" thread is completed, >> due to the other non-daemon thread. >> >> Now let's consider the exact same program converted into a jtreg, by >> adding just the javadoc annotations: >> >> >> /** >> ?* @test >> ?* @summary Test jtreg >> ?* @run main/othervm FooTest >> ?*/ >> public class FooTest { >> ??? public static void main(final String[] args) throws Exception { >> ??? ??? Thread t = new Thread(new Task()); >> ??? ??? t.setName("Thread-A"); >> ??? ??? t.start(); >> ??? ??? System.out.println("Main done"); >> ??? } >> >> ??? public static class Task implements Runnable { >> ??? ??? @Override >> ??? ??? public void run() { >> ??? ??? ??? // wait forever >> ??? ??? ??? System.out.println("Initiating a wait"); >> ??? ??? ??? try { >> ??? ??? ??? ??? new java.util.concurrent.CountDownLatch(1).await(); >> ??? ??? ??? } catch (Throwable t) { >> ??? ??? ??? ??? t.printStackTrace(); >> ??? ??? ??? } >> ??? ??? } >> ??? } >> } >> >> (no change to the code, just the jtreg annotations/markers have been >> added). >> >> >> Now run this from within the JDK testsuite (for example), using jtreg: >> >> jtreg -jdk:build/macosx-x86_64-server-release/images/jdk >> test/jdk/java/lang/FooTest.java >> >> This "passes" (immediately). i.e. the jtreg launched program/test >> doesn't wait for the non-daemon thread to complete and instead just >> exits successfully when the main thread is done. I have verified the >> logs to make sure it indeed exits cleanly without errors or timeouts >> and does the run the code in that test. >> >> Is this expected? I haven't found this mentioned in the user guide >> (as far as I can see) and a quick glance in the jtreg source code >> (the MainWrapper specifically) doesn't tell me how this change in >> behaviour of the JVM exit semantics would be possible (since it >> ultimately uses ProcessBuilder to launch the program). >> >> -Jaikiran >> >> >>