From 0c2233b8fc41d92c23a7304cace0630234c3e12d Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 6 Oct 2014 18:39:01 +0400 Subject: [PATCH 1/4] comment --- .../src/com/intellij/openapi/project/CacheUpdateRunner.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/project/CacheUpdateRunner.java b/platform/platform-impl/src/com/intellij/openapi/project/CacheUpdateRunner.java index bb65c53285b6..968ac8720d1b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/CacheUpdateRunner.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/CacheUpdateRunner.java @@ -263,7 +263,7 @@ public class CacheUpdateRunner extends DumbModeTask { try { final FileContent fileContent = myQueue.take(myInnerIndicator); if (fileContent == null) { - myFinished.set(Boolean.TRUE); + myFinished.set(true); return; } @@ -295,6 +295,7 @@ public class CacheUpdateRunner extends DumbModeTask { @Override public void run() { if (myProcessInReadAction) { + // in wait methods we don't want to deadlock by grabbing write lock (or having it in queue) and trying to run read action in separate thread if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(action)) { throw new ProcessCanceledException(); } From f49ec72513fa0b212e2642c5837e92fa585cb624 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 6 Oct 2014 20:01:26 +0400 Subject: [PATCH 2/4] compilation --- .../component/ArrangementAtomMatchConditionComponent.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAtomMatchConditionComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAtomMatchConditionComponent.java index a1b15c6bf33f..04c0f2dc1726 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAtomMatchConditionComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAtomMatchConditionComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -237,7 +237,7 @@ public class ArrangementAtomMatchConditionComponent implements ArrangementUiComp @NotNull @Override public ArrangementAtomMatchCondition getMatchCondition() { - if (Boolean.valueOf(myInverted) == myCondition.getValue()) { + if (Boolean.valueOf(myInverted).equals(myCondition.getValue())) { if (myOppositeCondition == null) { myOppositeCondition = new ArrangementAtomMatchCondition(myCondition.getType(), !myInverted); } From b1eb1477f8de96c47a2e362368036a4a39798941 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Tue, 7 Oct 2014 13:17:10 +0400 Subject: [PATCH 3/4] https://ea.jetbrains.com/browser/ea_problems/61344 --- .../impl/InjectedGeneralHighlightingPass.java | 4 ++- .../intellij/concurrency/JobLauncherImpl.java | 30 +++++++++++++------ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java index 0321191294c5..a960d7da87f7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import com.intellij.concurrency.JobLauncher; import com.intellij.injected.editor.DocumentWindow; import com.intellij.lang.Language; import com.intellij.lang.injection.InjectedLanguageManager; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -145,6 +146,7 @@ public class InjectedGeneralHighlightingPass extends GeneralHighlightingPass imp private Set getInjectedPsiFiles(@NotNull final List elements1, @NotNull final List elements2, @NotNull final ProgressIndicator progress) { + ApplicationManager.getApplication().assertReadAccessAllowed(); final Set outInjected = new THashSet(); List injected = InjectedLanguageUtil.getCachedInjectedDocuments(myFile); diff --git a/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java b/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java index 3c9ae67c1980..ef88f15ee2d3 100644 --- a/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java +++ b/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java @@ -16,6 +16,7 @@ package com.intellij.concurrency; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; @@ -129,19 +130,30 @@ public class JobLauncherImpl extends JobLauncher { if (things.size() <= 1 || JobSchedulerImpl.CORES_COUNT <= CORES_FORK_THRESHOLD) { final AtomicBoolean result = new AtomicBoolean(true); - ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() { + Runnable runnable = new Runnable() { @Override public void run() { - //noinspection ForLoopReplaceableByForEach - for (int i = 0; i < things.size(); i++) { - T thing = things.get(i); - if (!thingProcessor.process(thing)) { - result.set(false); - break; + ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() { + @Override + public void run() { + //noinspection ForLoopReplaceableByForEach + for (int i = 0; i < things.size(); i++) { + T thing = things.get(i); + if (!thingProcessor.process(thing)) { + result.set(false); + break; + } + } } - } + }, wrapper); } - }, wrapper); + }; + if (runInReadAction) { + if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(runnable)) return false; + } + else { + runnable.run(); + } return result.get(); } From 3afe58c4cefca5b9087ee2ae2166198e872594b0 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Tue, 7 Oct 2014 13:30:04 +0400 Subject: [PATCH 4/4] replace EDT safely in tests --- .../testFramework/src/_FirstInSuiteTest.java | 24 +++++++++---------- .../testFramework/LightPlatformTestCase.java | 12 ++++++---- .../testFramework/PlatformTestCase.java | 1 + .../testFramework/UsefulTestCase.java | 24 +++++++++++++++++++ 4 files changed, 44 insertions(+), 17 deletions(-) diff --git a/platform/testFramework/src/_FirstInSuiteTest.java b/platform/testFramework/src/_FirstInSuiteTest.java index 4d3ff5829323..99c146f4a7b1 100644 --- a/platform/testFramework/src/_FirstInSuiteTest.java +++ b/platform/testFramework/src/_FirstInSuiteTest.java @@ -14,12 +14,10 @@ * limitations under the License. */ -import com.intellij.openapi.util.EmptyRunnable; -import com.intellij.psi.impl.DocumentCommitThread; -import com.intellij.testFramework.LightPlatformTestCase; -import com.intellij.util.ui.UIUtil; +import com.intellij.testFramework.UsefulTestCase; import junit.framework.TestCase; -import sun.awt.AWTAutoShutdown; + +import javax.swing.*; /** * This is should be first test in all tests so we can measure how long tests are starting up. @@ -28,18 +26,20 @@ import sun.awt.AWTAutoShutdown; @SuppressWarnings("JUnitTestClassNamingConvention") public class _FirstInSuiteTest extends TestCase { public void testNothing() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + System.out.println("EDT is "+Thread.currentThread()); + } + }); // in tests EDT inexplicably shuts down sometimes during the first access, // which leads to nasty problems in ApplicationImpl which assumes there is only one EDT. // so we try to forcibly terminate EDT here to urge JVM to re-spawn new shiny permanent EDT-1 - UIUtil.invokeAndWaitIfNeeded(EmptyRunnable.getInstance()); - final Thread mainThread = Thread.currentThread(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { + UsefulTestCase.replaceIdeEventQueueSafely(); + SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { - AWTAutoShutdown.getInstance().notifyThreadBusy(mainThread); - LightPlatformTestCase.initApplication(); - DocumentCommitThread.getInstance(); - Thread.currentThread().interrupt(); // exit current EDT, ignore all queued events since they are in a wrong thread by now + System.out.println("EDT is "+Thread.currentThread()); } }); } diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index 3e1c2a5f8e27..3fcde7de7160 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -110,6 +110,7 @@ import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.util.*; +import java.util.concurrent.atomic.AtomicReference; import static com.intellij.openapi.roots.ModuleRootModificationUtil.updateModel; @@ -666,8 +667,9 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da return; } - final Throwable[] throwables = new Throwable[1]; + final AtomicReference throwable = new AtomicReference(); + replaceIdeEventQueueSafely(); SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { @@ -675,8 +677,8 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da ourTestThread = Thread.currentThread(); startRunAndTear(); } - catch (Throwable throwable) { - throwables[0] = throwable; + catch (Throwable e) { + throwable.set(e); } finally { ourTestThread = null; @@ -694,8 +696,8 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da } }); - if (throwables[0] != null) { - throw throwables[0]; + if (throwable.get() != null) { + throw throwable.get(); } // just to make sure all deferred Runnables to finish diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java index 36d63ebb17dc..f3f0861a44bf 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java @@ -599,6 +599,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro public void runBare() throws Throwable { if (!shouldRunTest()) return; + replaceIdeEventQueueSafely(); try { runBareImpl(); } diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index 6f03fd02446e..a64129ee51d2 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -17,6 +17,7 @@ package com.intellij.testFramework; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.diagnostic.PerformanceWatcher; +import com.intellij.ide.IdeEventQueue; import com.intellij.mock.MockApplication; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.Application; @@ -57,6 +58,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.Assert; +import javax.swing.*; import javax.swing.Timer; import java.awt.*; import java.io.File; @@ -72,6 +74,7 @@ import java.util.List; import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; /** @@ -335,11 +338,32 @@ public abstract class UsefulTestCase extends TestCase { super.runBare(); } + public static void replaceIdeEventQueueSafely() throws InterruptedException, InvocationTargetException { + if (Toolkit.getDefaultToolkit().getSystemEventQueue() instanceof IdeEventQueue) { + return; + } + if (SwingUtilities.isEventDispatchThread()) { + throw new RuntimeException("must not call under EDT"); + } + + // in JDK 1.6 java.awt.EventQueue.push() causes slow painful death of current EDT + // so we have to wait through its agony to termination + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + IdeEventQueue.getInstance(); + } + }); + SwingUtilities.invokeAndWait(EmptyRunnable.getInstance()); + SwingUtilities.invokeAndWait(EmptyRunnable.getInstance()); + } + @Override public void runBare() throws Throwable { if (!shouldRunTest()) return; if (runInDispatchThread()) { + replaceIdeEventQueueSafely(); final Throwable[] exception = {null}; UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override