Beispiel #1
0
    /** Unlinks s from the stack. */
    void clean(SNode s) {
      s.item = null; // forget item
      s.waiter = null; // forget thread

      /*
       * At worst we may need to traverse entire stack to unlink
       * s. If there are multiple concurrent calls to clean, we
       * might not see s if another thread has already removed
       * it. But we can stop when we see any node known to
       * follow s. We use s.next unless it too is cancelled, in
       * which case we try the node one past. We don't check any
       * further because we don't want to doubly traverse just to
       * find sentinel.
       */

      SNode past = s.next;
      if (past != null && past.isCancelled()) past = past.next;

      // Absorb cancelled nodes at head
      SNode p;
      while ((p = head) != null && p != past && p.isCancelled()) casHead(p, p.next);

      // Unsplice embedded nodes
      while (p != null && p != past) {
        SNode n = p.next;
        if (n != null && n.isCancelled()) p.casNext(n, n.next);
        else p = n;
      }
    }
Beispiel #2
0
    /** Puts or takes an item. */
    Object transfer(Object e, boolean timed, long nanos) {
      /*
       * Basic algorithm is to loop trying one of three actions:
       *
       * 1. If apparently empty or already containing nodes of same
       *    mode, try to push node on stack and wait for a match,
       *    returning it, or null if cancelled.
       *
       * 2. If apparently containing node of complementary mode,
       *    try to push a fulfilling node on to stack, match
       *    with corresponding waiting node, pop both from
       *    stack, and return matched item. The matching or
       *    unlinking might not actually be necessary because of
       *    other threads performing action 3:
       *
       * 3. If top of stack already holds another fulfilling node,
       *    help it out by doing its match and/or pop
       *    operations, and then continue. The code for helping
       *    is essentially the same as for fulfilling, except
       *    that it doesn't return the item.
       */

      SNode s = null; // constructed/reused as needed
      int mode = (e == null) ? REQUEST : DATA;

      for (; ; ) {
        SNode h = head;
        if (h == null || h.mode == mode) { // empty or same-mode
          if (timed && nanos <= 0) { // can't wait
            if (h != null && h.isCancelled()) casHead(h, h.next); // pop cancelled node
            else return null;
          } else if (casHead(h, s = snode(s, e, h, mode))) {
            SNode m = awaitFulfill(s, timed, nanos);
            if (m == s) { // wait was cancelled
              clean(s);
              return null;
            }
            if ((h = head) != null && h.next == s) casHead(h, s.next); // help s's fulfiller
            return (mode == REQUEST) ? m.item : s.item;
          }
        } else if (!isFulfilling(h.mode)) { // try to fulfill
          if (h.isCancelled()) // already cancelled
          casHead(h, h.next); // pop and retry
          else if (casHead(h, s = snode(s, e, h, FULFILLING | mode))) {
            for (; ; ) { // loop until matched or waiters disappear
              SNode m = s.next; // m is s's match
              if (m == null) { // all waiters are gone
                casHead(s, null); // pop fulfill node
                s = null; // use new node next time
                break; // restart main loop
              }
              SNode mn = m.next;
              if (m.tryMatch(s)) {
                casHead(s, mn); // pop both s and m
                return (mode == REQUEST) ? m.item : s.item;
              } else // lost match
              s.casNext(m, mn); // help unlink
            }
          }
        } else { // help a fulfiller
          SNode m = h.next; // m is h's match
          if (m == null) // waiter is gone
          casHead(h, null); // pop fulfilling node
          else {
            SNode mn = m.next;
            if (m.tryMatch(h)) // help match
            casHead(h, mn); // pop both h and m
            else // lost match
            h.casNext(m, mn); // help unlink
          }
        }
      }
    }