41
41
42
42
/**
43
43
* {@link JavaMonitorQueuedSynchronizer} is based on the code of
44
- * {@link java.util.concurrent.locks.AbstractQueuedLongSynchronizer} as of JDK 21+26 . This class
44
+ * {@link java.util.concurrent.locks.AbstractQueuedLongSynchronizer} as of JDK 24+11 . This class
45
45
* could be merged with {@link JavaMonitor} but we keep it separate because that way diffing against
46
46
* the JDK sources is easier.
47
47
*
60
60
*/
61
61
@ BasedOnJDKClass (AbstractQueuedLongSynchronizer .class )
62
62
abstract class JavaMonitorQueuedSynchronizer {
63
- // Node. status field values
63
+ // Node status bits, also used as argument and return values
64
64
static final int WAITING = 1 ; // must be 1
65
65
static final int CANCELLED = 0x80000000 ; // must be negative
66
66
static final int COND = 2 ; // in a condition wait
@@ -71,38 +71,38 @@ abstract class JavaMonitorQueuedSynchronizer {
71
71
// see AbstractQueuedLongSynchronizer.Node
72
72
@ BasedOnJDKClass (value = AbstractQueuedLongSynchronizer .class , innerClass = "Node" )
73
73
abstract static class Node {
74
- volatile Node prev ;
75
- volatile Node next ;
76
- Thread waiter ;
77
- volatile int status ;
74
+ volatile Node prev ; // initially attached via casTail
75
+ volatile Node next ; // visibly nonnull when signallable
76
+ Thread waiter ; // visibly nonnull when enqueued
77
+ volatile int status ; // written by owner, atomic bit ops by others
78
78
79
79
// see AbstractQueuedLongSynchronizer.Node.casPrev(Node, Node)
80
- final boolean casPrev (Node c , Node v ) {
80
+ final boolean casPrev (Node c , Node v ) { // for cleanQueue
81
81
return U .weakCompareAndSetReference (this , PREV , c , v );
82
82
}
83
83
84
84
// see AbstractQueuedLongSynchronizer.Node.casNext(Node, Node)
85
- final boolean casNext (Node c , Node v ) {
85
+ final boolean casNext (Node c , Node v ) { // for cleanQueue
86
86
return U .weakCompareAndSetReference (this , NEXT , c , v );
87
87
}
88
88
89
89
// see AbstractQueuedLongSynchronizer.Node.getAndUnsetStatus(int)
90
- final int getAndUnsetStatus (int v ) {
90
+ final int getAndUnsetStatus (int v ) { // for signalling
91
91
return U .getAndBitwiseAndInt (this , STATUS , ~v );
92
92
}
93
93
94
94
// see AbstractQueuedLongSynchronizer.Node.setPrevRelaxed(Node)
95
- final void setPrevRelaxed (Node p ) {
95
+ final void setPrevRelaxed (Node p ) { // for off-queue assignment
96
96
U .putReference (this , PREV , p );
97
97
}
98
98
99
99
// see AbstractQueuedLongSynchronizer.Node.setStatusRelaxed(int)
100
- final void setStatusRelaxed (int s ) {
100
+ final void setStatusRelaxed (int s ) { // for off-queue assignment
101
101
U .putInt (this , STATUS , s );
102
102
}
103
103
104
104
// see AbstractQueuedLongSynchronizer.Node.clearStatus()
105
- final void clearStatus () {
105
+ final void clearStatus () { // for reducing unneeded signals
106
106
U .putIntOpaque (this , STATUS , 0 );
107
107
}
108
108
@@ -119,7 +119,7 @@ static final class ExclusiveNode extends Node {
119
119
// see AbstractQueuedLongSynchronizer.ConditionNode
120
120
@ BasedOnJDKClass (value = AbstractQueuedLongSynchronizer .class , innerClass = "ConditionNode" )
121
121
static final class ConditionNode extends Node {
122
- ConditionNode nextWaiter ;
122
+ ConditionNode nextWaiter ; // link to next waiting node
123
123
long notifierJfrTid ;
124
124
125
125
// see AbstractQueuedLongSynchronizer.ConditionNode.isReleasable()
@@ -153,16 +153,17 @@ protected final long getState() {
153
153
154
154
// see AbstractQueuedLongSynchronizer.setState(long)
155
155
protected final void setState (long newState ) {
156
- this . state = newState ;
156
+ state = newState ;
157
157
}
158
158
159
159
/**
160
- * For {@linkplain JavaMonitorConditionObject#await conditional waiting}, returns the number of
161
- * acquisitions, which is subsequently passed to {@link #tryRelease} to entirely release
162
- * ownership, and later to {@link #tryAcquire} to regain ownership after waiting.
160
+ * Used for {@linkplain JavaMonitorConditionObject#await conditional waiting}. Returns the
161
+ * number of acquisitions, which is subsequently passed to {@link #tryRelease} to entirely
162
+ * release ownership, and later to {@link #tryAcquire} to regain ownership after waiting.
163
163
*
164
- * While {@code AbstractQueuedLongSynchronizer} calls {@link #getState()} assuming that it
165
- * encodes the acquisition count, this method allows for more flexibility in implementations.
164
+ * Note that {@code AbstractQueuedLongSynchronizer} calls {@link #getState()} instead, assuming
165
+ * that the state encodes the acquisition count. This method allows for more flexibility in
166
+ * implementations.
166
167
*/
167
168
protected abstract long getAcquisitions ();
168
169
@@ -205,13 +206,13 @@ final void enqueue(ConditionNode node) {
205
206
boolean unpark = false ;
206
207
for (Node t ;;) {
207
208
if ((t = tail ) == null && (t = tryInitializeHead ()) == null ) {
208
- unpark = true ; // wake up to spin on OOME
209
+ unpark = true ; // wake up to spin on OOME
209
210
break ;
210
211
}
211
- node .setPrevRelaxed (t ); // avoid unnecessary fence
212
+ node .setPrevRelaxed (t ); // avoid unnecessary fence
212
213
if (casTail (t , node )) {
213
214
t .next = node ;
214
- if (t .status < 0 ) { // wake up to clean link
215
+ if (t .status < 0 ) { // wake up to clean link
215
216
unpark = true ;
216
217
}
217
218
break ;
@@ -279,14 +280,15 @@ protected int getSpinAttempts(int parks) {
279
280
return (1 << parks ) - 1 ;
280
281
}
281
282
282
- // see AbstractQueuedLongSynchronizer.acquire(Node, long, boolean, boolean, boolean, long )
283
+ // see AbstractQueuedLongSynchronizer.acquire(Node, long, false, false, false, 0L )
283
284
@ SuppressWarnings ("all" )
284
285
final int acquire (Node node , long arg ) {
285
286
Thread current = Thread .currentThread ();
287
+ /* Spinning logic is SVM-specific. */
286
288
int parks = 0 ;
287
289
int spins = getSpinAttempts (parks );
288
290
boolean first = false ;
289
- Node pred = null ;
291
+ Node pred = null ; // predecessor of node when enqueued
290
292
291
293
for (;;) {
292
294
if (!first && (pred = (node == null ) ? null : node .prev ) != null && !(first = (head == pred ))) {
@@ -302,6 +304,7 @@ final int acquire(Node node, long arg) {
302
304
boolean acquired ;
303
305
try {
304
306
if (spins > 0 ) {
307
+ /* Spinning logic is SVM-specific. */
305
308
spins = trySpinAcquire (spins , arg );
306
309
acquired = (spins == SPIN_SUCCESS );
307
310
assert !acquired || isHeldExclusively ();
@@ -323,11 +326,11 @@ final int acquire(Node node, long arg) {
323
326
}
324
327
}
325
328
Node t ;
326
- if ((t = tail ) == null ) { // initialize queue
329
+ if ((t = tail ) == null ) { // initialize queue
327
330
if (tryInitializeHead () == null ) {
328
331
return acquireOnOOME (arg );
329
332
}
330
- } else if (node == null ) { // allocate; retry before enqueue
333
+ } else if (node == null ) { // allocate; retry before enqueue
331
334
try {
332
335
node = new ExclusiveNode ();
333
336
} catch (OutOfMemoryError oome ) {
@@ -346,22 +349,28 @@ final int acquire(Node node, long arg) {
346
349
} else if (node .status == 0 ) {
347
350
node .status = WAITING ; // enable signal and recheck
348
351
} else {
352
+ /* Spinning logic is SVM-specific. */
349
353
parks ++;
350
354
spins = getSpinAttempts (parks );
351
- LockSupport .park (this );
355
+ try {
356
+ LockSupport .park (this );
357
+ } catch (Error | RuntimeException ex ) {
358
+ cancelAcquire (node ); // cancel & rethrow
359
+ throw ex ;
360
+ }
352
361
node .clearStatus ();
353
362
}
354
363
}
355
364
}
356
365
357
- // see AbstractQueuedLongSynchronizer.acquireOnOOME(boolean , long)
366
+ // see AbstractQueuedLongSynchronizer.acquireOnOOME(false , long)
358
367
private int acquireOnOOME (long arg ) {
359
368
for (long nanos = 1L ;;) {
360
369
if (tryAcquire (arg )) {
361
370
return 1 ;
362
371
}
363
- U .park (false , nanos ); // must use Unsafe park to sleep
364
- if (nanos < 1L << 30 ) { // max about 1 second
372
+ U .park (false , nanos ); // must use Unsafe park to sleep
373
+ if (nanos < 1L << 30 ) { // max about 1 second
365
374
nanos <<= 1 ;
366
375
}
367
376
}
@@ -401,7 +410,7 @@ private void cleanQueue() {
401
410
}
402
411
}
403
412
404
- // see AbstractQueuedLongSynchronizer.cancelAcquire(Node, boolean, boolean )
413
+ // see AbstractQueuedLongSynchronizer.cancelAcquire(Node, false, false )
405
414
private int cancelAcquire (Node node ) {
406
415
if (node != null ) {
407
416
node .waiter = null ;
@@ -446,23 +455,29 @@ public final class JavaMonitorConditionObject {
446
455
447
456
static final long OOME_COND_WAIT_DELAY = 10L * 1000L * 1000L ; // 10 ms
448
457
458
+ JavaMonitorConditionObject () {
459
+ }
460
+
449
461
// see AbstractQueuedLongSynchronizer.ConditionObject.doSignal(ConditionNode, boolean)
450
462
@ SuppressWarnings ("all" )
451
463
private void doSignal (ConditionNode first , boolean all ) {
452
464
while (first != null ) {
453
465
ConditionNode next = first .nextWaiter ;
466
+
454
467
if ((firstWaiter = next ) == null ) {
455
468
lastWaiter = null ;
456
469
} else {
457
470
first .nextWaiter = null ; // GC assistance
458
471
}
459
472
if ((first .getAndUnsetStatus (COND ) & COND ) != 0 ) {
473
+ /* JFR-related code is SVM-specific. */
460
474
first .notifierJfrTid = SubstrateJVM .getCurrentThreadId ();
461
475
enqueue (first );
462
476
if (!all ) {
463
477
break ;
464
478
}
465
479
}
480
+
466
481
first = next ;
467
482
}
468
483
}
@@ -562,6 +577,7 @@ private ConditionNode newConditionNode() {
562
577
// see AbstractQueuedLongSynchronizer.ConditionObject.await()
563
578
@ SuppressWarnings ("all" )
564
579
public void await (Object obj ) throws InterruptedException {
580
+ /* JFR-related code is SVM-specific. */
565
581
long startTicks = JfrTicks .elapsedTicks ();
566
582
if (Thread .interrupted ()) {
567
583
JavaMonitorWaitEvent .emit (startTicks , obj , 0 , 0L , false );
@@ -601,6 +617,7 @@ public void await(Object obj) throws InterruptedException {
601
617
// see AbstractQueuedLongSynchronizer.ConditionObject.await(long, TimeUnit)
602
618
@ SuppressWarnings ("all" )
603
619
public boolean await (Object obj , long time , TimeUnit unit ) throws InterruptedException {
620
+ /* JFR-related code is SVM-specific. */
604
621
long startTicks = JfrTicks .elapsedTicks ();
605
622
long nanosTimeout = unit .toNanos (time );
606
623
if (Thread .interrupted ()) {
@@ -643,7 +660,7 @@ public boolean await(Object obj, long time, TimeUnit unit) throws InterruptedExc
643
660
644
661
// Unsafe
645
662
private static final Unsafe U = Unsafe .getUnsafe ();
646
- static final long STATE = U .objectFieldOffset (JavaMonitorQueuedSynchronizer .class , "state" );
663
+ private static final long STATE = U .objectFieldOffset (JavaMonitorQueuedSynchronizer .class , "state" );
647
664
private static final long HEAD = U .objectFieldOffset (JavaMonitorQueuedSynchronizer .class , "head" );
648
665
private static final long TAIL = U .objectFieldOffset (JavaMonitorQueuedSynchronizer .class , "tail" );
649
666
}
0 commit comments