Skip to content

Commit ed7b864

Browse files
committed
currentCoroutineContext is back as a choice of the context
1 parent dbcd841 commit ed7b864

File tree

6 files changed

+53
-13
lines changed

6 files changed

+53
-13
lines changed

kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Builders.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import kotlin.coroutines.suspendCoroutine
1111
/**
1212
* Launches new coroutine without blocking current thread and returns a reference to the coroutine as a [Job].
1313
* The [context] for the new coroutine must be explicitly specified and must include [CoroutineDispatcher] element.
14+
* See [CoroutineDispatcher] for the standard [context] implementations that are provided by `kotlinx.coroutines`.
1415
* The specified context is added to the context of the parent running coroutine (if any) inside which this function
1516
* is invoked. The [Job] of the resulting coroutine is a child of the job of the parent coroutine (if any).
1617
*
@@ -41,6 +42,7 @@ public suspend fun <T> run(context: CoroutineContext, block: suspend () -> T): T
4142
* This function should not be used from coroutine. It is designed to bridge regular code blocking code
4243
* to libraries that are written in suspending style.
4344
* The [context] for the new coroutine must be explicitly specified and must include [CoroutineDispatcher] element.
45+
* See [CoroutineDispatcher] for the standard [context] implementations that are provided by `kotlinx.coroutines`.
4446
* The specified context is added to the context of the parent running coroutine (if any) inside which this function
4547
* is invoked. The [Job] of the resulting coroutine is a child of the job of the parent coroutine (if any).
4648
*

kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CommonPool.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import java.util.concurrent.ForkJoinPool
66
import java.util.concurrent.atomic.AtomicInteger
77

88
/**
9-
* Represents common pool of threads as coroutine dispatcher for compute-intensive tasks.
9+
* Represents common pool of shared threads as coroutine dispatcher for compute-intensive tasks.
1010
* It uses [ForkJoinPool] when available, which implements efficient work-stealing algorithm for its queues, so every
1111
* coroutine resumption is dispatched as a separate task even when it already executes inside the pool.
12-
* When available, it wraps `ForkJoinPool.commonPool()` and provides a similar shared pool where not.
12+
* When available, it wraps [ForkJoinPool.commonPool] and provides a similar shared pool where not.
1313
*/
1414
object CommonPool : CoroutineDispatcher() {
1515
private val pool: Executor = findPool()

kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CoroutineDispatcher.kt

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,25 @@ import kotlin.coroutines.Continuation
55
import kotlin.coroutines.ContinuationInterceptor
66

77
/**
8-
* Base class that shall be extended by all coroutine dispatcher implementations so that that [newCoroutineContext] is
9-
* correctly transferred to a new thread.
8+
* Base class that shall be extended by all coroutine dispatcher implementations.
9+
*
10+
* The following standard implementations are provided by `kotlinx.coroutines`:
11+
* * [Here] -- starts coroutine execution _right here_ in the current call-frame until the first suspension. On first
12+
* suspension the coroutine builder function returns. The coroutine will resume in whatever thread that is used by the
13+
* corresponding suspending function, without mandating any specific threading policy.
14+
* This in an appropriate choice for IO-intensive coroutines that do not consume CPU resources.
15+
* * [CommonPool] -- immediately returns from the coroutine builder and schedules coroutine execution to
16+
* a common pool of shared background threads.
17+
* This is an appropriate choice for compute-intensive coroutines that consume a lot of CPU resources.
18+
* * Private thread pools can be created with [newSingleThreadContext] and [newFixedThreadPoolContext].
19+
* * [currentCoroutineContext] -- inherits the context of the parent coroutine,
20+
* but throws [IllegalStateException] if used outside of coroutine. Use [currentCoroutineContextOrDefault]
21+
* if a default is needed when outside of coroutine.
22+
* This is an appropriate choice for libraries that need to inherit parent coroutine context.
23+
* * There are context implementations for UI libraries like `Swing` and `JavaFx` in separate modules.
24+
*
25+
* This class ensures that [currentCoroutineContext] is correctly transferred to a new thread and that
26+
* debugging facilities in [newCoroutineContext] function work properly.
1027
*/
1128
public abstract class CoroutineDispatcher :
1229
AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {

kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CurrentCoroutineContext.kt

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package kotlinx.coroutines.experimental
33
import java.util.concurrent.atomic.AtomicLong
44
import kotlin.coroutines.AbstractCoroutineContextElement
55
import kotlin.coroutines.ContinuationInterceptor
6+
import kotlin.coroutines.ContinuationInterceptor.Key
67
import kotlin.coroutines.CoroutineContext
78
import kotlin.coroutines.EmptyCoroutineContext
89

@@ -23,6 +24,26 @@ public object Here : CoroutineDispatcher() {
2324
override fun dispatch(block: Runnable) { throw UnsupportedOperationException() }
2425
}
2526

27+
/**
28+
* Returns the context of the coroutine that this function is invoked in or throws
29+
* [IllegalStateException] if not invoked inside a coroutine.
30+
* This function can be used to inherit execution context of the parent coroutine if needed,
31+
* like in `launch(currentCoroutineContext()) { ... }`.
32+
* This function properly works only for coroutines that are created using [newCoroutineContext] function,
33+
* as all coroutine builders in `kotlinx.coroutines` do.
34+
*/
35+
public val currentCoroutineContext: CoroutineContext
36+
get() = CURRENT_CONTEXT.get() ?: throw IllegalStateException("Not inside a coroutine")
37+
38+
39+
/**
40+
* Returns the context of the coroutine that this function is invoked in or a specified [default]
41+
* if not invoked inside a coroutine. A [default] must be a singleton [CoroutineDispatcher] element.
42+
* See [CoroutineDispatcher] for the standard implementations that are provided by `kotlinx.coroutines`.
43+
*/
44+
public fun currentCoroutineContextOrDefault(default: CoroutineDispatcher): CoroutineContext =
45+
CURRENT_CONTEXT.get() ?: default
46+
2647
/**
2748
* Creates context for the new coroutine with user-specified overrides from [context] parameter.
2849
* The [context] for the new coroutine must be explicitly specified and must include [CoroutineDispatcher] element.
@@ -40,16 +61,20 @@ public object Here : CoroutineDispatcher() {
4061
* The string "coroutine" is used as a default name.
4162
*/
4263
public fun newCoroutineContext(context: CoroutineContext): CoroutineContext {
43-
validateContext(context)
44-
return ((CURRENT_CONTEXT.get() ?: EmptyCoroutineContext) + context).let {
64+
val current = CURRENT_CONTEXT.get()
65+
if (context !== current) {
66+
check(context[ContinuationInterceptor] is CoroutineDispatcher) {
67+
"Context of new coroutine must include CoroutineDispatcher"
68+
}
69+
}
70+
return ((current ?: EmptyCoroutineContext) + context).let {
4571
if (DEBUG) it + CoroutineId(COROUTINE_ID.incrementAndGet()) else it
4672
}
4773
}
4874

4975
/**
5076
* Executes a block using a given default coroutine context.
5177
* This context affects all new coroutines that are started withing the block.
52-
* The specified [context] is merged onto the current coroutine context (if any).
5378
*/
5479
internal inline fun <T> withDefaultCoroutineContext(context: CoroutineContext, block: () -> T): T {
5580
val oldContext = CURRENT_CONTEXT.get()
@@ -61,12 +86,6 @@ internal inline fun <T> withDefaultCoroutineContext(context: CoroutineContext, b
6186
}
6287
}
6388

64-
private fun validateContext(context: CoroutineContext) {
65-
check(context[ContinuationInterceptor] is CoroutineDispatcher) {
66-
"Context of new coroutine must include CoroutineDispatcher"
67-
}
68-
}
69-
7089
@PublishedApi
7190
internal fun updateContext(oldContext: CoroutineContext?, newContext: CoroutineContext): String? {
7291
if (newContext === oldContext) return null

kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Deferred.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public interface Deferred<out T> : Job {
2929
* Starts new coroutine and returns its result as an implementation of [Deferred].
3030
* The running coroutine is cancelled when the resulting job is cancelled.
3131
* The [context] for the new coroutine must be explicitly specified and must include [CoroutineDispatcher] element.
32+
* See [CoroutineDispatcher] for the standard [context] implementations that are provided by `kotlinx.coroutines`.
3233
* The specified context is added to the context of the parent running coroutine (if any) inside which this function
3334
* is invoked. The [Job] of the resulting coroutine is a child of the job of the parent coroutine (if any).
3435
*/

kotlinx-coroutines-jdk8/src/main/kotlin/kotlinx/coroutines/experimental/future/Future.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import kotlin.coroutines.startCoroutine
1212
*
1313
* The running coroutine is cancelled when the resulting future is cancelled or otherwise completed
1414
* The [context] for the new coroutine must include [CoroutineDispatcher] element.
15+
* See [CoroutineDispatcher] for the standard [context] implementations that are provided by `kotlinx.coroutines`.
1516
* The specified context is added to the context of the parent running coroutine (if any) inside which this function
1617
* is invoked. The [Job] of the resulting coroutine is a child of the job of the parent coroutine (if any).
1718
*

0 commit comments

Comments
 (0)