@@ -6,13 +6,20 @@ import kotlin.coroutines.*
6
6
* Defines elements in [CoroutineContext] that are installed into thread context
7
7
* every time the coroutine with this element in the context is resumed on a thread.
8
8
*
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.
11
18
*
12
19
* Example usage looks like this:
13
20
*
14
21
* ```
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
16
23
* class CoroutineName(val name: String) : ThreadContextElement<String> {
17
24
* // declare companion object for a key of this element in coroutine context
18
25
* companion object Key : CoroutineContext.Key<CoroutineName>
@@ -21,14 +28,14 @@ import kotlin.coroutines.*
21
28
* override val key: CoroutineContext.Key<CoroutineName>
22
29
* get() = Key
23
30
*
24
- * // this is invoked before coroutine is resumed on current thread
31
+ * // this is invoked before a coroutine is resumed on the current thread
25
32
* override fun updateThreadContext(context: CoroutineContext): String {
26
33
* val previousName = Thread.currentThread().name
27
34
* Thread.currentThread().name = "$previousName # $name"
28
35
* return previousName
29
36
* }
30
37
*
31
- * // this is invoked after coroutine has suspended on current thread
38
+ * // this is invoked after a coroutine has suspended on the current thread
32
39
* override fun restoreThreadContext(context: CoroutineContext, oldState: String) {
33
40
* Thread.currentThread().name = oldState
34
41
* }
@@ -38,13 +45,13 @@ import kotlin.coroutines.*
38
45
* launch(Dispatchers.Main + CoroutineName("Progress bar coroutine")) { ... }
39
46
* ```
40
47
*
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
43
50
* this coroutine suspends.
44
51
*
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.
46
53
*
47
- * ### Reentrancy and thread- safety
54
+ * ### Reentrancy and thread safety
48
55
*
49
56
* Correct implementations of this interface must expect that calls to [restoreThreadContext]
50
57
* may happen in parallel to the subsequent [updateThreadContext] and [restoreThreadContext] operations.
@@ -55,50 +62,65 @@ import kotlin.coroutines.*
55
62
*/
56
63
public interface ThreadContextElement <S > : CoroutineContext .Element {
57
64
/* *
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.
64
74
*
65
- * @param context the coroutine context .
75
+ * @param context the context of the coroutine that's being started or resumed .
66
76
*/
67
77
public fun updateThreadContext (context : CoroutineContext ): S
68
78
69
79
/* *
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.
77
81
*
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].
80
92
*/
81
93
public fun restoreThreadContext (context : CoroutineContext , oldState : S )
82
94
}
83
95
84
96
/* *
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
98
115
* correctly, regardless of the coroutine's structured concurrency.
99
116
*
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:
102
124
*
103
125
* ```
104
126
* class TraceContextElement(private val traceData: TraceData?) : CopyableThreadContextElement<TraceData?> {
@@ -117,14 +139,14 @@ public interface ThreadContextElement<S> : CoroutineContext.Element {
117
139
* }
118
140
*
119
141
* 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
122
144
* // child coroutine visible to the child.
123
145
* return TraceContextElement(traceThreadLocal.get()?.copy())
124
146
* }
125
147
*
126
148
* 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
128
150
* // the parent coroutine has an element in the context and
129
151
* // an element with the same key was also
130
152
* // explicitly passed to the child coroutine.
@@ -135,8 +157,8 @@ public interface ThreadContextElement<S> : CoroutineContext.Element {
135
157
* }
136
158
* ```
137
159
*
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.
140
162
*
141
163
* ### Reentrancy and thread-safety
142
164
*
@@ -164,7 +186,7 @@ public interface ThreadContextElement<S> : CoroutineContext.Element {
164
186
public interface CopyableThreadContextElement <S > : ThreadContextElement <S > {
165
187
166
188
/* *
167
- * Returns a [CopyableThreadContextElement] to replace `this` `CopyableThreadContextElement` in the child
189
+ * Returns the [CopyableThreadContextElement] to replace `this` `CopyableThreadContextElement` in the child
168
190
* coroutine's context that is under construction if the added context does not contain an element with the same [key].
169
191
*
170
192
* 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> {
176
198
public fun copyForChild (): CopyableThreadContextElement <S >
177
199
178
200
/* *
179
- * Returns a [CopyableThreadContextElement] to replace `this` `CopyableThreadContextElement` in the child
201
+ * Returns the [CopyableThreadContextElement] to replace `this` `CopyableThreadContextElement` in the child
180
202
* coroutine's context that is under construction if the added context does contain an element with the same [key].
181
203
*
182
204
* This method is invoked on the original element, accepting as the parameter
0 commit comments