/** * Spins/yields/blocks until node s is matched or caller gives up. * * @param s the waiting node * @param pred the predecessor of s, or s itself if it has no predecessor, or null if unknown (the * null case does not occur in any current calls but may in possible future extensions) * @param e the comparison value for checking match * @param timed if true, wait only until timeout elapses * @param nanos timeout in nanosecs, used only if timed is true * @return matched item, or e if unmatched on interrupt or timeout */ private Message awaitMatch(Node s, Node pred, Message e, boolean timed, long nanos) throws SuspendExecution { long lastTime = timed ? System.nanoTime() : 0L; Strand w = Strand.currentStrand(); int spins = (w.isFiber() ? 0 : -1); // no spins in fiber; otherwise, initialized after first item and cancel checks ThreadLocalRandom randomYields = null; // bound if needed if (spins == 0) requestUnpark(s, w); for (; ; ) { Object item = s.item; if (item == CHANNEL_CLOSED) setReceiveClosed(); if (item != e) { // matched // assert item != s; s.forgetContents(); // avoid garbage return this.<Message>cast(item); } if ((w.isInterrupted() || (timed && nanos <= 0)) && s.casItem(e, s)) { // cancel unsplice(pred, s); return e; } if (spins < 0) { // establish spins at/near front if ((spins = spinsFor(pred, s.isData)) > 0) randomYields = ThreadLocalRandom.current(); } else if (spins > 0) { // spin --spins; if (randomYields.nextInt(CHAINED_SPINS) == 0) Strand.yield(); // occasionally yield } else if (s.waiter == null) { requestUnpark(s, w); // request unpark then recheck } else if (timed) { long now = System.nanoTime(); if ((nanos -= now - lastTime) > 0) Strand.parkNanos(this, nanos); lastTime = now; } else { Strand.park(this); } } }