42
42
import com .oracle .svm .core .annotate .TargetClass ;
43
43
import com .oracle .svm .core .jdk .ContinuationsSupported ;
44
44
import com .oracle .svm .core .jdk .NotLoomJDK ;
45
+ import com .oracle .svm .core .monitor .MonitorSupport ;
45
46
import com .oracle .svm .core .stack .JavaFrameAnchor ;
46
47
import com .oracle .svm .core .stack .JavaFrameAnchors ;
47
48
import com .oracle .svm .core .util .VMError ;
@@ -168,10 +169,13 @@ private void mount() {
168
169
if (JavaThreads .isInterrupted (this )) {
169
170
JavaThreads .platformSetInterrupt (carrier );
170
171
} else if (JavaThreads .isInterrupted (carrier )) {
171
- synchronized (interruptLock ()) {
172
+ Object token = switchToCarrierAndAcquireInterruptLock ();
173
+ try {
172
174
if (!JavaThreads .isInterrupted (this )) {
173
175
JavaThreads .platformGetAndClearInterrupt (carrier );
174
176
}
177
+ } finally {
178
+ releaseInterruptLockAndSwitchBack (token );
175
179
}
176
180
}
177
181
@@ -374,11 +378,14 @@ void unpark() {
374
378
submitRunContinuation ();
375
379
}
376
380
} else if (s == PINNED ) {
377
- synchronized (interruptLock ()) {
381
+ Object token = switchToCarrierAndAcquireInterruptLock ();
382
+ try {
378
383
Thread carrier = carrierThread ;
379
384
if (carrier != null && state () == PINNED ) {
380
385
U .unpark (carrier );
381
386
}
387
+ } finally {
388
+ releaseInterruptLockAndSwitchBack (token );
382
389
}
383
390
}
384
391
}
@@ -428,10 +435,41 @@ private Object interruptLock() {
428
435
return JavaThreads .toTarget (this ).blockerLock ;
429
436
}
430
437
438
+ /** @see #releaseInterruptLockAndSwitchBack */
439
+ private Object switchToCarrierAndAcquireInterruptLock () {
440
+ Object token = null ;
441
+ Thread current = Thread .currentThread ();
442
+ if (current instanceof SubstrateVirtualThread ) {
443
+ SubstrateVirtualThread vthread = (SubstrateVirtualThread ) current ;
444
+ /*
445
+ * If we block on the interrupt lock in the virtual thread, we yield, for which we first
446
+ * unmount. Unmounting also tries to acquire the interrupt lock and we might block
447
+ * again, this time on the carrier thread. Then, the virtual thread cannot continue to
448
+ * yield and execute on another thread later, and the carrier thread might not get
449
+ * unparked, and both threads are stuck.
450
+ */
451
+ Thread carrier = vthread .carrierThread ;
452
+ JavaThreads .setCurrentThread (carrier , carrier );
453
+ token = vthread ;
454
+ }
455
+ MonitorSupport .singleton ().monitorEnter (interruptLock ());
456
+ return token ;
457
+ }
458
+
459
+ /** @see #switchToCarrierAndAcquireInterruptLock */
460
+ private void releaseInterruptLockAndSwitchBack (Object token ) {
461
+ MonitorSupport .singleton ().monitorExit (interruptLock ());
462
+ if (token != null ) {
463
+ SubstrateVirtualThread vthread = (SubstrateVirtualThread ) token ;
464
+ JavaThreads .setCurrentThread (vthread .carrierThread , vthread );
465
+ }
466
+ }
467
+
431
468
@ Override
432
469
public void interrupt () {
433
470
if (Thread .currentThread () != this ) {
434
- synchronized (interruptLock ()) {
471
+ Object token = switchToCarrierAndAcquireInterruptLock ();
472
+ try {
435
473
JavaThreads .getAndWriteInterruptedFlag (this , true );
436
474
Target_sun_nio_ch_Interruptible b = JavaThreads .toTarget (this ).blocker ;
437
475
if (b != null ) {
@@ -441,6 +479,8 @@ public void interrupt() {
441
479
if (carrier != null ) {
442
480
JavaThreads .platformSetInterrupt (carrier );
443
481
}
482
+ } finally {
483
+ releaseInterruptLockAndSwitchBack (token );
444
484
}
445
485
} else {
446
486
JavaThreads .getAndWriteInterruptedFlag (this , true );
@@ -451,8 +491,11 @@ public void interrupt() {
451
491
452
492
boolean getAndClearCarrierInterrupt () {
453
493
assert Thread .currentThread () == this ;
454
- synchronized (interruptLock ()) {
494
+ Object token = switchToCarrierAndAcquireInterruptLock ();
495
+ try {
455
496
return JavaThreads .platformGetAndClearInterrupt (carrierThread );
497
+ } finally {
498
+ releaseInterruptLockAndSwitchBack (token );
456
499
}
457
500
}
458
501
@@ -496,12 +539,15 @@ public Thread.State getState() {
496
539
return Thread .State .RUNNABLE ;
497
540
case RUNNING :
498
541
// if mounted then return state of carrier thread
499
- synchronized (interruptLock ()) {
542
+ Object token = switchToCarrierAndAcquireInterruptLock ();
543
+ try {
500
544
@ SuppressWarnings ("hiding" )
501
545
Thread carrierThread = this .carrierThread ;
502
546
if (carrierThread != null ) {
503
547
return JavaThreads .getThreadState (carrierThread );
504
548
}
549
+ } finally {
550
+ releaseInterruptLockAndSwitchBack (token );
505
551
}
506
552
// runnable, mounted
507
553
return Thread .State .RUNNABLE ;
@@ -533,14 +579,17 @@ public String toString() {
533
579
Thread carrier = carrierThread ;
534
580
if (carrier != null ) {
535
581
// include the carrier thread state and name when mounted
536
- synchronized (interruptLock ()) {
582
+ Object token = switchToCarrierAndAcquireInterruptLock ();
583
+ try {
537
584
carrier = carrierThread ;
538
585
if (carrier != null ) {
539
586
String stateAsString = JavaThreads .getThreadState (carrier ).toString ();
540
587
sb .append (stateAsString .toLowerCase (Locale .ROOT ));
541
588
sb .append ('@' );
542
589
sb .append (carrier .getName ());
543
590
}
591
+ } finally {
592
+ releaseInterruptLockAndSwitchBack (token );
544
593
}
545
594
}
546
595
// include virtual thread state when not mounted
0 commit comments