diff --git a/platform/instanceContainer/src/internal/LazyInstanceHolder.kt b/platform/instanceContainer/src/internal/LazyInstanceHolder.kt index 98acd9744fe1..3f06490c25ea 100644 --- a/platform/instanceContainer/src/internal/LazyInstanceHolder.kt +++ b/platform/instanceContainer/src/internal/LazyInstanceHolder.kt @@ -1,6 +1,7 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.platform.instanceContainer.internal +import com.intellij.concurrency.ExternalIntelliJContextElement import com.intellij.concurrency.IntelliJContextElement import com.intellij.platform.instanceContainer.CycleInitializationException import com.intellij.util.findCycle @@ -128,7 +129,9 @@ internal abstract class LazyInstanceHolder( currentCoroutineContext().minusKey(Job) } else { - EmptyCoroutineContext + currentCoroutineContext().fold(EmptyCoroutineContext) { acc, element -> + if (element is ExternalIntelliJContextElement) acc + element else acc + } } return suspendCancellableCoroutine { waiter -> tryAwait(newState, waiter) diff --git a/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt b/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt index da21a79fd5ca..33cf9cd16ba6 100644 --- a/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt +++ b/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt @@ -7,9 +7,7 @@ package com.intellij.serviceContainer import com.intellij.codeWithMe.ClientIdContextElement import com.intellij.codeWithMe.ClientIdContextElementPrecursor -import com.intellij.concurrency.currentTemporaryThreadContextOrNull -import com.intellij.concurrency.resetThreadContext -import com.intellij.concurrency.withThreadLocal +import com.intellij.concurrency.* import com.intellij.configurationStore.ProjectIdManager import com.intellij.configurationStore.SettingsSavingComponent import com.intellij.diagnostic.ActivityCategory @@ -50,6 +48,7 @@ import com.intellij.util.messages.Topic import com.intellij.util.messages.impl.* import com.intellij.util.runSuppressing import kotlinx.coroutines.* +import kotlinx.coroutines.Job import kotlinx.coroutines.internal.intellij.IntellijCoroutines import org.jetbrains.annotations.ApiStatus.Internal import org.jetbrains.annotations.TestOnly @@ -874,8 +873,13 @@ abstract class ComponentManagerImpl( final override fun instantiateClass(aClass: Class, pluginId: PluginId): T { checkCanceledIfNotInClassInit() + val external = currentThreadContext().fold(EmptyCoroutineContext) { acc, element -> + if (element is ExternalIntelliJContextElement) acc + element else acc + } return resetThreadContext { - doInstantiateClass(aClass, pluginId) + installThreadContext(external) { + doInstantiateClass(aClass, pluginId) + } } } @@ -1649,8 +1653,12 @@ private fun throwAlreadyDisposedIfNotUnderIndicatorOrJob(cause: Throwable) { private fun runBlockingInitialization(action: suspend CoroutineScope.() -> X): X { return prepareThreadContext { ctx -> // reset thread context val (lockPermitContext, cleanup) = getLockPermitContext(ctx, false) + val external = ctx.fold(EmptyCoroutineContext) { acc, element -> + if (element is ExternalIntelliJContextElement) acc + element else acc + } try { val contextForInitializer = + external + (ctx.contextModality()?.asContextElement() ?: EmptyCoroutineContext) + // leak modality state into initialization coroutine (ctx[Job] ?: EmptyCoroutineContext) + // bind to caller Job lockPermitContext + // capture whether the caller holds the read lock diff --git a/platform/util/src/com/intellij/concurrency/ExternalIntelliJContextElement.kt b/platform/util/src/com/intellij/concurrency/ExternalIntelliJContextElement.kt new file mode 100644 index 000000000000..9da1ee5fee8e --- /dev/null +++ b/platform/util/src/com/intellij/concurrency/ExternalIntelliJContextElement.kt @@ -0,0 +1,7 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.concurrency + +import org.jetbrains.annotations.ApiStatus + +@ApiStatus.Internal +interface ExternalIntelliJContextElement : IntelliJContextElement \ No newline at end of file diff --git a/platform/util/src/com/intellij/concurrency/IntelliJContextElement.kt b/platform/util/src/com/intellij/concurrency/IntelliJContextElement.kt index 245393c49f87..8faddfe4bf0c 100644 --- a/platform/util/src/com/intellij/concurrency/IntelliJContextElement.kt +++ b/platform/util/src/com/intellij/concurrency/IntelliJContextElement.kt @@ -108,6 +108,7 @@ import kotlin.coroutines.CoroutineContext */ @ApiStatus.Experimental interface IntelliJContextElement : CoroutineContext.Element { + /** * Called when _scheduling_ of a child computation is requested. *