diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index 5bd677cac64..94fdd3e0216 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -1249,16 +1249,16 @@ public class ForkJoinPool extends AbstractExecutorService */ final void push(ForkJoinTask task, ForkJoinPool pool, int unlock) { ForkJoinTask[] a = array; - int b = base, s = top, m; + int b = base, s = top, room, m; if (a != null && - (a.length > s + 1 - b || (a = growArray()) != null) && + ((room = a.length - (s + 1 - b)) > 0 || (a = growArray()) != null) && (m = a.length - 1) >= 0) { // else rejected or disabled top = s + 1; U.putReferenceVolatile(a, slotOffset(m & s), task); if (unlock != 1) // release external lock - U.putInt(this, PHASE, unlock); - if (U.getReferenceAcquire(a, slotOffset(m & (s - 1))) == null && - pool != null) + phase = unlock; + if ((U.getReferenceAcquire(a, slotOffset(m & (s - 1))) == null || + room <= 0) && pool != null) pool.signalWork(this, s); // may have appeared empty } } @@ -1307,13 +1307,16 @@ public class ForkJoinPool extends AbstractExecutorService if (a != null && s - b >= 0 && (cap = a.length) > 0) { if (fifo == 0) { if ((t = (ForkJoinTask)U.getAndSetReference( - a, slotOffset((cap - 1) & s), null)) != null) + a, slotOffset((cap - 1) & s), null)) != null) { top = s; + U.storeFence(); + } } else { do { if ((t = (ForkJoinTask)U.getAndSetReference( a, slotOffset((cap - 1) & b), null)) != null) { base = b + 1; + U.storeFence(); break; } if (b == s) @@ -1330,10 +1333,7 @@ public class ForkJoinPool extends AbstractExecutorService * Takes next task, if one exists, using configured mode. */ final ForkJoinTask nextLocalTask() { - U.loadFence(); // ensure ordering for external callers - ForkJoinTask t= nextLocalTask(config & FIFO); - U.storeFence(); - return t; + return nextLocalTask(config & FIFO); } /** @@ -1350,10 +1350,11 @@ public class ForkJoinPool extends AbstractExecutorService (internal || (lock = tryLockPhase()) != 1)) { if (top == p && U.compareAndSetReference(a, k, task, null)) { taken = true; - U.putIntOpaque(this, TOP, s); + top = s; + U.storeFence(); } if (!internal) - U.putIntRelease(this, PHASE, lock + NEXTIDLE); + phase = lock + NEXTIDLE; } return taken; } @@ -1413,6 +1414,7 @@ public class ForkJoinPool extends AbstractExecutorService /** * Runs the given task, as well as remaining local tasks */ + // @jdk.internal.vm.annotation.DontInline final void topLevelExec(ForkJoinTask task, int fifo) { while (task != null) { task.doExec(); @@ -1452,9 +1454,10 @@ public class ForkJoinPool extends AbstractExecutorService a, slotOffset(s & m), null)); top = s; } + U.storeFence(); } if (!internal) - U.putIntRelease(this, PHASE, lock + NEXTIDLE); + phase = lock + NEXTIDLE; if (taken) task.doExec(); break; @@ -1498,10 +1501,12 @@ public class ForkJoinPool extends AbstractExecutorService break; if (taken = (top == p && - U.compareAndSetReference(a, k, t, null))) + U.compareAndSetReference(a, k, t, null))) { top = s; + U.storeFence(); + } if (!internal) - U.putIntRelease(this, PHASE, lock + NEXTIDLE); + phase = lock + NEXTIDLE; if (!taken) break; t.doExec(); @@ -1537,6 +1542,7 @@ public class ForkJoinPool extends AbstractExecutorService if (base == b && t != null && U.compareAndSetReference(a, k, t, null)) { base = b + 1; + U.storeFence(); t.doExec(); } } @@ -2015,16 +2021,23 @@ public class ForkJoinPool extends AbstractExecutorService } long sp = (phase + NEXTIDLE) & LMASK, pc = ctl; U.putInt(w, WorkQueue.PHASE, phase | IDLE); - for (long c;;) { // try to enqueue + for (;;) { // try to enqueue + long c, e; w.stackPred = (int)pc; if (pc == (pc = U.compareAndExchangeLong( this, CTL, pc, c = ((pc - RC_UNIT) & UMASK) | sp))) { idle = IDLE; - if ((c & RC_MASK) == 0L) - quiescent(); // check quiescent termination + if (((e = runState) & STOP) == 0L && + ((e & SHUTDOWN) == 0L || (c & RC_MASK) > 0L || + quiescent() <= 0)) { // spin for approx 1 scan cost + int tc = (short)(c >>> TC_SHIFT); + int spins = Math.max((tc << 1) + tc, SPIN_WAITS); + while ((idle = w.phase & IDLE) != 0 && --spins != 0) + Thread.onSpinWait(); + } break; } - else if ((c & RC_MASK) <= (pc & RC_MASK)) { + else if ((c & RC_MASK) < (pc & RC_MASK)) { w.phase = phase; // back out if lost to signal break; }