diff options
Diffstat (limited to 'platform/lang-impl/src/com/intellij/psi/impl/DocumentCommitThread.java')
-rw-r--r-- | platform/lang-impl/src/com/intellij/psi/impl/DocumentCommitThread.java | 95 |
1 files changed, 71 insertions, 24 deletions
diff --git a/platform/lang-impl/src/com/intellij/psi/impl/DocumentCommitThread.java b/platform/lang-impl/src/com/intellij/psi/impl/DocumentCommitThread.java index c8793c085a58..32a2e38384d9 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/DocumentCommitThread.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/DocumentCommitThread.java @@ -18,8 +18,8 @@ package com.intellij.psi.impl; import com.intellij.codeInsight.daemon.impl.DaemonProgressIndicator; import com.intellij.ide.startup.impl.StartupManagerImpl; import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ex.ApplicationManagerEx; +import com.intellij.openapi.application.ApplicationAdapter; +import com.intellij.openapi.application.ex.ApplicationEx; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; @@ -54,17 +54,44 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run private final Queue<CommitTask> documentsToCommit = new Queue<CommitTask>(10); private final List<CommitTask> documentsToApplyInEDT = new ArrayList<CommitTask>(10); // guarded by documentsToCommit + private final ApplicationEx myApplication; private volatile boolean isDisposed; private CommitTask currentTask; // guarded by documentsToCommit private volatile boolean threadFinished; - private volatile boolean myEnabled = true; // true if we can do commits. set to false temporarily during the write action. + private volatile boolean myEnabled; // true if we can do commits. set to false temporarily during the write action. public static DocumentCommitThread getInstance() { return ServiceManager.getService(DocumentCommitThread.class); } - public DocumentCommitThread() { - log("Starting thread",null, false); + public DocumentCommitThread(final ApplicationEx application) { + myApplication = application; + // install listener in EDT to avoid missing events in case we are inside write action right now + application.invokeLater(new Runnable() { + @Override + public void run() { + application.addApplicationListener(new ApplicationAdapter() { + private int runningWriteActions; + + @Override + public void beforeWriteActionStart(Object action) { + if (runningWriteActions++ == 0) { + disable("Write action started: " + action); + } + } + + @Override + public void writeActionFinished(Object action) { + if (--runningWriteActions == 0) { + enable("Write action finished: " + action); + } + } + }, DocumentCommitThread.this); + + enable("Listener installed, started"); + } + }); + log("Starting thread", null, false); new Thread(this, "Document commit thread").start(); } @@ -88,14 +115,14 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run } } - public void disable(@NonNls Object reason) { + private void disable(@NonNls Object reason) { // write action has just started, all commits are useless cancel(reason); myEnabled = false; log("Disabled", null, false, reason); } - public void enable(Object reason) { + private void enable(@NonNls Object reason) { myEnabled = true; wakeUpQueue(); log("Enabled", null, false, reason); @@ -107,7 +134,7 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run } } - private void cancel(@NonNls Object reason) { + private void cancel(@NonNls @NotNull Object reason) { startNewTask(null, reason); } @@ -126,7 +153,7 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run doQueue(project, document, reason); } - private void doQueue(Project project, Document document, Object reason) { + private void doQueue(@NotNull Project project, @NotNull Document document, @NotNull Object reason) { synchronized (documentsToCommit) { ProgressIndicator indicator = new DaemonProgressIndicator(); CommitTask newTask = new CommitTask(document, project, indicator, reason); @@ -193,7 +220,6 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run public void clearQueue() { cancelAll(); log.setLength(0); - disable("end of test"); wakeUpQueue(); } @@ -303,9 +329,9 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run } if (success) { - assert !ApplicationManager.getApplication().isDispatchThread(); + assert !myApplication.isDispatchThread(); UIUtil.invokeLaterIfNeeded(finishRunnable); - log("Invoked later finishRunnable", task, false, success, finishRunnable, indicator); + log("Invoked later finishRunnable", task, false, finishRunnable, indicator); } } catch (ProcessCanceledException e) { @@ -334,7 +360,7 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run @Override public void commitSynchronously(@NotNull Document document, @NotNull Project project) { assert !isDisposed; - ApplicationManager.getApplication().assertWriteAccessAllowed(); + myApplication.assertWriteAccessAllowed(); if (!project.isInitialized() && !project.isDefault()) { @NonNls String s = project + "; Disposed: "+project.isDisposed()+"; Open: "+project.isOpen(); @@ -380,7 +406,7 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run return new ProgressIndicatorBase(); } - private void startNewTask(CommitTask task, Object reason) { + private void startNewTask(@Nullable CommitTask task, @NotNull Object reason) { synchronized (documentsToCommit) { // sync to prevent overwriting CommitTask cur = currentTask; if (cur != null) { @@ -388,19 +414,19 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run } currentTask = task; } + log("new task started", task, false, reason); } // returns finish commit Runnable (to be invoked later in EDT), or null on failure @Nullable - private Runnable commitUnderProgress(@NotNull final CommitTask task, - final boolean synchronously) { + private Runnable commitUnderProgress(@NotNull final CommitTask task, final boolean synchronously) { final Project project = task.project; final Document document = task.document; final List<Processor<Document>> finishProcessors = new SmartList<Processor<Document>>(); Runnable runnable = new Runnable() { @Override public void run() { - ApplicationManager.getApplication().assertReadAccessAllowed(); + myApplication.assertReadAccessAllowed(); if (project.isDisposed()) return; final PsiDocumentManagerImpl documentManager = (PsiDocumentManagerImpl)PsiDocumentManager.getInstance(project); @@ -424,14 +450,12 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run } }; if (synchronously) { - ApplicationManager.getApplication().assertWriteAccessAllowed(); + myApplication.assertWriteAccessAllowed(); runnable.run(); } - else { - if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(runnable)) { - log("Could not start read action", task, synchronously, ApplicationManager.getApplication().isReadAccessAllowed(), Thread.currentThread()); - return null; - } + else if (!myApplication.tryRunReadAction(runnable)) { + log("Could not start read action", task, synchronously, myApplication.isReadAccessAllowed(), Thread.currentThread()); + return null; } boolean canceled = task.indicator.isCanceled(); @@ -443,7 +467,7 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run Runnable finishRunnable = new Runnable() { @Override public void run() { - ApplicationManager.getApplication().assertIsDispatchThread(); + myApplication.assertIsDispatchThread(); Project project = task.project; if (project.isDisposed()) return; @@ -525,4 +549,27 @@ public class DocumentCommitThread extends DocumentCommitProcessor implements Run } return result[0]; } + + @TestOnly + boolean isEnabled() { + return myEnabled; + } + + @TestOnly + public void waitUntilAllCommitted(long timeout) throws InterruptedException { + if (!myEnabled) { + throw new IllegalStateException("DocumentCommitThread is disabled"); + } + int attempts = 0; + int delay = 100; + synchronized (documentsToCommit) { + while(!documentsToCommit.isEmpty() || currentTask != null) { + documentsToCommit.wait(delay); + if (delay * attempts > timeout) { + throw new RuntimeException("timeout"); + } + attempts++; + } + } + } } |