[^cdr] fix data race in DumbService.runWhenSmart
authorpeter <peter@jetbrains.com>
Fri, 6 Nov 2015 15:19:37 +0000 (16:19 +0100)
committerpeter <peter@jetbrains.com>
Fri, 6 Nov 2015 15:48:32 +0000 (16:48 +0100)
platform/core-api/src/com/intellij/openapi/project/DumbService.java
platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java

index 8062d86390b85483bd266e082396eb86fbe0a987..fcd2ec68fa294509511403d9f08b34a49825d6ba 100644 (file)
@@ -64,7 +64,9 @@ public abstract class DumbService {
   }
 
   /**
-   * Executes the runnable immediately if not in dumb mode, or on AWT Event Dispatch thread when the dumb mode ends.
+   * Executes the runnable immediately if not in dumb mode, or on AWT Event Dispatch thread after the dumb mode ends.
+   * Note that it's not guaranteed that the dumb mode won't start again during this runnable execution, it should manage that situation explicitly
+   * (e.g. by starting a read action; it's still necessary to check isDumb inside the read action).
    * @param runnable runnable to run
    */
   public abstract void runWhenSmart(@NotNull Runnable runnable);
index 788864eaabb457e317e2c93e8ada168753d81557..a1d1cc15b81e62ccd810bc8152c7b386ba1c5000 100644 (file)
@@ -151,14 +151,14 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica
 
   @Override
   public void runWhenSmart(@NotNull Runnable runnable) {
-    if (!isDumb()) {
-      runnable.run();
-    }
-    else {
-      synchronized (myRunWhenSmartQueue) {
+    synchronized (myRunWhenSmartQueue) {
+      if (isDumb()) {
         myRunWhenSmartQueue.addLast(runnable);
+        return;
       }
     }
+
+    runnable.run();
   }
 
   private void scheduleCacheUpdate(@NotNull final DumbModeTask task, boolean forceDumbMode) {
@@ -220,7 +220,9 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica
           application.runWriteAction(new Runnable() {
             @Override
             public void run() {
-              myDumb = true;
+              synchronized (myRunWhenSmartQueue) {
+                myDumb = true;
+              }
               myDumbStart = trace;
               myModificationCount++;
               try {
@@ -286,7 +288,9 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica
   }
 
   private void updateFinished(boolean modal) {
-    myDumb = false;
+    synchronized (myRunWhenSmartQueue) {
+      myDumb = false;
+    }
     myDumbStart = null;
     myModificationCount++;
     if (myProject.isDisposed()) return;