ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/StampedLock.java
(Generate patch)

Comparing jsr166/src/jsr166e/StampedLock.java (file contents):
Revision 1.2 by jsr166, Fri Oct 12 16:22:40 2012 UTC vs.
Revision 1.23 by dl, Sun Oct 28 22:35:46 2012 UTC

# Line 11 | Line 11 | 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
15 < * mode. Lock acquisition methods return a stamp that represents and
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
# Line 26 | Line 26 | import java.util.concurrent.TimeUnit;
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 observer validations will fail.  </li>
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
# Line 55 | Line 55 | import java.util.concurrent.TimeUnit;
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 < * valid write stamp if (1) already in writing mode (2) in reading
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 in a different (and generally
65 < * narrower) range of contexts than most other locks: They are not
66 < * reentrant, so locked bodies should not call other unknown methods
67 < * that may try to re-acquire locks (although you may pass a stamp to
68 < * other methods that can use or convert it). Unvalidated optimistic
69 < * read sections should further not call methods that are not known to
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
# Line 76 | Line 79 | import java.util.concurrent.TimeUnit;
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 prefer
83 < * readers over writers or vice versa.
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
# Line 87 | Line 93 | import java.util.concurrent.TimeUnit;
93   *
94   *  <pre>{@code
95   * class Point {
96 < *   private volatile double x, y;
96 > *   private double x, y;
97   *   private final StampedLock sl = new StampedLock();
98   *
99   *   void move(double deltaX, double deltaY) { // an exclusively locked method
# Line 119 | Line 125 | import java.util.concurrent.TimeUnit;
125   *   }
126   *
127   *   double distanceFromOriginV2() { // combines code paths
128 < *     for (long stamp = sl.optimisticRead(); ; stamp = sl.readLock()) {
129 < *       double currentX, currentY;
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 < *           return Math.sqrt(currentX * currentX + currentY * currentY);
135 > *           break;
136   *       }
137   *     }
138 + *     return Math.sqrt(currentX * currentX + currentY * currentY);
139   *   }
140   *
141   *   void moveIfAtOrigin(double newX, double newY) { // upgrade
# Line 136 | Line 143 | import java.util.concurrent.TimeUnit;
143   *     long stamp = sl.readLock();
144   *     try {
145   *       while (x == 0.0 && y == 0.0) {
146 < *         long ws = tryConvertToWriteLock(stamp);
146 > *         long ws = sl.tryConvertToWriteLock(stamp);
147   *         if (ws != 0L) {
148   *           stamp = ws;
149   *           x = newX;
# Line 177 | Line 184 | public class StampedLock implements java
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 <     * supplementatry reader overflow word is used when then number of
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.
# Line 213 | Line 220 | public class StampedLock implements java
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% probability) 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
# Line 235 | Line 256 | public class StampedLock implements java
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;
259 >    private static final int SPINS = (NCPU > 1) ? 1 << 6 : 1;
260  
261 <    /** Maximum number of retries before re-blocking on write lock */
262 <    private static final int MAX_HEAD_SPINS = NCPU > 1 ? 1 << 12 : 1;
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;
268 >    private static final int LG_READERS = 7;
269  
270      // Values for lock state and stamp operations
271      private static final long RUNIT = 1L;
# Line 293 | Line 314 | public class StampedLock implements java
314      private transient int readerOverflow;
315  
316      /**
317 <     * Creates a new lock initially in unlocked state.
317 >     * Creates a new lock, initially in unlocked state.
318       */
319      public StampedLock() {
320          state = ORIGIN;
# Line 303 | Line 324 | public class StampedLock implements java
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.
327 >     * @return a stamp that can be used to unlock or convert mode
328       */
329      public long writeLock() {
330          long s, next;
# Line 317 | Line 338 | public class StampedLock implements java
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.
341 >     * or zero if the lock is not available
342       */
343      public long tryWriteLock() {
344          long s, next;
# Line 329 | Line 350 | public class StampedLock implements java
350  
351      /**
352       * Exclusively acquires the lock if it is available within the
353 <     * given time and the current thread has not been interrupted
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.
356 >     * or zero if the lock is not available
357       * @throws InterruptedException if the current thread is interrupted
358 <     * before acquiring the lock.
358 >     * before acquiring the lock
359       */
360      public long tryWriteLock(long time, TimeUnit unit)
361          throws InterruptedException {
362 <        long nanos =  unit.toNanos(time);
362 >        long nanos = unit.toNanos(time);
363          if (!Thread.interrupted()) {
364              long s, next, deadline;
365              if (((s = state) & ABITS) == 0L &&
# Line 358 | Line 379 | public class StampedLock implements java
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.
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.
384 >     * before acquiring the lock
385       */
386      public long writeLockInterruptibly() throws InterruptedException {
387          if (!Thread.interrupted()) {
# Line 378 | Line 399 | public class StampedLock implements java
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.
402 >     * @return a stamp that can be used to unlock or convert mode
403       */
404      public long readLock() {
405          for (;;) {
# Line 401 | Line 422 | public class StampedLock implements java
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.
425 >     * or zero if the lock is not available
426       */
427      public long tryReadLock() {
428          for (;;) {
# Line 419 | Line 440 | public class StampedLock implements java
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
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.
446 >     * or zero if the lock is not available
447       * @throws InterruptedException if the current thread is interrupted
448 <     * before acquiring the lock.
448 >     * before acquiring the lock
449       */
450      public long tryReadLock(long time, TimeUnit unit)
451          throws InterruptedException {
# Line 457 | Line 478 | public class StampedLock implements java
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.
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.
483 >     * before acquiring the lock
484       */
485      public long readLockInterruptibly() throws InterruptedException {
486          if (!Thread.interrupted()) {
# Line 494 | Line 515 | public class StampedLock implements java
515      }
516  
517      /**
518 <     * Returns true if the lock has not been exclusively held since
519 <     * issuance of the given stamp. Always returns false if the stamp
520 <     * is zero. Always returns true if the stamp represents a
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 held since
524 <     * issuance of the given stamp; else false
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  
# Line 512 | Line 534 | public class StampedLock implements java
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.
537 >     * not match the current state of this lock
538       */
539      public void unlockWrite(long stamp) {
540          if (state != stamp || (stamp & WBIT) == 0L)
# Line 522 | Line 544 | public class StampedLock implements java
544      }
545  
546      /**
547 <     * If the lock state matches the given stamp, releases
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.
552 >     * not match the current state of this lock
553       */
554      public void unlockRead(long stamp) {
555          long s, m;
# Line 557 | Line 579 | public class StampedLock implements java
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.
582 >     * not match the current state of this lock
583       */
584      public void unlock(long stamp) {
585          long a = stamp & ABITS, m, s;
# Line 589 | Line 611 | public class StampedLock implements java
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 and returns a write stamp. Or, if
616 <     * an optimistic read, returns a write stamp only if immediately
617 <     * available. This method returns zero in all other cases.
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
# Line 611 | Line 634 | public class StampedLock implements java
634                      break;
635                  return stamp;
636              }
637 <            else if (m == RUNIT && a != 0L && a < WBIT) {
637 >            else if (m == RUNIT && a != 0L) {
638                  if (U.compareAndSwapLong(this, STATE, s,
639                                           next = s - RUNIT + WBIT))
640                      return next;
# Line 649 | Line 672 | public class StampedLock implements java
672              else if (m == WBIT) {
673                  if (a != m)
674                      break;
675 <                next = state = s + (WBIT + RUNIT);
675 >                state = next = s + (WBIT + RUNIT);
676                  readerPrefSignal();
677                  return next;
678              }
# Line 683 | Line 706 | public class StampedLock implements java
706              else if (m == WBIT) {
707                  if (a != m)
708                      break;
709 <                next = state = (s += WBIT) == 0L ? ORIGIN : s;
709 >                state = next = (s += WBIT) == 0L ? ORIGIN : s;
710                  readerPrefSignal();
711                  return next;
712              }
# Line 707 | Line 730 | public class StampedLock implements java
730       * stamp value. This method may be useful for recovery after
731       * errors.
732       *
733 <     * @return true if the lock was held, else false.
733 >     * @return true if the lock was held, else false
734       */
735      public boolean tryUnlockWrite() {
736          long s;
# Line 724 | Line 747 | public class StampedLock implements java
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.
750 >     * @return true if the read lock was held, else false
751       */
752      public boolean tryUnlockRead() {
753          long s, m;
# Line 757 | Line 780 | public class StampedLock implements java
780       * @return true if the lock is currently held non-exclusively
781       */
782      public boolean isReadLocked() {
783 <        long m;
761 <        return (m = state & ABITS) > 0L && m < WBIT;
783 >        return (state & RBITS) != 0L;
784      }
785  
786      private void readObject(java.io.ObjectInputStream s)
# Line 773 | Line 795 | public class StampedLock implements java
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 <     * @param stamp, assumed that (stamp & ABITS) >= RFULL
798 >     *
799 >     * @param s, assumed that (s & ABITS) >= RFULL
800       * @return new stamp on success, else zero
801       */
802      private long tryIncReaderOverflow(long s) {
# Line 792 | Line 815 | public class StampedLock implements java
815  
816      /**
817       * Tries to decrement readerOverflow.
818 <     * @param stamp, assumed that (stamp & ABITS) >= RFULL
818 >     *
819 >     * @param s, assumed that (s & ABITS) >= RFULL
820       * @return new stamp on success, else zero
821       */
822      private long tryDecReaderOverflow(long s) {
# Line 848 | Line 872 | public class StampedLock implements java
872                  U.compareAndSwapObject(p, WAITER, w, null))
873                  U.unpark(w);
874          }
875 <        if (!readers && (state & ABITS) == 0L &&
876 <            (h = whead) != null && h.status != 0) {
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) {
855                q = null;
879                  for (WNode t = wtail; t != null && t != h; t = t.prev)
880                      if (t.status <= 0)
881                          q = t;
# Line 867 | Line 890 | public class StampedLock implements java
890          if ((h = whead) != null && h.status != 0) {
891              U.compareAndSwapInt(h, STATUS, WAITING, 0);
892              if ((q = h.next) == null || q.status == CANCELLED) {
870                q = null;
893                  for (WNode t = wtail; t != null && t != h; t = t.prev)
894                      if (t.status <= 0)
895                          q = t;
# Line 889 | Line 911 | public class StampedLock implements java
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.  Both await
893 <     * methods use a similar spin strategy: If associated queue
894 <     * appears to be empty, then the thread spin-waits up to SPINS
895 <     * times before enqueing, and then, if the first thread to be
896 <     * enqueued, spins again up to SPINS times before blocking. If,
897 <     * upon wakening it fails to obtain lock, and is still (or
898 <     * becomes) the first waiting thread (which indicates that some
899 <     * other thread barged and obtained lock), it escalates spins (up
900 <     * to MAX_HEAD_SPINS) to reduce the likelihood of continually
901 <     * losing to barging threads.
914 >     * use an xorShift to further reduce memory traffic.
915       */
916      private static int nextRandom(int r) {
917          if (r == 0)
# Line 911 | Line 924 | public class StampedLock implements java
924  
925      /**
926       * Possibly spins trying to obtain write lock, then enqueues and
927 <     * blocks while not head of write queue or cannot aquire lock,
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).
934 >     * at (and return zero)
935       */
936      private long awaitWrite(boolean interruptible, long deadline) {
937          WNode node = null;
# Line 946 | Line 959 | public class StampedLock implements java
959              else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
960                  p.next = node;
961                  for (int headSpins = SPINS;;) {
962 <                    WNode np; int ps;
963 <                    if ((np = node.prev) != p && np != null)
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;;) {
# Line 969 | Line 982 | public class StampedLock implements java
982                      }
983                      if ((ps = p.status) == 0)
984                          U.compareAndSwapInt(p, STATUS, 0, WAITING);
985 <                    else if (ps == CANCELLED)
986 <                        node.prev = p.prev;
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)
# Line 978 | Line 995 | public class StampedLock implements java
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
998 >                            (p != whead || (state & ABITS) != 0L)) // recheck
999                              U.park(false, time);
1000 <                            if (interruptible && Thread.interrupted())
1001 <                                return cancelWriter(node, true);
985 <                        }
1000 >                        if (interruptible && Thread.interrupted())
1001 >                            return cancelWriter(node, true);
1002                      }
1003                  }
1004              }
# Line 991 | Line 1007 | public class StampedLock implements java
1007  
1008      /**
1009       * If node non-null, forces cancel status and unsplices from queue
1010 <     * if possible. This is a streamlined variant of cancellation
1011 <     * methods in AbstractQueuedSynchronizer that includes a detailed
1012 <     * explanation.
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 <        WNode pred;
1000 <        if (node != null && (pred = node.prev) != null) {
1001 <            WNode pp;
1017 >        if (node != null) {
1018              node.thread = null;
1003            while (pred.status == CANCELLED && (pp = pred.prev) != null)
1004                pred = node.prev = pp;
1005            WNode predNext = pred.next;
1019              node.status = CANCELLED;
1020 <            if (predNext != null) {
1021 <                Thread w = null;
1022 <                WNode succ = node.next;
1023 <                while (succ != null && succ.status == CANCELLED)
1024 <                    succ = succ.next;
1025 <                if (succ != null)
1026 <                    w = succ.thread;
1027 <                else if (node == wtail)
1028 <                    U.compareAndSwapObject(this, WTAIL, node, pred);
1029 <                U.compareAndSwapObject(pred, WNEXT, predNext, succ);
1030 <                if (w != null)
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;
1046 >        return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
1047      }
1048  
1049 <    /*
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
# Line 1089 | Line 1113 | public class StampedLock implements java
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
1116 >                if ((state & WBIT) != 0L && node.waiter != null) // recheck
1117                      U.park(false, time);
1118 <                    if (interruptible && Thread.interrupted())
1119 <                        return cancelReader(node, true);
1096 <                }
1118 >                if (interruptible && Thread.interrupted())
1119 >                    return cancelReader(node, true);
1120              }
1121          }
1122      }
# Line 1101 | Line 1124 | public class StampedLock implements java
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, cleaning out all at head, but stopping upon first
1105 <     * encounter otherwise.
1127 >     * nodes.
1128       */
1129      private long cancelReader(RNode node, boolean interrupted) {
1130          Thread w;
# Line 1117 | Line 1139 | public class StampedLock implements java
1139                      }
1140                      else {
1141                          U.compareAndSwapObject(pred, RNEXT, p, q);
1142 <                        break;
1142 >                        p = pred.next;
1143                      }
1144                  }
1145                  else {
# Line 1127 | Line 1149 | public class StampedLock implements java
1149              }
1150          }
1151          readerPrefSignal();
1152 <        return (interrupted || Thread.interrupted())? INTERRUPTED : 0L;
1152 >        return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
1153      }
1154  
1155      // Unsafe mechanics
# Line 1201 | Line 1223 | public class StampedLock implements java
1223      }
1224  
1225   }
1204

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines