207 |
|
* pointing back to its sources. So we null out fields as soon as |
208 |
|
* possible. The screening checks needed anyway harmlessly ignore |
209 |
|
* null arguments that may have been obtained during races with |
210 |
< |
* threads nulling out fields. We also try to unlink fired |
211 |
< |
* Completions from stacks that might never be popped (see method |
212 |
< |
* postFire). Completion fields need not be declared as final or |
213 |
< |
* volatile because they are only visible to other threads upon |
214 |
< |
* safe publication. |
210 |
> |
* threads nulling out fields. We also try to unlink non-isLive |
211 |
> |
* (fired or cancelled) Completions from stacks that might |
212 |
> |
* otherwise never be popped: Method cleanStack always unlinks non |
213 |
> |
* isLive completions from the head of stack; others may |
214 |
> |
* occasionally remain if racing with other cancellations or |
215 |
> |
* removals. |
216 |
> |
* |
217 |
> |
* Completion fields need not be declared as final or volatile |
218 |
> |
* because they are only visible to other threads upon safe |
219 |
> |
* publication. |
220 |
|
*/ |
221 |
|
|
222 |
|
volatile Object result; // Either the result or boxed AltResult |
453 |
|
U.putOrderedObject(c, NEXT, next); |
454 |
|
} |
455 |
|
|
456 |
+ |
static boolean casNext(Completion c, Completion cmp, Completion val) { |
457 |
+ |
return U.compareAndSwapObject(c, NEXT, cmp, val); |
458 |
+ |
} |
459 |
+ |
|
460 |
|
/** |
461 |
|
* Pops and tries to trigger all reachable dependents. Call only |
462 |
|
* when known to be done. |
477 |
|
pushStack(h); |
478 |
|
continue; |
479 |
|
} |
480 |
< |
h.next = null; // detach |
480 |
> |
casNext(h, t, null); // try to detach |
481 |
|
} |
482 |
|
f = (d = h.tryFire(NESTED)) == null ? this : d; |
483 |
|
} |
484 |
|
} |
485 |
|
} |
486 |
|
|
487 |
< |
/** Traverses stack and unlinks dead Completions. */ |
487 |
> |
/** Traverses stack and unlinks one or more dead Completions, if found. */ |
488 |
|
final void cleanStack() { |
489 |
< |
for (Completion p = null, q = stack; q != null;) { |
490 |
< |
Completion s = q.next; |
491 |
< |
if (q.isLive()) { |
492 |
< |
p = q; |
493 |
< |
q = s; |
494 |
< |
} |
495 |
< |
else if (p == null) { |
496 |
< |
casStack(q, s); |
497 |
< |
q = stack; |
489 |
< |
} |
490 |
< |
else { |
491 |
< |
p.next = s; |
492 |
< |
if (p.isLive()) |
489 |
> |
boolean unlinked = false; |
490 |
> |
Completion p; |
491 |
> |
while ((p = stack) != null && !p.isLive()) // ensure head of stack live |
492 |
> |
unlinked = casStack(p, p.next); |
493 |
> |
if (p != null && !unlinked) { // try to unlink first nonlive |
494 |
> |
for (Completion q = p.next; q != null;) { |
495 |
> |
Completion s = q.next; |
496 |
> |
if (q.isLive()) { |
497 |
> |
p = q; |
498 |
|
q = s; |
499 |
+ |
} |
500 |
|
else { |
501 |
< |
p = null; // restart |
502 |
< |
q = stack; |
501 |
> |
casNext(p, q, s); |
502 |
> |
break; |
503 |
|
} |
504 |
|
} |
505 |
|
} |
554 |
|
*/ |
555 |
|
final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) { |
556 |
|
if (a != null && a.stack != null) { |
557 |
< |
if (a.result == null) |
557 |
> |
Object r; |
558 |
> |
if ((r = a.result) == null) |
559 |
|
a.cleanStack(); |
560 |
< |
else if (mode >= 0) |
560 |
> |
if (mode >= 0 && (r != null || a.result != null)) |
561 |
|
a.postComplete(); |
562 |
|
} |
563 |
|
if (result != null && stack != null) { |
1133 |
|
final CompletableFuture<T> postFire(CompletableFuture<?> a, |
1134 |
|
CompletableFuture<?> b, int mode) { |
1135 |
|
if (b != null && b.stack != null) { // clean second source |
1136 |
< |
if (b.result == null) |
1136 |
> |
Object r; |
1137 |
> |
if ((r = b.result) == null) |
1138 |
|
b.cleanStack(); |
1139 |
< |
else if (mode >= 0) |
1139 |
> |
if (mode >= 0 && (r != null || b.result != null)) |
1140 |
|
b.postComplete(); |
1141 |
|
} |
1142 |
|
return postFire(a, mode); |
1859 |
|
break; |
1860 |
|
} |
1861 |
|
} |
1862 |
< |
if (q != null) { |
1862 |
> |
if (q != null && queued) { |
1863 |
|
q.thread = null; |
1864 |
< |
if (q.interrupted) { |
1865 |
< |
if (interruptible) |
1866 |
< |
cleanStack(); |
1867 |
< |
else |
1860 |
< |
Thread.currentThread().interrupt(); |
1861 |
< |
} |
1864 |
> |
if (!interruptible && q.interrupted) |
1865 |
> |
Thread.currentThread().interrupt(); |
1866 |
> |
if (r == null) |
1867 |
> |
cleanStack(); |
1868 |
|
} |
1869 |
< |
if (r != null) |
1869 |
> |
if (r != null || (r = result) != null) |
1870 |
|
postComplete(); |
1871 |
|
return r; |
1872 |
|
} |
1903 |
|
break; |
1904 |
|
} |
1905 |
|
} |
1906 |
< |
if (q != null) |
1906 |
> |
if (q != null && queued) { |
1907 |
|
q.thread = null; |
1908 |
< |
if (r != null) |
1908 |
> |
if (r == null) |
1909 |
> |
cleanStack(); |
1910 |
> |
} |
1911 |
> |
if (r != null || (r = result) != null) |
1912 |
|
postComplete(); |
1904 |
– |
else |
1905 |
– |
cleanStack(); |
1913 |
|
if (r != null || (q != null && q.interrupted)) |
1914 |
|
return r; |
1915 |
|
} |