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 id=default
26 * @bug 8312498
27 * @summary Basic test for JVMTI GetThreadState with virtual threads
28 * @run junit/othervm/native GetThreadStateTest
29 */
30
31 /*
32 * @test id=no-vmcontinuations
33 * @requires vm.continuations
34 * @run junit/othervm/native -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations GetThreadStateTest
35 */
36
37 import java.util.StringJoiner;
38 import java.util.concurrent.CountDownLatch;
39 import java.util.concurrent.atomic.AtomicBoolean;
40 import java.util.concurrent.locks.LockSupport;
41
42 import org.junit.jupiter.api.BeforeAll;
43 import org.junit.jupiter.api.Test;
44 import static org.junit.jupiter.api.Assertions.*;
45
46 class GetThreadStateTest {
47
48 @BeforeAll
49 static void setup() {
50 System.loadLibrary("GetThreadStateTest");
51 init();
52 }
53
54 /**
55 * Test state of new/unstarted thread.
56 */
57 @Test
58 void testUnstarted() {
59 var thread = Thread.ofVirtual().unstarted(() -> { });
60 check(thread, /*new*/ 0);
61 }
62
63 /**
64 * Test state of terminated thread.
65 */
66 @Test
67 void testTerminated() throws Exception {
68 var thread = Thread.ofVirtual().start(() -> { });
69 thread.join();
70 check(thread, JVMTI_THREAD_STATE_TERMINATED);
71 }
72
73 /**
74 * Test state of runnable thread.
75 */
76 @Test
77 void testRunnable() throws Exception {
78 var latch = new CountDownLatch(1);
79 var done = new AtomicBoolean();
80 var thread = Thread.ofVirtual().start(() -> {
81 latch.countDown();
82
83 // spin until done
84 while (!done.get()) {
85 Thread.onSpinWait();
86 }
87 });
88 try {
89 // wait for thread to start execution
90 latch.await();
91
92 // thread should be runnable
93 int expected = JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_RUNNABLE;
94 check(thread, expected);
95
96 // re-test with interrupt status set
97 thread.interrupt();
98 check(thread, expected | JVMTI_THREAD_STATE_INTERRUPTED);
99 } finally {
100 done.set(true);
101 thread.join();
102 }
103 }
104
105 /**
106 * Test state of thread waiting to enter a monitor.
107 */
108 @Test
109 void testMonitorEnter() throws Exception {
110 var latch = new CountDownLatch(1);
111 Object lock = new Object();
112 var thread = Thread.ofVirtual().unstarted(() -> {
113 latch.countDown();
114 synchronized (lock) { }
115 });
116 try {
117 synchronized (lock) {
118 // start thread and wait for it to start execution
119 thread.start();
120 latch.await();
121
122 // thread should block on monitor enter
123 int expected = JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER;
124 await(thread, expected);
125
126 // re-test with interrupt status set
127 thread.interrupt();
128 check(thread, expected | JVMTI_THREAD_STATE_INTERRUPTED);
129 }
130 } finally {
131 thread.join();
132 }
133 }
134
135 /**
136 * Test state of thread waiting in Object.wait().
137 */
138 @Test
139 void testObjectWait() throws Exception {
140 var latch = new CountDownLatch(1);
141 Object lock = new Object();
142 var thread = Thread.ofVirtual().start(() -> {
143 synchronized (lock) {
144 latch.countDown();
145 try {
146 lock.wait();
147 } catch (InterruptedException e) { }
148 }
149 });
150 try {
151 // wait for thread to own monitor
152 latch.await();
153
154 // thread should wait
155 int expected = JVMTI_THREAD_STATE_ALIVE |
156 JVMTI_THREAD_STATE_WAITING |
157 JVMTI_THREAD_STATE_WAITING_INDEFINITELY |
158 JVMTI_THREAD_STATE_IN_OBJECT_WAIT;
159 await(thread, expected);
160
161 // notify so thread waits to re-enter monitor
162 synchronized (lock) {
163 lock.notifyAll();
164 expected = JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER;
165 check(thread, expected);
166
167 // re-test with interrupt status set
168 thread.interrupt();
169 check(thread, expected | JVMTI_THREAD_STATE_INTERRUPTED);
170 }
171 } finally {
172 thread.interrupt();
173 thread.join();
174 }
175 }
176
177 /**
178 * Test state of thread waiting in Object.wait(millis).
179 */
180 @Test
181 void testObjectWaitMillis() throws Exception {
182 var latch = new CountDownLatch(1);
183 Object lock = new Object();
184 var thread = Thread.ofVirtual().start(() -> {
185 synchronized (lock) {
186 latch.countDown();
187 try {
188 lock.wait(Long.MAX_VALUE);
189 } catch (InterruptedException e) { }
190 }
191 });
192 try {
193 // wait for thread to own monitor
194 latch.await();
195
196 // thread should wait
197 int expected = JVMTI_THREAD_STATE_ALIVE |
198 JVMTI_THREAD_STATE_WAITING |
199 JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT |
200 JVMTI_THREAD_STATE_IN_OBJECT_WAIT;
201 await(thread, expected);
202
203 // notify so thread waits to re-enter monitor
204 synchronized (lock) {
205 lock.notifyAll();
206 expected = JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER;
207 check(thread, expected);
208
209 // re-test with interrupt status set
210 thread.interrupt();
211 check(thread, expected | JVMTI_THREAD_STATE_INTERRUPTED);
212 }
213 } finally {
214 thread.interrupt();
215 thread.join();
216 }
217 }
218
219 /**
220 * Test state of thread parked with LockSupport.park.
221 */
222 @Test
223 void testPark() throws Exception {
224 var latch = new CountDownLatch(1);
225 var done = new AtomicBoolean();
226 var thread = Thread.ofVirtual().start(() -> {
227 latch.countDown();
228 while (!done.get()) {
229 LockSupport.park();
230 }
231 });
232 try {
233 // wait for thread to start execution
234 latch.await();
235
236 // thread should park
237 int expected = JVMTI_THREAD_STATE_ALIVE |
238 JVMTI_THREAD_STATE_WAITING |
239 JVMTI_THREAD_STATE_WAITING_INDEFINITELY |
240 JVMTI_THREAD_STATE_PARKED;
241 await(thread, expected);
242 } finally {
243 done.set(true);
244 LockSupport.unpark(thread);
245 thread.join();
246 }
247 }
248
249 /**
250 * Test state of thread parked with LockSupport.parkNanos.
251 */
252 @Test
253 void testParkNanos() throws Exception {
254 var latch = new CountDownLatch(1);
255 var done = new AtomicBoolean();
256 var thread = Thread.ofVirtual().start(() -> {
257 latch.countDown();
258 while (!done.get()) {
259 LockSupport.parkNanos(Long.MAX_VALUE);
260 }
261 });
262 try {
263 // wait for thread to start execution
264 latch.await();
265
266 // thread should park
267 int expected = JVMTI_THREAD_STATE_ALIVE |
268 JVMTI_THREAD_STATE_WAITING |
269 JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT |
270 JVMTI_THREAD_STATE_PARKED;
271 await(thread, expected);
272 } finally {
273 done.set(true);
274 LockSupport.unpark(thread);
275 thread.join();
276 }
277 }
278
279 /**
280 * Test state of thread parked with LockSupport.park while holding a monitor.
281 */
282 @Test
283 void testParkWhenPinned() throws Exception {
284 var latch = new CountDownLatch(1);
285 Object lock = new Object();
286 var done = new AtomicBoolean();
287 var thread = Thread.ofVirtual().start(() -> {
288 synchronized (lock) {
289 latch.countDown();
290 while (!done.get()) {
291 LockSupport.park();
292 }
293 }
294 });
295 try {
296 // wait for thread to own monitor
297 latch.await();
298
299 // thread should park
300 int expected = JVMTI_THREAD_STATE_ALIVE |
301 JVMTI_THREAD_STATE_WAITING |
302 JVMTI_THREAD_STATE_WAITING_INDEFINITELY |
303 JVMTI_THREAD_STATE_PARKED;
304 await(thread, expected);
305 } finally {
306 done.set(true);
307 LockSupport.unpark(thread);
308 thread.join();
309 }
310 }
311
312 /**
313 * Test state of thread parked with LockSupport.parkNanos while holding a monitor.
314 */
315 @Test
316 void testParkNanosWhenPinned() throws Exception {
317 var latch = new CountDownLatch(1);
318 Object lock = new Object();
319 var done = new AtomicBoolean();
320 var thread = Thread.ofVirtual().start(() -> {
321 synchronized (lock) {
322 latch.countDown();
323 while (!done.get()) {
324 LockSupport.parkNanos(Long.MAX_VALUE);
325 }
326 }
327 });
328 try {
329 // wait for thread to own monitor
330 latch.await();
331
332 // thread should park
333 int expected = JVMTI_THREAD_STATE_ALIVE |
334 JVMTI_THREAD_STATE_WAITING |
335 JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT |
336 JVMTI_THREAD_STATE_PARKED;
337 await(thread, expected);
338 } finally {
339 done.set(true);
340 LockSupport.unpark(thread);
341 thread.join();
342 }
343 }
344
345 /**
346 * Asserts that the given thread has the expected JVMTI state.
347 */
348 private static void check(Thread thread, int expected) {
349 System.err.format(" expect state=0x%x (%s) ...%n", expected, jvmtiStateToString(expected));
350 int state = jvmtiState(thread);
351 System.err.format(" thread state=0x%x (%s)%n", state, jvmtiStateToString(state));
352 assertEquals(expected, state);
353 }
354
355 /**
356 * Waits indefinitely for the given thread to get to the target JVMTI state.
357 */
358 private static void await(Thread thread, int targetState) throws Exception {
359 System.err.format(" await state=0x%x (%s) ...%n", targetState, jvmtiStateToString(targetState));
360 int state = jvmtiState(thread);
361 System.err.format(" thread state=0x%x (%s)%n", state, jvmtiStateToString(state));
362 while (state != targetState) {
363 assertTrue(thread.isAlive(), "Thread has terminated");
364 Thread.sleep(20);
|
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 id=default
26 * @bug 8312498
27 * @summary Basic test for JVMTI GetThreadState with virtual threads
28 * @library /test/lib
29 * @run junit/othervm/native GetThreadStateTest
30 */
31
32 /*
33 * @test id=no-vmcontinuations
34 * @requires vm.continuations
35 * @library /test/lib
36 * @run junit/othervm/native -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations GetThreadStateTest
37 */
38
39 import java.util.StringJoiner;
40 import java.util.concurrent.atomic.AtomicBoolean;
41 import java.util.concurrent.locks.LockSupport;
42
43 import jdk.test.lib.thread.VThreadPinner;
44 import org.junit.jupiter.api.BeforeAll;
45 import org.junit.jupiter.api.Test;
46 import static org.junit.jupiter.api.Assertions.*;
47
48 class GetThreadStateTest {
49
50 @BeforeAll
51 static void setup() {
52 System.loadLibrary("GetThreadStateTest");
53 init();
54 }
55
56 /**
57 * Test state of new/unstarted thread.
58 */
59 @Test
60 void testUnstarted() {
61 var thread = Thread.ofVirtual().unstarted(() -> { });
62 check(thread, /*new*/ 0);
63 }
64
65 /**
66 * Test state of terminated thread.
67 */
68 @Test
69 void testTerminated() throws Exception {
70 var thread = Thread.ofVirtual().start(() -> { });
71 thread.join();
72 check(thread, JVMTI_THREAD_STATE_TERMINATED);
73 }
74
75 /**
76 * Test state of runnable thread.
77 */
78 @Test
79 void testRunnable() throws Exception {
80 var started = new AtomicBoolean();
81 var done = new AtomicBoolean();
82 var thread = Thread.ofVirtual().start(() -> {
83 started.set(true);
84
85 // spin until done
86 while (!done.get()) {
87 Thread.onSpinWait();
88 }
89 });
90 try {
91 // wait for thread to start execution
92 awaitTrue(started);
93
94 // thread should be runnable
95 int expected = JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_RUNNABLE;
96 check(thread, expected);
97
98 // re-test with interrupt status set
99 thread.interrupt();
100 check(thread, expected | JVMTI_THREAD_STATE_INTERRUPTED);
101 } finally {
102 done.set(true);
103 thread.join();
104 }
105 }
106
107 /**
108 * Test state of thread waiting to enter a monitor.
109 */
110 @Test
111 void testMonitorEnter() throws Exception {
112 var started = new AtomicBoolean();
113 Object lock = new Object();
114 var thread = Thread.ofVirtual().unstarted(() -> {
115 started.set(true);
116 synchronized (lock) { }
117 });
118 try {
119 synchronized (lock) {
120 // start thread and wait for it to start execution
121 thread.start();
122 awaitTrue(started);
123
124 // thread should block on monitor enter
125 int expected = JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER;
126 await(thread, expected);
127
128 // re-test with interrupt status set
129 thread.interrupt();
130 check(thread, expected | JVMTI_THREAD_STATE_INTERRUPTED);
131 }
132 } finally {
133 thread.join();
134 }
135 }
136
137 /**
138 * Test state of thread waiting in Object.wait().
139 */
140 @Test
141 void testObjectWait() throws Exception {
142 var started = new AtomicBoolean();
143 Object lock = new Object();
144 var thread = Thread.ofVirtual().start(() -> {
145 synchronized (lock) {
146 started.set(true);
147 try {
148 lock.wait();
149 } catch (InterruptedException e) { }
150 }
151 });
152 try {
153 // wait for thread to start execution
154 awaitTrue(started);
155
156 // thread should wait
157 int expected = JVMTI_THREAD_STATE_ALIVE |
158 JVMTI_THREAD_STATE_WAITING |
159 JVMTI_THREAD_STATE_WAITING_INDEFINITELY |
160 JVMTI_THREAD_STATE_IN_OBJECT_WAIT;
161 await(thread, expected);
162
163 // notify so thread waits to re-enter monitor
164 synchronized (lock) {
165 lock.notifyAll();
166 expected = JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER;
167 check(thread, expected);
168
169 // re-test with interrupt status set
170 thread.interrupt();
171 check(thread, expected | JVMTI_THREAD_STATE_INTERRUPTED);
172 }
173 } finally {
174 thread.interrupt();
175 thread.join();
176 }
177 }
178
179 /**
180 * Test state of thread waiting in Object.wait(millis).
181 */
182 @Test
183 void testObjectWaitMillis() throws Exception {
184 var started = new AtomicBoolean();
185 Object lock = new Object();
186 var thread = Thread.ofVirtual().start(() -> {
187 synchronized (lock) {
188 started.set(true);
189 try {
190 lock.wait(Long.MAX_VALUE);
191 } catch (InterruptedException e) { }
192 }
193 });
194 try {
195 // wait for thread to start execution
196 awaitTrue(started);
197
198 // thread should wait
199 int expected = JVMTI_THREAD_STATE_ALIVE |
200 JVMTI_THREAD_STATE_WAITING |
201 JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT |
202 JVMTI_THREAD_STATE_IN_OBJECT_WAIT;
203 await(thread, expected);
204
205 // notify so thread waits to re-enter monitor
206 synchronized (lock) {
207 lock.notifyAll();
208 expected = JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER;
209 check(thread, expected);
210
211 // re-test with interrupt status set
212 thread.interrupt();
213 check(thread, expected | JVMTI_THREAD_STATE_INTERRUPTED);
214 }
215 } finally {
216 thread.interrupt();
217 thread.join();
218 }
219 }
220
221 /**
222 * Test state of thread parked with LockSupport.park.
223 */
224 @Test
225 void testPark() throws Exception {
226 var started = new AtomicBoolean();
227 var done = new AtomicBoolean();
228 var thread = Thread.ofVirtual().start(() -> {
229 started.set(true);
230 while (!done.get()) {
231 LockSupport.park();
232 }
233 });
234 try {
235 // wait for thread to start execution
236 awaitTrue(started);
237
238 // thread should park
239 int expected = JVMTI_THREAD_STATE_ALIVE |
240 JVMTI_THREAD_STATE_WAITING |
241 JVMTI_THREAD_STATE_WAITING_INDEFINITELY |
242 JVMTI_THREAD_STATE_PARKED;
243 await(thread, expected);
244 } finally {
245 done.set(true);
246 LockSupport.unpark(thread);
247 thread.join();
248 }
249 }
250
251 /**
252 * Test state of thread parked with LockSupport.parkNanos.
253 */
254 @Test
255 void testParkNanos() throws Exception {
256 var started = new AtomicBoolean();
257 var done = new AtomicBoolean();
258 var thread = Thread.ofVirtual().start(() -> {
259 started.set(true);
260 while (!done.get()) {
261 LockSupport.parkNanos(Long.MAX_VALUE);
262 }
263 });
264 try {
265 // wait for thread to start execution
266 awaitTrue(started);
267
268 // thread should park
269 int expected = JVMTI_THREAD_STATE_ALIVE |
270 JVMTI_THREAD_STATE_WAITING |
271 JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT |
272 JVMTI_THREAD_STATE_PARKED;
273 await(thread, expected);
274 } finally {
275 done.set(true);
276 LockSupport.unpark(thread);
277 thread.join();
278 }
279 }
280
281 /**
282 * Test state of thread parked with LockSupport.park while holding a monitor.
283 */
284 @Test
285 void testParkWhenPinned() throws Exception {
286 var started = new AtomicBoolean();
287 var done = new AtomicBoolean();
288 var thread = Thread.ofVirtual().start(() -> {
289 VThreadPinner.runPinned(() -> {
290 started.set(true);
291 while (!done.get()) {
292 LockSupport.park();
293 }
294 });
295 });
296 try {
297 // wait for thread to start execution
298 awaitTrue(started);
299
300 // thread should park
301 int expected = JVMTI_THREAD_STATE_ALIVE |
302 JVMTI_THREAD_STATE_WAITING |
303 JVMTI_THREAD_STATE_WAITING_INDEFINITELY |
304 JVMTI_THREAD_STATE_PARKED;
305 await(thread, expected);
306 } finally {
307 done.set(true);
308 LockSupport.unpark(thread);
309 thread.join();
310 }
311 }
312
313 /**
314 * Test state of thread parked with LockSupport.parkNanos while holding a monitor.
315 */
316 @Test
317 void testParkNanosWhenPinned() throws Exception {
318 var started = new AtomicBoolean();
319 var done = new AtomicBoolean();
320 var thread = Thread.ofVirtual().start(() -> {
321 VThreadPinner.runPinned(() -> {
322 started.set(true);
323 while (!done.get()) {
324 LockSupport.parkNanos(Long.MAX_VALUE);
325 }
326 });
327 });
328 try {
329 // wait for thread to start execution
330 awaitTrue(started);
331
332 // thread should park
333 int expected = JVMTI_THREAD_STATE_ALIVE |
334 JVMTI_THREAD_STATE_WAITING |
335 JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT |
336 JVMTI_THREAD_STATE_PARKED;
337 await(thread, expected);
338 } finally {
339 done.set(true);
340 LockSupport.unpark(thread);
341 thread.join();
342 }
343 }
344
345 /**
346 * Waits for the boolean value to become true.
347 */
348 private static void awaitTrue(AtomicBoolean ref) throws Exception {
349 while (!ref.get()) {
350 Thread.sleep(20);
351 }
352 }
353
354 /**
355 * Asserts that the given thread has the expected JVMTI state.
356 */
357 private static void check(Thread thread, int expected) {
358 System.err.format(" expect state=0x%x (%s) ...%n", expected, jvmtiStateToString(expected));
359 int state = jvmtiState(thread);
360 System.err.format(" thread state=0x%x (%s)%n", state, jvmtiStateToString(state));
361 assertEquals(expected, state);
362 }
363
364 /**
365 * Waits indefinitely for the given thread to get to the target JVMTI state.
366 */
367 private static void await(Thread thread, int targetState) throws Exception {
368 System.err.format(" await state=0x%x (%s) ...%n", targetState, jvmtiStateToString(targetState));
369 int state = jvmtiState(thread);
370 System.err.format(" thread state=0x%x (%s)%n", state, jvmtiStateToString(state));
371 while (state != targetState) {
372 assertTrue(thread.isAlive(), "Thread has terminated");
373 Thread.sleep(20);
|