Пример #1
0
 /**
  * If node non-null, forces cancel status and unsplices it from queue if possible and wakes up any
  * cowaiters (of the node, or group, as applicable), and in any case helps release current first
  * waiter if lock is free. (Calling with null arguments serves as a conditional form of release,
  * which is not currently needed but may be needed under possible future cancellation policies).
  * This is a variant of cancellation methods in AbstractQueuedSynchronizer (see its detailed
  * explanation in AQS internal documentation).
  *
  * @param node if nonnull, the waiter
  * @param group either node or the group node is cowaiting with
  * @param interrupted if already interrupted
  * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
  */
 private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
   if (node != null && group != null) {
     Thread w;
     node.status = CANCELLED;
     // unsplice cancelled nodes from group
     for (WNode p = group, q; (q = p.cowait) != null; ) {
       if (q.status == CANCELLED) {
         U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
         p = group; // restart
       } else p = q;
     }
     if (group == node) {
       for (WNode r = group.cowait; r != null; r = r.cowait) {
         if ((w = r.thread) != null) U.unpark(w); // wake up uncancelled co-waiters
       }
       for (WNode pred = node.prev; pred != null; ) { // unsplice
         WNode succ, pp; // find valid successor
         while ((succ = node.next) == null || succ.status == CANCELLED) {
           WNode q = null; // find successor the slow way
           for (WNode t = wtail; t != null && t != node; t = t.prev)
             if (t.status != CANCELLED) q = t; // don't link if succ cancelled
           if (succ == q
               || // ensure accurate successor
               U.compareAndSwapObject(node, WNEXT, succ, succ = q)) {
             if (succ == null && node == wtail) U.compareAndSwapObject(this, WTAIL, node, pred);
             break;
           }
         }
         if (pred.next == node) // unsplice pred link
         U.compareAndSwapObject(pred, WNEXT, node, succ);
         if (succ != null && (w = succ.thread) != null) {
           succ.thread = null;
           U.unpark(w); // wake up succ to observe new pred
         }
         if (pred.status != CANCELLED || (pp = pred.prev) == null) break;
         node.prev = pp; // repeat if new pred wrong/cancelled
         U.compareAndSwapObject(pp, WNEXT, pred, succ);
         pred = pp;
       }
     }
   }
   WNode h; // Possibly release first waiter
   while ((h = whead) != null) {
     long s;
     WNode q; // similar to release() but check eligibility
     if ((q = h.next) == null || q.status == CANCELLED) {
       for (WNode t = wtail; t != null && t != h; t = t.prev) if (t.status <= 0) q = t;
     }
     if (h == whead) {
       if (q != null
           && h.status == 0
           && ((s = state) & ABITS) != WBIT
           && // waiter is eligible
           (s == 0L || q.mode == RMODE)) release(h);
       break;
     }
   }
   return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
 }
Пример #2
0
  /**
   * See above for explanation.
   *
   * @param interruptible true if should check interrupts and if so return INTERRUPTED
   * @param deadline if nonzero, the System.nanoTime value to timeout at (and return zero)
   * @return next state, or INTERRUPTED
   */
  private long acquireRead(boolean interruptible, long deadline) {
    WNode node = null, p;
    boolean interrupted = false;
    for (int spins = -1; ; ) {
      WNode h;
      if ((h = whead) == (p = wtail)) {
        for (long m, s, ns; ; ) {
          if ((m = (s = state) & ABITS) < RFULL
              ? U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT)
              : (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
            if (interrupted) Thread.currentThread().interrupt();
            return ns;
          } else if (m >= WBIT) {
            if (spins > 0) {
              if (LockSupport.nextSecondarySeed() >= 0) --spins;
            } else {
              if (spins == 0) {
                WNode nh = whead, np = wtail;
                if ((nh == h && np == p) || (h = nh) != (p = np)) break;
              }
              spins = SPINS;
            }
          }
        }
      }
      if (p == null) { // initialize queue
        WNode hd = new WNode(WMODE, null);
        if (U.compareAndSwapObject(this, WHEAD, null, hd)) wtail = hd;
      } else if (node == null) node = new WNode(RMODE, p);
      else if (h == p || p.mode != RMODE) {
        if (node.prev != p) node.prev = p;
        else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
          p.next = node;
          break;
        }
      } else if (!U.compareAndSwapObject(p, WCOWAIT, node.cowait = p.cowait, node))
        node.cowait = null;
      else {
        for (; ; ) {
          WNode pp, c;
          Thread w;
          if ((h = whead) != null
              && (c = h.cowait) != null
              && U.compareAndSwapObject(h, WCOWAIT, c, c.cowait)
              && (w = c.thread) != null) // help release
          U.unpark(w);
          if (h == (pp = p.prev) || h == p || pp == null) {
            long m, s, ns;
            do {
              if ((m = (s = state) & ABITS) < RFULL
                  ? U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT)
                  : (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
                if (interrupted) Thread.currentThread().interrupt();
                return ns;
              }
            } while (m < WBIT);
          }
          if (whead == h && p.prev == pp) {
            long time;
            if (pp == null || h == p || p.status > 0) {
              node = null; // throw away
              break;
            }
            if (deadline == 0L) time = 0L;
            else if ((time = deadline - System.nanoTime()) <= 0L)
              return cancelWaiter(node, p, false);
            Thread wt = Thread.currentThread();
            U.putObject(wt, PARKBLOCKER, this);
            node.thread = wt;
            if ((h != pp || (state & ABITS) == WBIT) && whead == h && p.prev == pp)
              U.park(false, time);
            node.thread = null;
            U.putObject(wt, PARKBLOCKER, null);
            //                        if (interruptible && Thread.interrupted())
            //                            return cancelWaiter(node, p, true);
            if (Thread.interrupted()) {
              if (interruptible) return cancelWaiter(node, p, true);
              else interrupted = true;
            }
          }
        }
      }
    }

    for (int spins = -1; ; ) {
      WNode h, np, pp;
      int ps;
      if ((h = whead) == p) {
        if (spins < 0) spins = HEAD_SPINS;
        else if (spins < MAX_HEAD_SPINS) spins <<= 1;
        for (int k = spins; ; ) { // spin at head
          long m, s, ns;
          if ((m = (s = state) & ABITS) < RFULL
              ? U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT)
              : (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
            WNode c;
            Thread w;
            whead = node;
            node.prev = null;
            while ((c = node.cowait) != null) {
              if (U.compareAndSwapObject(node, WCOWAIT, c, c.cowait) && (w = c.thread) != null)
                U.unpark(w);
            }
            if (interrupted) Thread.currentThread().interrupt();
            return ns;
          } else if (m >= WBIT && LockSupport.nextSecondarySeed() >= 0 && --k <= 0) break;
        }
      } else if (h != null) {
        WNode c;
        Thread w;
        while ((c = h.cowait) != null) {
          if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && (w = c.thread) != null)
            U.unpark(w);
        }
      }
      if (whead == h) {
        if ((np = node.prev) != p) {
          if (np != null) (p = np).next = node; // stale
        } else if ((ps = p.status) == 0) U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
        else if (ps == CANCELLED) {
          if ((pp = p.prev) != null) {
            node.prev = pp;
            pp.next = node;
          }
        } else {
          long time;
          if (deadline == 0L) time = 0L;
          else if ((time = deadline - System.nanoTime()) <= 0L)
            return cancelWaiter(node, node, false);
          Thread wt = Thread.currentThread();
          U.putObject(wt, PARKBLOCKER, this);
          node.thread = wt;
          if (p.status < 0 && (p != h || (state & ABITS) == WBIT) && whead == h && node.prev == p)
            U.park(false, time);
          node.thread = null;
          U.putObject(wt, PARKBLOCKER, null);
          //                    if (interruptible && Thread.interrupted())
          //                        return cancelWaiter(node, node, true);
          if (Thread.interrupted()) {
            if (interruptible) return cancelWaiter(node, p, true);
            else interrupted = true;
          }
        }
      }
    }
  }
Пример #3
0
  /**
   * See above for explanation.
   *
   * @param interruptible true if should check interrupts and if so return INTERRUPTED
   * @param deadline if nonzero, the System.nanoTime value to timeout at (and return zero)
   * @return next state, or INTERRUPTED
   */
  private long acquireWrite(boolean interruptible, long deadline) {
    WNode node = null, p;
    boolean interrupted = false;
    for (int spins = -1; ; ) { // spin while enqueuing
      long m, s, ns;
      if ((m = (s = state) & ABITS) == 0L) {
        if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT)) {
          if (interrupted) Thread.currentThread().interrupt();
          return ns;
        }
      } else if (spins < 0) spins = (m == WBIT && wtail == whead) ? SPINS : 0;
      else if (spins > 0) {
        if (LockSupport.nextSecondarySeed() >= 0) --spins;
      } else if ((p = wtail) == null) { // initialize queue
        WNode hd = new WNode(WMODE, null);
        if (U.compareAndSwapObject(this, WHEAD, null, hd)) wtail = hd;
      } else if (node == null) node = new WNode(WMODE, p);
      else if (node.prev != p) node.prev = p;
      else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
        p.next = node;
        break;
      }
    }

    for (int spins = -1; ; ) {
      WNode h, np, pp;
      int ps;
      if ((h = whead) == p) {
        if (spins < 0) spins = HEAD_SPINS;
        else if (spins < MAX_HEAD_SPINS) spins <<= 1;
        for (int k = spins; ; ) { // spin at head
          long s, ns;
          if (((s = state) & ABITS) == 0L) {
            if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT)) {
              whead = node;
              node.prev = null;
              if (interrupted) Thread.currentThread().interrupt();
              return ns;
            }
          } else if (LockSupport.nextSecondarySeed() >= 0 && --k <= 0) break;
        }
      } else if (h != null) { // help release stale waiters
        WNode c;
        Thread w;
        while ((c = h.cowait) != null) {
          if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && (w = c.thread) != null)
            U.unpark(w);
        }
      }
      if (whead == h) {
        if ((np = node.prev) != p) {
          if (np != null) (p = np).next = node; // stale
        } else if ((ps = p.status) == 0) U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
        else if (ps == CANCELLED) {
          if ((pp = p.prev) != null) {
            node.prev = pp;
            pp.next = node;
          }
        } else {
          long time; // 0 argument to park means no timeout
          if (deadline == 0L) time = 0L;
          else if ((time = deadline - System.nanoTime()) <= 0L)
            return cancelWaiter(node, node, false);
          Thread wt = Thread.currentThread();
          U.putObject(wt, PARKBLOCKER, this);
          node.thread = wt;
          if (p.status < 0 && (p != h || (state & ABITS) != 0L) && whead == h && node.prev == p)
            U.park(false, time); // emulate LockSupport.park
          node.thread = null;
          U.putObject(wt, PARKBLOCKER, null);
          //                    if (interruptible && Thread.interrupted())
          //                        return cancelWaiter(node, node, true);
          if (Thread.interrupted()) {
            if (interruptible) return cancelWaiter(node, node, true);
            else interrupted = true;
          }
        }
      }
    }
  }