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.18 by jsr166, Mon Oct 15 05:26:53 2012 UTC vs.
Revision 1.19 by dl, Mon Oct 15 12:12:42 2012 UTC

# Line 61 | Line 61 | import java.util.concurrent.TimeUnit;
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 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 123 | Line 126 | import java.util.concurrent.TimeUnit;
126   *
127   *   double distanceFromOriginV2() { // combines code paths
128   *     for (long stamp = sl.tryOptimisticRead(); ; stamp = sl.readLock()) {
129 < *       double currentX, currentY;
129 > *       double currentX = 0.0, currentY = 0.0;
130   *       try {
131   *         currentX = x;
132   *         currentY = y;
# Line 139 | Line 142 | import java.util.concurrent.TimeUnit;
142   *     long stamp = sl.readLock();
143   *     try {
144   *       while (x == 0.0 && y == 0.0) {
145 < *         long ws = tryConvertToWriteLock(stamp);
145 > *         long ws = sl.tryConvertToWriteLock(stamp);
146   *         if (ws != 0L) {
147   *           stamp = ws;
148   *           x = newX;
# Line 511 | Line 514 | public class StampedLock implements java
514      }
515  
516      /**
517 <     * Returns true if the lock has not been exclusively held since
518 <     * issuance of the given stamp. Always returns false if the stamp
519 <     * is zero. Always returns true if the stamp represents a
517 >     * Returns true if the lock has not been exclusively acquired
518 >     * since issuance of the given stamp. Always returns false if the
519 >     * stamp is zero. Always returns true if the stamp represents a
520       * currently held lock.
521       *
522 <     * @return true if the lock has not been exclusively held since
523 <     * issuance of the given stamp; else false
522 >     * @return true if the lock has not been exclusively acquired
523 >     * since issuance of the given stamp; else false
524       */
525      public boolean validate(long stamp) {
526 +        // See above about current use of getLongVolatile here
527          return (stamp & SBITS) == (U.getLongVolatile(this, STATE) & SBITS);
528      }
529  
# Line 629 | Line 633 | public class StampedLock implements java
633                      break;
634                  return stamp;
635              }
636 <            else if (m == RUNIT && a != 0L && a < WBIT) {
636 >            else if (m == RUNIT && a != 0L) {
637                  if (U.compareAndSwapLong(this, STATE, s,
638                                           next = s - RUNIT + WBIT))
639                      return next;
# Line 775 | Line 779 | public class StampedLock implements java
779       * @return true if the lock is currently held non-exclusively
780       */
781      public boolean isReadLocked() {
782 <        long m;
779 <        return (m = state & ABITS) > 0L && m < WBIT;
782 >        return (state & RBITS) != 0L;
783      }
784  
785      private void readObject(java.io.ObjectInputStream s)
# Line 792 | Line 795 | public class StampedLock implements java
795       * access bits value to RBITS, indicating hold of spinlock,
796       * then updating, then releasing.
797       *
798 <     * @param stamp, assumed that (stamp & ABITS) >= RFULL
798 >     * @param s, assumed that (s & ABITS) >= RFULL
799       * @return new stamp on success, else zero
800       */
801      private long tryIncReaderOverflow(long s) {
# Line 812 | Line 815 | public class StampedLock implements java
815      /**
816       * Tries to decrement readerOverflow.
817       *
818 <     * @param stamp, assumed that (stamp & ABITS) >= RFULL
818 >     * @param s, assumed that (s & ABITS) >= RFULL
819       * @return new stamp on success, else zero
820       */
821      private long tryDecReaderOverflow(long s) {
# Line 868 | Line 871 | public class StampedLock implements java
871                  U.compareAndSwapObject(p, WAITER, w, null))
872                  U.unpark(w);
873          }
874 <        if (!readers && (state & ABITS) == 0L &&
875 <            (h = whead) != null && h.status != 0) {
874 >        if (!readers && (h = whead) != null && h.status != 0 &&
875 >            (state & ABITS) == 0L) {
876              U.compareAndSwapInt(h, STATUS, WAITING, 0);
877              if ((q = h.next) == null || q.status == CANCELLED) {
875                q = null;
878                  for (WNode t = wtail; t != null && t != h; t = t.prev)
879                      if (t.status <= 0)
880                          q = t;
# Line 887 | Line 889 | public class StampedLock implements java
889          if ((h = whead) != null && h.status != 0) {
890              U.compareAndSwapInt(h, STATUS, WAITING, 0);
891              if ((q = h.next) == null || q.status == CANCELLED) {
890                q = null;
892                  for (WNode t = wtail; t != null && t != h; t = t.prev)
893                      if (t.status <= 0)
894                          q = t;
# Line 957 | Line 958 | public class StampedLock implements java
958              else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
959                  p.next = node;
960                  for (int headSpins = SPINS;;) {
961 <                    WNode np; int ps;
962 <                    if ((np = node.prev) != p && np != null &&
963 <                        (p = np).next != node)
963 <                        p.next = node; // stale
961 >                    WNode np, pp; int ps;
962 >                    while ((np = node.prev) != p && np != null)
963 >                        (p = np).next = node; // stale
964                      if (p == whead) {
965                          for (int k = headSpins;;) {
966                              if (((s = state) & ABITS) == 0L) {
# Line 981 | Line 981 | public class StampedLock implements java
981                      }
982                      if ((ps = p.status) == 0)
983                          U.compareAndSwapInt(p, STATUS, 0, WAITING);
984 <                    else if (ps == CANCELLED)
985 <                        node.prev = p.prev;
984 >                    else if (ps == CANCELLED) {
985 >                        if ((pp = p.prev) != null) {
986 >                            node.prev = pp;
987 >                            pp.next = node;
988 >                        }
989 >                    }
990                      else {
991                          long time; // 0 argument to park means no timeout
992                          if (deadline == 0L)
# Line 990 | Line 994 | public class StampedLock implements java
994                          else if ((time = deadline - System.nanoTime()) <= 0L)
995                              return cancelWriter(node, false);
996                          if (node.prev == p && p.status == WAITING &&
997 <                            (p != whead || (state & WBIT) != 0L)) { // recheck
997 >                            (p != whead || (state & WBIT) != 0L)) // recheck
998                              U.park(false, time);
999 <                            if (interruptible && Thread.interrupted())
1000 <                                return cancelWriter(node, true);
997 <                        }
999 >                        if (interruptible && Thread.interrupted())
1000 >                            return cancelWriter(node, true);
1001                      }
1002                  }
1003              }
# Line 1003 | Line 1006 | public class StampedLock implements java
1006  
1007      /**
1008       * If node non-null, forces cancel status and unsplices from queue
1009 <     * if possible. This is a streamlined variant of cancellation
1010 <     * methods in AbstractQueuedSynchronizer that includes a detailed
1011 <     * explanation.
1009 >     * if possible. This is a variant of cancellation methods in
1010 >     * AbstractQueuedSynchronizer (see its detailed explanation in
1011 >     * internal documentation) that more conservatively wakes up other
1012 >     * threads that may have had their links changed so as to preserve
1013 >     * liveness in the main signalling methods.
1014       */
1015      private long cancelWriter(WNode node, boolean interrupted) {
1016 <        WNode pred;
1012 <        if (node != null && (pred = node.prev) != null) {
1013 <            WNode pp;
1016 >        if (node != null) {
1017              node.thread = null;
1015            while (pred.status == CANCELLED && (pp = pred.prev) != null)
1016                pred = node.prev = pp;
1017            WNode predNext = pred.next;
1018              node.status = CANCELLED;
1019 <            if (predNext != null) {
1020 <                Thread w;
1021 <                WNode succ = node.next;
1022 <                if (succ == null || succ.status == CANCELLED) {
1023 <                    succ = null;
1019 >            for (WNode pred = node.prev; pred != null; ) {
1020 >                WNode succ, pp; Thread w;
1021 >                while ((succ = node.next) == null || succ.status == CANCELLED) {
1022 >                    WNode q = null;
1023                      for (WNode t = wtail; t != null && t != node; t = t.prev)
1024 <                        if (t.status <= 0)
1025 <                            succ = t;
1026 <                    if (succ == null && node == wtail)
1027 <                        U.compareAndSwapObject(this, WTAIL, node, pred);
1024 >                        if (t.status != CANCELLED)
1025 >                            q = t;
1026 >                    if (succ == q ||
1027 >                        U.compareAndSwapObject(node, WNEXT, succ, succ = q)) {
1028 >                        if (succ == null && node == wtail)
1029 >                            U.compareAndSwapObject(this, WTAIL, node, pred);
1030 >                        break;
1031 >                    }
1032                  }
1033 <                U.compareAndSwapObject(pred, WNEXT, predNext, succ);
1033 >                if (pred.next == node)
1034 >                    U.compareAndSwapObject(pred, WNEXT, node, succ);
1035                  if (succ != null && (w = succ.thread) != null)
1036                      U.unpark(w);
1037 +                if (pred.status != CANCELLED || (pp = pred.prev) == null)
1038 +                    break;
1039 +                node.prev = pp; // repeat for new pred
1040 +                U.compareAndSwapObject(pp, WNEXT, pred, succ);
1041 +                pred = pp;
1042              }
1043          }
1044          writerPrefSignal();
# Line 1103 | Line 1112 | public class StampedLock implements java
1112                      time = 0L;
1113                  else if ((time = deadline - System.nanoTime()) <= 0L)
1114                      return cancelReader(node, false);
1115 <                if ((state & WBIT) != 0L && node.waiter != null) { // recheck
1115 >                if ((state & WBIT) != 0L && node.waiter != null) // recheck
1116                      U.park(false, time);
1117 <                    if (interruptible && Thread.interrupted())
1118 <                        return cancelReader(node, true);
1110 <                }
1117 >                if (interruptible && Thread.interrupted())
1118 >                    return cancelReader(node, true);
1119              }
1120          }
1121      }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines