make getExtensions interruptible by checkCanceled

to get more responsiveness while loading classes for all of those extensions
This commit is contained in:
peter
2018-11-20 14:13:13 +01:00
parent adf012f014
commit f519cdeff5
2 changed files with 36 additions and 4 deletions
@@ -8,6 +8,7 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.OpenTHashSet;
@@ -247,6 +248,7 @@ public final class ExtensionPointImpl<T> implements ExtensionPoint<T> {
myLoadedAdapters = Collections.emptyList();
boolean errorHappened = false;
for (int i = 0; i < adapters.size(); i++) {
CHECK_CANCELED.run();
ExtensionComponentAdapter adapter = adapters.get(i);
try {
@SuppressWarnings("unchecked") T extension = (T)adapter.getExtension();
@@ -548,4 +550,35 @@ public final class ExtensionPointImpl<T> implements ExtensionPoint<T> {
return myLoadingOrder;
}
}
@SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
private static Runnable CHECK_CANCELED = EmptyRunnable.getInstance();
public static void setCheckCanceledAction(Runnable checkCanceled) {
CHECK_CANCELED = new Runnable() {
final Set<Throwable> reported = ContainerUtil.newConcurrentSet();
@Override
public void run() {
try {
checkCanceled.run();
}
catch (ProcessCanceledException e) {
if (!isInsideClassInitializer(e.getStackTrace())) { // otherwise ExceptionInInitializerError happens and the class is screwed forever
throw e;
}
else {
Throwable throwable = new Throwable();
if (reported.add(throwable)) {
LOG.warn("Don't instantiate extensions from class initializer", throwable);
}
}
}
}
};
}
private static boolean isInsideClassInitializer(StackTraceElement[] trace) {
return Arrays.stream(trace).anyMatch(s -> "<clinit>".equals(s.getMethodName()));
}
}
@@ -5,10 +5,8 @@ package com.intellij.openapi.progress.impl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.extensions.impl.ExtensionPointImpl;
import com.intellij.openapi.progress.*;
import com.intellij.openapi.progress.util.PingProgress;
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
import com.intellij.openapi.progress.util.ProgressWindow;
@@ -58,6 +56,7 @@ public class ProgressManagerImpl extends CoreProgressManager implements Disposab
}
}, this);
ExtensionPointImpl.setCheckCanceledAction(ProgressManager::checkCanceled);
}
@Override