1 /*
2 * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /**
25 * @test
26 * @summary Test virtual threads using Object.wait/notifyAll
27 * @modules java.base/java.lang:+open
28 * @library /test/lib
29 * @run junit MonitorWaitNotify
30 */
31
32 import java.util.concurrent.Semaphore;
33
34 import jdk.test.lib.thread.VThreadRunner;
35 import org.junit.jupiter.api.Test;
36 import static org.junit.jupiter.api.Assertions.*;
37
38 class MonitorWaitNotify {
39
40 /**
41 * Test virtual thread waits, notified by platform thread.
42 */
43 @Test
44 void testWaitNotify1() throws Exception {
45 var lock = new Object();
46 var ready = new Semaphore(0);
47 var thread = Thread.ofVirtual().start(() -> {
48 synchronized (lock) {
49 ready.release();
50 try {
51 lock.wait();
52 } catch (InterruptedException e) { }
137 * Test interrupt when blocked in Object.wait.
138 */
139 @Test
140 void testWaitNotify5() throws Exception {
141 VThreadRunner.run(() -> {
142 Thread t = Thread.currentThread();
143 scheduleInterrupt(t, 1000);
144 Object lock = new Object();
145 synchronized (lock) {
146 try {
147 lock.wait();
148 fail();
149 } catch (InterruptedException e) {
150 // interrupt status should be cleared
151 assertFalse(t.isInterrupted());
152 }
153 }
154 });
155 }
156
157 /**
158 * Schedule a thread to be interrupted after a delay.
159 */
160 private static void scheduleInterrupt(Thread thread, long delay) {
161 Runnable interruptTask = () -> {
162 try {
163 Thread.sleep(delay);
164 thread.interrupt();
165 } catch (Exception e) {
166 e.printStackTrace();
167 }
168 };
169 new Thread(interruptTask).start();
170 }
171 }
|
1 /*
2 * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /**
25 * @test
26 * @summary Test virtual threads using Object.wait/notifyAll
27 * @modules java.base/java.lang:+open
28 * @library /test/lib
29 * @run junit MonitorWaitNotify
30 */
31
32 import java.util.concurrent.CountDownLatch;
33 import java.util.concurrent.Semaphore;
34 import java.util.concurrent.atomic.AtomicBoolean;
35 import java.util.concurrent.locks.LockSupport;
36
37 import jdk.test.lib.thread.VThreadRunner;
38 import org.junit.jupiter.api.Test;
39 import static org.junit.jupiter.api.Assertions.*;
40
41 class MonitorWaitNotify {
42
43 /**
44 * Test virtual thread waits, notified by platform thread.
45 */
46 @Test
47 void testWaitNotify1() throws Exception {
48 var lock = new Object();
49 var ready = new Semaphore(0);
50 var thread = Thread.ofVirtual().start(() -> {
51 synchronized (lock) {
52 ready.release();
53 try {
54 lock.wait();
55 } catch (InterruptedException e) { }
140 * Test interrupt when blocked in Object.wait.
141 */
142 @Test
143 void testWaitNotify5() throws Exception {
144 VThreadRunner.run(() -> {
145 Thread t = Thread.currentThread();
146 scheduleInterrupt(t, 1000);
147 Object lock = new Object();
148 synchronized (lock) {
149 try {
150 lock.wait();
151 fail();
152 } catch (InterruptedException e) {
153 // interrupt status should be cleared
154 assertFalse(t.isInterrupted());
155 }
156 }
157 });
158 }
159
160 /**
161 * Testing invoking Object.wait with interrupt status set.
162 */
163 @Test
164 void testWaitWithInterruptSet() throws Exception {
165 VThreadRunner.run(() -> {
166 Object obj = new Object();
167 synchronized (obj) {
168 Thread.currentThread().interrupt();
169 assertThrows(InterruptedException.class, obj::wait);
170 assertFalse(Thread.currentThread().isInterrupted());
171 }
172 });
173 }
174
175 /**
176 * Test interrupting a virtual thread waiting in Object.wait.
177 */
178 @Test
179 void testInterruptWait() throws Exception {
180 var lock = new Object();
181 var started = new CountDownLatch(1);
182 var interruptedException = new AtomicBoolean();
183 var vthread = Thread.ofVirtual().start(() -> {
184 started.countDown();
185 synchronized (lock) {
186 try {
187 lock.wait();
188 } catch (InterruptedException e) {
189 interruptedException.set(true);
190 }
191 }
192 });
193
194 // wait for thread to start and wait
195 started.await();
196 await(vthread, Thread.State.WAITING);
197
198 // interrupt thread, it should throw InterruptedException and terminate
199 vthread.interrupt();
200 vthread.join();
201 assertTrue(interruptedException.get());
202 }
203
204 /**
205 * Test interrupting a virtual thread blocked waiting to reenter after waiting.
206 */
207 @Test
208 void testInterruptReenter() throws Exception {
209 var lock = new Object();
210 var started = new CountDownLatch(1);
211 var interruptedException = new AtomicBoolean();
212 var vthread = Thread.ofVirtual().start(() -> {
213 started.countDown();
214 synchronized (lock) {
215 try {
216 lock.wait();
217 } catch (InterruptedException e) {
218 interruptedException.set(true);
219 }
220 }
221 });
222
223 // wait for thread to start and wait
224 started.await();
225 await(vthread, Thread.State.WAITING);
226
227 // notify, thread should block waiting to reenter
228 synchronized (lock) {
229 lock.notifyAll();
230 await(vthread, Thread.State.BLOCKED);
231 vthread.interrupt();
232 }
233
234 vthread.join();
235 assertFalse(interruptedException.get());
236 assertTrue(vthread.isInterrupted());
237 }
238
239 /**
240 * Test that Object.wait does not consume the thread's parking permit.
241 */
242 @Test
243 void testParkingPermitNotConsumed() throws Exception {
244 var lock = new Object();
245 var started = new CountDownLatch(1);
246 var completed = new AtomicBoolean();
247 var vthread = Thread.ofVirtual().start(() -> {
248 started.countDown();
249 LockSupport.unpark(Thread.currentThread());
250 synchronized (lock) {
251 try {
252 lock.wait();
253 } catch (InterruptedException e) {
254 fail("wait interrupted");
255 }
256 }
257 LockSupport.park(); // should not park
258 completed.set(true);
259 });
260
261 // wait for thread to start and wait
262 started.await();
263 await(vthread, Thread.State.WAITING);
264
265 // wakeup thread
266 synchronized (lock) {
267 lock.notifyAll();
268 }
269
270 // thread should terminate
271 vthread.join();
272 assertTrue(completed.get());
273 }
274
275 /**
276 * Test that Object.wait does not make available the thread's parking permit.
277 */
278 @Test
279 void testParkingPermitNotOffered() throws Exception {
280 var lock = new Object();
281 var started = new CountDownLatch(1);
282 var readyToPark = new CountDownLatch(1);
283 var completed = new AtomicBoolean();
284 var vthread = Thread.ofVirtual().start(() -> {
285 started.countDown();
286 synchronized (lock) {
287 try {
288 lock.wait();
289 } catch (InterruptedException e) {
290 fail("wait interrupted");
291 }
292 }
293 readyToPark.countDown();
294 LockSupport.park(); // should park
295 completed.set(true);
296 });
297
298 // wait for thread to start and wait
299 started.await();
300 await(vthread, Thread.State.WAITING);
301
302 // wakeup thread
303 synchronized (lock) {
304 lock.notifyAll();
305 }
306
307 // thread should park
308 readyToPark.await();
309 await(vthread, Thread.State.WAITING);
310
311 LockSupport.unpark(vthread);
312
313 // thread should terminate
314 vthread.join();
315 assertTrue(completed.get());
316 }
317
318 /**
319 * Test that wait(long) throws IAE when timeout is negative.
320 */
321 @Test
322 void testIllegalArgumentException() throws Exception {
323 VThreadRunner.run(() -> {
324 Object obj = new Object();
325 synchronized (obj) {
326 assertThrows(IllegalArgumentException.class, () -> obj.wait(-1L));
327 assertThrows(IllegalArgumentException.class, () -> obj.wait(-1000L));
328 assertThrows(IllegalArgumentException.class, () -> obj.wait(Long.MIN_VALUE));
329 }
330 });
331 }
332
333 /**
334 * Test that wait throws IMSE when not owner.
335 */
336 @Test
337 void testIllegalMonitorStateException() throws Exception {
338 VThreadRunner.run(() -> {
339 Object obj = new Object();
340 assertThrows(IllegalMonitorStateException.class, () -> obj.wait());
341 assertThrows(IllegalMonitorStateException.class, () -> obj.wait(0));
342 assertThrows(IllegalMonitorStateException.class, () -> obj.wait(1000));
343 assertThrows(IllegalMonitorStateException.class, () -> obj.wait(Long.MAX_VALUE));
344 });
345 }
346
347 /**
348 * Waits for the given thread to reach a given state.
349 */
350 private void await(Thread thread, Thread.State expectedState) throws InterruptedException {
351 Thread.State state = thread.getState();
352 while (state != expectedState) {
353 assertTrue(state != Thread.State.TERMINATED, "Thread has terminated");
354 Thread.sleep(10);
355 state = thread.getState();
356 }
357 }
358
359 /**
360 * Schedule a thread to be interrupted after a delay.
361 */
362 private static void scheduleInterrupt(Thread thread, long delay) {
363 Runnable interruptTask = () -> {
364 try {
365 Thread.sleep(delay);
366 thread.interrupt();
367 } catch (Exception e) {
368 e.printStackTrace();
369 }
370 };
371 new Thread(interruptTask).start();
372 }
373 }
|