/** Tries to artificially match a data node -- used by remove. */ final boolean tryMatchData() { // assert isData; Object x = item; if (x != null && x != this && casItem(x, null)) { Strand.unpark(waiter, this); return true; } return false; }
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; }
private void signalWaitersOnClose() { for (Node p = head; p != null; ) { if (!p.isMatched()) { if (!p.isData) { if (p.casItem(null, CHANNEL_CLOSED)) // match waiting requesters with CHANNEL_CLOSED Strand.unpark(p.waiter, this); // ... and wake 'em up } else p.tryMatchData(); } Node n = p.next; if (n != p) p = n; else p = head; } }