diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java index ddeb076ac72f..de2e7d87577f 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java @@ -3,7 +3,6 @@ package com.intellij.compiler.server; import com.intellij.concurrency.ConcurrentCollectionFactory; import com.intellij.concurrency.ThreadContext; -import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.concurrency.ChildContext; import com.intellij.util.concurrency.Propagation; @@ -247,30 +246,34 @@ class BuildMessageDispatcher extends SimpleChannelInboundHandlerAdapter { myCapturedContext.runInChildContext(() -> myDelegate.buildStarted(sessionId)); - } + return null; + }); } @Override public void handleBuildMessage(Channel channel, UUID sessionId, CmdlineRemoteProto.Message.BuilderMessage msg) { - try (AccessToken ignored = ThreadContext.resetThreadContext()) { + ThreadContext.resetThreadContext(() -> { myCapturedContext.runInChildContext(() -> myDelegate.handleBuildMessage(channel, sessionId, msg)); - } + return null; + }); } @Override public void handleFailure(@NotNull UUID sessionId, CmdlineRemoteProto.Message.Failure failure) { - try (AccessToken ignored = ThreadContext.resetThreadContext()) { + ThreadContext.resetThreadContext(() -> { myCapturedContext.runInChildContext(() -> myDelegate.handleFailure(sessionId, failure)); - } + return null; + }); } @Override public void sessionTerminated(@NotNull UUID sessionId) { - try (AccessToken ignored = ThreadContext.resetThreadContext()) { + ThreadContext.resetThreadContext(() -> { myCapturedContext.runInChildContext(() -> myDelegate.sessionTerminated(sessionId)); - } + return null; + }); } } } diff --git a/platform/core-api/src/com/intellij/openapi/progress/context.kt b/platform/core-api/src/com/intellij/openapi/progress/context.kt index eb9da77bf131..fe9276a2bf11 100644 --- a/platform/core-api/src/com/intellij/openapi/progress/context.kt +++ b/platform/core-api/src/com/intellij/openapi/progress/context.kt @@ -78,7 +78,7 @@ fun prepareThreadContext(action: (CoroutineContext) -> T): T { return prepareIndicatorThreadContext(indicator, action) } val currentContext = prepareCurrentThreadContext() - return resetThreadContext().use { + return resetThreadContext { action(currentContext) } } @@ -93,7 +93,7 @@ internal fun prepareIndicatorThreadContext(indicator: ProgressIndicator, act (ProgressManager.getInstance().currentProgressModality?.asContextElement() ?: EmptyCoroutineContext) if (currentlyInstalledContext[Job] == NonCancellable) { return ProgressManager.getInstance().silenceGlobalIndicator { - resetThreadContext().use { + resetThreadContext { // we define a non-cancellable section as a scope of computation having a NonCancellable job. // therefore, to maintain further speculation about non-cancellable sections, we need to provide the NonCancellable job here val modifiedContext = context + NonCancellable @@ -105,7 +105,7 @@ internal fun prepareIndicatorThreadContext(indicator: ProgressIndicator, act val indicatorWatcher = cancelWithIndicator(currentJob, indicator) return try { ProgressManager.getInstance().silenceGlobalIndicator { - resetThreadContext().use { + resetThreadContext { action(context + currentJob) }.also { currentJob.complete() diff --git a/platform/core-impl/src/com/intellij/openapi/application/impl/FlushQueue.java b/platform/core-impl/src/com/intellij/openapi/application/impl/FlushQueue.java index 94d9a902885f..f35225f5b21f 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/impl/FlushQueue.java +++ b/platform/core-impl/src/com/intellij/openapi/application/impl/FlushQueue.java @@ -4,7 +4,6 @@ package com.intellij.openapi.application.impl; import com.intellij.concurrency.ContextAwareRunnable; import com.intellij.concurrency.ThreadContext; import com.intellij.diagnostic.EventWatcher; -import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; @@ -28,7 +27,7 @@ final class FlushQueue { private final BulkArrayQueue myQueue = new BulkArrayQueue<>(); //guarded by getQueueLock() private void flushNow() { - try (AccessToken ignored = ThreadContext.resetThreadContext()) { + ThreadContext.resetThreadContext(() -> { ThreadingAssertions.assertEventDispatchThread(); synchronized (getQueueLock()) { FLUSHER_SCHEDULED = false; @@ -48,7 +47,8 @@ final class FlushQueue { break; } } - } + return null; + }); } private Object getQueueLock() { diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java index fe92019d7c0b..1f8b2133ea76 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java @@ -762,8 +762,11 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen List> exceptions = new ArrayList<>(); for (Runnable action : actions) { //noinspection IncorrectCancellationExceptionHandling - try (AccessToken ignored = ThreadContext.resetThreadContext()) { - action.run(); + try { + ThreadContext.resetThreadContext(() -> { + action.run(); + return null; + }); } catch (ProcessCanceledException e) { // some actions are crazy enough to use PCE for their own control flow. diff --git a/platform/ide-core/src/com/intellij/util/ui/update/UiNotifyConnector.kt b/platform/ide-core/src/com/intellij/util/ui/update/UiNotifyConnector.kt index f3fe2abcff68..a8605381297f 100644 --- a/platform/ide-core/src/com/intellij/util/ui/update/UiNotifyConnector.kt +++ b/platform/ide-core/src/com/intellij/util/ui/update/UiNotifyConnector.kt @@ -78,13 +78,13 @@ open class UiNotifyConnector : Disposable, HierarchyListener { private val childContext = createChildContextIgnoreStructuredConcurrency(ContextActivatable::class.java.name) override fun showNotify() { - resetThreadContext().use { + resetThreadContext { childContext.runInChildContext { target.showNotify() } } } override fun hideNotify() { - resetThreadContext().use { + resetThreadContext { childContext.runInChildContext { target.hideNotify() } } } diff --git a/platform/lang-impl/testSources/com/intellij/ide/actions/searcheverywhere/SearchBufferedListenersTest.kt b/platform/lang-impl/testSources/com/intellij/ide/actions/searcheverywhere/SearchBufferedListenersTest.kt index d57da4d8b955..1ba950ae91ad 100644 --- a/platform/lang-impl/testSources/com/intellij/ide/actions/searcheverywhere/SearchBufferedListenersTest.kt +++ b/platform/lang-impl/testSources/com/intellij/ide/actions/searcheverywhere/SearchBufferedListenersTest.kt @@ -362,7 +362,7 @@ class SearchBufferedListenersTest : BasePlatformTestCase() { myMockery!!.assertIsSatisfied() } - private fun awaitShutdownNonBlocking(executorService: ScheduledExecutorService) = resetThreadContext().use { + private fun awaitShutdownNonBlocking(executorService: ScheduledExecutorService) = resetThreadContext { val eventQueue = Toolkit.getDefaultToolkit().systemEventQueue as IdeEventQueue while (!executorService.awaitTermination(10, TimeUnit.MILLISECONDS)) { val event = eventQueue.nextEvent diff --git a/platform/platform-impl/concurrency/src/concurrency/ApplierCompleter.java b/platform/platform-impl/concurrency/src/concurrency/ApplierCompleter.java index 24ff641b808d..d8fdaf2c0ed9 100644 --- a/platform/platform-impl/concurrency/src/concurrency/ApplierCompleter.java +++ b/platform/platform-impl/concurrency/src/concurrency/ApplierCompleter.java @@ -177,8 +177,11 @@ final class ApplierCompleter extends ForkJoinTask { } } private void helpAll() { - try (AccessToken ignored = ThreadContext.resetThreadContext()) { - helpOthers(); + try { + ThreadContext.resetThreadContext(() -> { + helpOthers(); + return null; + }); } catch (IndexNotReadyException ignore) { } @@ -256,7 +259,7 @@ final class ApplierCompleter extends ForkJoinTask { final boolean[] result = {true}; // these tasks could not be executed in the other thread; do them here boolean inReadAction = ApplicationManager.getApplication().isReadAccessAllowed(); // we are going to reset the thread context here, so the information about locks will be lost - try (AccessToken ignored = ThreadContext.resetThreadContext()) { + ThreadContext.resetThreadContext(() -> { for (ApplierCompleter task : array) { ProgressManager.checkCanceled(); Runnable r = () -> { @@ -276,7 +279,8 @@ final class ApplierCompleter extends ForkJoinTask { ApplicationManager.getApplication().runReadAction(r); } } - } + return null; + }); return result[0]; } diff --git a/platform/platform-impl/concurrency/src/concurrency/JobLauncherImpl.java b/platform/platform-impl/concurrency/src/concurrency/JobLauncherImpl.java index 0c800e0bf82f..48efc997fdfd 100644 --- a/platform/platform-impl/concurrency/src/concurrency/JobLauncherImpl.java +++ b/platform/platform-impl/concurrency/src/concurrency/JobLauncherImpl.java @@ -10,6 +10,7 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.impl.CoreProgressManager; import com.intellij.openapi.progress.util.StandardProgressIndicatorBase; +import com.intellij.openapi.util.Ref; import com.intellij.util.ObjectUtils; import com.intellij.util.Processor; import com.intellij.util.ThrowableConsumer; @@ -101,13 +102,14 @@ public final class JobLauncherImpl extends JobLauncher { runWhileForking.run(); // help all others - try (AccessToken ignored = ThreadContext.resetThreadContext()) { + ThreadContext.resetThreadContext(() -> { safeIterate(globalCompleters, thrown, completer -> { wrapper.checkCanceled(); // don't call .invoke() or other FJP-setting status functions completer.wrapAndRun(() -> completer.execAll()); }); - } + return null; + }); // all work is done or distributed; wait for in-flight appliers and manifest exceptions safeIterate(globalCompleters, thrown, completer -> { while (true) { @@ -121,8 +123,19 @@ public final class JobLauncherImpl extends JobLauncher { completer.get(); } else { - try (AccessToken ignored = ThreadContext.resetThreadContext()) { - completer.get(1, TimeUnit.MILLISECONDS); + Ref throwableRef = new Ref<>(null); + ThreadContext.resetThreadContext(() -> { + try { + completer.get(1, TimeUnit.MILLISECONDS); + } + catch (Throwable e) { + throwableRef.set(e); + } + return null; + }); + Throwable throwable = throwableRef.get(); + if (throwable != null) { + throw throwable; } } break; @@ -319,11 +332,12 @@ public final class JobLauncherImpl extends JobLauncher { if (toWait < 0) { return false; } - try (AccessToken ignored = ThreadContext.resetThreadContext()) { + ThreadContext.resetThreadContext(() -> { // wait while helping other tasks in the meantime, but not for too long // we are avoiding calling timed myForkJoinTask.get() because it's very expensive when timed out (bc of TimeoutException) myForkJoinPool.awaitQuiescence(Math.min(toWait, 10), TimeUnit.MILLISECONDS); - } + return null; + }); } if (myForkJoinTask.isDone()) { try { diff --git a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.kt b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.kt index 32aa164cccc1..0fe51dcbb05d 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.kt +++ b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.kt @@ -515,7 +515,7 @@ class IdeEventQueue private constructor() : EventQueue() { idleTracker() synchronized(lock) { lastActiveTime = System.nanoTime() - resetThreadContext().use { + resetThreadContext { for (activityListener in activityListeners) { activityListener.run() } @@ -608,9 +608,9 @@ class IdeEventQueue private constructor() : EventQueue() { @Internal fun flushQueue() { EDT.assertIsEdt() - resetThreadContext().use { + resetThreadContext { while (true) { - peekEvent() ?: return + peekEvent() ?: return@resetThreadContext try { dispatchEvent(nextEvent) } @@ -622,7 +622,7 @@ class IdeEventQueue private constructor() : EventQueue() { } fun pumpEventsForHierarchy(modalComponent: Component, exitCondition: Future<*>, eventConsumer: Consumer) { - resetThreadContext().use { + resetThreadContext { EDT.assertIsEdt() Logs.LOG.debug { "pumpEventsForHierarchy($modalComponent, $exitCondition)" } @@ -1260,9 +1260,9 @@ fun IdeEventQueue.flushExistingEvents() { EDT.assertIsEdt() var stop = false EventQueue.invokeLater(ContextAwareRunnable { stop = true }) - resetThreadContext().use { + resetThreadContext { while (!stop) { - peekEvent() ?: return + peekEvent() ?: return@resetThreadContext try { dispatchEvent(nextEvent) } diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/Utils.kt b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/Utils.kt index 17a6a24899a6..f5af8b12e27b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/Utils.kt +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/Utils.kt @@ -1249,7 +1249,7 @@ private object AltEdtDispatcher : CoroutineDispatcher() { fun runOwnQueueBlockingAndSwitchBackToEDT(job: Job, timeInMillis: Int) { try { - resetThreadContext().use { + resetThreadContext { // block EDT for a short and process the explicit EDT queue for update while (!job.isCompleted && TimeoutUtil.getDurationMillis(switchedAt) < timeInMillis) { val runnable = queue.poll(1, TimeUnit.MILLISECONDS) diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java index 6cf4aa276b4d..86a06d529e3e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java @@ -8,7 +8,10 @@ import com.intellij.concurrency.ThreadContext; import com.intellij.ide.plugins.DynamicPluginListener; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.TransactionGuard; +import com.intellij.openapi.application.TransactionGuardImpl; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.UndoConfirmationPolicy; import com.intellij.openapi.diagnostic.Logger; @@ -727,15 +730,15 @@ public class FileDocumentManagerImpl extends FileDocumentManagerBase implements @Override public void reloadFromDisk(@NotNull Document document, @Nullable Project project) { - try (AccessToken ignored = ThreadContext.resetThreadContext()) { + ThreadContext.resetThreadContext(() -> { ThreadingAssertions.assertEventDispatchThread(); VirtualFile file = getFile(document); assert file != null; - if (!file.isValid()) return; + if (!file.isValid()) return null; if (!fireBeforeFileContentReload(file, document)) { - return; + return null; } boolean[] isReloadable = {isReloadable(file, document, project)}; @@ -771,7 +774,8 @@ public class FileDocumentManagerImpl extends FileDocumentManagerBase implements myUnsavedDocuments.remove(document); document.putUserData(FORCE_SAVE_DOCUMENT_KEY, null); - } + return null; + }); } private static boolean isReloadable(@NotNull VirtualFile file, @NotNull Document document, @Nullable Project project) { diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.kt b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.kt index 493de4a3d329..6065d027b45c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.kt @@ -171,7 +171,7 @@ class AsyncEditorLoader internal constructor( } private fun executeDelayedActions(delayedActions: Array) { - resetThreadContext().use { + resetThreadContext { for (action in delayedActions) { action.run() } diff --git a/platform/platform-impl/src/com/intellij/openapi/progress/impl/PlatformTaskSupport.kt b/platform/platform-impl/src/com/intellij/openapi/progress/impl/PlatformTaskSupport.kt index e21072ef6510..d02f54801140 100644 --- a/platform/platform-impl/src/com/intellij/openapi/progress/impl/PlatformTaskSupport.kt +++ b/platform/platform-impl/src/com/intellij/openapi/progress/impl/PlatformTaskSupport.kt @@ -688,7 +688,7 @@ private fun IdeEventQueue.pumpEventsForHierarchy( @Internal fun IdeEventQueue.pumpEventsForHierarchy(exitCondition: () -> Boolean) { - resetThreadContext().use { + resetThreadContext { pumpEventsForHierarchy( exitCondition = exitCondition, modalComponent = { null }, diff --git a/platform/platform-impl/src/com/intellij/openapi/project/SmartModeScheduler.kt b/platform/platform-impl/src/com/intellij/openapi/project/SmartModeScheduler.kt index 56d8e48add26..c8d884c83f74 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/SmartModeScheduler.kt +++ b/platform/platform-impl/src/com/intellij/openapi/project/SmartModeScheduler.kt @@ -110,7 +110,7 @@ class SmartModeScheduler(private val project: Project, sc: CoroutineScope) : Dis // in this case we should quit processing pending actions and postpone them until the newly started dumb mode finishes. while (canRunSmart()) { val runnable = myRunWhenSmartQueue.pollFirst() ?: break - resetThreadContext().use { + resetThreadContext { doRun(runnable) } } diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java b/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java index c04d88a957d9..cae0ef6de591 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java @@ -47,7 +47,6 @@ import com.intellij.ui.mac.foundation.Foundation; import com.intellij.ui.mac.foundation.ID; import com.intellij.ui.mac.foundation.MacUtil; import com.intellij.ui.mac.touchbar.TouchbarSupport; -import com.intellij.ui.scale.JBUIScale; import com.intellij.util.IJSwingUtilities; import com.intellij.util.ObjectUtils; import com.intellij.util.SlowOperations; @@ -70,6 +69,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; public class DialogWrapperPeerImpl extends DialogWrapperPeer { @SuppressWarnings("LoggerInitializedWithForeignClass") @@ -432,7 +432,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer { @SuppressWarnings("deprecation") boolean changeModalityState = appStarted && myDialog.isModal() && !isProgressDialog(); Project project = myProject; - AccessToken lockContextCleanup; + Consumer lockContextWrapper; Function0 lockCleanup; if (changeModalityState) { @@ -442,11 +442,18 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer { var pair = ApplicationManager.getApplication().isWriteAccessAllowed() ? new Pair<>(EmptyCoroutineContext.INSTANCE, emptyFunction) : IntelliJLockingUtil.getGlobalThreadingSupport().getPermitAsContextElement(ThreadContext.currentThreadContext(), true); - lockContextCleanup = ThreadContext.installThreadContext(pair.getFirst(), true); + lockContextWrapper = (r) -> { + try (AccessToken ignored = ThreadContext.installThreadContext(pair.getFirst(), true)) { + r.run(); + } + }; lockCleanup = pair.getSecond(); } else { - lockContextCleanup = ThreadContext.resetThreadContext(); + lockContextWrapper = (r) -> ThreadContext.resetThreadContext(() -> { + r.run(); + return null; + }); lockCleanup = emptyFunction; } @@ -471,16 +478,18 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer { CompletableFuture result = new CompletableFuture<>(); SplashManagerKt.hideSplash(); try ( - AccessToken ignore = SlowOperations.startSection(SlowOperations.RESET); - AccessToken ignore3 = lockContextCleanup + AccessToken ignore = SlowOperations.startSection(SlowOperations.RESET) ) { - if (!isProgressDialog() && !ApplicationManager.getApplication().isReadAccessAllowed()) { - WriteIntentReadAction.run((Runnable) () -> { + lockContextWrapper.accept(() -> { + if (!isProgressDialog() && !ApplicationManager.getApplication().isReadAccessAllowed()) { + WriteIntentReadAction.run((Runnable)() -> { + myDialog.show(); + }); + } + else { myDialog.show(); - }); - } else { - myDialog.show(); - } + } + }); } finally { lockCleanup.invoke(); @@ -950,9 +959,10 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer { @Override @SuppressWarnings("deprecation") public void hide() { - try (@NotNull AccessToken ignored = ThreadContext.resetThreadContext()) { + ThreadContext.resetThreadContext(() -> { super.hide(); - } + return null; + }); } @Override diff --git a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java index 56d8469d3c09..473f66b61c33 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java @@ -1473,9 +1473,10 @@ public class AbstractPopup implements JBPopup, ScreenAreaConsumer, AlignedPopup if (myPreferredFocusedComponent != null) { // `resetThreadContext` here is needed because `setVisible` runs event loop // IJPL-161712 - try (AccessToken ignored = ThreadContext.resetThreadContext()) { + ThreadContext.resetThreadContext(() -> { myPreferredFocusedComponent.requestFocus(); - } + return null; + }); } else { _requestFocus(); diff --git a/platform/platform-impl/src/com/intellij/ui/popup/LocalPopupComponentFactory.kt b/platform/platform-impl/src/com/intellij/ui/popup/LocalPopupComponentFactory.kt index a6719ac8959c..21abbfdf5de0 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/LocalPopupComponentFactory.kt +++ b/platform/platform-impl/src/com/intellij/ui/popup/LocalPopupComponentFactory.kt @@ -103,7 +103,7 @@ open class LocalPopupComponentFactory: PopupComponentFactory { if (!dispose) { // `resetThreadContext` here is needed because `setVisible` runs eventloop // IJPL-161712 - resetThreadContext().use { + resetThreadContext { window?.isVisible = false } return diff --git a/platform/platform-tests/testSrc/com/intellij/concurrency/ThreadContextTest.kt b/platform/platform-tests/testSrc/com/intellij/concurrency/ThreadContextTest.kt index 571799920308..d4b9011ff5b1 100644 --- a/platform/platform-tests/testSrc/com/intellij/concurrency/ThreadContextTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/concurrency/ThreadContextTest.kt @@ -14,7 +14,7 @@ class ThreadContextTest { assertNull(currentThreadContextOrNull()) installThreadContext(EmptyCoroutineContext).use { assertNotNull(currentThreadContextOrNull()) - resetThreadContext().use { + resetThreadContext() { assertNull(currentThreadContextOrNull()) } assertNotNull(currentThreadContextOrNull()) diff --git a/platform/platform-tests/testSrc/com/intellij/util/concurrency/ImplicitBlockingContextTest.kt b/platform/platform-tests/testSrc/com/intellij/util/concurrency/ImplicitBlockingContextTest.kt index baa4c434d570..346a508edd80 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/concurrency/ImplicitBlockingContextTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/util/concurrency/ImplicitBlockingContextTest.kt @@ -103,7 +103,7 @@ class ImplicitBlockingContextTest { fun resetThreadContextTakesPriority(): Unit = runBlockingWithCatchingExceptions { withContext(E()) { val context = coroutineContext - resetThreadContext().use { + resetThreadContext { assertEquals(IntellijCoroutines.currentThreadCoroutineContext(), context) assertNull(currentThreadContextOrNull()) assertEquals(EmptyCoroutineContext, currentThreadContext()) diff --git a/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt b/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt index 6695123fd266..e1b62b3b4850 100644 --- a/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt +++ b/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt @@ -874,7 +874,7 @@ abstract class ComponentManagerImpl( final override fun instantiateClass(aClass: Class, pluginId: PluginId): T { checkCanceledIfNotInClassInit() - return resetThreadContext().use { + return resetThreadContext { doInstantiateClass(aClass, pluginId) } } @@ -904,7 +904,7 @@ abstract class ComponentManagerImpl( } final override fun instantiateClassWithConstructorInjection(aClass: Class, key: Any, pluginId: PluginId): T { - return resetThreadContext().use { + return resetThreadContext { instantiateUsingPicoContainer(aClass = aClass, requestorKey = key, pluginId = pluginId, componentManager = this) } } diff --git a/platform/statistics/src/com/intellij/internal/statistic/eventLog/StatisticsFileEventLogger.kt b/platform/statistics/src/com/intellij/internal/statistic/eventLog/StatisticsFileEventLogger.kt index d485cab2f365..c98eff6f3c39 100644 --- a/platform/statistics/src/com/intellij/internal/statistic/eventLog/StatisticsFileEventLogger.kt +++ b/platform/statistics/src/com/intellij/internal/statistic/eventLog/StatisticsFileEventLogger.kt @@ -93,7 +93,7 @@ open class StatisticsFileEventLogger(private val recorderId: String, if (StatisticsRecorderUtil.isTestModeEnabled(recorderId)) { lastEventFlushFuture?.cancel(false) // call flush() instead of logLastEvent() directly so that logLastEvent is executed on the logExecutor thread and not on scheduled executor pool thread - resetThreadContext().use { + resetThreadContext { lastEventFlushFuture = AppExecutorUtil.getAppScheduledExecutorService().schedule(this::flush, eventMergeTimeoutMs, TimeUnit.MILLISECONDS) } } diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java index 232928f3ef6c..2bdb9677882f 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java @@ -33,7 +33,10 @@ import com.intellij.model.psi.PsiSymbolReferenceService; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionUtil; -import com.intellij.openapi.application.*; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.impl.LaterInvocator; import com.intellij.openapi.application.impl.NonBlockingReadActionImpl; import com.intellij.openapi.diagnostic.Logger; @@ -485,7 +488,7 @@ public final class PlatformTestUtil { public static void dispatchAllInvocationEventsInIdeEventQueue() { assertDispatchThreadWithoutWriteAccess(); IdeEventQueue eventQueue = IdeEventQueue.getInstance(); - try (AccessToken ignored = ThreadContext.resetThreadContext()) { + ThreadContext.resetThreadContext(() -> { while (true) { AWTEvent event = eventQueue.peekEvent(); if (event == null) break; @@ -494,7 +497,8 @@ public final class PlatformTestUtil { eventQueue.dispatchEvent(event); } } - } + return null; + }); } /** @@ -516,7 +520,7 @@ public final class PlatformTestUtil { * Dispatch one pending event (if any) in the {@link IdeEventQueue}. Should only be invoked from EDT. */ public static AWTEvent dispatchNextEventIfAny() throws InterruptedException { - try (AccessToken ignored = ThreadContext.resetThreadContext()) { + return ThreadContext.resetThreadContext(() -> { assertEventQueueDispatchThread(); IdeEventQueue eventQueue = IdeEventQueue.getInstance(); AWTEvent event = eventQueue.peekEvent(); @@ -524,7 +528,7 @@ public final class PlatformTestUtil { AWTEvent event1 = eventQueue.getNextEvent(); eventQueue.dispatchEvent(event1); return event1; - } + }); } public static @NotNull StringBuilder print(@NotNull AbstractTreeStructure structure, diff --git a/platform/util/api-dump-experimental.txt b/platform/util/api-dump-experimental.txt index e6f777c395b5..1a5921cbac3c 100644 --- a/platform/util/api-dump-experimental.txt +++ b/platform/util/api-dump-experimental.txt @@ -14,6 +14,7 @@ - sf:installThreadContext(kotlin.coroutines.CoroutineContext,Z):com.intellij.openapi.application.AccessToken - bs:installThreadContext$default(kotlin.coroutines.CoroutineContext,Z,I,java.lang.Object):com.intellij.openapi.application.AccessToken - sf:resetThreadContext():com.intellij.openapi.application.AccessToken +- sf:resetThreadContext(kotlin.jvm.functions.Function0):java.lang.Object *:com.intellij.openapi.diagnostic.ReportingClassSubstitutor - s:getClassToReport(java.lang.Object):java.lang.Class - a:getSubstitutedClass():java.lang.Class diff --git a/platform/util/src/com/intellij/concurrency/threadContext.kt b/platform/util/src/com/intellij/concurrency/threadContext.kt index 0d0a6859dc10..ad917c9924be 100644 --- a/platform/util/src/com/intellij/concurrency/threadContext.kt +++ b/platform/util/src/com/intellij/concurrency/threadContext.kt @@ -269,10 +269,10 @@ If this behavior is unexpected, please consult the documentation for com.intelli } /** - * Resets the current thread context to initial value. - * - * @return handle to restore the previous thread context + * Do not use this function -- it is invisible in stacktraces, and it complicates the debugging of erroneously dropped thread context. + * Consider using the overload with an explicit action. */ +@Deprecated("Use resetThreadContext", ReplaceWith("resetThreadContext(action)")) fun resetThreadContext(): AccessToken { return withThreadLocal(tlCoroutineContext) { _ -> @OptIn(InternalCoroutinesApi::class) @@ -281,6 +281,18 @@ fun resetThreadContext(): AccessToken { } } +/** + * Resets [currentThreadContext] context to [EmptyCoroutineContext]. + * + * This may be useful if you are going to run an event loop synchronously. + * This function is often used before dispatching the AWT events. + */ +fun resetThreadContext(action: () -> T): T { + return resetThreadContext().use { + action() + } +} + /** * Installs [coroutineContext] as the current thread context. * If [replace] is `false` (default) and the current thread already has context, then this function logs an error. diff --git a/platform/util/src/com/intellij/util/concurrency/ContextBiConsumer.java b/platform/util/src/com/intellij/util/concurrency/ContextBiConsumer.java index 724f8cfddcc8..ee3a7486a0f9 100644 --- a/platform/util/src/com/intellij/util/concurrency/ContextBiConsumer.java +++ b/platform/util/src/com/intellij/util/concurrency/ContextBiConsumer.java @@ -2,7 +2,6 @@ package com.intellij.util.concurrency; import com.intellij.concurrency.ThreadContext; -import com.intellij.openapi.application.AccessToken; import org.jetbrains.annotations.Async; import org.jetbrains.annotations.NotNull; @@ -22,10 +21,11 @@ final class ContextBiConsumer implements BiConsumer { @Async.Execute @Override public void accept(T t, U u) { - try (AccessToken ignored = ThreadContext.resetThreadContext()) { + ThreadContext.resetThreadContext(() -> { myChildContext.runInChildContext(() -> { myRunnable.accept(t, u); }); - } + return null; + }); } } diff --git a/platform/util/src/com/intellij/util/concurrency/ContextRunnable.java b/platform/util/src/com/intellij/util/concurrency/ContextRunnable.java index 729a83071578..8976211bf0ab 100644 --- a/platform/util/src/com/intellij/util/concurrency/ContextRunnable.java +++ b/platform/util/src/com/intellij/util/concurrency/ContextRunnable.java @@ -2,7 +2,6 @@ package com.intellij.util.concurrency; import com.intellij.concurrency.ThreadContext; -import com.intellij.openapi.application.AccessToken; import org.jetbrains.annotations.Async; import org.jetbrains.annotations.NotNull; @@ -23,9 +22,10 @@ final class ContextRunnable implements Runnable { @Async.Execute @Override public void run() { - try (AccessToken ignored = ThreadContext.resetThreadContext()) { + ThreadContext.resetThreadContext(() -> { myContext.runInChildContext(myRunnable); - } + return null; + }); } public Runnable getDelegate() { diff --git a/platform/util/src/com/intellij/util/ui/EDT.java b/platform/util/src/com/intellij/util/ui/EDT.java index 8d67d845c021..c0a1169143b4 100644 --- a/platform/util/src/com/intellij/util/ui/EDT.java +++ b/platform/util/src/com/intellij/util/ui/EDT.java @@ -3,7 +3,6 @@ package com.intellij.util.ui; import com.intellij.concurrency.ThreadContext; import com.intellij.diagnostic.ThreadDumper; -import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.ExceptionUtilRt; import com.intellij.util.ReflectionUtil; @@ -101,9 +100,10 @@ public final class EDT { */ @TestOnly public static void dispatchAllInvocationEvents() { - try (AccessToken ignored = ThreadContext.resetThreadContext()) { + ThreadContext.resetThreadContext(() -> { dispatchAllInvocationEventsImpl(); - } + return null; + }); } private static void dispatchAllInvocationEventsImpl() { diff --git a/plugins/stream-debugger/test/com/intellij/debugger/streams/test/TestWithCoroutinesHacks.kt b/plugins/stream-debugger/test/com/intellij/debugger/streams/test/TestWithCoroutinesHacks.kt index 1b8b3885ef37..be80204781a2 100644 --- a/plugins/stream-debugger/test/com/intellij/debugger/streams/test/TestWithCoroutinesHacks.kt +++ b/plugins/stream-debugger/test/com/intellij/debugger/streams/test/TestWithCoroutinesHacks.kt @@ -37,7 +37,7 @@ fun runBlockingWithFlushing(id: String, timeout: Duration, action: suspend C withTimeoutAndDump("runBlockingWithFlushing $id", timeout, action) } - resetThreadContext().use { + resetThreadContext { pumpMessages { task.isCompleted } } task.await()