context propagation for global elements

GitOrigin-RevId: 5d85b1fe414ec8aab806f77d57d5069ab19f66aa
This commit is contained in:
Gregory.Shrago
2025-08-29 18:54:52 +00:00
committed by intellij-monorepo-bot
parent f3490e3dbd
commit cd669f4904
4 changed files with 24 additions and 5 deletions
@@ -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<CoroutineContext>(EmptyCoroutineContext) { acc, element ->
if (element is ExternalIntelliJContextElement) acc + element else acc
}
}
return suspendCancellableCoroutine { waiter ->
tryAwait(newState, waiter)
@@ -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 <T : Any> instantiateClass(aClass: Class<T>, pluginId: PluginId): T {
checkCanceledIfNotInClassInit()
val external = currentThreadContext().fold<CoroutineContext>(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 <X> runBlockingInitialization(action: suspend CoroutineScope.() -> X): X {
return prepareThreadContext { ctx -> // reset thread context
val (lockPermitContext, cleanup) = getLockPermitContext(ctx, false)
val external = ctx.fold<CoroutineContext>(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
@@ -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
@@ -108,6 +108,7 @@ import kotlin.coroutines.CoroutineContext
*/
@ApiStatus.Experimental
interface IntelliJContextElement : CoroutineContext.Element {
/**
* Called when _scheduling_ of a child computation is requested.
*