mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8259800: timeout in tck test testForkJoin(ForkJoinPool8Test)
Reviewed-by: martin, dholmes
This commit is contained in:
parent
419717ddae
commit
5b7b18c5bf
2 changed files with 241 additions and 172 deletions
|
@ -521,7 +521,10 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
* terminate others by cancelling their unprocessed tasks, and
|
* terminate others by cancelling their unprocessed tasks, and
|
||||||
* waking them up. Calls to non-abrupt shutdown() preface this by
|
* waking them up. Calls to non-abrupt shutdown() preface this by
|
||||||
* checking isQuiescent before triggering the "STOP" phase of
|
* checking isQuiescent before triggering the "STOP" phase of
|
||||||
* termination.
|
* termination. To conform to ExecutorService invoke, invokeAll,
|
||||||
|
* and invokeAny specs, we must track pool status while waiting,
|
||||||
|
* and interrupt interruptible callers on termination (see
|
||||||
|
* ForkJoinTask.joinForPoolInvoke etc).
|
||||||
*
|
*
|
||||||
* Joining Tasks
|
* Joining Tasks
|
||||||
* =============
|
* =============
|
||||||
|
@ -631,6 +634,13 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
* amounts to an odd form of limited spin-wait before blocking in
|
* amounts to an odd form of limited spin-wait before blocking in
|
||||||
* ForkJoinTask.join.
|
* ForkJoinTask.join.
|
||||||
*
|
*
|
||||||
|
* Guarantees for common pool parallelism zero are limited to
|
||||||
|
* tasks that are joined by their callers in a tree-structured
|
||||||
|
* fashion or use CountedCompleters (as is true for jdk
|
||||||
|
* parallelStreams). Support infiltrates several methods,
|
||||||
|
* including those that retry helping steps until we are sure that
|
||||||
|
* none apply if there are no workers.
|
||||||
|
*
|
||||||
* As a more appropriate default in managed environments, unless
|
* As a more appropriate default in managed environments, unless
|
||||||
* overridden by system properties, we use workers of subclass
|
* overridden by system properties, we use workers of subclass
|
||||||
* InnocuousForkJoinWorkerThread when there is a SecurityManager
|
* InnocuousForkJoinWorkerThread when there is a SecurityManager
|
||||||
|
@ -893,7 +903,7 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
}
|
}
|
||||||
static final boolean casSlotToNull(ForkJoinTask<?>[] a, int i,
|
static final boolean casSlotToNull(ForkJoinTask<?>[] a, int i,
|
||||||
ForkJoinTask<?> c) {
|
ForkJoinTask<?> c) {
|
||||||
return QA.weakCompareAndSet(a, i, c, null);
|
return QA.compareAndSet(a, i, c, null);
|
||||||
}
|
}
|
||||||
final boolean tryLock() {
|
final boolean tryLock() {
|
||||||
return SOURCE.compareAndSet(this, 0, 1);
|
return SOURCE.compareAndSet(this, 0, 1);
|
||||||
|
@ -1046,13 +1056,22 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
*/
|
*/
|
||||||
final boolean externalTryUnpush(ForkJoinTask<?> task) {
|
final boolean externalTryUnpush(ForkJoinTask<?> task) {
|
||||||
boolean taken = false;
|
boolean taken = false;
|
||||||
|
for (;;) {
|
||||||
int s = top, cap, k; ForkJoinTask<?>[] a;
|
int s = top, cap, k; ForkJoinTask<?>[] a;
|
||||||
if ((a = array) != null && (cap = a.length) > 0 &&
|
if ((a = array) == null || (cap = a.length) <= 0 ||
|
||||||
a[k = (cap - 1) & (s - 1)] == task && tryLock()) {
|
a[k = (cap - 1) & (s - 1)] != task)
|
||||||
if (top == s && array == a &&
|
break;
|
||||||
(taken = casSlotToNull(a, k, task)))
|
if (tryLock()) {
|
||||||
|
if (top == s && array == a) {
|
||||||
|
if (taken = casSlotToNull(a, k, task)) {
|
||||||
top = s - 1;
|
top = s - 1;
|
||||||
source = 0; // release lock
|
source = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
source = 0; // release lock for retry
|
||||||
|
}
|
||||||
|
Thread.yield(); // trylock failure
|
||||||
}
|
}
|
||||||
return taken;
|
return taken;
|
||||||
}
|
}
|
||||||
|
@ -1194,15 +1213,16 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
top = s;
|
top = s;
|
||||||
source = 0;
|
source = 0;
|
||||||
}
|
}
|
||||||
|
if (taken)
|
||||||
|
t.doExec();
|
||||||
|
else if (!owned)
|
||||||
|
Thread.yield(); // tryLock failure
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if ((f = f.completer) == null)
|
else if ((f = f.completer) == null)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!taken)
|
if (taken && limit != 0 && --limit == 0)
|
||||||
break;
|
|
||||||
t.doExec();
|
|
||||||
if (limit != 0 && --limit == 0)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
|
@ -1586,7 +1606,7 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
* @param w caller's WorkQueue (may be null on failed initialization)
|
* @param w caller's WorkQueue (may be null on failed initialization)
|
||||||
*/
|
*/
|
||||||
final void runWorker(WorkQueue w) {
|
final void runWorker(WorkQueue w) {
|
||||||
if (w != null) { // skip on failed init
|
if (mode >= 0 && w != null) { // skip on failed init
|
||||||
w.config |= SRC; // mark as valid source
|
w.config |= SRC; // mark as valid source
|
||||||
int r = w.stackPred, src = 0; // use seed from registerWorker
|
int r = w.stackPred, src = 0; // use seed from registerWorker
|
||||||
do {
|
do {
|
||||||
|
@ -1710,22 +1730,6 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
|
|
||||||
// Utilities used by ForkJoinTask
|
// Utilities used by ForkJoinTask
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if all workers are busy, possibly creating one if allowed
|
|
||||||
*/
|
|
||||||
final boolean isSaturated() {
|
|
||||||
int maxTotal = bounds >>> SWIDTH;
|
|
||||||
for (long c;;) {
|
|
||||||
if (((int)(c = ctl) & ~UNSIGNALLED) != 0)
|
|
||||||
return false;
|
|
||||||
if ((short)(c >>> TC_SHIFT) >= maxTotal)
|
|
||||||
return true;
|
|
||||||
long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK);
|
|
||||||
if (compareAndSetCtl(c, nc))
|
|
||||||
return !createWorker();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if can start terminating if enabled, or already terminated
|
* Returns true if can start terminating if enabled, or already terminated
|
||||||
*/
|
*/
|
||||||
|
@ -1765,13 +1769,16 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
*/
|
*/
|
||||||
private int tryCompensate(long c) {
|
private int tryCompensate(long c) {
|
||||||
Predicate<? super ForkJoinPool> sat;
|
Predicate<? super ForkJoinPool> sat;
|
||||||
int b = bounds; // counts are signed; centered at parallelism level == 0
|
int md = mode, b = bounds;
|
||||||
|
// counts are signed; centered at parallelism level == 0
|
||||||
int minActive = (short)(b & SMASK),
|
int minActive = (short)(b & SMASK),
|
||||||
maxTotal = b >>> SWIDTH,
|
maxTotal = b >>> SWIDTH,
|
||||||
active = (int)(c >> RC_SHIFT),
|
active = (int)(c >> RC_SHIFT),
|
||||||
total = (short)(c >>> TC_SHIFT),
|
total = (short)(c >>> TC_SHIFT),
|
||||||
sp = (int)c & ~UNSIGNALLED;
|
sp = (int)c & ~UNSIGNALLED;
|
||||||
if (total >= 0) {
|
if ((md & SMASK) == 0)
|
||||||
|
return 0; // cannot compensate if parallelism zero
|
||||||
|
else if (total >= 0) {
|
||||||
if (sp != 0) { // activate idle worker
|
if (sp != 0) { // activate idle worker
|
||||||
WorkQueue[] qs; int n; WorkQueue v;
|
WorkQueue[] qs; int n; WorkQueue v;
|
||||||
if ((qs = queues) != null && (n = qs.length) > 0 &&
|
if ((qs = queues) != null && (n = qs.length) > 0 &&
|
||||||
|
@ -1819,9 +1826,10 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
*
|
*
|
||||||
* @param task the task
|
* @param task the task
|
||||||
* @param w caller's WorkQueue
|
* @param w caller's WorkQueue
|
||||||
|
* @param canHelp if false, compensate only
|
||||||
* @return task status on exit, or UNCOMPENSATE for compensated blocking
|
* @return task status on exit, or UNCOMPENSATE for compensated blocking
|
||||||
*/
|
*/
|
||||||
final int helpJoin(ForkJoinTask<?> task, WorkQueue w) {
|
final int helpJoin(ForkJoinTask<?> task, WorkQueue w, boolean canHelp) {
|
||||||
int s = 0;
|
int s = 0;
|
||||||
if (task != null && w != null) {
|
if (task != null && w != null) {
|
||||||
int wsrc = w.source, wid = w.config & SMASK, r = wid + 2;
|
int wsrc = w.source, wid = w.config & SMASK, r = wid + 2;
|
||||||
|
@ -1836,7 +1844,7 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
else if (c == (c = ctl) && (s = tryCompensate(c)) >= 0)
|
else if (c == (c = ctl) && (s = tryCompensate(c)) >= 0)
|
||||||
break; // block
|
break; // block
|
||||||
}
|
}
|
||||||
else { // scan for subtasks
|
else if (canHelp) { // scan for subtasks
|
||||||
WorkQueue[] qs = queues;
|
WorkQueue[] qs = queues;
|
||||||
int n = (qs == null) ? 0 : qs.length, m = n - 1;
|
int n = (qs == null) ? 0 : qs.length, m = n - 1;
|
||||||
for (int i = n; i > 0; i -= 2, r += 2) {
|
for (int i = n; i > 0; i -= 2, r += 2) {
|
||||||
|
@ -2194,6 +2202,16 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
qs[(n - 1) & (r << 1)] : null;
|
qs[(n - 1) & (r << 1)] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns queue for an external thread, if one exists
|
||||||
|
*/
|
||||||
|
final WorkQueue externalQueue() {
|
||||||
|
WorkQueue[] qs;
|
||||||
|
int r = ThreadLocalRandom.getProbe(), n;
|
||||||
|
return ((qs = queues) != null && (n = qs.length) > 0 && r != 0) ?
|
||||||
|
qs[(n - 1) & (r << 1)] : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the given executor is a ForkJoinPool, poll and execute
|
* If the given executor is a ForkJoinPool, poll and execute
|
||||||
* AsynchronousCompletionTasks from worker's queue until none are
|
* AsynchronousCompletionTasks from worker's queue until none are
|
||||||
|
@ -2205,8 +2223,8 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
if ((wt = (ForkJoinWorkerThread)t).pool == e)
|
if ((wt = (ForkJoinWorkerThread)t).pool == e)
|
||||||
w = wt.workQueue;
|
w = wt.workQueue;
|
||||||
}
|
}
|
||||||
else if (e == common)
|
else if (e instanceof ForkJoinPool)
|
||||||
w = commonQueue();
|
w = ((ForkJoinPool)e).externalQueue();
|
||||||
if (w != null)
|
if (w != null)
|
||||||
w.helpAsyncBlocker(blocker);
|
w.helpAsyncBlocker(blocker);
|
||||||
}
|
}
|
||||||
|
@ -2292,14 +2310,18 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
return false;
|
return false;
|
||||||
md = getAndBitwiseOrMode(STOP);
|
md = getAndBitwiseOrMode(STOP);
|
||||||
}
|
}
|
||||||
for (int k = 0; k < 2; ++k) { // twice in case of lagging qs updates
|
for (boolean rescan = true;;) { // repeat until no changes
|
||||||
for (ForkJoinTask<?> t; (t = pollScan(false)) != null; )
|
boolean changed = false;
|
||||||
|
for (ForkJoinTask<?> t; (t = pollScan(false)) != null; ) {
|
||||||
|
changed = true;
|
||||||
ForkJoinTask.cancelIgnoringExceptions(t); // help cancel
|
ForkJoinTask.cancelIgnoringExceptions(t); // help cancel
|
||||||
|
}
|
||||||
WorkQueue[] qs; int n; WorkQueue q; Thread thread;
|
WorkQueue[] qs; int n; WorkQueue q; Thread thread;
|
||||||
if ((qs = queues) != null && (n = qs.length) > 0) {
|
if ((qs = queues) != null && (n = qs.length) > 0) {
|
||||||
for (int j = 1; j < n; j += 2) { // unblock other workers
|
for (int j = 1; j < n; j += 2) { // unblock other workers
|
||||||
if ((q = qs[j]) != null && (thread = q.owner) != null &&
|
if ((q = qs[j]) != null && (thread = q.owner) != null &&
|
||||||
!thread.isInterrupted()) {
|
!thread.isInterrupted()) {
|
||||||
|
changed = true;
|
||||||
try {
|
try {
|
||||||
thread.interrupt();
|
thread.interrupt();
|
||||||
} catch (Throwable ignore) {
|
} catch (Throwable ignore) {
|
||||||
|
@ -2317,6 +2339,12 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
cond.signalAll();
|
cond.signalAll();
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
if (changed)
|
||||||
|
rescan = true;
|
||||||
|
else if (rescan)
|
||||||
|
rescan = false;
|
||||||
|
else
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2539,17 +2567,23 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
parallelism = Integer.parseInt(pp);
|
parallelism = Integer.parseInt(pp);
|
||||||
} catch (Exception ignore) {
|
} catch (Exception ignore) {
|
||||||
}
|
}
|
||||||
int p = this.mode = Math.min(Math.max(parallelism, 0), MAX_CAP);
|
|
||||||
int size = 1 << (33 - Integer.numberOfLeadingZeros(p > 0 ? p - 1 : 1));
|
|
||||||
this.factory = (fac != null) ? fac :
|
|
||||||
new DefaultCommonPoolForkJoinWorkerThreadFactory();
|
|
||||||
this.ueh = handler;
|
this.ueh = handler;
|
||||||
this.keepAlive = DEFAULT_KEEPALIVE;
|
this.keepAlive = DEFAULT_KEEPALIVE;
|
||||||
this.saturate = null;
|
this.saturate = null;
|
||||||
this.workerNamePrefix = null;
|
this.workerNamePrefix = null;
|
||||||
|
int p = Math.min(Math.max(parallelism, 0), MAX_CAP), size;
|
||||||
|
if (p > 0) {
|
||||||
|
size = 1 << (33 - Integer.numberOfLeadingZeros(p - 1));
|
||||||
this.bounds = ((1 - p) & SMASK) | (COMMON_MAX_SPARES << SWIDTH);
|
this.bounds = ((1 - p) & SMASK) | (COMMON_MAX_SPARES << SWIDTH);
|
||||||
this.ctl = ((((long)(-p) << TC_SHIFT) & TC_MASK) |
|
this.ctl = ((((long)(-p) << TC_SHIFT) & TC_MASK) |
|
||||||
(((long)(-p) << RC_SHIFT) & RC_MASK));
|
(((long)(-p) << RC_SHIFT) & RC_MASK));
|
||||||
|
} else { // zero min, max, spare counts, 1 slot
|
||||||
|
size = 1;
|
||||||
|
this.bounds = 0;
|
||||||
|
this.ctl = 0L;
|
||||||
|
}
|
||||||
|
this.factory = (fac != null) ? fac :
|
||||||
|
new DefaultCommonPoolForkJoinWorkerThreadFactory();
|
||||||
this.queues = new WorkQueue[size];
|
this.queues = new WorkQueue[size];
|
||||||
this.registrationLock = new ReentrantLock();
|
this.registrationLock = new ReentrantLock();
|
||||||
}
|
}
|
||||||
|
@ -2593,7 +2627,7 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
*/
|
*/
|
||||||
public <T> T invoke(ForkJoinTask<T> task) {
|
public <T> T invoke(ForkJoinTask<T> task) {
|
||||||
externalSubmit(task);
|
externalSubmit(task);
|
||||||
return task.join();
|
return task.joinForPoolInvoke(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2685,7 +2719,7 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
externalSubmit(f);
|
externalSubmit(f);
|
||||||
}
|
}
|
||||||
for (int i = futures.size() - 1; i >= 0; --i)
|
for (int i = futures.size() - 1; i >= 0; --i)
|
||||||
((ForkJoinTask<?>)futures.get(i)).quietlyJoin();
|
((ForkJoinTask<?>)futures.get(i)).awaitPoolInvoke(this);
|
||||||
return futures;
|
return futures;
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
for (Future<T> e : futures)
|
for (Future<T> e : futures)
|
||||||
|
@ -2715,11 +2749,7 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
if (timedOut)
|
if (timedOut)
|
||||||
ForkJoinTask.cancelIgnoringExceptions(f);
|
ForkJoinTask.cancelIgnoringExceptions(f);
|
||||||
else {
|
else {
|
||||||
try {
|
((ForkJoinTask<T>)f).awaitPoolInvoke(this, ns);
|
||||||
f.get(ns, TimeUnit.NANOSECONDS);
|
|
||||||
} catch (CancellationException | TimeoutException |
|
|
||||||
ExecutionException ok) {
|
|
||||||
}
|
|
||||||
if ((ns = nanos - (System.nanoTime() - startTime)) < 0L)
|
if ((ns = nanos - (System.nanoTime() - startTime)) < 0L)
|
||||||
timedOut = true;
|
timedOut = true;
|
||||||
}
|
}
|
||||||
|
@ -2746,11 +2776,16 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
}
|
}
|
||||||
final void tryComplete(Callable<E> c) { // called by InvokeAnyTasks
|
final void tryComplete(Callable<E> c) { // called by InvokeAnyTasks
|
||||||
Throwable ex = null;
|
Throwable ex = null;
|
||||||
boolean failed = (c == null || isCancelled() ||
|
boolean failed;
|
||||||
(pool != null && pool.mode < 0));
|
if (c == null || Thread.interrupted() ||
|
||||||
if (!failed && !isDone()) {
|
(pool != null && pool.mode < 0))
|
||||||
|
failed = true;
|
||||||
|
else if (isDone())
|
||||||
|
failed = false;
|
||||||
|
else {
|
||||||
try {
|
try {
|
||||||
complete(c.call());
|
complete(c.call());
|
||||||
|
failed = false;
|
||||||
} catch (Throwable tx) {
|
} catch (Throwable tx) {
|
||||||
ex = tx;
|
ex = tx;
|
||||||
failed = true;
|
failed = true;
|
||||||
|
@ -2817,7 +2852,7 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
if (root.isDone())
|
if (root.isDone())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return root.get();
|
return root.getForPoolInvoke(this);
|
||||||
} finally {
|
} finally {
|
||||||
for (InvokeAnyTask<T> f : fs)
|
for (InvokeAnyTask<T> f : fs)
|
||||||
ForkJoinTask.cancelIgnoringExceptions(f);
|
ForkJoinTask.cancelIgnoringExceptions(f);
|
||||||
|
@ -2844,7 +2879,7 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||||
if (root.isDone())
|
if (root.isDone())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return root.get(nanos, TimeUnit.NANOSECONDS);
|
return root.getForPoolInvoke(this, nanos);
|
||||||
} finally {
|
} finally {
|
||||||
for (InvokeAnyTask<T> f : fs)
|
for (InvokeAnyTask<T> f : fs)
|
||||||
ForkJoinTask.cancelIgnoringExceptions(f);
|
ForkJoinTask.cancelIgnoringExceptions(f);
|
||||||
|
|
|
@ -276,7 +276,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
return (int)STATUS.getAndBitwiseOr(this, v);
|
return (int)STATUS.getAndBitwiseOr(this, v);
|
||||||
}
|
}
|
||||||
private boolean casStatus(int c, int v) {
|
private boolean casStatus(int c, int v) {
|
||||||
return STATUS.weakCompareAndSet(this, c, v);
|
return STATUS.compareAndSet(this, c, v);
|
||||||
}
|
}
|
||||||
private boolean casAux(Aux c, Aux v) {
|
private boolean casAux(Aux c, Aux v) {
|
||||||
return AUX.compareAndSet(this, c, v);
|
return AUX.compareAndSet(this, c, v);
|
||||||
|
@ -295,84 +295,6 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Possibly blocks until task is done or interrupted or timed out.
|
|
||||||
*
|
|
||||||
* @param interruptible true if wait can be cancelled by interrupt
|
|
||||||
* @param deadline if non-zero use timed waits and possibly timeout
|
|
||||||
* @param pool if nonnull pool to uncompensate after unblocking
|
|
||||||
* @return status on exit, or ABNORMAL if interrupted while waiting
|
|
||||||
*/
|
|
||||||
private int awaitDone(boolean interruptible, long deadline,
|
|
||||||
ForkJoinPool pool) {
|
|
||||||
int s;
|
|
||||||
boolean interrupted = false, queued = false, parked = false;
|
|
||||||
Aux node = null;
|
|
||||||
while ((s = status) >= 0) {
|
|
||||||
Aux a; long ns;
|
|
||||||
if (parked && Thread.interrupted()) {
|
|
||||||
if (interruptible) {
|
|
||||||
s = ABNORMAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
interrupted = true;
|
|
||||||
}
|
|
||||||
else if (queued) {
|
|
||||||
if (deadline != 0L) {
|
|
||||||
if ((ns = deadline - System.nanoTime()) <= 0L)
|
|
||||||
break;
|
|
||||||
LockSupport.parkNanos(ns);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LockSupport.park();
|
|
||||||
parked = true;
|
|
||||||
}
|
|
||||||
else if (node != null) {
|
|
||||||
if ((a = aux) != null && a.ex != null)
|
|
||||||
Thread.onSpinWait(); // exception in progress
|
|
||||||
else if (queued = casAux(node.next = a, node))
|
|
||||||
LockSupport.setCurrentBlocker(this);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
node = new Aux(Thread.currentThread(), null);
|
|
||||||
} catch (Throwable ex) { // try to cancel if cannot create
|
|
||||||
casStatus(s, s | (DONE | ABNORMAL));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pool != null)
|
|
||||||
pool.uncompensate();
|
|
||||||
|
|
||||||
if (queued) {
|
|
||||||
LockSupport.setCurrentBlocker(null);
|
|
||||||
if (s >= 0) { // cancellation similar to AbstractQueuedSynchronizer
|
|
||||||
outer: for (Aux a; (a = aux) != null && a.ex == null; ) {
|
|
||||||
for (Aux trail = null;;) {
|
|
||||||
Aux next = a.next;
|
|
||||||
if (a == node) {
|
|
||||||
if (trail != null)
|
|
||||||
trail.casNext(trail, next);
|
|
||||||
else if (casAux(a, next))
|
|
||||||
break outer; // cannot be re-encountered
|
|
||||||
break; // restart
|
|
||||||
} else {
|
|
||||||
trail = a;
|
|
||||||
if ((a = next) == null)
|
|
||||||
break outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
signalWaiters(); // help clean or signal
|
|
||||||
if (interrupted)
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets DONE status and wakes up threads waiting to join this task.
|
* Sets DONE status and wakes up threads waiting to join this task.
|
||||||
* @return status on exit
|
* @return status on exit
|
||||||
|
@ -463,27 +385,36 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
* Helps and/or waits for completion from join, get, or invoke;
|
* Helps and/or waits for completion from join, get, or invoke;
|
||||||
* called from either internal or external threads.
|
* called from either internal or external threads.
|
||||||
*
|
*
|
||||||
|
* @param pool if nonnull, known submitted pool, else assumes current pool
|
||||||
* @param ran true if task known to have been exec'd
|
* @param ran true if task known to have been exec'd
|
||||||
* @param interruptible true if park interruptibly when external
|
* @param interruptible true if park interruptibly when external
|
||||||
* @param timed true if use timed wait
|
* @param timed true if use timed wait
|
||||||
* @param nanos if timed, timeout value
|
* @param nanos if timed, timeout value
|
||||||
* @return ABNORMAL if interrupted, else status on exit
|
* @return ABNORMAL if interrupted, else status on exit
|
||||||
*/
|
*/
|
||||||
private int awaitJoin(boolean ran, boolean interruptible, boolean timed,
|
private int awaitDone(ForkJoinPool pool, boolean ran,
|
||||||
|
boolean interruptible, boolean timed,
|
||||||
long nanos) {
|
long nanos) {
|
||||||
boolean internal; ForkJoinPool p; ForkJoinPool.WorkQueue q; int s;
|
ForkJoinPool p; boolean internal; int s; Thread t;
|
||||||
Thread t; ForkJoinWorkerThread wt;
|
ForkJoinPool.WorkQueue q = null;
|
||||||
if (internal = ((t = Thread.currentThread())
|
if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
|
||||||
instanceof ForkJoinWorkerThread)) {
|
ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t;
|
||||||
p = (wt = (ForkJoinWorkerThread)t).pool;
|
p = wt.pool;
|
||||||
|
if (pool == null)
|
||||||
|
pool = p;
|
||||||
|
if (internal = (pool == p))
|
||||||
q = wt.workQueue;
|
q = wt.workQueue;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
internal = false;
|
||||||
p = ForkJoinPool.common;
|
p = ForkJoinPool.common;
|
||||||
q = ForkJoinPool.commonQueue();
|
if (pool == null)
|
||||||
|
pool = p;
|
||||||
|
if (pool == p && p != null)
|
||||||
|
q = p.externalQueue();
|
||||||
|
}
|
||||||
if (interruptible && Thread.interrupted())
|
if (interruptible && Thread.interrupted())
|
||||||
return ABNORMAL;
|
return ABNORMAL;
|
||||||
}
|
|
||||||
if ((s = status) < 0)
|
if ((s = status) < 0)
|
||||||
return s;
|
return s;
|
||||||
long deadline = 0L;
|
long deadline = 0L;
|
||||||
|
@ -493,22 +424,94 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
else if ((deadline = nanos + System.nanoTime()) == 0L)
|
else if ((deadline = nanos + System.nanoTime()) == 0L)
|
||||||
deadline = 1L;
|
deadline = 1L;
|
||||||
}
|
}
|
||||||
ForkJoinPool uncompensate = null;
|
boolean uncompensate = false;
|
||||||
if (q != null && p != null) { // try helping
|
if (q != null && p != null) { // try helping
|
||||||
if ((!timed || p.isSaturated()) &&
|
// help even in timed mode if pool has no parallelism
|
||||||
((this instanceof CountedCompleter) ?
|
boolean canHelp = !timed || (p.mode & SMASK) == 0;
|
||||||
(s = p.helpComplete(this, q, internal)) < 0 :
|
if (canHelp) {
|
||||||
(q.tryRemove(this, internal) && (s = doExec()) < 0)))
|
if ((this instanceof CountedCompleter) &&
|
||||||
|
(s = p.helpComplete(this, q, internal)) < 0)
|
||||||
return s;
|
return s;
|
||||||
|
if (!ran && ((!internal && q.externalTryUnpush(this)) ||
|
||||||
|
q.tryRemove(this, internal)) && (s = doExec()) < 0)
|
||||||
|
return s;
|
||||||
|
}
|
||||||
if (internal) {
|
if (internal) {
|
||||||
if ((s = p.helpJoin(this, q)) < 0)
|
if ((s = p.helpJoin(this, q, canHelp)) < 0)
|
||||||
return s;
|
return s;
|
||||||
if (s == UNCOMPENSATE)
|
if (s == UNCOMPENSATE)
|
||||||
uncompensate = p;
|
uncompensate = true;
|
||||||
interruptible = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return awaitDone(interruptible, deadline, uncompensate);
|
// block until done or cancelled wait
|
||||||
|
boolean interrupted = false, queued = false;
|
||||||
|
boolean parked = false, fail = false;
|
||||||
|
Aux node = null;
|
||||||
|
while ((s = status) >= 0) {
|
||||||
|
Aux a; long ns;
|
||||||
|
if (fail || (fail = (pool != null && pool.mode < 0)))
|
||||||
|
casStatus(s, s | (DONE | ABNORMAL)); // try to cancel
|
||||||
|
else if (parked && Thread.interrupted()) {
|
||||||
|
if (interruptible) {
|
||||||
|
s = ABNORMAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
interrupted = true;
|
||||||
|
}
|
||||||
|
else if (queued) {
|
||||||
|
if (deadline != 0L) {
|
||||||
|
if ((ns = deadline - System.nanoTime()) <= 0L)
|
||||||
|
break;
|
||||||
|
LockSupport.parkNanos(ns);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LockSupport.park();
|
||||||
|
parked = true;
|
||||||
|
}
|
||||||
|
else if (node != null) {
|
||||||
|
if ((a = aux) != null && a.ex != null)
|
||||||
|
Thread.onSpinWait(); // exception in progress
|
||||||
|
else if (queued = casAux(node.next = a, node))
|
||||||
|
LockSupport.setCurrentBlocker(this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
node = new Aux(Thread.currentThread(), null);
|
||||||
|
} catch (Throwable ex) { // cannot create
|
||||||
|
fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pool != null && uncompensate)
|
||||||
|
pool.uncompensate();
|
||||||
|
|
||||||
|
if (queued) {
|
||||||
|
LockSupport.setCurrentBlocker(null);
|
||||||
|
if (s >= 0) { // cancellation similar to AbstractQueuedSynchronizer
|
||||||
|
outer: for (Aux a; (a = aux) != null && a.ex == null; ) {
|
||||||
|
for (Aux trail = null;;) {
|
||||||
|
Aux next = a.next;
|
||||||
|
if (a == node) {
|
||||||
|
if (trail != null)
|
||||||
|
trail.casNext(trail, next);
|
||||||
|
else if (casAux(a, next))
|
||||||
|
break outer; // cannot be re-encountered
|
||||||
|
break; // restart
|
||||||
|
} else {
|
||||||
|
trail = a;
|
||||||
|
if ((a = next) == null)
|
||||||
|
break outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
signalWaiters(); // help clean or signal
|
||||||
|
if (interrupted)
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -664,7 +667,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
public final V join() {
|
public final V join() {
|
||||||
int s;
|
int s;
|
||||||
if ((s = status) >= 0)
|
if ((s = status) >= 0)
|
||||||
s = awaitJoin(false, false, false, 0L);
|
s = awaitDone(null, false, false, false, 0L);
|
||||||
if ((s & ABNORMAL) != 0)
|
if ((s & ABNORMAL) != 0)
|
||||||
reportException(s);
|
reportException(s);
|
||||||
return getRawResult();
|
return getRawResult();
|
||||||
|
@ -681,7 +684,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
public final V invoke() {
|
public final V invoke() {
|
||||||
int s;
|
int s;
|
||||||
if ((s = doExec()) >= 0)
|
if ((s = doExec()) >= 0)
|
||||||
s = awaitJoin(true, false, false, 0L);
|
s = awaitDone(null, true, false, false, 0L);
|
||||||
if ((s & ABNORMAL) != 0)
|
if ((s & ABNORMAL) != 0)
|
||||||
reportException(s);
|
reportException(s);
|
||||||
return getRawResult();
|
return getRawResult();
|
||||||
|
@ -710,12 +713,12 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
throw new NullPointerException();
|
throw new NullPointerException();
|
||||||
t2.fork();
|
t2.fork();
|
||||||
if ((s1 = t1.doExec()) >= 0)
|
if ((s1 = t1.doExec()) >= 0)
|
||||||
s1 = t1.awaitJoin(true, false, false, 0L);
|
s1 = t1.awaitDone(null, true, false, false, 0L);
|
||||||
if ((s1 & ABNORMAL) != 0) {
|
if ((s1 & ABNORMAL) != 0) {
|
||||||
cancelIgnoringExceptions(t2);
|
cancelIgnoringExceptions(t2);
|
||||||
t1.reportException(s1);
|
t1.reportException(s1);
|
||||||
}
|
}
|
||||||
else if (((s2 = t2.awaitJoin(false, false, false, 0L)) & ABNORMAL) != 0)
|
else if (((s2 = t2.awaitDone(null, false, false, false, 0L)) & ABNORMAL) != 0)
|
||||||
t2.reportException(s2);
|
t2.reportException(s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -746,7 +749,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
int s;
|
int s;
|
||||||
if ((s = t.doExec()) >= 0)
|
if ((s = t.doExec()) >= 0)
|
||||||
s = t.awaitJoin(true, false, false, 0L);
|
s = t.awaitDone(null, true, false, false, 0L);
|
||||||
if ((s & ABNORMAL) != 0)
|
if ((s & ABNORMAL) != 0)
|
||||||
ex = t.getException(s);
|
ex = t.getException(s);
|
||||||
break;
|
break;
|
||||||
|
@ -759,7 +762,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
if ((t = tasks[i]) != null) {
|
if ((t = tasks[i]) != null) {
|
||||||
int s;
|
int s;
|
||||||
if ((s = t.status) >= 0)
|
if ((s = t.status) >= 0)
|
||||||
s = t.awaitJoin(false, false, false, 0L);
|
s = t.awaitDone(null, false, false, false, 0L);
|
||||||
if ((s & ABNORMAL) != 0 && (ex = t.getException(s)) != null)
|
if ((s & ABNORMAL) != 0 && (ex = t.getException(s)) != null)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -809,7 +812,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
int s;
|
int s;
|
||||||
if ((s = t.doExec()) >= 0)
|
if ((s = t.doExec()) >= 0)
|
||||||
s = t.awaitJoin(true, false, false, 0L);
|
s = t.awaitDone(null, true, false, false, 0L);
|
||||||
if ((s & ABNORMAL) != 0)
|
if ((s & ABNORMAL) != 0)
|
||||||
ex = t.getException(s);
|
ex = t.getException(s);
|
||||||
break;
|
break;
|
||||||
|
@ -822,7 +825,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
if ((t = ts.get(i)) != null) {
|
if ((t = ts.get(i)) != null) {
|
||||||
int s;
|
int s;
|
||||||
if ((s = t.status) >= 0)
|
if ((s = t.status) >= 0)
|
||||||
s = t.awaitJoin(false, false, false, 0L);
|
s = t.awaitDone(null, false, false, false, 0L);
|
||||||
if ((s & ABNORMAL) != 0 && (ex = t.getException(s)) != null)
|
if ((s & ABNORMAL) != 0 && (ex = t.getException(s)) != null)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -973,8 +976,8 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
* member of a ForkJoinPool and was interrupted while waiting
|
* member of a ForkJoinPool and was interrupted while waiting
|
||||||
*/
|
*/
|
||||||
public final V get() throws InterruptedException, ExecutionException {
|
public final V get() throws InterruptedException, ExecutionException {
|
||||||
int s;
|
int s = awaitDone(null, false, true, false, 0L);
|
||||||
if (((s = awaitJoin(false, true, false, 0L)) & ABNORMAL) != 0)
|
if ((s & ABNORMAL) != 0)
|
||||||
reportExecutionException(s);
|
reportExecutionException(s);
|
||||||
return getRawResult();
|
return getRawResult();
|
||||||
}
|
}
|
||||||
|
@ -995,9 +998,9 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
*/
|
*/
|
||||||
public final V get(long timeout, TimeUnit unit)
|
public final V get(long timeout, TimeUnit unit)
|
||||||
throws InterruptedException, ExecutionException, TimeoutException {
|
throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
int s;
|
long nanos = unit.toNanos(timeout);
|
||||||
if ((s = awaitJoin(false, true, true, unit.toNanos(timeout))) >= 0 ||
|
int s = awaitDone(null, false, true, true, nanos);
|
||||||
(s & ABNORMAL) != 0)
|
if (s >= 0 || (s & ABNORMAL) != 0)
|
||||||
reportExecutionException(s);
|
reportExecutionException(s);
|
||||||
return getRawResult();
|
return getRawResult();
|
||||||
}
|
}
|
||||||
|
@ -1010,9 +1013,10 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
*/
|
*/
|
||||||
public final void quietlyJoin() {
|
public final void quietlyJoin() {
|
||||||
if (status >= 0)
|
if (status >= 0)
|
||||||
awaitJoin(false, false, false, 0L);
|
awaitDone(null, false, false, false, 0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commences performing this task and awaits its completion if
|
* Commences performing this task and awaits its completion if
|
||||||
* necessary, without returning its result or throwing its
|
* necessary, without returning its result or throwing its
|
||||||
|
@ -1020,7 +1024,37 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||||
*/
|
*/
|
||||||
public final void quietlyInvoke() {
|
public final void quietlyInvoke() {
|
||||||
if (doExec() >= 0)
|
if (doExec() >= 0)
|
||||||
awaitJoin(true, false, false, 0L);
|
awaitDone(null, true, false, false, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Versions of join/get for pool.invoke* methods that use external,
|
||||||
|
// possibly-non-commonPool submits
|
||||||
|
|
||||||
|
final void awaitPoolInvoke(ForkJoinPool pool) {
|
||||||
|
awaitDone(pool, false, false, false, 0L);
|
||||||
|
}
|
||||||
|
final void awaitPoolInvoke(ForkJoinPool pool, long nanos) {
|
||||||
|
awaitDone(pool, false, true, true, nanos);
|
||||||
|
}
|
||||||
|
final V joinForPoolInvoke(ForkJoinPool pool) {
|
||||||
|
int s = awaitDone(pool, false, false, false, 0L);
|
||||||
|
if ((s & ABNORMAL) != 0)
|
||||||
|
reportException(s);
|
||||||
|
return getRawResult();
|
||||||
|
}
|
||||||
|
final V getForPoolInvoke(ForkJoinPool pool)
|
||||||
|
throws InterruptedException, ExecutionException {
|
||||||
|
int s = awaitDone(pool, false, true, false, 0L);
|
||||||
|
if ((s & ABNORMAL) != 0)
|
||||||
|
reportExecutionException(s);
|
||||||
|
return getRawResult();
|
||||||
|
}
|
||||||
|
final V getForPoolInvoke(ForkJoinPool pool, long nanos)
|
||||||
|
throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
|
int s = awaitDone(pool, false, true, true, nanos);
|
||||||
|
if (s >= 0 || (s & ABNORMAL) != 0)
|
||||||
|
reportExecutionException(s);
|
||||||
|
return getRawResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue