platform: fix notBlocking task leaking via Disposer

GitOrigin-RevId: 923f6fcff2438e285a259a82770440ffb21212e7
This commit is contained in:
Aleksey Pivovarov
2022-02-14 10:46:32 +00:00
committed by intellij-monorepo-bot
parent a33b82d7c9
commit 14f58cbce4
2 changed files with 58 additions and 27 deletions
@@ -423,39 +423,44 @@ public final class NonBlockingReadActionImpl<T> implements NonBlockingReadAction
}
T executeSynchronously() {
while (true) {
attemptComputation();
try {
while (true) {
attemptComputation();
if (isCancelled()) {
throw new ProcessCanceledException();
}
if (isDone()) {
try {
return blockingGet(0, TimeUnit.MILLISECONDS);
}
catch (TimeoutException e) {
throw new RuntimeException(e);
}
}
ProgressIndicatorUtils.checkCancelledEvenWithPCEDisabled(myProgressIndicator);
ContextConstraint[] constraints = builder.myConstraints;
if (shouldFinishOnEdt() || constraints.length != 0) {
Semaphore semaphore = new Semaphore(1);
invokeLater(() -> {
if (checkObsolete()) {
semaphore.up();
}
else {
BaseConstrainedExecution.scheduleWithinConstraints(semaphore::up, null, constraints);
}
});
ProgressIndicatorUtils.awaitWithCheckCanceled(semaphore, myProgressIndicator);
if (isCancelled()) {
throw new ProcessCanceledException();
}
if (isDone()) {
try {
return blockingGet(0, TimeUnit.MILLISECONDS);
}
catch (TimeoutException e) {
throw new RuntimeException(e);
}
}
ProgressIndicatorUtils.checkCancelledEvenWithPCEDisabled(myProgressIndicator);
ContextConstraint[] constraints = builder.myConstraints;
if (shouldFinishOnEdt() || constraints.length != 0) {
Semaphore semaphore = new Semaphore(1);
invokeLater(() -> {
if (checkObsolete()) {
semaphore.up();
}
else {
BaseConstrainedExecution.scheduleWithinConstraints(semaphore::up, null, constraints);
}
});
ProgressIndicatorUtils.awaitWithCheckCanceled(semaphore, myProgressIndicator);
if (isCancelled()) {
throw new ProcessCanceledException();
}
}
}
}
finally {
cleanupIfNeeded();
}
}
private boolean attemptComputation() {
@@ -256,6 +256,32 @@ public class NonBlockingReadActionTest extends LightPlatformTestCase {
}
}
public void testDoNotLeakDisposablesOnCancelledIndicator() {
ProgressIndicator outerIndicator = new EmptyProgressIndicator();
Disposable disposable = Disposer.newDisposable();
try {
Future<?> future = ApplicationManager.getApplication().executeOnPooledThread(() -> {
assertThrows(ProcessCanceledException.class, () -> {
ReadAction.nonBlocking(() -> {
outerIndicator.cancel();
throw new ProcessCanceledException();
})
.expireWith(disposable)
.wrapProgress(outerIndicator)
.executeSynchronously();
});
});
waitForFuture(future);
Disposer.disposeChildren(disposable, (child) -> {
throw new IllegalStateException(child.toString());
});
}
finally {
Disposer.dispose(disposable);
}
}
public void testSyncExecutionHonorsConstraints() {
setupUncommittedDocument();