Skip to content

Commit aedbcc7

Browse files
authored
Clarify implementation contract of ThreadContextElement and CopyableThreadContextElement (#3314)
1 parent cc5b86a commit aedbcc7

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

integration/kotlinx-coroutines-slf4j/src/MDCContext.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public typealias MDCContextMap = Map<String, String>?
2828
* }
2929
* ```
3030
*
31-
* Note that you cannot update MDC context from inside of the coroutine simply
31+
* Note that you cannot update MDC context from inside the coroutine simply
3232
* using [MDC.put]. These updates are going to be lost on the next suspension and
3333
* reinstalled to the MDC context that was captured or explicitly specified in
3434
* [contextMap] when this object was created on the next resumption.

kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@ import kotlin.coroutines.*
4848
* this coroutine suspends.
4949
*
5050
* To use [ThreadLocal] variable within the coroutine use [ThreadLocal.asContextElement][asContextElement] function.
51+
*
52+
* ### Reentrancy and thread-safety
53+
*
54+
* Correct implementations of this interface must expect that calls to [restoreThreadContext]
55+
* may happen in parallel to the subsequent [updateThreadContext] and [restoreThreadContext] operations.
56+
* See [CopyableThreadContextElement] for advanced interleaving details.
57+
*
58+
* All implementations of [ThreadContextElement] should be thread-safe and guard their internal mutable state
59+
* within an element accordingly.
5160
*/
5261
public interface ThreadContextElement<S> : CoroutineContext.Element {
5362
/**
@@ -133,6 +142,27 @@ public interface ThreadContextElement<S> : CoroutineContext.Element {
133142
*
134143
* A coroutine using this mechanism can safely call Java code that assumes the corresponding thread local element's
135144
* value is installed into the target thread local.
145+
*
146+
* ### Reentrancy and thread-safety
147+
*
148+
* Correct implementations of this interface must expect that calls to [restoreThreadContext]
149+
* may happen in parallel to the subsequent [updateThreadContext] and [restoreThreadContext] operations.
150+
*
151+
* Even though an element is copied for each child coroutine, an implementation should be able to handle the following
152+
* interleaving when a coroutine with the corresponding element is launched on a multithreaded dispatcher:
153+
*
154+
* ```
155+
* coroutine.updateThreadContext() // Thread #1
156+
* ... coroutine body ...
157+
* // suspension + immediate dispatch happen here
158+
* coroutine.updateThreadContext() // Thread #2, coroutine is already resumed
159+
* // ... coroutine body after suspension point on Thread #2 ...
160+
* coroutine.restoreThreadContext() // Thread #1, is invoked late because Thread #1 is slow
161+
* coroutine.restoreThreadContext() // Thread #2, may happen in parallel with the previous restore
162+
* ```
163+
*
164+
* All implementations of [CopyableThreadContextElement] should be thread-safe and guard their internal mutable state
165+
* within an element accordingly.
136166
*/
137167
@DelicateCoroutinesApi
138168
@ExperimentalCoroutinesApi

0 commit comments

Comments
 (0)