2525 * @test
2626 * @bug 8283044
2727 * @summary Stress delivery of asynchronous exceptions while target is at monitorenter
28- * @requires test.thread.factory == null
2928 * @library /test/hotspot/jtreg/testlibrary
3029 * @run main/othervm/native AsyncExceptionOnMonitorEnter 0
3130 * @run main/othervm/native -agentlib:AsyncExceptionOnMonitorEnter AsyncExceptionOnMonitorEnter 1
@@ -45,9 +44,13 @@ public class AsyncExceptionOnMonitorEnter extends Thread {
4544 public static native int exitRawMonitor ();
4645 public static native void destroyRawMonitor ();
4746
47+ // Avoid using CountDownLatch or similar objects that require unparking the
48+ // main thread. Otherwise, if the main thread is run as a virtual thread, the
49+ // async exception could be sent while the target is still executing FJP logic.
50+ public volatile boolean started = false ;
51+ public volatile boolean gotMonitor = false ;
52+
4853 private static Object o1 = new Object ();
49- private static boolean firstWorker = true ;
50- private static Semaphore sem = new Semaphore (0 );
5154
5255 @ Override
5356 public void run () {
@@ -60,11 +63,9 @@ public void run() {
6063
6164 public void testWithJavaMonitor () {
6265 try {
66+ started = true ;
6367 synchronized (o1 ) {
64- if (firstWorker ) {
65- firstWorker = false ;
66- sem .release ();
67- }
68+ gotMonitor = true ;
6869 Thread .sleep (1000 );
6970 }
7071 } catch (ThreadDeath td ) {
@@ -75,20 +76,16 @@ public void testWithJavaMonitor() {
7576
7677
7778 public void testWithJVMTIRawMonitor () {
78- boolean savedFirst = false ;
7979 try {
80+ started = true ;
8081 int retCode = enterRawMonitor ();
81- if (retCode != 0 && firstWorker ) {
82+ if (retCode != 0 ) {
8283 throw new RuntimeException ("error in JVMTI RawMonitorEnter: retCode=" + retCode );
8384 }
84- if (firstWorker ) {
85- firstWorker = false ;
86- savedFirst = true ;
87- sem .release ();
88- }
89- Thread .sleep (1000 );
85+ gotMonitor = true ;
86+ Thread .sleep (500 );
9087 retCode = exitRawMonitor ();
91- if (retCode != 0 && savedFirst ) {
88+ if (retCode != 0 ) {
9289 throw new RuntimeException ("error in JVMTI RawMonitorExit: retCode=" + retCode );
9390 }
9491 } catch (ThreadDeath td ) {
@@ -134,15 +131,18 @@ public static void main(String[] args) {
134131 AsyncExceptionOnMonitorEnter worker2 = new AsyncExceptionOnMonitorEnter ();
135132
136133 try {
137- // Start firstWorker worker and wait until monitor is acquired
138- firstWorker = true ;
134+ // Start first worker and wait until monitor is acquired
139135 worker1 .start ();
140- sem .acquire ();
136+ while (!worker1 .gotMonitor ) {
137+ Thread .sleep (1 );
138+ }
141139
142140 // Start second worker and allow some time for target to block on monitorenter
143141 // before executing Thread.stop()
144142 worker2 .start ();
145- Thread .sleep (300 );
143+ while (!worker2 .started ) {
144+ Thread .sleep (10 );
145+ }
146146
147147 while (true ) {
148148 JVMTIUtils .stopThread (worker2 );
@@ -151,6 +151,8 @@ public static void main(String[] args) {
151151 // not released worker2 will deadlock on enter
152152 JVMTIUtils .stopThread (worker1 );
153153 }
154+ // Give time to throw exception
155+ Thread .sleep (10 );
154156
155157 if (!worker1 .isAlive () && !worker2 .isAlive ()) {
156158 // Done with Thread.stop() calls since
0 commit comments