Esempio n. 1
0
 /**
  * Spins/blocks until node s is matched by a fulfill operation.
  *
  * @param s the waiting node
  * @param timed true if timed wait
  * @param nanos timeout value
  * @return matched node, or s if cancelled
  */
 SNode awaitFulfill(SNode s, boolean timed, long nanos) {
   /*
    * When a node/thread is about to block, it sets its waiter
    * field and then rechecks state at least one more time
    * before actually parking, thus covering race vs
    * fulfiller noticing that waiter is non-null so should be
    * woken.
    *
    * When invoked by nodes that appear at the point of call
    * to be at the head of the stack, calls to park are
    * preceded by spins to avoid blocking when producers and
    * consumers are arriving very close in time.  This can
    * happen enough to bother only on multiprocessors.
    *
    * The order of checks for returning out of main loop
    * reflects fact that interrupts have precedence over
    * normal returns, which have precedence over
    * timeouts. (So, on timeout, one last check for match is
    * done before giving up.) Except that calls from untimed
    * SynchronousQueue.{poll/offer} don't check interrupts
    * and don't wait at all, so are trapped in transfer
    * method rather than calling awaitFulfill.
    */
   long lastTime = timed ? System.nanoTime() : 0;
   Thread w = Thread.currentThread();
   SNode h = head;
   int spins = (shouldSpin(s) ? (timed ? maxTimedSpins : maxUntimedSpins) : 0);
   for (; ; ) {
     if (w.isInterrupted()) s.tryCancel();
     SNode m = s.match;
     if (m != null) return m;
     if (timed) {
       long now = System.nanoTime();
       nanos -= now - lastTime;
       lastTime = now;
       if (nanos <= 0) {
         s.tryCancel();
         continue;
       }
     }
     if (spins > 0) spins = shouldSpin(s) ? (spins - 1) : 0;
     else if (s.waiter == null) s.waiter = w; // establish waiter so can park next iter
     else if (!timed) LockSupport.park(this);
     else if (nanos > spinForTimeoutThreshold) LockSupport.parkNanos(this, nanos);
   }
 }
Esempio n. 2
0
 /**
  * Tries to match node s to this node, if so, waking up thread. Fulfillers call tryMatch to
  * identify their waiters. Waiters block until they have been matched.
  *
  * @param s the node to match
  * @return true if successfully matched to s
  */
 boolean tryMatch(SNode s) {
   if (match == null && UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) {
     Thread w = waiter;
     if (w != null) { // waiters need at most one unpark
       waiter = null;
       LockSupport.unpark(w);
     }
     return true;
   }
   return match == s;
 }
Esempio n. 3
0
 /**
  * Tries to increment readerOverflow by first setting state access bits value to RBITS, indicating
  * hold of spinlock, then updating, then releasing.
  *
  * @param s a reader overflow stamp: (s & ABITS) >= RFULL
  * @return new stamp on success, else zero
  */
 private long tryIncReaderOverflow(long s) {
   // assert (s & ABITS) >= RFULL;
   if ((s & ABITS) == RFULL) {
     if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
       ++readerOverflow;
       state = s;
       return s;
     }
   } else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0) Thread.yield();
   return 0L;
 }
Esempio n. 4
0
 /**
  * Spins/blocks until node s is fulfilled.
  *
  * @param s the waiting node
  * @param e the comparison value for checking match
  * @param timed true if timed wait
  * @param nanos timeout value
  * @return matched item, or s if cancelled
  */
 Object awaitFulfill(QNode s, Object e, boolean timed, long nanos) {
   /* Same idea as TransferStack.awaitFulfill */
   long lastTime = timed ? System.nanoTime() : 0;
   Thread w = Thread.currentThread();
   int spins = ((head.next == s) ? (timed ? maxTimedSpins : maxUntimedSpins) : 0);
   for (; ; ) {
     if (w.isInterrupted()) s.tryCancel(e);
     Object x = s.item;
     if (x != e) return x;
     if (timed) {
       long now = System.nanoTime();
       nanos -= now - lastTime;
       lastTime = now;
       if (nanos <= 0) {
         s.tryCancel(e);
         continue;
       }
     }
     if (spins > 0) --spins;
     else if (s.waiter == null) s.waiter = w;
     else if (!timed) LockSupport.park(this);
     else if (nanos > spinForTimeoutThreshold) LockSupport.parkNanos(this, nanos);
   }
 }
Esempio n. 5
0
 /**
  * Tries to decrement readerOverflow.
  *
  * @param s a reader overflow stamp: (s & ABITS) >= RFULL
  * @return new stamp on success, else zero
  */
 private long tryDecReaderOverflow(long s) {
   // assert (s & ABITS) >= RFULL;
   if ((s & ABITS) == RFULL) {
     if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
       int r;
       long next;
       if ((r = readerOverflow) > 0) {
         readerOverflow = r - 1;
         next = s;
       } else next = s - RUNIT;
       state = next;
       return next;
     }
   } else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0) Thread.yield();
   return 0L;
 }
Esempio n. 6
0
    /** Puts or takes an item. */
    Object transfer(Object e, boolean timed, long nanos) {
      /* Basic algorithm is to loop trying to take either of
       * two actions:
       *
       * 1. If queue apparently empty or holding same-mode nodes,
       *    try to add node to queue of waiters, wait to be
       *    fulfilled (or cancelled) and return matching item.
       *
       * 2. If queue apparently contains waiting items, and this
       *    call is of complementary mode, try to fulfill by CAS'ing
       *    item field of waiting node and dequeuing it, and then
       *    returning matching item.
       *
       * In each case, along the way, check for and try to help
       * advance head and tail on behalf of other stalled/slow
       * threads.
       *
       * The loop starts off with a null check guarding against
       * seeing uninitialized head or tail values. This never
       * happens in current SynchronousQueue, but could if
       * callers held non-volatile/final ref to the
       * transferer. The check is here anyway because it places
       * null checks at top of loop, which is usually faster
       * than having them implicitly interspersed.
       */

      QNode s = null; // constructed/reused as needed
      boolean isData = (e != null);

      for (; ; ) {
        QNode t = tail;
        QNode h = head;
        if (t == null || h == null) // saw uninitialized value
        continue; // spin

        if (h == t || t.isData == isData) { // empty or same-mode
          QNode tn = t.next;
          if (t != tail) // inconsistent read
          continue;
          if (tn != null) { // lagging tail
            advanceTail(t, tn);
            continue;
          }
          if (timed && nanos <= 0) // can't wait
          return null;
          if (s == null) s = new QNode(e, isData);
          if (!t.casNext(null, s)) // failed to link in
          continue;

          advanceTail(t, s); // swing tail and wait
          Object x = awaitFulfill(s, e, timed, nanos);
          if (x == s) { // wait was cancelled
            clean(t, s);
            return null;
          }

          if (!s.isOffList()) { // not already unlinked
            advanceHead(t, s); // unlink if head
            if (x != null) // and forget fields
            s.item = s;
            s.waiter = null;
          }
          return (x != null) ? x : e;

        } else { // complementary-mode
          QNode m = h.next; // node to fulfill
          if (t != tail || m == null || h != head) continue; // inconsistent read

          Object x = m.item;
          if (isData == (x != null)
              || // m already fulfilled
              x == m
              || // m cancelled
              !m.casItem(x, e)) { // lost CAS
            advanceHead(h, m); // dequeue and retry
            continue;
          }

          advanceHead(h, m); // successfully fulfilled
          LockSupport.unpark(m.waiter);
          return (x != null) ? x : e;
        }
      }
    }
Esempio n. 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 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;
          }
        }
      }
    }
  }
Esempio n. 8
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;
          }
        }
      }
    }
  }