@@ -274,21 +274,56 @@ enterVThreadTransitionCritical(J9VMThread *currentThread, jobject thread)
274
274
MM_ObjectAccessBarrierAPI objectAccessBarrier = MM_ObjectAccessBarrierAPI (currentThread);
275
275
j9object_t threadObj = J9_JNI_UNWRAP_REFERENCE (thread);
276
276
277
- while (!objectAccessBarrier.inlineMixedObjectCompareAndSwapU64 (currentThread, threadObj, vm->virtualThreadInspectorCountOffset , 0 , (U_64)-1 )) {
277
+ retry:
278
+ while (!objectAccessBarrier.inlineMixedObjectCompareAndSwapU64 (currentThread, threadObj, vm->virtualThreadInspectorCountOffset , 0 , ~(U_64)0 )) {
278
279
/* Thread is being inspected or unmounted, wait. */
279
280
vmFuncs->internalReleaseVMAccess (currentThread);
280
281
VM_AtomicSupport::yieldCPU ();
281
282
/* After wait, the thread may suspend here. */
282
283
vmFuncs->internalAcquireVMAccess (currentThread);
283
284
threadObj = J9_JNI_UNWRAP_REFERENCE (thread);
284
285
}
286
+
287
+ /* Link the current J9VMThread with the virtual thread object. */
288
+ if (!objectAccessBarrier.inlineMixedObjectCompareAndSwapU64 (currentThread, threadObj, vm->internalSuspendStateOffset , J9_VIRTUALTHREAD_INTERNAL_STATE_NONE, (U_64)currentThread)) {
289
+ /* If virtual thread is suspended while unmounted, reset the inspectorCount and do a wait and retry. */
290
+ if (VM_VMHelpers::isThreadSuspended (currentThread, threadObj)) {
291
+ J9OBJECT_I64_STORE (currentThread, threadObj, vm->virtualThreadInspectorCountOffset , 0 );
292
+ }
293
+ vmFuncs->internalReleaseVMAccess (currentThread);
294
+ /* Spin is used instead of the halt flag as we cannot guarantee suspend flag is still set now.
295
+ *
296
+ * TODO: Dynamically increase the sleep time to a bounded maximum.
297
+ */
298
+ f_threadSleep (10 );
299
+ /* After wait, the thread may suspend here. */
300
+ vmFuncs->internalAcquireVMAccess (currentThread);
301
+ threadObj = J9_JNI_UNWRAP_REFERENCE (thread);
302
+ goto retry;
303
+ }
285
304
}
286
305
287
306
static void
288
- exitVThreadTransitionCritical (J9VMThread *currentThread, j9object_t vthread )
307
+ exitVThreadTransitionCritical (J9VMThread *currentThread, jobject thread )
289
308
{
290
- Assert_SC_true (-1 == J9OBJECT_I64_LOAD (currentThread, vthread, currentThread->javaVM ->virtualThreadInspectorCountOffset ));
291
- J9OBJECT_I64_STORE (currentThread, vthread, currentThread->javaVM ->virtualThreadInspectorCountOffset , 0 );
309
+ J9JavaVM *vm = currentThread->javaVM ;
310
+ J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions ;
311
+ j9object_t vthread = J9_JNI_UNWRAP_REFERENCE (thread);
312
+ MM_ObjectAccessBarrierAPI objectAccessBarrier = MM_ObjectAccessBarrierAPI (currentThread);
313
+
314
+ /* Remove J9VMThread address from internalSuspendedState field, as the thread state is no longer in a transition. */
315
+ while (!objectAccessBarrier.inlineMixedObjectCompareAndSwapU64 (currentThread, vthread, vm->internalSuspendStateOffset , (U_64)currentThread, J9_VIRTUALTHREAD_INTERNAL_STATE_NONE)) {
316
+ /* Wait if the suspend flag is set. */
317
+ vmFuncs->internalReleaseVMAccess (currentThread);
318
+ VM_AtomicSupport::yieldCPU ();
319
+ /* After wait, the thread may suspend here. */
320
+ vmFuncs->internalAcquireVMAccess (currentThread);
321
+ vthread = J9_JNI_UNWRAP_REFERENCE (thread);
322
+ }
323
+
324
+ /* Update to virtualThreadInspectorCount must be after clearing isSuspendedInternal field to retain sync ordering. */
325
+ Assert_SC_true (-1 == J9OBJECT_I64_LOAD (currentThread, vthread, vm->virtualThreadInspectorCountOffset ));
326
+ J9OBJECT_I64_STORE (currentThread, vthread, vm->virtualThreadInspectorCountOffset , 0 );
292
327
}
293
328
294
329
static void
@@ -301,7 +336,7 @@ setContinuationStateToLastUnmount(J9VMThread *currentThread, jobject thread)
301
336
ContinuationState volatile *continuationStatePtr = VM_ContinuationHelpers::getContinuationStateAddress (currentThread, continuationObj);
302
337
/* Used in JVMTI to not suspend the virtual thread once it enters the last unmount phase. */
303
338
VM_ContinuationHelpers::setLastUnmount (continuationStatePtr);
304
- exitVThreadTransitionCritical (currentThread, threadObj );
339
+ exitVThreadTransitionCritical (currentThread, thread );
305
340
}
306
341
307
342
/* Caller must have VMAccess. */
@@ -329,27 +364,6 @@ virtualThreadMountBegin(JNIEnv *env, jobject thread)
329
364
330
365
enterVThreadTransitionCritical (currentThread, thread);
331
366
332
- /* Virtual thread is being mounted but it has been suspended. Spin until the
333
- * virtual thread is resumed. The virtual thread should not be mounted until
334
- * it is resumed.
335
- */
336
- J9JavaVM *vm = currentThread->javaVM ;
337
- J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions ;
338
- threadObj = J9_JNI_UNWRAP_REFERENCE (thread);
339
- while (0 != J9OBJECT_U32_LOAD (currentThread, threadObj, vm->isSuspendedInternalOffset )) {
340
- exitVThreadTransitionCritical (currentThread, threadObj);
341
- vmFuncs->internalReleaseVMAccess (currentThread);
342
- /* Spin is used instead of the halt flag; otherwise, the carrier thread will
343
- * show as suspended.
344
- *
345
- * TODO: Dynamically increase the sleep time to a bounded maximum.
346
- */
347
- f_threadSleep (10 );
348
- vmFuncs->internalAcquireVMAccess (currentThread);
349
- enterVThreadTransitionCritical (currentThread, thread);
350
- threadObj = J9_JNI_UNWRAP_REFERENCE (thread);
351
- }
352
-
353
367
VM_VMHelpers::virtualThreadHideFrames (currentThread, JNI_TRUE);
354
368
}
355
369
@@ -378,7 +392,7 @@ virtualThreadMountEnd(JNIEnv *env, jobject thread)
378
392
VM_VMHelpers::virtualThreadHideFrames (currentThread, JNI_FALSE);
379
393
380
394
/* Allow thread to be inspected again. */
381
- exitVThreadTransitionCritical (currentThread, threadObj );
395
+ exitVThreadTransitionCritical (currentThread, thread );
382
396
383
397
TRIGGER_J9HOOK_VM_VIRTUAL_THREAD_MOUNT (vm->hookInterface , currentThread);
384
398
}
@@ -412,13 +426,12 @@ virtualThreadUnmountBegin(JNIEnv *env, jobject thread)
412
426
413
427
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions ;
414
428
j9object_t carrierThreadObject = currentThread->carrierThreadObject ;
415
- threadObj = J9_JNI_UNWRAP_REFERENCE (thread);
416
429
/* Virtual thread is being umounted. If its carrier thread is suspended, spin until
417
430
* the carrier thread is resumed. The carrier thread should not be mounted until it
418
431
* is resumed.
419
432
*/
420
- while (0 != J9OBJECT_U32_LOAD (currentThread, carrierThreadObject, vm-> isSuspendedInternalOffset )) {
421
- exitVThreadTransitionCritical (currentThread, threadObj );
433
+ while (VM_VMHelpers::isThreadSuspended (currentThread, carrierThreadObject)) {
434
+ exitVThreadTransitionCritical (currentThread, thread );
422
435
vmFuncs->internalReleaseVMAccess (currentThread);
423
436
/* Spin is used instead of the halt flag; otherwise, the virtual thread will
424
437
* show as suspended.
@@ -429,7 +442,6 @@ virtualThreadUnmountBegin(JNIEnv *env, jobject thread)
429
442
vmFuncs->internalAcquireVMAccess (currentThread);
430
443
enterVThreadTransitionCritical (currentThread, thread);
431
444
carrierThreadObject = currentThread->carrierThreadObject ;
432
- threadObj = J9_JNI_UNWRAP_REFERENCE (thread);
433
445
}
434
446
435
447
VM_VMHelpers::virtualThreadHideFrames (currentThread, JNI_TRUE);
@@ -467,7 +479,7 @@ virtualThreadUnmountEnd(JNIEnv *env, jobject thread)
467
479
VM_VMHelpers::virtualThreadHideFrames (currentThread, JNI_FALSE);
468
480
469
481
/* Allow thread to be inspected again. */
470
- exitVThreadTransitionCritical (currentThread, threadObj );
482
+ exitVThreadTransitionCritical (currentThread, thread );
471
483
}
472
484
#endif /* JAVA_SPEC_VERSION >= 19 */
473
485
@@ -609,7 +621,7 @@ JVM_VirtualThreadHideFrames(
609
621
610
622
if (!hide) {
611
623
Assert_SC_true (hiddenFrames);
612
- exitVThreadTransitionCritical (currentThread, vThreadObj );
624
+ exitVThreadTransitionCritical (currentThread, (jobject)¤tThread-> threadObject );
613
625
}
614
626
615
627
vmFuncs->internalExitVMToJNI (currentThread);
0 commit comments