@@ -6,13 +6,20 @@ import kotlin.coroutines.*
66 * Defines elements in [CoroutineContext] that are installed into thread context
77 * every time the coroutine with this element in the context is resumed on a thread.
88 *
9- * Implementations of this interface define a type [S] of the thread-local state that they need to store on
10- * resume of a coroutine and restore later on suspend. The infrastructure provides the corresponding storage.
9+ * In this context, by a "thread" we mean an environment where coroutines are executed in parallel to coroutines
10+ * other threads.
11+ * On JVM and Native, this is the same as an operating system thread.
12+ * On JS, Wasm/JS, and Wasm/WASI, because coroutines can not actually execute in parallel,
13+ * we say that there is a single thread running all coroutines.
14+ *
15+ * Implementations of this interface define a type [S] of the thread-local state that they need to store
16+ * when the coroutine is resumed and restore later on when it suspends.
17+ * The coroutines infrastructure provides the corresponding storage.
1118 *
1219 * Example usage looks like this:
1320 *
1421 * ```
15- * // Appends "name" of a coroutine to a current thread name when coroutine is executed
22+ * // Appends "name" of a coroutine to the current thread name when a coroutine is executed
1623 * class CoroutineName(val name: String) : ThreadContextElement<String> {
1724 * // declare companion object for a key of this element in coroutine context
1825 * companion object Key : CoroutineContext.Key<CoroutineName>
@@ -21,14 +28,14 @@ import kotlin.coroutines.*
2128 * override val key: CoroutineContext.Key<CoroutineName>
2229 * get() = Key
2330 *
24- * // this is invoked before coroutine is resumed on current thread
31+ * // this is invoked before a coroutine is resumed on the current thread
2532 * override fun updateThreadContext(context: CoroutineContext): String {
2633 * val previousName = Thread.currentThread().name
2734 * Thread.currentThread().name = "$previousName # $name"
2835 * return previousName
2936 * }
3037 *
31- * // this is invoked after coroutine has suspended on current thread
38+ * // this is invoked after a coroutine has suspended on the current thread
3239 * override fun restoreThreadContext(context: CoroutineContext, oldState: String) {
3340 * Thread.currentThread().name = oldState
3441 * }
@@ -38,13 +45,13 @@ import kotlin.coroutines.*
3845 * launch(Dispatchers.Main + CoroutineName("Progress bar coroutine")) { ... }
3946 * ```
4047 *
41- * Every time this coroutine is resumed on a thread, UI thread name is updated to
42- * "UI thread original name # Progress bar coroutine" and the thread name is restored to the original one when
48+ * Every time this coroutine is resumed on a thread, the name of the thread backing [Dispatchers.Main] is updated to
49+ * "UI thread original name # Progress bar coroutine", and the thread name is restored to the original one when
4350 * this coroutine suspends.
4451 *
45- * To use [ ThreadLocal] variable within the coroutine use [ ThreadLocal.asContextElement][asContextElement] function.
52+ * On JVM, to use a ` ThreadLocal` variable within the coroutine, use the ` ThreadLocal.asContextElement` function.
4653 *
47- * ### Reentrancy and thread- safety
54+ * ### Reentrancy and thread safety
4855 *
4956 * Correct implementations of this interface must expect that calls to [restoreThreadContext]
5057 * may happen in parallel to the subsequent [updateThreadContext] and [restoreThreadContext] operations.
@@ -55,50 +62,65 @@ import kotlin.coroutines.*
5562 */
5663public interface ThreadContextElement <S > : CoroutineContext .Element {
5764 /* *
58- * Updates context of the current thread.
59- * This function is invoked before the coroutine in the specified [context] is resumed in the current thread
60- * when the context of the coroutine this element.
61- * The result of this function is the old value of the thread-local state that will be passed to [restoreThreadContext].
62- * This method should handle its own exceptions and do not rethrow it. Thrown exceptions will leave coroutine which
63- * context is updated in an undefined state and may crash an application.
65+ * Updates the context of the current thread.
66+ *
67+ * This function is invoked before the coroutine in the specified [context] is started or resumed
68+ * in the current thread when this element is present in the context of the coroutine.
69+ * The result of this function is the old value of the thread-local state
70+ * that will be passed to [restoreThreadContext] when the coroutine eventually suspends or completes.
71+ * This method should handle its own exceptions and not rethrow them.
72+ * Thrown exceptions will leave the coroutine whose context is updated in an undefined state
73+ * and may crash the application.
6474 *
65- * @param context the coroutine context .
75+ * @param context the context of the coroutine that's being started or resumed .
6676 */
6777 public fun updateThreadContext (context : CoroutineContext ): S
6878
6979 /* *
70- * Restores context of the current thread.
71- * This function is invoked after the coroutine in the specified [context] is suspended in the current thread
72- * if [updateThreadContext] was previously invoked on resume of this coroutine.
73- * The value of [oldState] is the result of the previous invocation of [updateThreadContext] and it should
74- * be restored in the thread-local state by this function.
75- * This method should handle its own exceptions and do not rethrow it. Thrown exceptions will leave coroutine which
76- * context is updated in an undefined state and may crash an application.
80+ * Restores the context of the current thread.
7781 *
78- * @param context the coroutine context.
79- * @param oldState the value returned by the previous invocation of [updateThreadContext].
82+ * This function is invoked after the coroutine in the specified [context] has suspended or finished
83+ * in the current thread if [updateThreadContext] was previously invoked when this coroutine was started or resumed.
84+ * [oldState] is the result of the preceding invocation of [updateThreadContext],
85+ * and this value should be restored in the thread-local state by this function.
86+ * This method should handle its own exceptions and not rethrow them.
87+ * Thrown exceptions will leave the coroutine whose context is updated in an undefined state
88+ * and may crash the application.
89+ *
90+ * @param context the context of the coroutine that has suspended or finished.
91+ * @param oldState the value returned by the preceding invocation of [updateThreadContext].
8092 */
8193 public fun restoreThreadContext (context : CoroutineContext , oldState : S )
8294}
8395
8496/* *
85- * A [ThreadContextElement] copied whenever a child coroutine inherits a context containing it.
86- *
87- * When an API uses a _mutable_ [ThreadLocal] for consistency, a [CopyableThreadContextElement]
88- * can give coroutines "coroutine-safe" write access to that `ThreadLocal`.
89- *
90- * A write made to a `ThreadLocal` with a matching [CopyableThreadContextElement] by a coroutine
91- * will be visible to _itself_ and any child coroutine launched _after_ that write.
92- *
93- * Writes will not be visible to the parent coroutine, peer coroutines, or coroutines that happen
94- * to use the same thread. Writes made to the `ThreadLocal` by the parent coroutine _after_
95- * launching a child coroutine will not be visible to that child coroutine.
96- *
97- * This can be used to allow a coroutine to use a mutable ThreadLocal API transparently and
97+ * A [ThreadContextElement] that is copied whenever a child coroutine inherits a context containing it.
98+ *
99+ * [ThreadContextElement] can be used to ensure that when several coroutines share the same thread,
100+ * they can each have their personal (though immutable) thread-local state without affecting the other coroutines.
101+ * Often, however, it is desirable to propagate the thread-local state across coroutine suspensions
102+ * and to child coroutines.
103+ * A [CopyableThreadContextElement] is an instrument for implementing exactly this kind of
104+ * hierarchical mutable thread-local state.
105+ *
106+ * A change made to a thread-local value with a matching [CopyableThreadContextElement] by a coroutine
107+ * will be visible to _itself_ (even after the coroutine suspends and subsequently resumes)
108+ * and any child coroutine launched _after_ that write.
109+ * Changes introduced to the thread-local value by the parent coroutine _after_ launching a child coroutine
110+ * will not be visible to that child coroutine.
111+ * Changes will not be visible to the parent coroutine, peer coroutines, or coroutines that also have
112+ * this [CopyableThreadContextElement] in their context and simply happen to use the same thread.
113+ *
114+ * This can be used to allow a coroutine to use a mutable-thread-local-value-based API transparently and
98115 * correctly, regardless of the coroutine's structured concurrency.
99116 *
100- * This example adapts a `ThreadLocal` method trace to be "coroutine local" while the method trace
101- * is in a coroutine:
117+ * The changes *may* be visible to unrelated coroutines that are launched on the same thread if those coroutines
118+ * do not have a [CopyableThreadContextElement] with the same key in their context.
119+ * Because of this, it is an error to access a thread-local value from a coroutine without the corresponding
120+ * [CopyableThreadContextElement] when other coroutines may have modified it.
121+ *
122+ * This example adapts thread-local-value-based method tracing to follow coroutine switches and child coroutine creation.
123+ * when the tracing happens inside a coroutine:
102124 *
103125 * ```
104126 * class TraceContextElement(private val traceData: TraceData?) : CopyableThreadContextElement<TraceData?> {
@@ -117,14 +139,14 @@ public interface ThreadContextElement<S> : CoroutineContext.Element {
117139 * }
118140 *
119141 * override fun copyForChild(): TraceContextElement {
120- * // Copy from the ThreadLocal source of truth at child coroutine launch time. This makes
121- * // ThreadLocal writes between resumption of the parent coroutine and the launch of the
142+ * // Copy from the ThreadLocal source of truth at the child coroutine launch time. This makes
143+ * // ThreadLocal writes between the resumption of the parent coroutine and the launch of the
122144 * // child coroutine visible to the child.
123145 * return TraceContextElement(traceThreadLocal.get()?.copy())
124146 * }
125147 *
126148 * override fun mergeForChild(overwritingElement: CoroutineContext.Element): CoroutineContext {
127- * // Merge operation defines how to handle situations when both
149+ * // The merge operation defines how to handle situations when both
128150 * // the parent coroutine has an element in the context and
129151 * // an element with the same key was also
130152 * // explicitly passed to the child coroutine.
@@ -135,8 +157,8 @@ public interface ThreadContextElement<S> : CoroutineContext.Element {
135157 * }
136158 * ```
137159 *
138- * A coroutine using this mechanism can safely call Java code that assumes the corresponding thread local element's
139- * value is installed into the target thread local.
160+ * A coroutine using this mechanism can safely call coroutine-oblivious code that assumes
161+ * a specific thread local element's value is installed into the target thread local.
140162 *
141163 * ### Reentrancy and thread-safety
142164 *
@@ -164,7 +186,7 @@ public interface ThreadContextElement<S> : CoroutineContext.Element {
164186public interface CopyableThreadContextElement <S > : ThreadContextElement <S > {
165187
166188 /* *
167- * Returns a [CopyableThreadContextElement] to replace `this` `CopyableThreadContextElement` in the child
189+ * Returns the [CopyableThreadContextElement] to replace `this` `CopyableThreadContextElement` in the child
168190 * coroutine's context that is under construction if the added context does not contain an element with the same [key].
169191 *
170192 * This function is called on the element each time a new coroutine inherits a context containing it,
@@ -176,7 +198,7 @@ public interface CopyableThreadContextElement<S> : ThreadContextElement<S> {
176198 public fun copyForChild (): CopyableThreadContextElement <S >
177199
178200 /* *
179- * Returns a [CopyableThreadContextElement] to replace `this` `CopyableThreadContextElement` in the child
201+ * Returns the [CopyableThreadContextElement] to replace `this` `CopyableThreadContextElement` in the child
180202 * coroutine's context that is under construction if the added context does contain an element with the same [key].
181203 *
182204 * This method is invoked on the original element, accepting as the parameter
0 commit comments