From f374cc7d192c91223f24ebaae00fbd7ea7a75fbe Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 6 Feb 2017 17:22:08 +0300 Subject: [PATCH] project leak: explicitly wait for project scan in background to complete --- .../progress/util/ProgressIndicatorUtils.java | 74 +++++++++++-------- 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressIndicatorUtils.java b/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressIndicatorUtils.java index b7e98b11dd81..6ddfe9195d3b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressIndicatorUtils.java +++ b/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressIndicatorUtils.java @@ -32,7 +32,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.ide.PooledThreadExecutor; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import java.util.concurrent.Future; +import java.util.function.BiConsumer; /** * Methods in this class are used to equip long background processes which take read actions with a special listener @@ -60,16 +63,23 @@ public class ProgressIndicatorUtils { return progress; } + @NotNull + public static Future submitWithWriteActionPriority(@NotNull ReadTask task) { + return scheduleWithWriteActionPriority(new ProgressIndicatorBase(), task); + } + public static void scheduleWithWriteActionPriority(@NotNull ReadTask task) { - scheduleWithWriteActionPriority(new ProgressIndicatorBase(), task); + submitWithWriteActionPriority(task); } - public static void scheduleWithWriteActionPriority(@NotNull ProgressIndicator progressIndicator, @NotNull ReadTask readTask) { - scheduleWithWriteActionPriority(progressIndicator, PooledThreadExecutor.INSTANCE, readTask); + @NotNull + public static Future scheduleWithWriteActionPriority(@NotNull ProgressIndicator progressIndicator, @NotNull ReadTask readTask) { + return scheduleWithWriteActionPriority(progressIndicator, PooledThreadExecutor.INSTANCE, readTask); } - public static void scheduleWithWriteActionPriority(@NotNull Executor executor, @NotNull ReadTask task) { - scheduleWithWriteActionPriority(new ProgressIndicatorBase(), executor, task); + @NotNull + public static Future scheduleWithWriteActionPriority(@NotNull Executor executor, @NotNull ReadTask task) { + return scheduleWithWriteActionPriority(new ProgressIndicatorBase(), executor, task); } /** @@ -148,9 +158,10 @@ public class ProgressIndicatorUtils { return wasCancelled.get() != Boolean.TRUE; } - public static void scheduleWithWriteActionPriority(@NotNull final ProgressIndicator progressIndicator, - @NotNull final Executor executor, - @NotNull final ReadTask readTask) { + @NotNull + public static Future scheduleWithWriteActionPriority(@NotNull final ProgressIndicator progressIndicator, + @NotNull final Executor executor, + @NotNull final ReadTask readTask) { final Application application = ApplicationManager.getApplication(); // invoke later even if on EDT // to avoid tasks eagerly restarting immediately, allocating many pooled threads @@ -160,9 +171,13 @@ public class ProgressIndicatorUtils { // use SwingUtilities instead of application.invokeLater // to tolerate any immediate modality changes (e.g. https://youtrack.jetbrains.com/issue/IDEA-135180) + CompletableFuture future = new CompletableFuture<>(); //noinspection SSBasedInspection EdtInvocationManager.getInstance().invokeLater(() -> { - if (application.isDisposed()) return; + if (application.isDisposed()) { + future.complete(null); + return; + } final ApplicationAdapter listener = new ApplicationAdapter() { @Override public void beforeWriteActionStart(@NotNull Object action) { @@ -173,35 +188,34 @@ public class ProgressIndicatorUtils { } }; application.addApplicationListener(listener); + future.whenComplete((BiConsumer)(o, throwable) -> application.removeApplicationListener(listener)); try { executor.execute(new Runnable() { @Override public void run() { - boolean continued = false; - try { - final ReadTask.Continuation continuation = runUnderProgress(progressIndicator, readTask); - continued = continuation != null; - if (continuation != null) { - application.invokeLater(new Runnable() { - @Override - public void run() { - application.removeApplicationListener(listener); + final ReadTask.Continuation continuation = runUnderProgress(progressIndicator, readTask); + if (continuation == null) { + future.complete(null); + } + else { + application.invokeLater(new Runnable() { + @Override + public void run() { + try { if (!progressIndicator.isCanceled()) { continuation.getAction().run(); } } - - @Override - public String toString() { - return "continuation of " + readTask; + finally { + future.complete(null); } - }, continuation.getModalityState()); - } - } - finally { - if (!continued) { - application.removeApplicationListener(listener); - } + } + + @Override + public String toString() { + return "continuation of " + readTask; + } + }, continuation.getModalityState()); } } @@ -213,9 +227,11 @@ public class ProgressIndicatorUtils { } catch (RuntimeException | Error e) { application.removeApplicationListener(listener); + future.completeExceptionally(e); throw e; } }); + return future; } private static ReadTask.Continuation runUnderProgress(@NotNull final ProgressIndicator progressIndicator, @NotNull final ReadTask task) {