WNode node = null, group = null, p;
for (int spins = -1;;) {
for (;;) {
long s, m, ns;
WNode h, q;
Strand w; // anti-barging guard
if (group == null && (h = whead) != null
&& (q = h.next) != null && q.mode != RMODE)
break;
if ((m = (s = state) & ABITS) < RFULL
? U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT)
: (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
if (group != null) { // help release others
for (WNode r = group;;) {
if ((w = r.strand) != null) {
r.strand = null;
w.unpark();
}
if ((r = group.cowait) == null)
break;
U.compareAndSwapObject(group, WCOWAIT, r, r.cowait);
}
}
return ns;
}
if (m >= WBIT)
break;
}
if (spins > 0) {
if (ThreadLocalRandom.current().nextInt() >= 0)
--spins;
} else if ((p = wtail) == null) {
WNode h = new WNode(WMODE, null);
if (U.compareAndSwapObject(this, WHEAD, null, h))
wtail = h;
} else if (spins < 0)
spins = (p == whead) ? SPINS : 0;
else if (node == null)
node = new WNode(WMODE, p);
else if (node.prev != p)
node.prev = p;
else if (p.mode == RMODE && p != whead) {
WNode pp = p.prev; // become co-waiter with group p
if (pp != null && p == wtail
&& U.compareAndSwapObject(p, WCOWAIT,
node.cowait = p.cowait, node)) {
node.strand = Strand.currentStrand();
for (long time;;) {
if (interruptible && Strand.interrupted())
return cancelWaiter(node, p, true);
if (deadline == 0L)
time = 0L;
else if ((time = deadline - System.nanoTime()) <= 0L)
return cancelWaiter(node, p, false);
if (node.strand == null)
break;
if (p.prev != pp || p.status == CANCELLED
|| p == whead || p.prev != pp) {
node.strand = null;
break;
}
if (node.strand == null) // must recheck
break;
park(time);
}
group = p;
}
node = null; // throw away
} else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
p.next = node;
break;
}
}
for (int spins = SPINS;;) {
WNode np, pp, r;
int ps;
long m, s, ns;
Strand w;
while ((np = node.prev) != p && np != null)
(p = np).next = node;
if (whead == p) {
for (int k = spins;;) {
if ((m = (s = state) & ABITS) != WBIT) {
if (m < RFULL
? U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT)
: (ns = tryIncReaderOverflow(s)) != 0L) {
whead = node;
node.prev = null;
while ((r = node.cowait) != null) {
if (U.compareAndSwapObject(node, WCOWAIT,
r, r.cowait)
&& (w = r.strand) != null) {
r.strand = null;
w.unpark(); // release co-waiter
}
}
return ns;
}
} else if (ThreadLocalRandom.current().nextInt() >= 0