예제 #1
0
 /**
  * Equivalent to {@link #tryComplete} but does not invoke {@link #onCompletion(CountedCompleter)}
  * along the completion path: If the pending count is nonzero, decrements the count; otherwise,
  * similarly tries to complete this task's completer, if one exists, else marks this task as
  * complete. This method may be useful in cases where {@code onCompletion} should not, or need
  * not, be invoked for each completer in a computation.
  */
 public final void propagateCompletion() {
   CountedCompleter<?> a = this, s = a;
   for (int c; ; ) {
     if ((c = a.pending) == 0) {
       if ((a = (s = a).completer) == null) {
         s.quietlyComplete();
         return;
       }
     } else if (U.compareAndSwapInt(a, PENDING, c, c - 1)) return;
   }
 }
예제 #2
0
 /**
  * Wakes up the successor of h (normally whead). This is normally just h.next, but may require
  * traversal from wtail if next pointers are lagging. This may fail to wake up an acquiring thread
  * when one or more have been cancelled, but the cancel methods themselves provide extra
  * safeguards to ensure liveness.
  */
 private void release(WNode h) {
   if (h != null) {
     WNode q;
     Thread w;
     U.compareAndSwapInt(h, WSTATUS, WAITING, 0);
     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 (q != null && (w = q.thread) != null) U.unpark(w);
   }
 }
예제 #3
0
 /**
  * If this task's pending count is zero, returns this task; otherwise decrements its pending count
  * and returns {@code null}. This method is designed to be used with {@link #nextComplete} in
  * completion traversal loops.
  *
  * @return this task, if pending count was zero, else {@code null}
  */
 public final CountedCompleter<?> firstComplete() {
   for (int c; ; ) {
     if ((c = pending) == 0) return this;
     else if (U.compareAndSwapInt(this, PENDING, c, c - 1)) return null;
   }
 }
예제 #4
0
 /**
  * If the pending count is nonzero, (atomically) decrements it.
  *
  * @return the initial (undecremented) pending count holding on entry to this method
  */
 public final int decrementPendingCountUnlessZero() {
   int c;
   do {} while ((c = pending) != 0 && !U.compareAndSwapInt(this, PENDING, c, c - 1));
   return c;
 }
예제 #5
0
 /**
  * Sets (atomically) the pending count to the given count only if it currently holds the given
  * expected value.
  *
  * @param expected the expected value
  * @param count the new value
  * @return {@code true} if successful
  */
 public final boolean compareAndSetPendingCount(int expected, int count) {
   return U.compareAndSwapInt(this, PENDING, expected, count);
 }
예제 #6
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;
          }
        }
      }
    }
  }
예제 #7
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;
          }
        }
      }
    }
  }