79 |
|
* seems not to vary with number of CPUs (beyond 2) so is just |
80 |
|
* a constant. |
81 |
|
*/ |
82 |
< |
static final int maxTimedSpins = (NCPUS < 2)? 0 : 32; |
82 |
> |
static final int maxTimedSpins = (NCPUS < 2)? 0 : 32; |
83 |
|
|
84 |
|
/** |
85 |
|
* The number of times to spin before blocking in untimed waits. |
94 |
|
*/ |
95 |
|
static final long spinForTimeoutThreshold = 1000L; |
96 |
|
|
97 |
< |
/** |
97 |
> |
/** |
98 |
|
* Node class for LinkedTransferQueue. Opportunistically subclasses from |
99 |
|
* AtomicReference to represent item. Uses Object, not E, to allow |
100 |
|
* setting item to "this" after use, to avoid garbage |
132 |
|
|
133 |
|
|
134 |
|
private final QNode dummy = new QNode(null, false); |
135 |
< |
private final PaddedAtomicReference<QNode> head = |
135 |
> |
private final PaddedAtomicReference<QNode> head = |
136 |
|
new PaddedAtomicReference<QNode>(dummy); |
137 |
< |
private final PaddedAtomicReference<QNode> tail = |
137 |
> |
private final PaddedAtomicReference<QNode> tail = |
138 |
|
new PaddedAtomicReference<QNode>(dummy); |
139 |
|
|
140 |
|
/** |
156 |
|
} |
157 |
|
return false; |
158 |
|
} |
159 |
< |
|
159 |
> |
|
160 |
|
/** |
161 |
|
* Puts or takes an item. Used for most queue operations (except |
162 |
|
* poll() and tryTransfer()) |
188 |
|
return awaitFulfill(t, s, e, mode, nanos); |
189 |
|
} |
190 |
|
} |
191 |
< |
|
191 |
> |
|
192 |
|
else if (h != null) { |
193 |
|
QNode first = h.next; |
194 |
< |
if (t == tail.get() && first != null && |
194 |
> |
if (t == tail.get() && first != null && |
195 |
|
advanceHead(h, first)) { |
196 |
|
Object x = first.get(); |
197 |
|
if (x != first && first.compareAndSet(x, e)) { |
228 |
|
} |
229 |
|
else if (h != null) { |
230 |
|
QNode first = h.next; |
231 |
< |
if (t == tail.get() && |
231 |
> |
if (t == tail.get() && |
232 |
|
first != null && |
233 |
|
advanceHead(h, first)) { |
234 |
|
Object x = first.get(); |
252 |
|
* @param nanos timeout value |
253 |
|
* @return matched item, or s if cancelled |
254 |
|
*/ |
255 |
< |
private Object awaitFulfill(QNode pred, QNode s, Object e, |
255 |
> |
private Object awaitFulfill(QNode pred, QNode s, Object e, |
256 |
|
int mode, long nanos) { |
257 |
|
if (mode == NOWAIT) |
258 |
|
return null; |
268 |
|
advanceHead(pred, s); // unlink if head |
269 |
|
if (x == s) // was cancelled |
270 |
|
return clean(pred, s); |
271 |
< |
else if (x != null) { |
271 |
> |
else if (x != null) { |
272 |
|
s.set(s); // avoid garbage retention |
273 |
|
return x; |
274 |
|
} |
288 |
|
if (spins < 0) { |
289 |
|
QNode h = head.get(); // only spin if at head |
290 |
|
spins = ((h != null && h.next == s) ? |
291 |
< |
(mode == TIMEOUT? |
291 |
> |
(mode == TIMEOUT? |
292 |
|
maxTimedSpins : maxUntimedSpins) : 0); |
293 |
|
} |
294 |
|
if (spins > 0) |
321 |
|
if (w != Thread.currentThread()) |
322 |
|
LockSupport.unpark(w); |
323 |
|
} |
324 |
< |
|
324 |
> |
|
325 |
|
for (;;) { |
326 |
|
if (pred.next != s) // already cleaned |
327 |
< |
return null; |
327 |
> |
return null; |
328 |
|
QNode h = head.get(); |
329 |
|
QNode hn = h.next; // Absorb cancelled first node as head |
330 |
|
if (hn != null && hn.next == hn) { |
360 |
|
cleanMe.compareAndSet(dp, null); |
361 |
|
if (dp == pred) |
362 |
|
return null; // s is already saved node |
363 |
< |
} |
363 |
> |
} |
364 |
|
else if (cleanMe.compareAndSet(null, pred)) |
365 |
|
return null; // Postpone cleaning s |
366 |
|
} |
367 |
|
} |
368 |
< |
|
368 |
> |
|
369 |
|
/** |
370 |
|
* Creates an initially empty <tt>LinkedTransferQueue</tt>. |
371 |
|
*/ |
390 |
|
xfer(e, NOWAIT, 0); |
391 |
|
} |
392 |
|
|
393 |
< |
public boolean offer(E e, long timeout, TimeUnit unit) |
393 |
> |
public boolean offer(E e, long timeout, TimeUnit unit) |
394 |
|
throws InterruptedException { |
395 |
|
if (e == null) throw new NullPointerException(); |
396 |
|
if (Thread.interrupted()) throw new InterruptedException(); |
487 |
|
QNode last = t.next; |
488 |
|
QNode first = h.next; |
489 |
|
if (t == tail.get()) { |
490 |
< |
if (last != null) |
490 |
> |
if (last != null) |
491 |
|
tail.compareAndSet(t, last); |
492 |
|
else if (first != null) { |
493 |
|
Object x = first.get(); |
494 |
< |
if (x == first) |
495 |
< |
advanceHead(h, first); |
494 |
> |
if (x == first) |
495 |
> |
advanceHead(h, first); |
496 |
|
else |
497 |
|
return h; |
498 |
|
} |
520 |
|
QNode currentNode; // last returned node, for remove() |
521 |
|
QNode prevNode; // predecessor of last returned node |
522 |
|
E nextItem; // Cache of next item, once commited to in next |
523 |
< |
|
523 |
> |
|
524 |
|
Itr() { |
525 |
|
nextNode = traversalHead(); |
526 |
|
advance(); |
527 |
|
} |
528 |
< |
|
528 |
> |
|
529 |
|
E advance() { |
530 |
|
prevNode = currentNode; |
531 |
|
currentNode = nextNode; |
532 |
|
E x = nextItem; |
533 |
< |
|
533 |
> |
|
534 |
|
QNode p = nextNode.next; |
535 |
|
for (;;) { |
536 |
|
if (p == null || !p.isData) { |
543 |
|
nextNode = p; |
544 |
|
nextItem = (E)item; |
545 |
|
return x; |
546 |
< |
} |
546 |
> |
} |
547 |
|
prevNode = p; |
548 |
|
p = p.next; |
549 |
|
} |
550 |
|
} |
551 |
< |
|
551 |
> |
|
552 |
|
public boolean hasNext() { |
553 |
|
return nextNode != null; |
554 |
|
} |
555 |
< |
|
555 |
> |
|
556 |
|
public E next() { |
557 |
|
if (nextNode == null) throw new NoSuchElementException(); |
558 |
|
return advance(); |
559 |
|
} |
560 |
< |
|
560 |
> |
|
561 |
|
public void remove() { |
562 |
|
QNode p = currentNode; |
563 |
|
QNode prev = prevNode; |
564 |
< |
if (prev == null || p == null) |
564 |
> |
if (prev == null || p == null) |
565 |
|
throw new IllegalStateException(); |
566 |
|
Object x = p.get(); |
567 |
|
if (x != null && x != p && p.compareAndSet(x, p)) |
608 |
|
if (p == null) |
609 |
|
return false; |
610 |
|
Object x = p.get(); |
611 |
< |
if (p != x) |
611 |
> |
if (p != x) |
612 |
|
return !p.isData; |
613 |
|
} |
614 |
|
} |
615 |
< |
|
615 |
> |
|
616 |
|
/** |
617 |
|
* Returns the number of elements in this queue. If this queue |
618 |
|
* contains more than <tt>Integer.MAX_VALUE</tt> elements, returns |
630 |
|
QNode h = traversalHead(); |
631 |
|
for (QNode p = h.next; p != null && p.isData; p = p.next) { |
632 |
|
Object x = p.get(); |
633 |
< |
if (x != null && x != p) { |
633 |
> |
if (x != null && x != p) { |
634 |
|
if (++count == Integer.MAX_VALUE) // saturated |
635 |
|
break; |
636 |
|
} |