Exemple #1
0
  private Token xfer0(SelectActionImpl<Message> e) {
    final boolean haveData = e.isData();
    Node s = null; // the node to append, if needed

    retry:
    for (; ; ) { // restart on append race
      if (!e.lease()) return null;
      if (isClosed() || (isSendClosed() && e.isData())) {
        e.setItem(null);
        e.won();
        return null;
      }

      Object item = tryMatch(e, e.message(), haveData);
      if (item == LOST) return null;

      if (item != NO_MATCH) {
        e.setItem(item == CHANNEL_CLOSED ? null : (Message) item);
        e.won();
        return null;
      }
      e.returnLease();

      if (s == null) {
        s = new Node(e);
        requestUnpark(s, e.selector().getWaiter());
      }
      Node pred = tryAppend(s, haveData);
      if (pred == null) continue retry; // lost race vs opposite mode

      return new Token(s, pred);
    }
  }
Exemple #2
0
 void won() {
   if (sa != null) {
     Object x = item;
     sa.setItem(x == CHANNEL_CLOSED ? null : x);
     sa.won();
   }
 }
Exemple #3
0
  private Object tryMatch(SelectActionImpl sa, Message e, boolean haveData) {
    boolean closed = isSendClosed(); // must be read before trying to match so as not to miss puts

    for (Node h = head, p = h; p != null; ) { // find & match first node
      boolean isData = p.isData;
      Object item = p.item;

      if (item != p && (item != null) == isData) { // unmatched
        if (isData == haveData) // can't match
        break;

        // avoid deadlock by orderdering lease acquisition:
        // if p requires a lease and is of lower hashCode than sa, we return sa's lease, acquire
        // p's, and then reacquire sa's.
        SelectActionImpl sa2 = p.sa;
        boolean leasedp;
        if (sa != null && sa2 != null && sa2.selector().id < sa.selector().id) {
          sa.returnLease();
          leasedp = sa2.lease();
          if (!sa.lease()) {
            if (leasedp) sa2.returnLease();
            return LOST;
          }
        } else leasedp = p.lease();

        if (leasedp) {
          if (p.casItem(item, e)) { // match
            p.won();
            for (Node q = p; q != h; ) {
              Node n = q.next; // update by 2 unless singleton
              if (head == h && casHead(h, n == null ? q : n)) {
                h.forgetNext();
                break;
              } // advance and retry
              if ((h = head) == null || (q = h.next) == null || !q.isMatched())
                break; // unless slack < 2
            }
            Strand.unpark(p.waiter, this);
            return item;
          } else p.returnLease();
        }
      }
      Node n = p.next;
      p = (p != n) ? n : (h = head); // Use head if p offlist
    }

    if (closed) {
      assert !haveData;
      setReceiveClosed();
      return CHANNEL_CLOSED;
    }
    return NO_MATCH;
  }
Exemple #4
0
 void returnLease() {
   if (sa != null) sa.returnLease();
 }
Exemple #5
0
 boolean lease() {
   if (sa == null) return true;
   return sa.lease();
 }
Exemple #6
0
 /**
  * Constructs a new node. Uses relaxed write because item can only be seen after publication via
  * casNext.
  */
 Node(SelectActionImpl sa) {
   UNSAFE.putObject(this, itemOffset, sa.message()); // relaxed write
   UNSAFE.putObject(this, saOffset, sa); // relaxed write
   this.isData = sa.isData();
 }