don't allow PCE to interrupt side-effectful service creation at random moments (IDEA-202707)

This commit is contained in:
peter
2018-12-13 16:43:58 +01:00
parent 152f2ab8a0
commit 3ef1fb0000
3 changed files with 28 additions and 20 deletions
@@ -32,7 +32,8 @@ public abstract class ProgressIndicatorProvider {
@Nullable
public static ProgressIndicator getGlobalProgressIndicator() {
return getInstance().getProgressIndicator();
ProgressManager instance = ProgressManager.ourInstance;
return instance == null ? null : instance.getProgressIndicator();
}
/** use {@link ProgressManager#executeNonCancelableSection(Runnable)} instead */
@@ -29,7 +29,7 @@ import javax.swing.*;
import java.util.Set;
public abstract class ProgressManager extends ProgressIndicatorProvider {
private static ProgressManager ourInstance = CachedSingletonsRegistry.markCachedField(ProgressManager.class);
static ProgressManager ourInstance = CachedSingletonsRegistry.markCachedField(ProgressManager.class);
@NotNull
@SuppressWarnings("MethodOverridesStaticMethodOfSuperclass")
@@ -13,6 +13,8 @@ import com.intellij.openapi.components.ex.ComponentManagerEx;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.*;
import com.intellij.openapi.extensions.impl.ExtensionComponentAdapter;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
@@ -195,34 +197,39 @@ public class ServiceManagerImpl implements Disposable {
return instance;
}
ComponentAdapter delegate = getDelegate();
String implementation = myDescriptor.getImplementation();
if (LOG.isDebugEnabled() &&
ApplicationManager.getApplication().isWriteAccessAllowed() &&
!ApplicationManager.getApplication().isUnitTestMode() &&
PersistentStateComponent.class.isAssignableFrom(delegate.getComponentImplementation())) {
LOG.warn(new Throwable("Getting service from write-action leads to possible deadlock. Service implementation " + myDescriptor.getImplementation()));
PersistentStateComponent.class.isAssignableFrom(getDelegate().getComponentImplementation())) {
LOG.warn(new Throwable("Getting service from write-action leads to possible deadlock. Service implementation " +
implementation));
}
// prevent storages from flushing and blocking FS
AccessToken token = HeavyProcessLatch.INSTANCE.processStarted("Creating component '" + myDescriptor.getImplementation() + "'");
try {
instance = delegate.getComponentInstance(container);
if (instance instanceof Disposable) {
Disposer.register(myComponentManager, (Disposable)instance);
// heavy to prevent storages from flushing and blocking FS
try (AccessToken ignore = HeavyProcessLatch.INSTANCE.processStarted("Creating component '" + implementation + "'")) {
Runnable runnable = () -> myInitializedComponentInstance = createAndInitialize(container);
if (ProgressIndicatorProvider.getGlobalProgressIndicator() != null) {
ProgressManager.getInstance().executeNonCancelableSection(runnable);
} else {
runnable.run();
}
myComponentManager.initializeComponent(instance, true);
myInitializedComponentInstance = instance;
return instance;
}
finally {
token.finish();
return myInitializedComponentInstance;
}
}
}
@NotNull
private Object createAndInitialize(@NotNull PicoContainer container) {
Object instance = getDelegate().getComponentInstance(container);
if (instance instanceof Disposable) {
Disposer.register(myComponentManager, (Disposable)instance);
}
myComponentManager.initializeComponent(instance, true);
return instance;
}
@NotNull
private synchronized ComponentAdapter getDelegate() {
if (myDelegate == null) {