324 |
|
* for appends, so can only be removed later when other nodes are |
325 |
|
* appended. (2) We cannot necessarily unlink s given a |
326 |
|
* predecessor node that is matched (including the case of being |
327 |
< |
* cancelled): the predecessor may already be already unspliced, |
328 |
< |
* in which case some previous reachable node may still point to |
329 |
< |
* s. (For further explanation see Herlihy & Shavit "The Art of |
327 |
> |
* cancelled): the predecessor may already be unspliced, in which |
328 |
> |
* case some previous reachable node may still point to s. |
329 |
> |
* (For further explanation see Herlihy & Shavit "The Art of |
330 |
|
* Multiprocessor Programming" chapter 9). Although, in both |
331 |
|
* cases, we can rule out the need for further action if either s |
332 |
|
* or its predecessor are (or can be made to be) at, or fall off |
343 |
|
* When these cases arise, rather than always retraversing the |
344 |
|
* entire list to find an actual predecessor to unlink (which |
345 |
|
* won't help for case (1) anyway), we record a conservative |
346 |
< |
* estimate of possible unsplice failures (in "sweepVotes). We |
346 |
> |
* estimate of possible unsplice failures (in "sweepVotes"). We |
347 |
|
* trigger a full sweep when the estimate exceeds a threshold |
348 |
|
* indicating the maximum number of estimated removal failures to |
349 |
|
* tolerate before sweeping through, unlinking cancelled nodes |
359 |
|
* Because the sweepVotes estimate is conservative, and because |
360 |
|
* nodes become unlinked "naturally" as they fall off the head of |
361 |
|
* the queue, and because we allow votes to accumulate even while |
362 |
< |
* sweeps are in progress, there are typically signficantly fewer |
362 |
> |
* sweeps are in progress, there are typically significantly fewer |
363 |
|
* such nodes than estimated. Choice of a threshold value |
364 |
|
* balances the likelihood of wasted effort and contention, versus |
365 |
|
* providing a worst-case bound on retention of interior nodes in |
876 |
|
} |
877 |
|
|
878 |
|
/** |
879 |
< |
* Unlink matched nodes encountered in a traversal from head |
879 |
> |
* Unlinks matched nodes encountered in a traversal from head. |
880 |
|
*/ |
881 |
|
private void sweep() { |
882 |
< |
Node p = head, s, n; |
883 |
< |
while (p != null && (s = p.next) != null && (n = s.next) != null) { |
884 |
< |
if (p == s || s == n) |
885 |
< |
p = head; // stale |
886 |
< |
else if (s.isMatched()) |
887 |
< |
p.casNext(s, n); |
888 |
< |
else |
882 |
> |
for (Node p = head, s, n; p != null && (s = p.next) != null; ) { |
883 |
> |
if (p == s) // stale |
884 |
> |
p = head; |
885 |
> |
else if (!s.isMatched()) |
886 |
|
p = s; |
887 |
+ |
else if ((n = s.next) == null) // trailing node is pinned |
888 |
+ |
break; |
889 |
+ |
else |
890 |
+ |
p.casNext(s, n); |
891 |
|
} |
892 |
|
} |
893 |
|
|
1125 |
|
* @return {@code true} if this queue contains no elements |
1126 |
|
*/ |
1127 |
|
public boolean isEmpty() { |
1128 |
< |
return firstOfMode(true) == null; |
1128 |
> |
for (Node p = head; p != null; p = succ(p)) { |
1129 |
> |
if (!p.isMatched()) |
1130 |
> |
return !p.isData; |
1131 |
> |
} |
1132 |
> |
return true; |
1133 |
|
} |
1134 |
|
|
1135 |
|
public boolean hasWaitingConsumer() { |