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.32 by dl, Sat Jan 26 01:22:37 2013 UTC vs.
Revision 1.35 by jsr166, Mon Jan 28 22:22:08 2013 UTC

# Line 253 | Line 253 | public class StampedLock implements java
253       * motivation to further spread out contended locations, but might
254       * be subject to future improvements.
255       */
256 +
257      private static final long serialVersionUID = -6001602636862214147L;
258  
259      /** Number of processors, for spin control */
# Line 443 | Line 444 | public class StampedLock implements java
444       */
445      public long tryReadLock(long time, TimeUnit unit)
446          throws InterruptedException {
447 <        long next, deadline;
447 >        long s, m, next, deadline;
448          long nanos = unit.toNanos(time);
449          if (!Thread.interrupted()) {
450 <            if ((next = tryReadLock()) != 0L)
451 <                return next;
450 >            if ((m = (s = state) & ABITS) != WBIT) {
451 >                if (m < RFULL) {
452 >                    if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
453 >                        return next;
454 >                }
455 >                else if ((next = tryIncReaderOverflow(s)) != 0L)
456 >                    return next;
457 >            }
458              if (nanos <= 0L)
459                  return 0L;
460              if ((deadline = System.nanoTime() + nanos) == 0L)
# Line 889 | Line 896 | public class StampedLock implements java
896       * access bits value to RBITS, indicating hold of spinlock,
897       * then updating, then releasing.
898       *
899 <     * @param s, assumed that (s & ABITS) >= RFULL
899 >     * @param s a reader overflow stamp: (s & ABITS) >= RFULL
900       * @return new stamp on success, else zero
901       */
902      private long tryIncReaderOverflow(long s) {
903 +        // assert (s & ABITS) >= RFULL
904          if ((s & ABITS) == RFULL) {
905              if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
906                  ++readerOverflow;
# Line 909 | Line 917 | public class StampedLock implements java
917      /**
918       * Tries to decrement readerOverflow.
919       *
920 <     * @param s, assumed that (s & ABITS) >= RFULL
920 >     * @param s a reader overflow stamp: (s & ABITS) >= RFULL
921       * @return new stamp on success, else zero
922       */
923      private long tryDecReaderOverflow(long s) {
924 +        // assert (s & ABITS) >= RFULL
925          if ((s & ABITS) == RFULL) {
926              if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
927                  int r; long next;
# Line 932 | Line 941 | public class StampedLock implements java
941          return 0L;
942      }
943  
944 <    /*
944 >    /**
945       * Wakes up the successor of h (normally whead). This is normally
946       * just h.next, but may require traversal from wtail if next
947       * pointers are lagging. This may fail to wake up an acquiring
# Line 1033 | Line 1042 | public class StampedLock implements java
1042                  if (deadline == 0L)
1043                      time = 0L;
1044                  else if ((time = deadline - System.nanoTime()) <= 0L)
1045 <                    return cancelWaiter(node, null, false);
1045 >                    return cancelWaiter(node, node, false);
1046                  node.thread = Thread.currentThread();
1047                  if (node.prev == p && p.status == WAITING && // recheck
1048                      (p != whead || (state & ABITS) != 0L))
1049                      U.park(false, time);
1050                  node.thread = null;
1051                  if (interruptible && Thread.interrupted())
1052 <                    return cancelWaiter(node, null, true);
1052 >                    return cancelWaiter(node, node, true);
1053              }
1054          }
1055      }
# Line 1173 | Line 1182 | public class StampedLock implements java
1182                  if (deadline == 0L)
1183                      time = 0L;
1184                  else if ((time = deadline - System.nanoTime()) <= 0L)
1185 <                    return cancelWaiter(node, null, false);
1185 >                    return cancelWaiter(node, node, false);
1186                  node.thread = Thread.currentThread();
1187                  if (node.prev == p && p.status == WAITING &&
1188                      (p != whead || (state & ABITS) != WBIT))
1189                      U.park(false, time);
1190                  node.thread = null;
1191                  if (interruptible && Thread.interrupted())
1192 <                    return cancelWaiter(node, null, true);
1192 >                    return cancelWaiter(node, node, true);
1193              }
1194          }
1195      }
1196  
1197      /**
1198       * If node non-null, forces cancel status and unsplices it from
1199 <     * queue if possible and wakes up any cowaiters. This is a variant
1200 <     * of cancellation methods in AbstractQueuedSynchronizer (see its
1201 <     * detailed explanation in AQS internal documentation) that more
1202 <     * conservatively wakes up other threads that may have had their
1203 <     * links changed, so as to preserve liveness in the main
1204 <     * signalling methods.
1199 >     * queue if possible and wakes up any cowaiters (of the node, or
1200 >     * group, as applicable), and in any case helps release current
1201 >     * first waiter if lock is free. (Calling with null arguments
1202 >     * serves as a conditional form of release, which is not currently
1203 >     * needed but may be needed under possible future cancellation
1204 >     * policies). This is a variant of cancellation methods in
1205 >     * AbstractQueuedSynchronizer (see its detailed explanation in AQS
1206 >     * internal documentation).
1207       *
1208       * @param node if nonnull, the waiter
1209 <     * @param group, if nonnull, the group current thread is cowaiting with
1209 >     * @param group either node or the group node is cowaiting with
1210       * @param interrupted if already interrupted
1211       * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
1212       */
1213      private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
1214 <        if (node != null) {
1215 <            node.thread = null;
1214 >        if (node != null && group != null) {
1215 >            Thread w;
1216              node.status = CANCELLED;
1217 <            Thread w; // wake up co-waiters; unsplice cancelled ones
1218 <            for (WNode q, p = (group != null) ? group : node; p != null; ) {
1219 <                if ((q = p.cowait) == null)
1209 <                    break;
1210 <                if ((w = q.thread) != null) {
1211 <                    q.thread = null;
1212 <                    U.unpark(w);
1213 <                }
1217 >            node.thread = null;
1218 >            // unsplice cancelled nodes from group
1219 >            for (WNode p = group, q; (q = p.cowait) != null;) {
1220                  if (q.status == CANCELLED)
1221 <                    U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
1221 >                    U.compareAndSwapObject(p, WNEXT, q, q.next);
1222                  else
1223                      p = q;
1224              }
1225 <            if (group == null)  {        // unsplice both prev and next links
1226 <                for (WNode pred = node.prev; pred != null; ) {
1227 <                    WNode succ, pp;      // first unsplice next
1225 >            if (group == node) {
1226 >                WNode r; // detach and wake up uncancelled co-waiters
1227 >                while ((r = node.cowait) != null) {
1228 >                    if (U.compareAndSwapObject(node, WCOWAIT, r, r.cowait) &&
1229 >                        (w = r.thread) != null) {
1230 >                        r.thread = null;
1231 >                        U.unpark(w);
1232 >                    }
1233 >                }
1234 >                for (WNode pred = node.prev; pred != null; ) { // unsplice
1235 >                    WNode succ, pp;        // find valid successor
1236                      while ((succ = node.next) == null ||
1237                             succ.status == CANCELLED) {
1238 <                        WNode q = null;  // find successor the slow way
1238 >                        WNode q = null;    // find successor the slow way
1239                          for (WNode t = wtail; t != null && t != node; t = t.prev)
1240                              if (t.status != CANCELLED)
1241 <                                q = t;   // don't link if succ cancelled
1242 <                        if (succ == q || // ensure accurate successor
1241 >                                q = t;     // don't link if succ cancelled
1242 >                        if (succ == q ||   // ensure accurate successor
1243                              U.compareAndSwapObject(node, WNEXT,
1244                                                     succ, succ = q)) {
1245                              if (succ == null && node == wtail)
# Line 1237 | Line 1251 | public class StampedLock implements java
1251                          U.compareAndSwapObject(pred, WNEXT, node, succ);
1252                      if (succ != null && (w = succ.thread) != null) {
1253                          succ.thread = null;
1254 <                        U.unpark(w);      // conservatively wake up new succ
1254 >                        U.unpark(w);       // wake up succ to observe new pred
1255                      }
1256                      if (pred.status != CANCELLED || (pp = pred.prev) == null)
1257                          break;
1258 <                    node.prev = pp; // repeat in case new pred wrong/cancelled
1258 >                    node.prev = pp;        // repeat if new pred wrong/cancelled
1259                      U.compareAndSwapObject(pp, WNEXT, pred, succ);
1260                      pred = pp;
1261                  }
1262              }
1263          }
1264 <        release(whead);
1264 >        WNode h; // Possibly release first waiter
1265 >        while ((h = whead) != null) {
1266 >            long s; WNode q; // similar to release() but check eligibility
1267 >            if ((q = h.next) == null || q.status == CANCELLED) {
1268 >                for (WNode t = wtail; t != null && t != h; t = t.prev)
1269 >                    if (t.status <= 0)
1270 >                        q = t;
1271 >            }
1272 >            if (h == whead) {
1273 >                if (q != null && h.status == 0 &&
1274 >                    ((s = state) & ABITS) != WBIT && // waiter is eligible
1275 >                    (s == 0L || q.mode == RMODE))
1276 >                    release(h);
1277 >                break;
1278 >            }
1279 >        }
1280          return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
1281      }
1282  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines