102 * @summary Don't do the unlock and exit by throwing, by multiple threads
103 * @library /test/lib
104 * @modules java.base/java.lang:+open
105 * @requires vm.continuations
106 * @run driver JNIMonitor MultiMissingUnlockWithThrow
107 */
108
109 public class JNIMonitor {
110
111 public static void main(String[] args) throws Exception {
112 String test = args[0];
113 String[] cmdArgs = new String[] {
114 "-Djava.library.path=" + Utils.TEST_NATIVE_PATH,
115 // Grant access to ThreadBuilders$VirtualThreadBuilder
116 "--add-opens=java.base/java.lang=ALL-UNNAMED",
117 // Enable the JNI warning
118 "-Xcheck:jni",
119 "-Xlog:jni=debug",
120 // Enable thread termination logging as a visual cross-check
121 "-Xlog:thread+os=info",
122 "JNIMonitor$" + test,
123 };
124 OutputAnalyzer oa = ProcessTools.executeTestJava(cmdArgs);
125 oa.shouldHaveExitValue(0);
126 oa.stdoutShouldMatch(terminated);
127
128 switch(test) {
129 case "Normal":
130 case "MultiNormal":
131 oa.stdoutShouldNotMatch(stillLocked);
132 break;
133 case "MissingUnlock":
134 oa.stdoutShouldMatch(stillLocked);
135 break;
136 case "MultiMissingUnlock":
137 parseOutputForPattern(oa.stdoutAsLines(), stillLocked, MULTI_THREAD_COUNT);
138 break;
139 case "MissingUnlockWithThrow":
140 oa.stdoutShouldMatch(stillLocked);
141 oa.stderrShouldContain(throwMsg);
202 // unexpectedly, so we can force that condition too by shutting down our custom scheduler.
203 private static Thread.Builder.OfVirtual virtualThreadBuilder(Executor scheduler) {
204 Thread.Builder.OfVirtual builder = Thread.ofVirtual();
205 try {
206 Class<?> clazz = Class.forName("java.lang.ThreadBuilders$VirtualThreadBuilder");
207 Constructor<?> ctor = clazz.getDeclaredConstructor(Executor.class);
208 ctor.setAccessible(true);
209 return (Thread.Builder.OfVirtual) ctor.newInstance(scheduler);
210 } catch (InvocationTargetException e) {
211 Throwable cause = e.getCause();
212 if (cause instanceof RuntimeException re) {
213 throw re;
214 }
215 throw new RuntimeException(e);
216 } catch (Exception e) {
217 throw new RuntimeException(e);
218 }
219 }
220
221 static void runTest(int nThreads, boolean skipUnlock, boolean throwOnExit) throws Throwable {
222 final Object monitor = new Object();
223 final AtomicReference<Throwable> exception = new AtomicReference();
224 // Ensure all our VT's operate of the same carrier, sequentially.
225 ExecutorService scheduler = Executors.newSingleThreadExecutor();
226 ThreadFactory factory = virtualThreadBuilder(scheduler).factory();
227 for (int i = 0 ; i < nThreads; i++) {
228 Thread th = factory.newThread(() -> {
229 try {
230 int res = monitorEnter(monitor);
231 Asserts.assertTrue(res == 0, "monitorEnter should return 0.");
232 Asserts.assertTrue(Thread.holdsLock(monitor), "monitor should be owned");
233 Thread.yield();
234 if (!skipUnlock) {
235 res = monitorExit(monitor);
236 Asserts.assertTrue(res == 0, "monitorExit should return 0.");
237 Asserts.assertFalse(Thread.holdsLock(monitor), "monitor should be unowned");
238 }
239 } catch (Throwable t) {
240 exception.set(t);
241 }
242 if (throwOnExit) {
243 throw new RuntimeException(throwMsg);
244 }
245 });
246 th.start();
247 th.join();
|
102 * @summary Don't do the unlock and exit by throwing, by multiple threads
103 * @library /test/lib
104 * @modules java.base/java.lang:+open
105 * @requires vm.continuations
106 * @run driver JNIMonitor MultiMissingUnlockWithThrow
107 */
108
109 public class JNIMonitor {
110
111 public static void main(String[] args) throws Exception {
112 String test = args[0];
113 String[] cmdArgs = new String[] {
114 "-Djava.library.path=" + Utils.TEST_NATIVE_PATH,
115 // Grant access to ThreadBuilders$VirtualThreadBuilder
116 "--add-opens=java.base/java.lang=ALL-UNNAMED",
117 // Enable the JNI warning
118 "-Xcheck:jni",
119 "-Xlog:jni=debug",
120 // Enable thread termination logging as a visual cross-check
121 "-Xlog:thread+os=info",
122 // We only count monitors in LM_LEGACY mode
123 "-XX:LockingMode=1",
124 "JNIMonitor$" + test,
125 };
126 OutputAnalyzer oa = ProcessTools.executeTestJava(cmdArgs);
127 oa.shouldHaveExitValue(0);
128 oa.stdoutShouldMatch(terminated);
129
130 switch(test) {
131 case "Normal":
132 case "MultiNormal":
133 oa.stdoutShouldNotMatch(stillLocked);
134 break;
135 case "MissingUnlock":
136 oa.stdoutShouldMatch(stillLocked);
137 break;
138 case "MultiMissingUnlock":
139 parseOutputForPattern(oa.stdoutAsLines(), stillLocked, MULTI_THREAD_COUNT);
140 break;
141 case "MissingUnlockWithThrow":
142 oa.stdoutShouldMatch(stillLocked);
143 oa.stderrShouldContain(throwMsg);
204 // unexpectedly, so we can force that condition too by shutting down our custom scheduler.
205 private static Thread.Builder.OfVirtual virtualThreadBuilder(Executor scheduler) {
206 Thread.Builder.OfVirtual builder = Thread.ofVirtual();
207 try {
208 Class<?> clazz = Class.forName("java.lang.ThreadBuilders$VirtualThreadBuilder");
209 Constructor<?> ctor = clazz.getDeclaredConstructor(Executor.class);
210 ctor.setAccessible(true);
211 return (Thread.Builder.OfVirtual) ctor.newInstance(scheduler);
212 } catch (InvocationTargetException e) {
213 Throwable cause = e.getCause();
214 if (cause instanceof RuntimeException re) {
215 throw re;
216 }
217 throw new RuntimeException(e);
218 } catch (Exception e) {
219 throw new RuntimeException(e);
220 }
221 }
222
223 static void runTest(int nThreads, boolean skipUnlock, boolean throwOnExit) throws Throwable {
224 final Object[] monitors = new Object[nThreads];
225 for (int i = 0; i < nThreads; i++) {
226 monitors[i] = new Object();
227 }
228 final AtomicReference<Throwable> exception = new AtomicReference();
229 // Ensure all our VT's operate of the same carrier, sequentially.
230 ExecutorService scheduler = Executors.newSingleThreadExecutor();
231 ThreadFactory factory = virtualThreadBuilder(scheduler).factory();
232 for (int i = 0 ; i < nThreads; i++) {
233 Object monitor = skipUnlock ? monitors[i] : monitors[0];
234 Thread th = factory.newThread(() -> {
235 try {
236 int res = monitorEnter(monitor);
237 Asserts.assertTrue(res == 0, "monitorEnter should return 0.");
238 Asserts.assertTrue(Thread.holdsLock(monitor), "monitor should be owned");
239 Thread.yield();
240 if (!skipUnlock) {
241 res = monitorExit(monitor);
242 Asserts.assertTrue(res == 0, "monitorExit should return 0.");
243 Asserts.assertFalse(Thread.holdsLock(monitor), "monitor should be unowned");
244 }
245 } catch (Throwable t) {
246 exception.set(t);
247 }
248 if (throwOnExit) {
249 throw new RuntimeException(throwMsg);
250 }
251 });
252 th.start();
253 th.join();
|