--- jsr166/src/jsr166e/ForkJoinPool.java 2012/12/18 21:46:09 1.36 +++ jsr166/src/jsr166e/ForkJoinPool.java 2013/02/16 20:50:29 1.57 @@ -440,7 +440,7 @@ public class ForkJoinPool extends Abstra * Common Pool * =========== * - * The static commonPool always exists after static + * The static common Pool always exists after static * initialization. Since it (or any other created pool) need * never be used, we minimize initial construction overhead and * footprint to the setup of about a dozen fields, with no nested @@ -708,7 +708,7 @@ public class ForkJoinPool extends Abstra * shared-queue version is embedded in method externalPush.) * * @param task the task. Caller must ensure non-null. - * @throw RejectedExecutionException if array cannot be resized + * @throws RejectedExecutionException if array cannot be resized */ final void push(ForkJoinTask task) { ForkJoinTask[] a; ForkJoinPool p; @@ -907,7 +907,7 @@ public class ForkJoinPool extends Abstra * or any other cancelled task. Returns (true) on any CAS * or consistency check failure so caller can retry. * - * @return false if no progress can be made, else true; + * @return false if no progress can be made, else true */ final boolean tryRemoveAndExec(ForkJoinTask task) { boolean stat = true, removed = false, empty = true; @@ -952,7 +952,7 @@ public class ForkJoinPool extends Abstra /** * Polls for and executes the given task or any other task in - * its CountedCompleter computation + * its CountedCompleter computation. */ final boolean pollAndExecCC(ForkJoinTask root) { ForkJoinTask[] a; int b; Object o; @@ -1026,7 +1026,6 @@ public class ForkJoinPool extends Abstra private static final int ABASE; private static final int ASHIFT; static { - int s; try { U = getUnsafe(); Class k = WorkQueue.class; @@ -1034,13 +1033,13 @@ public class ForkJoinPool extends Abstra QLOCK = U.objectFieldOffset (k.getDeclaredField("qlock")); ABASE = U.arrayBaseOffset(ak); - s = U.arrayIndexScale(ak); + int scale = U.arrayIndexScale(ak); + if ((scale & (scale - 1)) != 0) + throw new Error("data type scale not a power of two"); + ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); } catch (Exception e) { throw new Error(e); } - if ((s & (s-1)) != 0) - throw new Error("data type scale not a power of two"); - ASHIFT = 31 - Integer.numberOfLeadingZeros(s); } } @@ -1074,12 +1073,12 @@ public class ForkJoinPool extends Abstra * to paranoically avoid potential initialization circularities * as well as to simplify generated code. */ - static final ForkJoinPool commonPool; + static final ForkJoinPool common; /** - * Common pool parallelism. Must equal commonPool.parallelism. + * Common pool parallelism. Must equal common.parallelism. */ - static final int commonPoolParallelism; + static final int commonParallelism; /** * Sequence number for creating workerNamePrefix. @@ -1087,8 +1086,8 @@ public class ForkJoinPool extends Abstra private static int poolNumberSequence; /** - * Return the next sequence number. We don't expect this to - * ever contend so use simple builtin sync. + * Returns the next sequence number. We don't expect this to + * ever contend, so use simple builtin sync. */ private static final synchronized int nextPoolId() { return ++poolNumberSequence; @@ -1132,7 +1131,7 @@ public class ForkJoinPool extends Abstra */ private static final int SEED_INCREMENT = 0x61c88647; - /** + /* * Bits and masks for control variables * * Field ctl is a long packed with: @@ -1245,10 +1244,10 @@ public class ForkJoinPool extends Abstra volatile Object pad10, pad11, pad12, pad13, pad14, pad15, pad16, pad17; volatile Object pad18, pad19, pad1a, pad1b; - /* + /** * Acquires the plock lock to protect worker array and related * updates. This method is called only if an initial CAS on plock - * fails. This acts as a spinLock for normal cases, but falls back + * fails. This acts as a spinlock for normal cases, but falls back * to builtin monitor to block when (rarely) needed. This would be * a terrible idea for a highly contended lock, but works fine as * a more conservative alternative to a pure spinlock. @@ -1303,39 +1302,6 @@ public class ForkJoinPool extends Abstra } /** - * Performs secondary initialization, called when plock is zero. - * Creates workQueue array and sets plock to a valid value. The - * lock body must be exception-free (so no try/finally) so we - * optimistically allocate new array outside the lock and throw - * away if (very rarely) not needed. (A similar tactic is used in - * fullExternalPush.) Because the plock seq value can eventually - * wrap around zero, this method harmlessly fails to reinitialize - * if workQueues exists, while still advancing plock. - * - * Additionally tries to create the first worker. - */ - private void initWorkers() { - WorkQueue[] ws, nws; int ps; - int p = config & SMASK; // find power of two table size - int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots - n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; - n = (n + 1) << 1; - if ((ws = workQueues) == null || ws.length == 0) - nws = new WorkQueue[n]; - else - nws = null; - if (((ps = plock) & PL_LOCK) != 0 || - !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) - ps = acquirePlock(); - if (((ws = workQueues) == null || ws.length == 0) && nws != null) - workQueues = nws; - int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); - if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) - releasePlock(nps); - tryAddWorker(); - } - - /** * Tries to create and start one worker if fewer than target * parallelism level exist. Adjusts counts etc on failure. */ @@ -1520,13 +1486,19 @@ public class ForkJoinPool extends Abstra /** * Full version of externalPush. This method is called, among * other times, upon the first submission of the first task to the - * pool, so must perform secondary initialization (via - * initWorkers). It also detects first submission by an external - * thread by looking up its ThreadLocal, and creates a new shared - * queue if the one at index if empty or contended. The plock lock - * body must be exception-free (so no try/finally) so we - * optimistically allocate new queues outside the lock and throw - * them away if (very rarely) not needed. + * pool, so must perform secondary initialization. It also + * detects first submission by an external thread by looking up + * its ThreadLocal, and creates a new shared queue if the one at + * index if empty or contended. The plock lock body must be + * exception-free (so no try/finally) so we optimistically + * allocate new queues outside the lock and throw them away if + * (very rarely) not needed. + * + * Secondary initialization occurs when plock is zero, to create + * workQueue array and set plock to a valid value. This lock body + * must also be exception-free. Because the plock seq value can + * eventually wrap around zero, this method harmlessly fails to + * reinitialize if workQueues exists, while still advancing plock. */ private void fullExternalPush(ForkJoinTask task) { int r = 0; // random index seed @@ -1537,17 +1509,31 @@ public class ForkJoinPool extends Abstra r += SEED_INCREMENT) && r != 0) submitters.set(z = new Submitter(r)); } - else if (r == 0) { // move to a different index + else if (r == 0) { // move to a different index r = z.seed; - r ^= r << 13; // same xorshift as WorkQueues + r ^= r << 13; // same xorshift as WorkQueues r ^= r >>> 17; z.seed = r ^ (r << 5); } else if ((ps = plock) < 0) throw new RejectedExecutionException(); else if (ps == 0 || (ws = workQueues) == null || - (m = ws.length - 1) < 0) - initWorkers(); + (m = ws.length - 1) < 0) { // initialize workQueues + int p = config & SMASK; // find power of two table size + int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots + n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; + n |= n >>> 8; n |= n >>> 16; n = (n + 1) << 1; + WorkQueue[] nws = ((ws = workQueues) == null || ws.length == 0 ? + new WorkQueue[n] : null); + if (((ps = plock) & PL_LOCK) != 0 || + !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) + ps = acquirePlock(); + if (((ws = workQueues) == null || ws.length == 0) && nws != null) + workQueues = nws; + int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); + if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) + releasePlock(nps); + } else if ((q = ws[k = r & m & SQMASK]) != null) { if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1)) { ForkJoinTask[] a = q.array; @@ -1674,7 +1660,7 @@ public class ForkJoinPool extends Abstra * park awaiting signal, else lingering to help scan and signal. * * * If a non-empty queue discovered or left as a hint, - * help wake up other workers before return + * help wake up other workers before return. * * @param w the worker (via its WorkQueue) * @return a task or null if none found @@ -1729,14 +1715,13 @@ public class ForkJoinPool extends Abstra else if ((int)(c >> AC_SHIFT) == 1 - (config & SMASK)) idleAwaitWork(w, nc, c); } - else if (w.eventCount < 0 && !tryTerminate(false, false) && - ctl == c) { // block + else if (w.eventCount < 0 && ctl == c) { Thread wt = Thread.currentThread(); Thread.interrupted(); // clear status U.putObject(wt, PARKBLOCKER, this); w.parker = wt; // emulate LockSupport.park if (w.eventCount < 0) // recheck - U.park(false, 0L); + U.park(false, 0L); // block w.parker = null; U.putObject(wt, PARKBLOCKER, null); } @@ -1745,7 +1730,7 @@ public class ForkJoinPool extends Abstra (ws = workQueues) != null && h < ws.length && (q = ws[h]) != null) { // signal others before retry WorkQueue v; Thread p; int u, i, s; - for (int n = (config & SMASK) >>> 1;;) { + for (int n = (config & SMASK) - 1;;) { int idleCount = (w.eventCount < 0) ? 0 : -1; if (((s = idleCount - q.base + q.top) <= n && (n = s) <= 0) || @@ -1785,7 +1770,8 @@ public class ForkJoinPool extends Abstra */ private void idleAwaitWork(WorkQueue w, long currentCtl, long prevCtl) { if (w != null && w.eventCount < 0 && - !tryTerminate(false, false) && (int)prevCtl != 0) { + !tryTerminate(false, false) && (int)prevCtl != 0 && + ctl == currentCtl) { int dc = -(short)(currentCtl >>> TC_SHIFT); long parkTime = dc < 0 ? FAST_IDLE_TIMEOUT: (dc + 1) * IDLE_TIMEOUT; long deadline = System.nanoTime() + parkTime - TIMEOUT_SLOP; @@ -1803,6 +1789,7 @@ public class ForkJoinPool extends Abstra if (deadline - System.nanoTime() <= 0L && U.compareAndSwapLong(this, CTL, currentCtl, prevCtl)) { w.eventCount = (w.eventCount + E_SEQ) | E_MASK; + w.hint = -1; w.qlock = -1; // shrink break; } @@ -1944,7 +1931,6 @@ public class ForkJoinPool extends Abstra * @param task the task to join * @param mode if shared, exit upon completing any task * if all workers are active - * */ private int helpComplete(ForkJoinTask task, int mode) { WorkQueue[] ws; WorkQueue q; int m, n, s, u; @@ -2096,26 +2082,22 @@ public class ForkJoinPool extends Abstra /** * Returns a (probably) non-empty steal queue, if one is found - * during a random, then cyclic scan, else null. This method must - * be retried by caller if, by the time it tries to use the queue, - * it is empty. + * during a scan, else null. This method must be retried by + * caller if, by the time it tries to use the queue, it is empty. * @param r a (random) seed for scanning */ private WorkQueue findNonEmptyStealQueue(int r) { - for (WorkQueue[] ws;;) { - int ps = plock, m; - if ((ws = workQueues) == null || (m = ws.length - 1) < 1) - return null; - for (int j = (m + 1) << 2; ;) { - WorkQueue q = ws[(((r + j) << 1) | 1) & m]; - if (q != null && q.base - q.top < 0) - return q; - else if (--j < 0) { - if (plock == ps) - return null; - break; + for (;;) { + int ps = plock, m; WorkQueue[] ws; WorkQueue q; + if ((ws = workQueues) != null && (m = ws.length - 1) >= 0) { + for (int j = (m + 1) << 2; j >= 0; --j) { + if ((q = ws[(((r + j) << 1) | 1) & m]) != null && + q.base - q.top < 0) + return q; } } + if (plock == ps) + return null; } } @@ -2127,15 +2109,14 @@ public class ForkJoinPool extends Abstra */ final void helpQuiescePool(WorkQueue w) { for (boolean active = true;;) { - ForkJoinTask localTask; // exhaust local queue - while ((localTask = w.nextLocalTask()) != null) - localTask.doExec(); - // Similar to loop in scan(), but ignoring submissions - WorkQueue q = findNonEmptyStealQueue(w.nextSeed()); - if (q != null) { - ForkJoinTask t; int b; + long c; WorkQueue q; ForkJoinTask t; int b; + while ((t = w.nextLocalTask()) != null) { + if (w.base - w.top < 0) + signalWork(w); + t.doExec(); + } + if ((q = findNonEmptyStealQueue(w.nextSeed())) != null) { if (!active) { // re-establish active count - long c; active = true; do {} while (!U.compareAndSwapLong (this, CTL, c = ctl, c + AC_UNIT)); @@ -2146,21 +2127,16 @@ public class ForkJoinPool extends Abstra w.runSubtask(t); } } - else { - long c; - if (active) { // decrement active count without queuing + else if (active) { // decrement active count without queuing + long nc = (c = ctl) - AC_UNIT; + if ((int)(nc >> AC_SHIFT) + (config & SMASK) == 0) + return; // bypass decrement-then-increment + if (U.compareAndSwapLong(this, CTL, c, nc)) active = false; - do {} while (!U.compareAndSwapLong - (this, CTL, c = ctl, c -= AC_UNIT)); - } - else - c = ctl; // re-increment on exit - if ((int)(c >> AC_SHIFT) + (config & SMASK) == 0) { - do {} while (!U.compareAndSwapLong - (this, CTL, c = ctl, c + AC_UNIT)); - break; - } } + else if ((int)((c = ctl) >> AC_SHIFT) + (config & SMASK) == 0 && + U.compareAndSwapLong(this, CTL, c, c + AC_UNIT)) + return; } } @@ -2209,7 +2185,7 @@ public class ForkJoinPool extends Abstra * producing extra tasks amortizes the uncertainty of progress and * diffusion assumptions. * - * So, users will want to use values larger, but not much larger + * So, users will want to use values larger (but not much larger) * than 1 to both smooth over transient shortages and hedge * against uneven progress; as traded off against the cost of * extra task overhead. We leave the user to pick a threshold @@ -2262,45 +2238,49 @@ public class ForkJoinPool extends Abstra * @return true if now terminating or terminated */ private boolean tryTerminate(boolean now, boolean enable) { - if (this == commonPool) // cannot shut down + int ps; + if (this == common) // cannot shut down return false; + if ((ps = plock) >= 0) { // enable by setting plock + if (!enable) + return false; + if ((ps & PL_LOCK) != 0 || + !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) + ps = acquirePlock(); + int nps = ((ps + PL_LOCK) & ~SHUTDOWN) | SHUTDOWN; + if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) + releasePlock(nps); + } for (long c;;) { - if (((c = ctl) & STOP_BIT) != 0) { // already terminating + if (((c = ctl) & STOP_BIT) != 0) { // already terminating if ((short)(c >>> TC_SHIFT) == -(config & SMASK)) { synchronized (this) { - notifyAll(); // signal when 0 workers + notifyAll(); // signal when 0 workers } } return true; } - if (plock >= 0) { // not yet enabled - int ps; - if (!enable) + if (!now) { // check if idle & no tasks + WorkQueue[] ws; WorkQueue w; + if ((int)(c >> AC_SHIFT) != -(config & SMASK)) return false; - if (((ps = plock) & PL_LOCK) != 0 || - !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) - ps = acquirePlock(); - if (!U.compareAndSwapInt(this, PLOCK, ps, SHUTDOWN)) - releasePlock(SHUTDOWN); - } - if (!now) { // check if idle & no tasks - if ((int)(c >> AC_SHIFT) != -(config & SMASK) || - hasQueuedSubmissions()) - return false; - // Check for unqueued inactive workers. One pass suffices. - WorkQueue[] ws = workQueues; WorkQueue w; - if (ws != null) { - for (int i = 1; i < ws.length; i += 2) { - if ((w = ws[i]) != null && w.eventCount >= 0) - return false; + if ((ws = workQueues) != null) { + for (int i = 0; i < ws.length; ++i) { + if ((w = ws[i]) != null) { + if (!w.isEmpty()) { // signal unprocessed tasks + signalWork(w); + return false; + } + if ((i & 1) != 0 && w.eventCount >= 0) + return false; // unqueued inactive worker + } } } } if (U.compareAndSwapLong(this, CTL, c, c | STOP_BIT)) { for (int pass = 0; pass < 3; ++pass) { - WorkQueue[] ws = workQueues; - if (ws != null) { - WorkQueue w; Thread wt; + WorkQueue[] ws; WorkQueue w; Thread wt; + if ((ws = workQueues) != null) { int n = ws.length; for (int i = 0; i < n; ++i) { if ((w = ws[i]) != null) { @@ -2311,7 +2291,7 @@ public class ForkJoinPool extends Abstra if (!wt.isInterrupted()) { try { wt.interrupt(); - } catch (SecurityException ignore) { + } catch (Throwable ignore) { } } U.unpark(wt); @@ -2322,7 +2302,7 @@ public class ForkJoinPool extends Abstra // Wake up workers parked on event queue int i, e; long cc; Thread p; while ((e = (int)(cc = ctl) & E_MASK) != 0 && - (i = e & SMASK) < n && + (i = e & SMASK) < n && i >= 0 && (w = ws[i]) != null) { long nc = ((long)(w.nextWait & E_MASK) | ((cc + AC_UNIT) & AC_MASK) | @@ -2350,7 +2330,7 @@ public class ForkJoinPool extends Abstra static WorkQueue commonSubmitterQueue() { ForkJoinPool p; WorkQueue[] ws; int m; Submitter z; return ((z = submitters.get()) != null && - (p = commonPool) != null && + (p = common) != null && (ws = p.workQueues) != null && (m = ws.length - 1) >= 0) ? ws[m & z.seed & SQMASK] : null; @@ -2364,7 +2344,7 @@ public class ForkJoinPool extends Abstra ForkJoinTask[] a; int m, s; if (t != null && (z = submitters.get()) != null && - (p = commonPool) != null && + (p = common) != null && (ws = p.workQueues) != null && (m = ws.length - 1) >= 0 && (q = ws[m & z.seed & SQMASK]) != null && @@ -2441,7 +2421,7 @@ public class ForkJoinPool extends Abstra ForkJoinTask[] a; int m, s, n; if (t != null && (z = submitters.get()) != null && - (p = commonPool) != null && + (p = common) != null && (ws = p.workQueues) != null && (m = ws.length - 1) >= 0 && (q = ws[m & z.seed & SQMASK]) != null && @@ -2470,21 +2450,6 @@ public class ForkJoinPool extends Abstra } } - /** - * Restricted version of helpQuiescePool for external callers - */ - static void externalHelpQuiescePool() { - ForkJoinPool p; ForkJoinTask t; WorkQueue q; int b; - if ((p = commonPool) != null && - (q = p.findNonEmptyStealQueue(1)) != null && - (b = q.base) - q.top < 0 && - (t = q.pollAt(b)) != null) { - if (q.base - q.top < 0) - p.signalWork(q); - t.doExec(); - } - } - // Exported methods // Constructors @@ -2501,7 +2466,7 @@ public class ForkJoinPool extends Abstra * java.lang.RuntimePermission}{@code ("modifyThread")} */ public ForkJoinPool() { - this(Runtime.getRuntime().availableProcessors(), + this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()), defaultForkJoinWorkerThreadFactory, null, false); } @@ -2584,14 +2549,20 @@ public class ForkJoinPool extends Abstra /** * Returns the common pool instance. This pool is statically - * constructed; its run state is unaffected by attempts to - * {@link #shutdown} or {@link #shutdownNow}. + * constructed; its run state is unaffected by attempts to {@link + * #shutdown} or {@link #shutdownNow}. However this pool and any + * ongoing processing are automatically terminated upon program + * {@link System#exit}. Any program that relies on asynchronous + * task processing to complete before program termination should + * invoke {@code commonPool().}{@link #awaitQuiescence}, before + * exit. * * @return the common pool instance + * @since 1.8 */ public static ForkJoinPool commonPool() { - // assert commonPool != null : "static init error"; - return commonPool; + // assert common != null : "static init error"; + return common; } // Execution methods @@ -2714,27 +2685,23 @@ public class ForkJoinPool extends Abstra // In previous versions of this class, this method constructed // a task to run ForkJoinTask.invokeAll, but now external // invocation of multiple tasks is at least as efficient. - List> fs = new ArrayList>(tasks.size()); - // Workaround needed because method wasn't declared with - // wildcards in return type but should have been. - @SuppressWarnings({"unchecked", "rawtypes"}) - List> futures = (List>) (List) fs; + ArrayList> futures = new ArrayList>(tasks.size()); boolean done = false; try { for (Callable t : tasks) { ForkJoinTask f = new ForkJoinTask.AdaptedCallable(t); + futures.add(f); externalPush(f); - fs.add(f); } - for (ForkJoinTask f : fs) - f.quietlyJoin(); + for (int i = 0, size = futures.size(); i < size; i++) + ((ForkJoinTask)futures.get(i)).quietlyJoin(); done = true; return futures; } finally { if (!done) - for (ForkJoinTask f : fs) - f.cancel(false); + for (int i = 0, size = futures.size(); i < size; i++) + futures.get(i).cancel(false); } } @@ -2770,9 +2737,10 @@ public class ForkJoinPool extends Abstra * Returns the targeted parallelism level of the common pool. * * @return the targeted parallelism level of the common pool + * @since 1.8 */ public static int getCommonPoolParallelism() { - return commonPoolParallelism; + return commonParallelism; } /** @@ -3030,7 +2998,7 @@ public class ForkJoinPool extends Abstra * Possibly initiates an orderly shutdown in which previously * submitted tasks are executed, but no new tasks will be * accepted. Invocation has no effect on execution state if this - * is the {@link #commonPool}, and no additional effect if + * is the {@link #commonPool()}, and no additional effect if * already shut down. Tasks that are in the process of being * submitted concurrently during the course of this method may or * may not be rejected. @@ -3048,7 +3016,7 @@ public class ForkJoinPool extends Abstra /** * Possibly attempts to cancel and/or stop all tasks, and reject * all subsequently submitted tasks. Invocation has no effect on - * execution state if this is the {@link #commonPool}, and no + * execution state if this is the {@link #commonPool()}, and no * additional effect if already shut down. Otherwise, tasks that * are in the process of being submitted or executed concurrently * during the course of this method may or may not be @@ -3111,9 +3079,10 @@ public class ForkJoinPool extends Abstra /** * Blocks until all tasks have completed execution after a * shutdown request, or the timeout occurs, or the current thread - * is interrupted, whichever happens first. Note that the {@link - * #commonPool()} never terminates until program shutdown so - * this method will always time out. + * is interrupted, whichever happens first. Because the {@link + * #commonPool()} never terminates until program shutdown, when + * applied to the common pool, this method is equivalent to {@link + * #awaitQuiescence} but always returns {@code false}. * * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument @@ -3123,6 +3092,12 @@ public class ForkJoinPool extends Abstra */ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + if (this == common) { + awaitQuiescence(timeout, unit); + return false; + } long nanos = unit.toNanos(timeout); if (isTerminated()) return true; @@ -3142,6 +3117,62 @@ public class ForkJoinPool extends Abstra } /** + * If called by a ForkJoinTask operating in this pool, equivalent + * in effect to {@link ForkJoinTask#helpQuiesce}. Otherwise, + * waits and/or attempts to assist performing tasks until this + * pool {@link #isQuiescent} or the indicated timeout elapses. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return {@code true} if quiescent; {@code false} if the + * timeout elapsed. + */ + public boolean awaitQuiescence(long timeout, TimeUnit unit) { + long nanos = unit.toNanos(timeout); + ForkJoinWorkerThread wt; + Thread thread = Thread.currentThread(); + if ((thread instanceof ForkJoinWorkerThread) && + (wt = (ForkJoinWorkerThread)thread).pool == this) { + helpQuiescePool(wt.workQueue); + return true; + } + long startTime = System.nanoTime(); + WorkQueue[] ws; + int r = 0, m; + boolean found = true; + while (!isQuiescent() && (ws = workQueues) != null && + (m = ws.length - 1) >= 0) { + if (!found) { + if ((System.nanoTime() - startTime) > nanos) + return false; + Thread.yield(); // cannot block + } + found = false; + for (int j = (m + 1) << 2; j >= 0; --j) { + ForkJoinTask t; WorkQueue q; int b; + if ((q = ws[r++ & m]) != null && (b = q.base) - q.top < 0) { + found = true; + if ((t = q.pollAt(b)) != null) { + if (q.base - q.top < 0) + signalWork(q); + t.doExec(); + } + break; + } + } + } + return true; + } + + /** + * Waits and/or attempts to assist performing tasks indefinitely + * until the {@link #commonPool()} {@link #isQuiescent}. + */ + static void quiesceCommonPool() { + common.awaitQuiescence(Long.MAX_VALUE, TimeUnit.NANOSECONDS); + } + + /** * Interface for extending managed parallelism for tasks running * in {@link ForkJoinPool}s. * @@ -3294,7 +3325,7 @@ public class ForkJoinPool extends Abstra private static final long QLOCK; static { - int s; // initialize field offsets for CAS etc + // initialize field offsets for CAS etc try { U = getUnsafe(); Class k = ForkJoinPool.class; @@ -3314,13 +3345,13 @@ public class ForkJoinPool extends Abstra (wk.getDeclaredField("qlock")); Class ak = ForkJoinTask[].class; ABASE = U.arrayBaseOffset(ak); - s = U.arrayIndexScale(ak); - ASHIFT = 31 - Integer.numberOfLeadingZeros(s); + int scale = U.arrayIndexScale(ak); + if ((scale & (scale - 1)) != 0) + throw new Error("data type scale not a power of two"); + ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); } catch (Exception e) { throw new Error(e); } - if ((s & (s-1)) != 0) - throw new Error("data type scale not a power of two"); submitters = new ThreadLocal(); ForkJoinWorkerThreadFactory fac = defaultForkJoinWorkerThreadFactory = @@ -3357,11 +3388,11 @@ public class ForkJoinPool extends Abstra par = Runtime.getRuntime().availableProcessors(); if (par > MAX_CAP) par = MAX_CAP; - commonPoolParallelism = par; + commonParallelism = par; long np = (long)(-par); // precompute initial ctl value long ct = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK); - commonPool = new ForkJoinPool(par, ct, fac, handler); + common = new ForkJoinPool(par, ct, fac, handler); } /** @@ -3374,22 +3405,23 @@ public class ForkJoinPool extends Abstra private static sun.misc.Unsafe getUnsafe() { try { return sun.misc.Unsafe.getUnsafe(); - } catch (SecurityException se) { - try { - return java.security.AccessController.doPrivileged - (new java.security - .PrivilegedExceptionAction() { - public sun.misc.Unsafe run() throws Exception { - java.lang.reflect.Field f = sun.misc - .Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - return (sun.misc.Unsafe) f.get(null); - }}); - } catch (java.security.PrivilegedActionException e) { - throw new RuntimeException("Could not initialize intrinsics", - e.getCause()); - } + } catch (SecurityException tryReflectionInstead) {} + try { + return java.security.AccessController.doPrivileged + (new java.security.PrivilegedExceptionAction() { + public sun.misc.Unsafe run() throws Exception { + Class k = sun.misc.Unsafe.class; + for (java.lang.reflect.Field f : k.getDeclaredFields()) { + f.setAccessible(true); + Object x = f.get(null); + if (k.isInstance(x)) + return k.cast(x); + } + throw new NoSuchFieldError("the Unsafe"); + }}); + } catch (java.security.PrivilegedActionException e) { + throw new RuntimeException("Could not initialize intrinsics", + e.getCause()); } } - }