7035020: ForkJoinPool.invoke may deadlock if parallelism = 1
authordl
Fri, 08 Apr 2011 10:33:14 +0100
changeset 9247 95f4914b7ead
parent 9246 c459f79af46b
child 9248 44d129a2adfa
7035020: ForkJoinPool.invoke may deadlock if parallelism = 1 Reviewed-by: chegar
jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java
--- a/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java	Fri Apr 08 02:00:09 2011 -0700
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java	Fri Apr 08 10:33:14 2011 +0100
@@ -791,18 +791,19 @@
 
     /**
      * Tries to enqueue worker w in wait queue and await change in
-     * worker's eventCount.  If the pool is quiescent, possibly
-     * terminates worker upon exit.  Otherwise, before blocking,
-     * rescans queues to avoid missed signals.  Upon finding work,
-     * releases at least one worker (which may be the current
-     * worker). Rescans restart upon detected staleness or failure to
-     * release due to contention. Note the unusual conventions about
-     * Thread.interrupt here and elsewhere: Because interrupts are
-     * used solely to alert threads to check termination, which is
-     * checked here anyway, we clear status (using Thread.interrupted)
-     * before any call to park, so that park does not immediately
-     * return due to status being set via some other unrelated call to
-     * interrupt in user code.
+     * worker's eventCount.  If the pool is quiescent and there is
+     * more than one worker, possibly terminates worker upon exit.
+     * Otherwise, before blocking, rescans queues to avoid missed
+     * signals.  Upon finding work, releases at least one worker
+     * (which may be the current worker). Rescans restart upon
+     * detected staleness or failure to release due to
+     * contention. Note the unusual conventions about Thread.interrupt
+     * here and elsewhere: Because interrupts are used solely to alert
+     * threads to check termination, which is checked here anyway, we
+     * clear status (using Thread.interrupted) before any call to
+     * park, so that park does not immediately return due to status
+     * being set via some other unrelated call to interrupt in user
+     * code.
      *
      * @param w the calling worker
      * @param c the ctl value on entry
@@ -823,7 +824,7 @@
             else if (w.eventCount != v)
                 return true;                      // update next time
         }
-        if (parallelism + (int)(nc >> AC_SHIFT) == 0 &&
+        if ((int)c != 0 && parallelism + (int)(nc >> AC_SHIFT) == 0 &&
             blockedCount == 0 && quiescerCount == 0)
             idleAwaitWork(w, nc, c, v);           // quiescent
         for (boolean rescanned = false;;) {
@@ -893,7 +894,8 @@
                 w.parked = false;
                 if (w.eventCount != v)
                     break;
-                else if (System.nanoTime() - startTime < SHRINK_RATE)
+                else if (System.nanoTime() - startTime <
+                         SHRINK_RATE - (SHRINK_RATE / 10)) // timing slop
                     Thread.interrupted();          // spurious wakeup
                 else if (UNSAFE.compareAndSwapLong(this, ctlOffset,
                                                    currentCtl, prevCtl)) {
@@ -1175,7 +1177,7 @@
                         ws[k] = w;
                         nextWorkerIndex = k + 1;
                         int m = g & SMASK;
-                        g = k >= m? ((m << 1) + 1) & SMASK : g + (SG_UNIT<<1);
+                        g = k > m? ((m << 1) + 1) & SMASK : g + (SG_UNIT<<1);
                     }
                 } finally {
                     scanGuard = g;