123 }
124 }
125 });
126 });
127
128 try {
129 // wait for thread to start and park
130 awaitTrue(started);
131 await(vthread, timed ? Thread.State.TIMED_WAITING : Thread.State.WAITING);
132 } finally {
133 done.set(true);
134 LockSupport.unpark(vthread);
135 vthread.join();
136 recording.stop();
137 }
138
139 assertContainsPinnedEvent(recording, vthread);
140 }
141 }
142
143 /**
144 * Test jdk.VirtualThreadSubmitFailed event.
145 */
146 @Test
147 void testVirtualThreadSubmitFailed() throws Exception {
148 try (Recording recording = new Recording()) {
149 recording.enable("jdk.VirtualThreadSubmitFailed");
150
151 recording.start();
152 try (ExecutorService pool = Executors.newCachedThreadPool()) {
153 Executor scheduler = task -> pool.execute(task);
154
155 // create virtual thread that uses custom scheduler
156 ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
157
158 // start a thread
159 Thread thread = factory.newThread(LockSupport::park);
160 thread.start();
161
162 // wait for thread to park
|
123 }
124 }
125 });
126 });
127
128 try {
129 // wait for thread to start and park
130 awaitTrue(started);
131 await(vthread, timed ? Thread.State.TIMED_WAITING : Thread.State.WAITING);
132 } finally {
133 done.set(true);
134 LockSupport.unpark(vthread);
135 vthread.join();
136 recording.stop();
137 }
138
139 assertContainsPinnedEvent(recording, vthread);
140 }
141 }
142
143 /**
144 * Test jdk.VirtualThreadPinned event when blocking on monitor while pinned.
145 */
146 @Test
147 void testBlockWhenPinned() throws Exception {
148 try (Recording recording = new Recording()) {
149 recording.enable("jdk.VirtualThreadPinned");
150 recording.start();
151
152 Object lock = new Object();
153
154 var started = new AtomicBoolean();
155 var vthread = Thread.ofVirtual().unstarted(() -> {
156 VThreadPinner.runPinned(() -> {
157 started.set(true);
158 synchronized (lock) { }
159 });
160 });
161
162 try {
163 synchronized (lock) {
164 vthread.start();
165 // wait for thread to start and block
166 awaitTrue(started);
167 await(vthread, Thread.State.BLOCKED);
168 }
169 } finally {
170 vthread.join();
171 recording.stop();
172 }
173
174 assertContainsPinnedEvent(recording, vthread);
175 }
176 }
177
178 /**
179 * Test jdk.VirtualThreadPinned event when waiting with Object.wait while pinned.
180 */
181 @ParameterizedTest
182 @ValueSource(booleans = { true, false })
183 void testObjectWaitWhenPinned(boolean timed) throws Exception {
184 try (Recording recording = new Recording()) {
185 recording.enable("jdk.VirtualThreadPinned");
186 recording.start();
187
188 Object lock = new Object();
189
190 var started = new AtomicBoolean();
191 var vthread = Thread.startVirtualThread(() -> {
192 VThreadPinner.runPinned(() -> {
193 started.set(true);
194 synchronized (lock) {
195 try {
196 if (timed) {
197 lock.wait(Long.MAX_VALUE);
198 } else {
199 lock.wait();
200 }
201 } catch (InterruptedException e) {
202 fail();
203 }
204 }
205 });
206 });
207
208 try {
209 // wait for thread to start and wait
210 awaitTrue(started);
211 await(vthread, timed ? Thread.State.TIMED_WAITING : Thread.State.WAITING);
212 } finally {
213 synchronized (lock) {
214 lock.notifyAll();
215 }
216 vthread.join();
217 recording.stop();
218 }
219
220 assertContainsPinnedEvent(recording, vthread);
221 }
222 }
223
224 /**
225 * Test jdk.VirtualThreadPinned event when parking in a class initializer.
226 */
227 @Test
228 void testParkInClassInitializer() throws Exception {
229 class TestClass {
230 static {
231 LockSupport.park();
232 }
233 static void m() {
234 // do nothing
235 }
236 }
237
238 try (Recording recording = new Recording()) {
239 recording.enable("jdk.VirtualThreadPinned");
240 recording.start();
241
242 var started = new AtomicBoolean();
243 Thread vthread = Thread.startVirtualThread(() -> {
244 started.set(true);
245 TestClass.m();
246 });
247
248 try {
249 // wait for it to start and park
250 awaitTrue(started);
251 await(vthread, Thread.State.WAITING);
252 } finally {
253 LockSupport.unpark(vthread);
254 vthread.join();
255 recording.stop();
256 }
257
258 assertContainsPinnedEvent(recording, vthread);
259 }
260 }
261
262 /**
263 * Test jdk.VirtualThreadPinned event when blocking on monitor in a class initializer.
264 */
265 @Test
266 void testBlockInClassInitializer() throws Exception {
267 class LockHolder {
268 static final Object lock = new Object();
269 }
270 class TestClass {
271 static {
272 synchronized (LockHolder.lock) { }
273 }
274 static void m() {
275 // no nothing
276 }
277 }
278
279 try (Recording recording = new Recording()) {
280 recording.enable("jdk.VirtualThreadPinned");
281 recording.start();
282
283 var started = new AtomicBoolean();
284 Thread vthread = Thread.ofVirtual().unstarted(() -> {
285 started.set(true);
286 TestClass.m();
287 });
288
289 try {
290 synchronized (LockHolder.lock) {
291 vthread.start();
292 // wait for thread to start and block
293 awaitTrue(started);
294 await(vthread, Thread.State.BLOCKED);
295 }
296 } finally {
297 vthread.join();
298 recording.stop();
299 }
300
301 assertContainsPinnedEvent(recording, vthread);
302 }
303 }
304
305 /**
306 * Test jdk.VirtualThreadPinned event when waiting for a class initializer.
307 */
308 @Test
309 void testWaitingForClassInitializer() throws Exception {
310 class TestClass {
311 static {
312 LockSupport.park();
313 }
314 static void m() {
315 // do nothing
316 }
317 }
318
319 try (Recording recording = new Recording()) {
320 recording.enable("jdk.VirtualThreadPinned");
321 recording.start();
322
323 var started1 = new AtomicBoolean();
324 var started2 = new AtomicBoolean();
325
326 Thread vthread1 = Thread.ofVirtual().unstarted(() -> {
327 started1.set(true);
328 TestClass.m();
329 });
330 Thread vthread2 = Thread.ofVirtual().unstarted(() -> {
331 started2.set(true);
332 TestClass.m();
333 });
334
335 try {
336 // start first virtual thread and wait for it to start + park
337 vthread1.start();
338 awaitTrue(started1);
339 await(vthread1, Thread.State.WAITING);
340
341 // start second virtual thread and wait for it to start
342 vthread2.start();
343 awaitTrue(started2);
344
345 // give time for second virtual thread to wait on the MutexLocker
346 Thread.sleep(3000);
347
348 } finally {
349 LockSupport.unpark(vthread1);
350 vthread1.join();
351 vthread2.join();
352 recording.stop();
353 }
354
355 // the recording should have a pinned event for vthread2
356 assertContainsPinnedEvent(recording, vthread2);
357 }
358 }
359
360 /**
361 * Test jdk.VirtualThreadSubmitFailed event.
362 */
363 @Test
364 void testVirtualThreadSubmitFailed() throws Exception {
365 try (Recording recording = new Recording()) {
366 recording.enable("jdk.VirtualThreadSubmitFailed");
367
368 recording.start();
369 try (ExecutorService pool = Executors.newCachedThreadPool()) {
370 Executor scheduler = task -> pool.execute(task);
371
372 // create virtual thread that uses custom scheduler
373 ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
374
375 // start a thread
376 Thread thread = factory.newThread(LockSupport::park);
377 thread.start();
378
379 // wait for thread to park
|