ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/StampedLock.java
Revision: 1.21
Committed: Tue Oct 16 23:50:08 2012 UTC (11 years, 7 months ago) by jsr166
Branch: MAIN
Changes since 1.20: +1 -1 lines
Log Message:
double-trouble

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7 package jsr166e;
8
9 import java.util.concurrent.ThreadLocalRandom;
10 import java.util.concurrent.TimeUnit;
11
12 /**
13 * A capability-based lock with three modes for controlling read/write
14 * access. The state of a StampedLock consists of a version and mode.
15 * Lock acquisition methods return a stamp that represents and
16 * controls access with respect to a lock state; "try" versions of
17 * these methods may instead return the special value zero to
18 * represent failure to acquire access. Lock release and conversion
19 * methods require stamps as arguments, and fail if they do not match
20 * the state of the lock. The three modes are:
21 *
22 * <ul>
23 *
24 * <li><b>Writing.</b> Method {@link #writeLock} possibly blocks
25 * waiting for exclusive access, returning a stamp that can be used
26 * in method {@link #unlockWrite} to release the lock. Untimed and
27 * timed versions of {@code tryWriteLock} are also provided. When
28 * the lock is held in write mode, no read locks may be obtained,
29 * and all optimistic read validations will fail. </li>
30 *
31 * <li><b>Reading.</b> Method {@link #readLock} possibly blocks
32 * waiting for non-exclusive access, returning a stamp that can be
33 * used in method {@link #unlockRead} to release the lock. Untimed
34 * and timed versions of {@code tryReadLock} are also provided. </li>
35 *
36 * <li><b>Optimistic Reading.</b> Method {@link #tryOptimisticRead}
37 * returns a non-zero stamp only if the lock is not currently held
38 * in write mode. Method {@link #validate} returns true if the lock
39 * has not since been acquired in write mode. This mode can be
40 * thought of as an extremely weak version of a read-lock, that can
41 * be broken by a writer at any time. The use of optimistic mode
42 * for short read-only code segments often reduces contention and
43 * improves throughput. However, its use is inherently fragile.
44 * Optimistic read sections should only read fields and hold them in
45 * local variables for later use after validation. Fields read while
46 * in optimistic mode may be wildly inconsistent, so usage applies
47 * only when you are familiar enough with data representations to
48 * check consistency and/or repeatedly invoke method {@code
49 * validate()}. For example, such steps are typically required when
50 * first reading an object or array reference, and then accessing
51 * one of its fields, elements or methods. </li>
52 *
53 * </ul>
54 *
55 * <p>This class also supports methods that conditionally provide
56 * conversions across the three modes. For example, method {@link
57 * #tryConvertToWriteLock} attempts to "upgrade" a mode, returning
58 * a valid write stamp if (1) already in writing mode (2) in reading
59 * mode and there are no other readers or (3) in optimistic mode and
60 * the lock is available. The forms of these methods are designed to
61 * help reduce some of the code bloat that otherwise occurs in
62 * retry-based designs.
63 *
64 * <p>StampedLocks are designed for use as internal utilities in the
65 * development of thread-safe components. Their use relies on
66 * knowledge of the internal properties of the data, objects, and
67 * methods they are protecting. They are not reentrant, so locked
68 * bodies should not call other unknown methods that may try to
69 * re-acquire locks (although you may pass a stamp to other methods
70 * that can use or convert it). The use of read lock modes relies on
71 * the associated code sections being side-effect-free. Unvalidated
72 * optimistic read sections cannot call methods that are not known to
73 * tolerate potential inconsistencies. Stamps use finite
74 * representations, and are not cryptographically secure (i.e., a
75 * valid stamp may be guessable). Stamp values may recycle after (no
76 * sooner than) one year of continuous operation. A stamp held without
77 * use or validation for longer than this period may fail to validate
78 * correctly. StampedLocks are serializable, but always deserialize
79 * into initial unlocked state, so they are not useful for remote
80 * locking.
81 *
82 * <p>The scheduling policy of StampedLock does not consistently
83 * prefer readers over writers or vice versa. A zero return from any
84 * "try" method for acquiring or converting locks does not carry any
85 * information about the state of the lock; a subsequent invocation
86 * may succeed.
87 *
88 * <p><b>Sample Usage.</b> The following illustrates some usage idioms
89 * in a class that maintains simple two-dimensional points. The sample
90 * code illustrates some try/catch conventions even though they are
91 * not strictly needed here because no exceptions can occur in their
92 * bodies.<br>
93 *
94 * <pre>{@code
95 * class Point {
96 * private double x, y;
97 * private final StampedLock sl = new StampedLock();
98 *
99 * void move(double deltaX, double deltaY) { // an exclusively locked method
100 * long stamp = sl.writeLock();
101 * try {
102 * x += deltaX;
103 * y += deltaY;
104 * } finally {
105 * sl.unlockWrite(stamp);
106 * }
107 * }
108 *
109 * double distanceFromOriginV1() { // A read-only method
110 * long stamp;
111 * if ((stamp = sl.tryOptimisticRead()) != 0L) { // optimistic
112 * double currentX = x;
113 * double currentY = y;
114 * if (sl.validate(stamp))
115 * return Math.sqrt(currentX * currentX + currentY * currentY);
116 * }
117 * stamp = sl.readLock(); // fall back to read lock
118 * try {
119 * double currentX = x;
120 * double currentY = y;
121 * return Math.sqrt(currentX * currentX + currentY * currentY);
122 * } finally {
123 * sl.unlockRead(stamp);
124 * }
125 * }
126 *
127 * double distanceFromOriginV2() { // combines code paths
128 * double currentX = 0.0, currentY = 0.0;
129 * for (long stamp = sl.tryOptimisticRead(); ; stamp = sl.readLock()) {
130 * try {
131 * currentX = x;
132 * currentY = y;
133 * } finally {
134 * if (sl.tryConvertToOptimisticRead(stamp) != 0L) // unlock or validate
135 * break;
136 * }
137 * }
138 * return Math.sqrt(currentX * currentX + currentY * currentY);
139 * }
140 *
141 * void moveIfAtOrigin(double newX, double newY) { // upgrade
142 * // Could instead start with optimistic, not read mode
143 * long stamp = sl.readLock();
144 * try {
145 * while (x == 0.0 && y == 0.0) {
146 * long ws = sl.tryConvertToWriteLock(stamp);
147 * if (ws != 0L) {
148 * stamp = ws;
149 * x = newX;
150 * y = newY;
151 * break;
152 * }
153 * else {
154 * sl.unlockRead(stamp);
155 * stamp = sl.writeLock();
156 * }
157 * }
158 * } finally {
159 * sl.unlock(stamp);
160 * }
161 * }
162 * }}</pre>
163 *
164 * @since 1.8
165 * @author Doug Lea
166 */
167 public class StampedLock implements java.io.Serializable {
168 /*
169 * Algorithmic notes:
170 *
171 * The design employs elements of Sequence locks
172 * (as used in linux kernels; see Lameter's
173 * http://www.lameter.com/gelato2005.pdf
174 * and elsewhere; see
175 * Boehm's http://www.hpl.hp.com/techreports/2012/HPL-2012-68.html)
176 * Ordered RW locks (see Shirako et al
177 * http://dl.acm.org/citation.cfm?id=2312015)
178 * and Phase-Fair locks (see Brandenburg & Anderson, especially
179 * http://www.cs.unc.edu/~bbb/diss/).
180 *
181 * Conceptually, the primary state of the lock includes a sequence
182 * number that is odd when write-locked and even otherwise.
183 * However, this is offset by a reader count that is non-zero when
184 * read-locked. The read count is ignored when validating
185 * "optimistic" seqlock-reader-style stamps. Because we must use
186 * a small finite number of bits (currently 7) for readers, a
187 * supplementary reader overflow word is used when the number of
188 * readers exceeds the count field. We do this by treating the max
189 * reader count value (RBITS) as a spinlock protecting overflow
190 * updates.
191 *
192 * Waiting readers and writers use different queues. The writer
193 * queue is a modified form of CLH lock. (For discussion of CLH,
194 * see the internal documentation of AbstractQueuedSynchronizer.)
195 * The reader "queue" is a form of Treiber stack, that supports
196 * simpler/faster operations because order within a queue doesn't
197 * matter and all are signalled at once. However the sequence of
198 * threads within the queue vs the current stamp does matter (see
199 * Shirako et al) so each carries its incoming stamp value.
200 * Waiting writers never need to track sequence values, so they
201 * don't.
202 *
203 * These queue mechanics hardwire the scheduling policy. Ignoring
204 * trylocks, cancellation, and spinning, they implement Phase-Fair
205 * preferences:
206 * 1. Unlocked writers prefer to signal waiting readers
207 * 2. Fully unlocked readers prefer to signal waiting writers
208 * 3. When read-locked and a waiting writer exists, the writer
209 * is preferred to incoming readers
210 *
211 * These rules apply to threads actually queued. All tryLock forms
212 * opportunistically try to acquire locks regardless of preference
213 * rules, and so may "barge" their way in. Additionally, initial
214 * phases of the await* methods (invoked from readLock() and
215 * writeLock()) use controlled spins that have similar effect.
216 * Phase-fair preferences may also be broken on cancellations due
217 * to timeouts and interrupts. Rule #3 (incoming readers when a
218 * waiting writer) is approximated with varying precision in
219 * different contexts -- some checks do not account for
220 * in-progress spins/signals, and others do not account for
221 * cancellations.
222 *
223 * Controlled, randomized spinning is used in the two await
224 * methods to reduce (increasingly expensive) context switching
225 * while also avoiding sustained memory thrashing among many
226 * threads. Both await methods use a similar spin strategy: If
227 * the associated queue appears to be empty, then the thread
228 * spin-waits up to SPINS times (where each iteration decreases
229 * spin count with 50% probablility) before enqueing, and then, if
230 * it is the first thread to be enqueued, spins again up to SPINS
231 * times before blocking. If, upon wakening it fails to obtain
232 * lock, and is still (or becomes) the first waiting thread (which
233 * indicates that some other thread barged and obtained lock), it
234 * escalates spins (up to MAX_HEAD_SPINS) to reduce the likelihood
235 * of continually losing to barging threads.
236 *
237 * As noted in Boehm's paper (above), sequence validation (mainly
238 * method validate()) requires stricter ordering rules than apply
239 * to normal volatile reads (of "state"). In the absence of (but
240 * continual hope for) explicit JVM support of intrinsics with
241 * double-sided reordering prohibition, or corresponding fence
242 * intrinsics, we for now uncomfortably rely on the fact that the
243 * Unsafe.getXVolatile intrinsic must have this property
244 * (syntactic volatile reads do not) for internal purposes anyway,
245 * even though it is not documented.
246 *
247 * The memory layout keeps lock state and queue pointers together
248 * (normally on the same cache line). This usually works well for
249 * read-mostly loads. In most other cases, the natural tendency of
250 * adaptive-spin CLH locks to reduce memory contention lessens
251 * motivation to further spread out contended locations, but might
252 * be subject to future improvements.
253 */
254
255 /** Number of processors, for spin control */
256 private static final int NCPU = Runtime.getRuntime().availableProcessors();
257
258 /** Maximum number of retries before blocking on acquisition */
259 private static final int SPINS = (NCPU > 1) ? 1 << 6 : 1;
260
261 /** Maximum number of retries before re-blocking */
262 private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 12 : 1;
263
264 /** The period for yielding when waiting for overflow spinlock */
265 private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1
266
267 /** The number of bits to use for reader count before overflowing */
268 private static final int LG_READERS = 7;
269
270 // Values for lock state and stamp operations
271 private static final long RUNIT = 1L;
272 private static final long WBIT = 1L << LG_READERS;
273 private static final long RBITS = WBIT - 1L;
274 private static final long RFULL = RBITS - 1L;
275 private static final long ABITS = RBITS | WBIT;
276 private static final long SBITS = ~RBITS; // note overlap with ABITS
277
278 // Initial value for lock state; avoid failure value zero
279 private static final long ORIGIN = WBIT << 1;
280
281 // Special value from cancelled await methods so caller can throw IE
282 private static final long INTERRUPTED = 1L;
283
284 // Values for writer status; order matters
285 private static final int WAITING = -1;
286 private static final int CANCELLED = 1;
287
288 /** Wait nodes for readers */
289 static final class RNode {
290 final long seq; // stamp value upon enqueue
291 volatile Thread waiter; // null if no longer waiting
292 volatile RNode next;
293 RNode(long s, Thread w) { seq = s; waiter = w; }
294 }
295
296 /** Wait nodes for writers */
297 static final class WNode {
298 volatile int status; // 0, WAITING, or CANCELLED
299 volatile WNode prev;
300 volatile WNode next;
301 volatile Thread thread;
302 WNode(Thread t, WNode p) { thread = t; prev = p; }
303 }
304
305 /** Head of writer CLH queue */
306 private transient volatile WNode whead;
307 /** Tail (last) of writer CLH queue */
308 private transient volatile WNode wtail;
309 /** Head of read queue */
310 private transient volatile RNode rhead;
311 /** The state of the lock -- high bits hold sequence, low bits read count */
312 private transient volatile long state;
313 /** extra reader count when state read count saturated */
314 private transient int readerOverflow;
315
316 /**
317 * Creates a new lock, initially in unlocked state.
318 */
319 public StampedLock() {
320 state = ORIGIN;
321 }
322
323 /**
324 * Exclusively acquires the lock, blocking if necessary
325 * until available.
326 *
327 * @return a stamp that can be used to unlock or convert mode
328 */
329 public long writeLock() {
330 long s, next;
331 if (((s = state) & ABITS) == 0L &&
332 U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
333 return next;
334 return awaitWrite(false, 0L);
335 }
336
337 /**
338 * Exclusively acquires the lock if it is immediately available.
339 *
340 * @return a stamp that can be used to unlock or convert mode,
341 * or zero if the lock is not available
342 */
343 public long tryWriteLock() {
344 long s, next;
345 if (((s = state) & ABITS) == 0L &&
346 U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
347 return next;
348 return 0L;
349 }
350
351 /**
352 * Exclusively acquires the lock if it is available within the
353 * given time and the current thread has not been interrupted.
354 *
355 * @return a stamp that can be used to unlock or convert mode,
356 * or zero if the lock is not available
357 * @throws InterruptedException if the current thread is interrupted
358 * before acquiring the lock
359 */
360 public long tryWriteLock(long time, TimeUnit unit)
361 throws InterruptedException {
362 long nanos = unit.toNanos(time);
363 if (!Thread.interrupted()) {
364 long s, next, deadline;
365 if (((s = state) & ABITS) == 0L &&
366 U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
367 return next;
368 if (nanos <= 0L)
369 return 0L;
370 if ((deadline = System.nanoTime() + nanos) == 0L)
371 deadline = 1L;
372 if ((next = awaitWrite(true, deadline)) != INTERRUPTED)
373 return next;
374 }
375 throw new InterruptedException();
376 }
377
378 /**
379 * Exclusively acquires the lock, blocking if necessary
380 * until available or the current thread is interrupted.
381 *
382 * @return a stamp that can be used to unlock or convert mode
383 * @throws InterruptedException if the current thread is interrupted
384 * before acquiring the lock
385 */
386 public long writeLockInterruptibly() throws InterruptedException {
387 if (!Thread.interrupted()) {
388 long s, next;
389 if (((s = state) & ABITS) == 0L &&
390 U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
391 return next;
392 if ((next = awaitWrite(true, 0L)) != INTERRUPTED)
393 return next;
394 }
395 throw new InterruptedException();
396 }
397
398 /**
399 * Non-exclusively acquires the lock, blocking if necessary
400 * until available.
401 *
402 * @return a stamp that can be used to unlock or convert mode
403 */
404 public long readLock() {
405 for (;;) {
406 long s, m, next;
407 if ((m = (s = state) & ABITS) == 0L ||
408 (m < WBIT && whead == wtail)) {
409 if (m < RFULL) {
410 if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
411 return next;
412 }
413 else if ((next = tryIncReaderOverflow(s)) != 0L)
414 return next;
415 }
416 else
417 return awaitRead(s, false, 0L);
418 }
419 }
420
421 /**
422 * Non-exclusively acquires the lock if it is immediately available.
423 *
424 * @return a stamp that can be used to unlock or convert mode,
425 * or zero if the lock is not available
426 */
427 public long tryReadLock() {
428 for (;;) {
429 long s, m, next;
430 if ((m = (s = state) & ABITS) == WBIT)
431 return 0L;
432 else if (m < RFULL) {
433 if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
434 return next;
435 }
436 else if ((next = tryIncReaderOverflow(s)) != 0L)
437 return next;
438 }
439 }
440
441 /**
442 * Non-exclusively acquires the lock if it is available within the
443 * given time and the current thread has not been interrupted.
444 *
445 * @return a stamp that can be used to unlock or convert mode,
446 * or zero if the lock is not available
447 * @throws InterruptedException if the current thread is interrupted
448 * before acquiring the lock
449 */
450 public long tryReadLock(long time, TimeUnit unit)
451 throws InterruptedException {
452 long nanos = unit.toNanos(time);
453 if (!Thread.interrupted()) {
454 for (;;) {
455 long s, m, next, deadline;
456 if ((m = (s = state) & ABITS) == WBIT ||
457 (m != 0L && whead != wtail)) {
458 if (nanos <= 0L)
459 return 0L;
460 if ((deadline = System.nanoTime() + nanos) == 0L)
461 deadline = 1L;
462 if ((next = awaitRead(s, true, deadline)) != INTERRUPTED)
463 return next;
464 break;
465 }
466 else if (m < RFULL) {
467 if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
468 return next;
469 }
470 else if ((next = tryIncReaderOverflow(s)) != 0L)
471 return next;
472 }
473 }
474 throw new InterruptedException();
475 }
476
477 /**
478 * Non-exclusively acquires the lock, blocking if necessary
479 * until available or the current thread is interrupted.
480 *
481 * @return a stamp that can be used to unlock or convert mode
482 * @throws InterruptedException if the current thread is interrupted
483 * before acquiring the lock
484 */
485 public long readLockInterruptibly() throws InterruptedException {
486 if (!Thread.interrupted()) {
487 for (;;) {
488 long s, next, m;
489 if ((m = (s = state) & ABITS) == WBIT ||
490 (m != 0L && whead != wtail)) {
491 if ((next = awaitRead(s, true, 0L)) != INTERRUPTED)
492 return next;
493 break;
494 }
495 else if (m < RFULL) {
496 if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
497 return next;
498 }
499 else if ((next = tryIncReaderOverflow(s)) != 0L)
500 return next;
501 }
502 }
503 throw new InterruptedException();
504 }
505
506 /**
507 * Returns a stamp that can later be validated, or zero
508 * if exclusively locked.
509 *
510 * @return a stamp, or zero if exclusively locked
511 */
512 public long tryOptimisticRead() {
513 long s;
514 return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;
515 }
516
517 /**
518 * Returns true if the lock has not been exclusively acquired
519 * since issuance of the given stamp. Always returns false if the
520 * stamp is zero. Always returns true if the stamp represents a
521 * currently held lock.
522 *
523 * @return true if the lock has not been exclusively acquired
524 * since issuance of the given stamp; else false
525 */
526 public boolean validate(long stamp) {
527 // See above about current use of getLongVolatile here
528 return (stamp & SBITS) == (U.getLongVolatile(this, STATE) & SBITS);
529 }
530
531 /**
532 * If the lock state matches the given stamp, releases the
533 * exclusive lock.
534 *
535 * @param stamp a stamp returned by a write-lock operation
536 * @throws IllegalMonitorStateException if the stamp does
537 * not match the current state of this lock
538 */
539 public void unlockWrite(long stamp) {
540 if (state != stamp || (stamp & WBIT) == 0L)
541 throw new IllegalMonitorStateException();
542 state = (stamp += WBIT) == 0L ? ORIGIN : stamp;
543 readerPrefSignal();
544 }
545
546 /**
547 * If the lock state matches the given stamp, releases the
548 * non-exclusive lock.
549 *
550 * @param stamp a stamp returned by a read-lock operation
551 * @throws IllegalMonitorStateException if the stamp does
552 * not match the current state of this lock
553 */
554 public void unlockRead(long stamp) {
555 long s, m;
556 if ((stamp & RBITS) != 0L) {
557 while (((s = state) & SBITS) == (stamp & SBITS)) {
558 if ((m = s & ABITS) == 0L)
559 break;
560 else if (m < RFULL) {
561 if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
562 if (m == RUNIT)
563 writerPrefSignal();
564 return;
565 }
566 }
567 else if (m >= WBIT)
568 break;
569 else if (tryDecReaderOverflow(s) != 0L)
570 return;
571 }
572 }
573 throw new IllegalMonitorStateException();
574 }
575
576 /**
577 * If the lock state matches the given stamp, releases the
578 * corresponding mode of the lock.
579 *
580 * @param stamp a stamp returned by a lock operation
581 * @throws IllegalMonitorStateException if the stamp does
582 * not match the current state of this lock
583 */
584 public void unlock(long stamp) {
585 long a = stamp & ABITS, m, s;
586 while (((s = state) & SBITS) == (stamp & SBITS)) {
587 if ((m = s & ABITS) == 0L)
588 break;
589 else if (m == WBIT) {
590 if (a != m)
591 break;
592 state = (s += WBIT) == 0L ? ORIGIN : s;
593 readerPrefSignal();
594 return;
595 }
596 else if (a == 0L || a >= WBIT)
597 break;
598 else if (m < RFULL) {
599 if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
600 if (m == RUNIT)
601 writerPrefSignal();
602 return;
603 }
604 }
605 else if (tryDecReaderOverflow(s) != 0L)
606 return;
607 }
608 throw new IllegalMonitorStateException();
609 }
610
611 /**
612 * If the lock state matches the given stamp then performs one of
613 * the following actions. If the stamp represents holding a write
614 * lock, returns it. Or, if a read lock, if the write lock is
615 * available, releases the read lock and returns a write stamp.
616 * Or, if an optimistic read, returns a write stamp only if
617 * immediately available. This method returns zero in all other
618 * cases.
619 *
620 * @param stamp a stamp
621 * @return a valid write stamp, or zero on failure
622 */
623 public long tryConvertToWriteLock(long stamp) {
624 long a = stamp & ABITS, m, s, next;
625 while (((s = state) & SBITS) == (stamp & SBITS)) {
626 if ((m = s & ABITS) == 0L) {
627 if (a != 0L)
628 break;
629 if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
630 return next;
631 }
632 else if (m == WBIT) {
633 if (a != m)
634 break;
635 return stamp;
636 }
637 else if (m == RUNIT && a != 0L) {
638 if (U.compareAndSwapLong(this, STATE, s,
639 next = s - RUNIT + WBIT))
640 return next;
641 }
642 else
643 break;
644 }
645 return 0L;
646 }
647
648 /**
649 * If the lock state matches the given stamp then performs one of
650 * the following actions. If the stamp represents holding a write
651 * lock, releases it and obtains a read lock. Or, if a read lock,
652 * returns it. Or, if an optimistic read, acquires a read lock and
653 * returns a read stamp only if immediately available. This method
654 * returns zero in all other cases.
655 *
656 * @param stamp a stamp
657 * @return a valid read stamp, or zero on failure
658 */
659 public long tryConvertToReadLock(long stamp) {
660 long a = stamp & ABITS, m, s, next;
661 while (((s = state) & SBITS) == (stamp & SBITS)) {
662 if ((m = s & ABITS) == 0L) {
663 if (a != 0L)
664 break;
665 else if (m < RFULL) {
666 if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
667 return next;
668 }
669 else if ((next = tryIncReaderOverflow(s)) != 0L)
670 return next;
671 }
672 else if (m == WBIT) {
673 if (a != m)
674 break;
675 state = next = s + (WBIT + RUNIT);
676 readerPrefSignal();
677 return next;
678 }
679 else if (a != 0L && a < WBIT)
680 return stamp;
681 else
682 break;
683 }
684 return 0L;
685 }
686
687 /**
688 * If the lock state matches the given stamp then, if the stamp
689 * represents holding a lock, releases it and returns an
690 * observation stamp. Or, if an optimistic read, returns it if
691 * validated. This method returns zero in all other cases, and so
692 * may be useful as a form of "tryUnlock".
693 *
694 * @param stamp a stamp
695 * @return a valid optimistic read stamp, or zero on failure
696 */
697 public long tryConvertToOptimisticRead(long stamp) {
698 long a = stamp & ABITS, m, s, next;
699 while (((s = U.getLongVolatile(this, STATE)) &
700 SBITS) == (stamp & SBITS)) {
701 if ((m = s & ABITS) == 0L) {
702 if (a != 0L)
703 break;
704 return s;
705 }
706 else if (m == WBIT) {
707 if (a != m)
708 break;
709 state = next = (s += WBIT) == 0L ? ORIGIN : s;
710 readerPrefSignal();
711 return next;
712 }
713 else if (a == 0L || a >= WBIT)
714 break;
715 else if (m < RFULL) {
716 if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT)) {
717 if (m == RUNIT)
718 writerPrefSignal();
719 return next & SBITS;
720 }
721 }
722 else if ((next = tryDecReaderOverflow(s)) != 0L)
723 return next & SBITS;
724 }
725 return 0L;
726 }
727
728 /**
729 * Releases the write lock if it is held, without requiring a
730 * stamp value. This method may be useful for recovery after
731 * errors.
732 *
733 * @return true if the lock was held, else false
734 */
735 public boolean tryUnlockWrite() {
736 long s;
737 if (((s = state) & WBIT) != 0L) {
738 state = (s += WBIT) == 0L ? ORIGIN : s;
739 readerPrefSignal();
740 return true;
741 }
742 return false;
743 }
744
745 /**
746 * Releases one hold of the read lock if it is held, without
747 * requiring a stamp value. This method may be useful for recovery
748 * after errors.
749 *
750 * @return true if the read lock was held, else false
751 */
752 public boolean tryUnlockRead() {
753 long s, m;
754 while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
755 if (m < RFULL) {
756 if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
757 if (m == RUNIT)
758 writerPrefSignal();
759 return true;
760 }
761 }
762 else if (tryDecReaderOverflow(s) != 0L)
763 return true;
764 }
765 return false;
766 }
767
768 /**
769 * Returns true if the lock is currently held exclusively.
770 *
771 * @return true if the lock is currently held exclusively
772 */
773 public boolean isWriteLocked() {
774 return (state & WBIT) != 0L;
775 }
776
777 /**
778 * Returns true if the lock is currently held non-exclusively.
779 *
780 * @return true if the lock is currently held non-exclusively
781 */
782 public boolean isReadLocked() {
783 return (state & RBITS) != 0L;
784 }
785
786 private void readObject(java.io.ObjectInputStream s)
787 throws java.io.IOException, ClassNotFoundException {
788 s.defaultReadObject();
789 state = ORIGIN; // reset to unlocked state
790 }
791
792 // internals
793
794 /**
795 * Tries to increment readerOverflow by first setting state
796 * access bits value to RBITS, indicating hold of spinlock,
797 * then updating, then releasing.
798 *
799 * @param s, assumed that (s & ABITS) >= RFULL
800 * @return new stamp on success, else zero
801 */
802 private long tryIncReaderOverflow(long s) {
803 if ((s & ABITS) == RFULL) {
804 if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
805 ++readerOverflow;
806 state = s;
807 return s;
808 }
809 }
810 else if ((ThreadLocalRandom.current().nextInt() &
811 OVERFLOW_YIELD_RATE) == 0)
812 Thread.yield();
813 return 0L;
814 }
815
816 /**
817 * Tries to decrement readerOverflow.
818 *
819 * @param s, assumed that (s & ABITS) >= RFULL
820 * @return new stamp on success, else zero
821 */
822 private long tryDecReaderOverflow(long s) {
823 if ((s & ABITS) == RFULL) {
824 if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
825 int r; long next;
826 if ((r = readerOverflow) > 0) {
827 readerOverflow = r - 1;
828 next = s;
829 }
830 else
831 next = s - RUNIT;
832 state = next;
833 return next;
834 }
835 }
836 else if ((ThreadLocalRandom.current().nextInt() &
837 OVERFLOW_YIELD_RATE) == 0)
838 Thread.yield();
839 return 0L;
840 }
841
842 /*
843 * The two versions of signal implement the phase-fair policy.
844 * They include almost the same code, but repacked in different
845 * ways. Integrating the policy with the mechanics eliminates
846 * state rechecks that would be needed with separate reader and
847 * writer signal methods. Both methods assume that they are
848 * called when the lock is last known to be available, and
849 * continue until the lock is unavailable, or at least one thread
850 * is signalled, or there are no more waiting threads. Signalling
851 * a reader entails popping (CASing) from rhead and unparking
852 * unless the thread already cancelled (indicated by a null waiter
853 * field). Signalling a writer requires finding the first node,
854 * i.e., the successor of whead. This is normally just head.next,
855 * but may require traversal from wtail if next pointers are
856 * lagging. These methods may fail to wake up an acquiring thread
857 * when one or more have been cancelled, but the cancel methods
858 * themselves provide extra safeguards to ensure liveness.
859 */
860
861 private void readerPrefSignal() {
862 boolean readers = false;
863 RNode p; WNode h, q; long s; Thread w;
864 while ((p = rhead) != null) {
865 if (((s = state) & WBIT) != 0L)
866 return;
867 if (p.seq == (s & SBITS))
868 break;
869 readers = true;
870 if (U.compareAndSwapObject(this, RHEAD, p, p.next) &&
871 (w = p.waiter) != null &&
872 U.compareAndSwapObject(p, WAITER, w, null))
873 U.unpark(w);
874 }
875 if (!readers && (h = whead) != null && h.status != 0 &&
876 (state & ABITS) == 0L) {
877 U.compareAndSwapInt(h, STATUS, WAITING, 0);
878 if ((q = h.next) == null || q.status == CANCELLED) {
879 for (WNode t = wtail; t != null && t != h; t = t.prev)
880 if (t.status <= 0)
881 q = t;
882 }
883 if (q != null && (w = q.thread) != null)
884 U.unpark(w);
885 }
886 }
887
888 private void writerPrefSignal() {
889 RNode p; WNode h, q; long s; Thread w;
890 if ((h = whead) != null && h.status != 0) {
891 U.compareAndSwapInt(h, STATUS, WAITING, 0);
892 if ((q = h.next) == null || q.status == CANCELLED) {
893 for (WNode t = wtail; t != null && t != h; t = t.prev)
894 if (t.status <= 0)
895 q = t;
896 }
897 if (q != null && (w = q.thread) != null)
898 U.unpark(w);
899 }
900 else {
901 while ((p = rhead) != null && ((s = state) & WBIT) == 0L &&
902 p.seq != (s & SBITS)) {
903 if (U.compareAndSwapObject(this, RHEAD, p, p.next) &&
904 (w = p.waiter) != null &&
905 U.compareAndSwapObject(p, WAITER, w, null))
906 U.unpark(w);
907 }
908 }
909 }
910
911 /**
912 * RNG for local spins. The first call from await{Read,Write}
913 * produces a thread-local value. Unless zero, subsequent calls
914 * use an xorShift to further reduce memory traffic.
915 */
916 private static int nextRandom(int r) {
917 if (r == 0)
918 return ThreadLocalRandom.current().nextInt();
919 r ^= r << 1; // xorshift
920 r ^= r >>> 3;
921 r ^= r << 10;
922 return r;
923 }
924
925 /**
926 * Possibly spins trying to obtain write lock, then enqueues and
927 * blocks while not head of write queue or cannot acquire lock,
928 * possibly spinning when at head; cancelling on timeout or
929 * interrupt.
930 *
931 * @param interruptible true if should check interrupts and if so
932 * return INTERRUPTED
933 * @param deadline if nonzero, the System.nanoTime value to timeout
934 * at (and return zero)
935 */
936 private long awaitWrite(boolean interruptible, long deadline) {
937 WNode node = null;
938 for (int r = 0, spins = -1;;) {
939 WNode p; long s, next;
940 if (((s = state) & ABITS) == 0L) {
941 if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
942 return next;
943 }
944 else if (spins < 0)
945 spins = whead == wtail ? SPINS : 0;
946 else if (spins > 0) {
947 if ((r = nextRandom(r)) >= 0)
948 --spins;
949 }
950 else if ((p = wtail) == null) { // initialize queue
951 if (U.compareAndSwapObject(this, WHEAD, null,
952 new WNode(null, null)))
953 wtail = whead;
954 }
955 else if (node == null)
956 node = new WNode(Thread.currentThread(), p);
957 else if (node.prev != p)
958 node.prev = p;
959 else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
960 p.next = node;
961 for (int headSpins = SPINS;;) {
962 WNode np, pp; int ps;
963 while ((np = node.prev) != p && np != null)
964 (p = np).next = node; // stale
965 if (p == whead) {
966 for (int k = headSpins;;) {
967 if (((s = state) & ABITS) == 0L) {
968 if (U.compareAndSwapLong(this, STATE,
969 s, next = s + WBIT)) {
970 whead = node;
971 node.thread = null;
972 node.prev = null;
973 return next;
974 }
975 break;
976 }
977 if ((r = nextRandom(r)) >= 0 && --k <= 0)
978 break;
979 }
980 if (headSpins < MAX_HEAD_SPINS)
981 headSpins <<= 1;
982 }
983 if ((ps = p.status) == 0)
984 U.compareAndSwapInt(p, STATUS, 0, WAITING);
985 else if (ps == CANCELLED) {
986 if ((pp = p.prev) != null) {
987 node.prev = pp;
988 pp.next = node;
989 }
990 }
991 else {
992 long time; // 0 argument to park means no timeout
993 if (deadline == 0L)
994 time = 0L;
995 else if ((time = deadline - System.nanoTime()) <= 0L)
996 return cancelWriter(node, false);
997 if (node.prev == p && p.status == WAITING &&
998 (p != whead || (state & WBIT) != 0L)) // recheck
999 U.park(false, time);
1000 if (interruptible && Thread.interrupted())
1001 return cancelWriter(node, true);
1002 }
1003 }
1004 }
1005 }
1006 }
1007
1008 /**
1009 * If node non-null, forces cancel status and unsplices from queue
1010 * if possible. This is a variant of cancellation methods in
1011 * AbstractQueuedSynchronizer (see its detailed explanation in AQS
1012 * internal documentation) that more conservatively wakes up other
1013 * threads that may have had their links changed, so as to preserve
1014 * liveness in the main signalling methods.
1015 */
1016 private long cancelWriter(WNode node, boolean interrupted) {
1017 if (node != null) {
1018 node.thread = null;
1019 node.status = CANCELLED;
1020 for (WNode pred = node.prev; pred != null; ) {
1021 WNode succ, pp; Thread w;
1022 while ((succ = node.next) == null || succ.status == CANCELLED) {
1023 WNode q = null;
1024 for (WNode t = wtail; t != null && t != node; t = t.prev)
1025 if (t.status != CANCELLED)
1026 q = t;
1027 if (succ == q ||
1028 U.compareAndSwapObject(node, WNEXT, succ, succ = q)) {
1029 if (succ == null && node == wtail)
1030 U.compareAndSwapObject(this, WTAIL, node, pred);
1031 break;
1032 }
1033 }
1034 if (pred.next == node)
1035 U.compareAndSwapObject(pred, WNEXT, node, succ);
1036 if (succ != null && (w = succ.thread) != null)
1037 U.unpark(w);
1038 if (pred.status != CANCELLED || (pp = pred.prev) == null)
1039 break;
1040 node.prev = pp; // repeat for new pred
1041 U.compareAndSwapObject(pp, WNEXT, pred, succ);
1042 pred = pp;
1043 }
1044 }
1045 writerPrefSignal();
1046 return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
1047 }
1048
1049 /**
1050 * Waits for read lock or timeout or interrupt. The form of
1051 * awaitRead differs from awaitWrite mainly because it must
1052 * restart (with a new wait node) if the thread was unqueued and
1053 * unparked but could not the obtain lock. We also need to help
1054 * with preference rules by not trying to acquire the lock before
1055 * enqueuing if there is a known waiting writer, but also helping
1056 * to release those threads that are still queued from the last
1057 * release.
1058 */
1059 private long awaitRead(long stamp, boolean interruptible, long deadline) {
1060 long seq = stamp & SBITS;
1061 RNode node = null;
1062 boolean queued = false;
1063 for (int r = 0, headSpins = SPINS, spins = -1;;) {
1064 long s, m, next; RNode p; WNode wh; Thread w;
1065 if ((m = (s = state) & ABITS) != WBIT &&
1066 ((s & SBITS) != seq || (wh = whead) == null ||
1067 wh.status == 0)) {
1068 if (m < RFULL ?
1069 U.compareAndSwapLong(this, STATE, s, next = s + RUNIT) :
1070 (next = tryIncReaderOverflow(s)) != 0L) {
1071 if (node != null && (w = node.waiter) != null)
1072 U.compareAndSwapObject(node, WAITER, w, null);
1073 if ((p = rhead) != null && (s & SBITS) != p.seq &&
1074 U.compareAndSwapObject(this, RHEAD, p, p.next) &&
1075 (w = p.waiter) != null &&
1076 U.compareAndSwapObject(p, WAITER, w, null))
1077 U.unpark(w); // help signal other waiters
1078 return next;
1079 }
1080 }
1081 else if (m != WBIT && (p = rhead) != null &&
1082 (s & SBITS) != p.seq) { // help release old readers
1083 if (U.compareAndSwapObject(this, RHEAD, p, p.next) &&
1084 (w = p.waiter) != null &&
1085 U.compareAndSwapObject(p, WAITER, w, null))
1086 U.unpark(w);
1087 }
1088 else if (queued && node != null && node.waiter == null) {
1089 node = null; // restart
1090 queued = false;
1091 spins = -1;
1092 }
1093 else if (spins < 0) {
1094 if (rhead != node)
1095 spins = 0;
1096 else if ((spins = headSpins) < MAX_HEAD_SPINS && node != null)
1097 headSpins <<= 1;
1098 }
1099 else if (spins > 0) {
1100 if ((r = nextRandom(r)) >= 0)
1101 --spins;
1102 }
1103 else if (node == null)
1104 node = new RNode(seq, Thread.currentThread());
1105 else if (!queued) {
1106 if (queued = U.compareAndSwapObject(this, RHEAD,
1107 node.next = rhead, node))
1108 spins = -1;
1109 }
1110 else {
1111 long time;
1112 if (deadline == 0L)
1113 time = 0L;
1114 else if ((time = deadline - System.nanoTime()) <= 0L)
1115 return cancelReader(node, false);
1116 if ((state & WBIT) != 0L && node.waiter != null) // recheck
1117 U.park(false, time);
1118 if (interruptible && Thread.interrupted())
1119 return cancelReader(node, true);
1120 }
1121 }
1122 }
1123
1124 /**
1125 * If node non-null, forces cancel status and unsplices from queue
1126 * if possible, by traversing entire queue looking for cancelled
1127 * nodes.
1128 */
1129 private long cancelReader(RNode node, boolean interrupted) {
1130 Thread w;
1131 if (node != null && (w = node.waiter) != null &&
1132 U.compareAndSwapObject(node, WAITER, w, null)) {
1133 for (RNode pred = null, p = rhead; p != null;) {
1134 RNode q = p.next;
1135 if (p.waiter == null) {
1136 if (pred == null) {
1137 U.compareAndSwapObject(this, RHEAD, p, q);
1138 p = rhead;
1139 }
1140 else {
1141 U.compareAndSwapObject(pred, RNEXT, p, q);
1142 p = pred.next;
1143 }
1144 }
1145 else {
1146 pred = p;
1147 p = q;
1148 }
1149 }
1150 }
1151 readerPrefSignal();
1152 return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
1153 }
1154
1155 // Unsafe mechanics
1156 private static final sun.misc.Unsafe U;
1157 private static final long STATE;
1158 private static final long RHEAD;
1159 private static final long WHEAD;
1160 private static final long WTAIL;
1161 private static final long RNEXT;
1162 private static final long WNEXT;
1163 private static final long WPREV;
1164 private static final long WAITER;
1165 private static final long STATUS;
1166
1167 static {
1168 try {
1169 U = getUnsafe();
1170 Class<?> k = StampedLock.class;
1171 Class<?> rk = RNode.class;
1172 Class<?> wk = WNode.class;
1173 STATE = U.objectFieldOffset
1174 (k.getDeclaredField("state"));
1175 RHEAD = U.objectFieldOffset
1176 (k.getDeclaredField("rhead"));
1177 WHEAD = U.objectFieldOffset
1178 (k.getDeclaredField("whead"));
1179 WTAIL = U.objectFieldOffset
1180 (k.getDeclaredField("wtail"));
1181 RNEXT = U.objectFieldOffset
1182 (rk.getDeclaredField("next"));
1183 WAITER = U.objectFieldOffset
1184 (rk.getDeclaredField("waiter"));
1185 STATUS = U.objectFieldOffset
1186 (wk.getDeclaredField("status"));
1187 WNEXT = U.objectFieldOffset
1188 (wk.getDeclaredField("next"));
1189 WPREV = U.objectFieldOffset
1190 (wk.getDeclaredField("prev"));
1191
1192 } catch (Exception e) {
1193 throw new Error(e);
1194 }
1195 }
1196
1197 /**
1198 * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package.
1199 * Replace with a simple call to Unsafe.getUnsafe when integrating
1200 * into a jdk.
1201 *
1202 * @return a sun.misc.Unsafe
1203 */
1204 private static sun.misc.Unsafe getUnsafe() {
1205 try {
1206 return sun.misc.Unsafe.getUnsafe();
1207 } catch (SecurityException se) {
1208 try {
1209 return java.security.AccessController.doPrivileged
1210 (new java.security
1211 .PrivilegedExceptionAction<sun.misc.Unsafe>() {
1212 public sun.misc.Unsafe run() throws Exception {
1213 java.lang.reflect.Field f = sun.misc
1214 .Unsafe.class.getDeclaredField("theUnsafe");
1215 f.setAccessible(true);
1216 return (sun.misc.Unsafe) f.get(null);
1217 }});
1218 } catch (java.security.PrivilegedActionException e) {
1219 throw new RuntimeException("Could not initialize intrinsics",
1220 e.getCause());
1221 }
1222 }
1223 }
1224
1225 }