mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
conservative fix for IDEA-132991
This commit is contained in:
@@ -125,4 +125,9 @@ public class MockApplicationEx extends MockApplication implements ApplicationEx
|
||||
public boolean isWriteActionInProgress() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWriteActionPending() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,12 @@ public interface ApplicationEx extends Application {
|
||||
*/
|
||||
boolean isWriteActionInProgress();
|
||||
|
||||
/**
|
||||
* @return true if the EDT started to acquire write action but has not acquired it yet.
|
||||
* @see #runWriteAction(Runnable)
|
||||
*/
|
||||
boolean isWriteActionPending();
|
||||
|
||||
void doNotSave();
|
||||
void doNotSave(boolean value);
|
||||
boolean isDoNotSave();
|
||||
|
||||
@@ -19,14 +19,13 @@
|
||||
*/
|
||||
package com.intellij.ui;
|
||||
|
||||
import com.intellij.concurrency.Job;
|
||||
import com.intellij.concurrency.JobLauncher;
|
||||
import com.intellij.ide.PowerSaveMode;
|
||||
import com.intellij.openapi.application.ApplicationAdapter;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
|
||||
import com.intellij.openapi.project.IndexNotReadyException;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
@@ -100,71 +99,54 @@ public class DeferredIconImpl<T> implements DeferredIcon {
|
||||
final Component paintingParent = SwingUtilities.getAncestorOfClass(PaintingParent.class, c);
|
||||
final Rectangle paintingParentRec = paintingParent == null ? null : ((PaintingParent)paintingParent).getChildRec(c);
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
JobLauncher.getInstance().submitToJobThread(Job.DEFAULT_PRIORITY, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int oldWidth = myDelegateIcon.getIconWidth();
|
||||
final Icon[] evaluated = new Icon[1];
|
||||
final Runnable evalRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
evaluated[0] = nonNull(myEvaluator.fun(myParam));
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
evaluated[0] = EMPTY_ICON;
|
||||
}
|
||||
catch (IndexNotReadyException e) {
|
||||
evaluated[0] = EMPTY_ICON;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final long startTime = System.currentTimeMillis();
|
||||
if (myNeedReadAction) {
|
||||
final ProgressIndicatorBase progress = new ProgressIndicatorBase();
|
||||
final ApplicationAdapter listener = new ApplicationAdapter() {
|
||||
@Override
|
||||
public void beforeWriteActionStart(Object action) {
|
||||
progress.cancel();
|
||||
}
|
||||
};
|
||||
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
|
||||
final Ref<Boolean> cancelled = new Ref<Boolean>();
|
||||
boolean result = ProgressIndicatorUtils.runWithWriteActionPriority(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().addApplicationListener(listener);
|
||||
}
|
||||
}, ModalityState.any());
|
||||
try {
|
||||
final Ref<Boolean> cancelled = new Ref<Boolean>();
|
||||
ProgressManager.getInstance().runProcess(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
IconDeferrerImpl.evaluateDeferred(evalRunnable);
|
||||
if (myAutoUpdatable) {
|
||||
myLastCalcTime = System.currentTimeMillis();
|
||||
myLastTimeSpent = myLastCalcTime - startTime;
|
||||
if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
IconDeferrerImpl.evaluateDeferred(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
evaluated[0] = nonNull(myEvaluator.fun(myParam));
|
||||
}
|
||||
catch (IndexNotReadyException e) {
|
||||
evaluated[0] = EMPTY_ICON;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (myAutoUpdatable) {
|
||||
myLastCalcTime = System.currentTimeMillis();
|
||||
myLastTimeSpent = myLastCalcTime - startTime;
|
||||
}
|
||||
})) {
|
||||
myIsScheduled = false;
|
||||
cancelled.set(Boolean.TRUE);
|
||||
}
|
||||
})) {
|
||||
cancelled.set(Boolean.TRUE);
|
||||
}
|
||||
}, progress);
|
||||
if (cancelled.get() == Boolean.TRUE) return;
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
}
|
||||
finally {
|
||||
ApplicationManager.getApplication().removeApplicationListener(listener);
|
||||
}
|
||||
});
|
||||
if (cancelled.get() == Boolean.TRUE || !result) {
|
||||
myIsScheduled = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
IconDeferrerImpl.evaluateDeferred(evalRunnable);
|
||||
IconDeferrerImpl.evaluateDeferred(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
evaluated[0] = nonNull(myEvaluator.fun(myParam));
|
||||
}
|
||||
});
|
||||
if (myAutoUpdatable) {
|
||||
myLastCalcTime = System.currentTimeMillis();
|
||||
myLastTimeSpent = myLastCalcTime - startTime;
|
||||
|
||||
+36
-21
@@ -1155,35 +1155,50 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
return new ReadAccessToken(status);
|
||||
}
|
||||
|
||||
private volatile boolean myWriteActionPending;
|
||||
|
||||
@Override
|
||||
public boolean isWriteActionPending() {
|
||||
return myWriteActionPending;
|
||||
}
|
||||
|
||||
private void startWrite(Class clazz) {
|
||||
ActivityTracker.getInstance().inc();
|
||||
fireBeforeWriteActionStart(clazz);
|
||||
boolean writeActionPending = myWriteActionPending;
|
||||
myWriteActionPending = true;
|
||||
|
||||
try {
|
||||
if (!isWriteAccessAllowed()) {
|
||||
assertNoPsiLock();
|
||||
}
|
||||
if (!myLock.writeLock().tryLock()) {
|
||||
final AtomicBoolean lockAcquired = new AtomicBoolean(false);
|
||||
if (ourDumpThreadsOnLongWriteActionWaiting > 0) {
|
||||
executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!lockAcquired.get()) {
|
||||
TimeoutUtil.sleep(ourDumpThreadsOnLongWriteActionWaiting);
|
||||
if (!lockAcquired.get()) {
|
||||
PerformanceWatcher.getInstance().dumpThreads(true);
|
||||
ActivityTracker.getInstance().inc();
|
||||
fireBeforeWriteActionStart(clazz);
|
||||
|
||||
try {
|
||||
if (!isWriteAccessAllowed()) {
|
||||
assertNoPsiLock();
|
||||
}
|
||||
if (!myLock.writeLock().tryLock()) {
|
||||
final AtomicBoolean lockAcquired = new AtomicBoolean(false);
|
||||
if (ourDumpThreadsOnLongWriteActionWaiting > 0) {
|
||||
executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!lockAcquired.get()) {
|
||||
TimeoutUtil.sleep(ourDumpThreadsOnLongWriteActionWaiting);
|
||||
if (!lockAcquired.get()) {
|
||||
PerformanceWatcher.getInstance().dumpThreads(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
myLock.writeLock().lockInterruptibly();
|
||||
lockAcquired.set(true);
|
||||
}
|
||||
myLock.writeLock().lockInterruptibly();
|
||||
lockAcquired.set(true);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeInterruptedException(e);
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeInterruptedException(e);
|
||||
finally {
|
||||
myWriteActionPending = writeActionPending;
|
||||
}
|
||||
|
||||
myWriteActionsStack.push(clazz);
|
||||
|
||||
+56
@@ -19,9 +19,11 @@ import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationAdapter;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ex.ApplicationEx;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.ide.PooledThreadExecutor;
|
||||
|
||||
@@ -61,6 +63,60 @@ public class ProgressIndicatorUtils {
|
||||
scheduleWithWriteActionPriority(progressIndicator, PooledThreadExecutor.INSTANCE, readTask);
|
||||
}
|
||||
|
||||
public static boolean runWithWriteActionPriority(@NotNull final Runnable action) {
|
||||
return runWithWriteActionPriority(action, new ProgressIndicatorBase());
|
||||
}
|
||||
|
||||
public static boolean runWithWriteActionPriority(@NotNull final Runnable action,
|
||||
@NotNull final ProgressIndicator progressIndicator) {
|
||||
final ApplicationEx application = (ApplicationEx)ApplicationManager.getApplication();
|
||||
|
||||
if (application.isWriteActionPending()) {
|
||||
// first catch: check if write action acquisition started: especially important when current thread has read action, because
|
||||
// tryRunReadAction below would just run without really checking if a write action is pending
|
||||
if (!progressIndicator.isCanceled()) progressIndicator.cancel();
|
||||
return false;
|
||||
}
|
||||
|
||||
final ApplicationAdapter listener = new ApplicationAdapter() {
|
||||
@Override
|
||||
public void beforeWriteActionStart(Object action) {
|
||||
if (!progressIndicator.isCanceled()) progressIndicator.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
boolean succeededWithAddingListener = application.tryRunReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Even if writeLock.lock() acquisition is in progress at this point then runProcess will block wanting read action which is
|
||||
// also ok as last resort.
|
||||
application.addApplicationListener(listener);
|
||||
}
|
||||
});
|
||||
if (!succeededWithAddingListener) { // second catch: writeLock.lock() acquisition is in progress or already acquired
|
||||
if (!progressIndicator.isCanceled()) progressIndicator.cancel();
|
||||
return false;
|
||||
}
|
||||
final Ref<Boolean> wasCancelled = new Ref<Boolean>();
|
||||
try {
|
||||
ProgressManager.getInstance().runProcess(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
action.run();
|
||||
}
|
||||
catch (ProcessCanceledException ignore) {
|
||||
wasCancelled.set(Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
}, progressIndicator);
|
||||
}
|
||||
finally {
|
||||
application.removeApplicationListener(listener);
|
||||
}
|
||||
return wasCancelled.get() != Boolean.TRUE;
|
||||
}
|
||||
|
||||
public static void scheduleWithWriteActionPriority(@NotNull final ProgressIndicator progressIndicator,
|
||||
@NotNull final Executor executor,
|
||||
@NotNull final ReadTask readTask) {
|
||||
|
||||
@@ -19,15 +19,14 @@ import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.caches.CacheUpdater;
|
||||
import com.intellij.ide.caches.FileContent;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationAdapter;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
|
||||
import com.intellij.openapi.progress.util.ProgressWrapper;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
@@ -142,56 +141,46 @@ public class CacheUpdateRunner extends DumbModeTask {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean processSomeFilesWhileUserIsInactive(@NotNull FileContentQueue queue,
|
||||
@NotNull Consumer<VirtualFile> progressUpdater,
|
||||
private static boolean processSomeFilesWhileUserIsInactive(@NotNull final FileContentQueue queue,
|
||||
@NotNull final Consumer<VirtualFile> progressUpdater,
|
||||
final boolean processInReadAction,
|
||||
@NotNull Project project,
|
||||
@NotNull Consumer<FileContent> fileProcessor) {
|
||||
@NotNull final Project project,
|
||||
@NotNull final Consumer<FileContent> fileProcessor) {
|
||||
final ProgressIndicatorBase innerIndicator = new ProgressIndicatorBase() {
|
||||
@Override
|
||||
protected boolean isCancelable() {
|
||||
return true; // the inner indicator must be always cancelable
|
||||
}
|
||||
};
|
||||
final ApplicationAdapter canceller = new ApplicationAdapter() {
|
||||
@Override
|
||||
public void beforeWriteActionStart(Object action) {
|
||||
innerIndicator.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
application.invokeAndWait(new Runnable() {
|
||||
final AtomicBoolean isFinished = new AtomicBoolean();
|
||||
|
||||
ProgressIndicatorUtils.runWithWriteActionPriority(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
application.addApplicationListener(canceller);
|
||||
}
|
||||
}, ModalityState.any());
|
||||
|
||||
final AtomicBoolean isFinished = new AtomicBoolean();
|
||||
try {
|
||||
int threadsCount = Registry.intValue("caches.indexerThreadsCount");
|
||||
if (threadsCount <= 0) {
|
||||
threadsCount = Math.max(1, Math.min(PROC_COUNT - 1, 4));
|
||||
}
|
||||
if (threadsCount == 1 || application.isWriteAccessAllowed()) {
|
||||
Runnable process = new MyRunnable(innerIndicator, queue, isFinished, progressUpdater, processInReadAction, project, fileProcessor);
|
||||
ProgressManager.getInstance().runProcess(process, innerIndicator);
|
||||
}
|
||||
else {
|
||||
AtomicBoolean[] finishedRefs = new AtomicBoolean[threadsCount];
|
||||
Future<?>[] futures = new Future<?>[threadsCount];
|
||||
for (int i = 0; i < threadsCount; i++) {
|
||||
AtomicBoolean ref = new AtomicBoolean();
|
||||
finishedRefs[i] = ref;
|
||||
Runnable process = new MyRunnable(innerIndicator, queue, ref, progressUpdater, processInReadAction, project, fileProcessor);
|
||||
futures[i] = ApplicationManager.getApplication().executeOnPooledThread(process);
|
||||
int threadsCount = Registry.intValue("caches.indexerThreadsCount");
|
||||
if (threadsCount <= 0) {
|
||||
threadsCount = Math.max(1, Math.min(PROC_COUNT - 1, 4));
|
||||
}
|
||||
if (threadsCount == 1 || application.isWriteAccessAllowed()) {
|
||||
Runnable process =
|
||||
new MyRunnable(innerIndicator, queue, isFinished, progressUpdater, processInReadAction, project, fileProcessor);
|
||||
ProgressManager.getInstance().runProcess(process, innerIndicator);
|
||||
}
|
||||
else {
|
||||
AtomicBoolean[] finishedRefs = new AtomicBoolean[threadsCount];
|
||||
Future<?>[] futures = new Future<?>[threadsCount];
|
||||
for (int i = 0; i < threadsCount; i++) {
|
||||
AtomicBoolean ref = new AtomicBoolean();
|
||||
finishedRefs[i] = ref;
|
||||
Runnable process = new MyRunnable(innerIndicator, queue, ref, progressUpdater, processInReadAction, project, fileProcessor);
|
||||
futures[i] = ApplicationManager.getApplication().executeOnPooledThread(process);
|
||||
}
|
||||
isFinished.set(waitForAll(finishedRefs, futures));
|
||||
}
|
||||
isFinished.set(waitForAll(finishedRefs, futures));
|
||||
}
|
||||
}
|
||||
finally {
|
||||
application.removeApplicationListener(canceller);
|
||||
}
|
||||
}, innerIndicator);
|
||||
|
||||
return isFinished.get();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user