currentCoroutineContext is back as a choice of the context
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Builders.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Builders.kt
index 27cb49e..cc6aaaf 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Builders.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Builders.kt
@@ -11,6 +11,7 @@
/**
* Launches new coroutine without blocking current thread and returns a reference to the coroutine as a [Job].
* The [context] for the new coroutine must be explicitly specified and must include [CoroutineDispatcher] element.
+ * See [CoroutineDispatcher] for the standard [context] implementations that are provided by `kotlinx.coroutines`.
* The specified context is added to the context of the parent running coroutine (if any) inside which this function
* is invoked. The [Job] of the resulting coroutine is a child of the job of the parent coroutine (if any).
*
@@ -41,6 +42,7 @@
* This function should not be used from coroutine. It is designed to bridge regular code blocking code
* to libraries that are written in suspending style.
* The [context] for the new coroutine must be explicitly specified and must include [CoroutineDispatcher] element.
+ * See [CoroutineDispatcher] for the standard [context] implementations that are provided by `kotlinx.coroutines`.
* The specified context is added to the context of the parent running coroutine (if any) inside which this function
* is invoked. The [Job] of the resulting coroutine is a child of the job of the parent coroutine (if any).
*
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CommonPool.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CommonPool.kt
index db9ee47..3089212 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CommonPool.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CommonPool.kt
@@ -6,10 +6,10 @@
import java.util.concurrent.atomic.AtomicInteger
/**
- * Represents common pool of threads as coroutine dispatcher for compute-intensive tasks.
+ * Represents common pool of shared threads as coroutine dispatcher for compute-intensive tasks.
* It uses [ForkJoinPool] when available, which implements efficient work-stealing algorithm for its queues, so every
* coroutine resumption is dispatched as a separate task even when it already executes inside the pool.
- * When available, it wraps `ForkJoinPool.commonPool()` and provides a similar shared pool where not.
+ * When available, it wraps [ForkJoinPool.commonPool] and provides a similar shared pool where not.
*/
object CommonPool : CoroutineDispatcher() {
private val pool: Executor = findPool()
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CoroutineDispatcher.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CoroutineDispatcher.kt
index 5e0e3b6..055f6f3 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CoroutineDispatcher.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CoroutineDispatcher.kt
@@ -5,8 +5,25 @@
import kotlin.coroutines.ContinuationInterceptor
/**
- * Base class that shall be extended by all coroutine dispatcher implementations so that that [newCoroutineContext] is
- * correctly transferred to a new thread.
+ * Base class that shall be extended by all coroutine dispatcher implementations.
+ *
+ * The following standard implementations are provided by `kotlinx.coroutines`:
+ * * [Here] -- starts coroutine execution _right here_ in the current call-frame until the first suspension. On first
+ * suspension the coroutine builder function returns. The coroutine will resume in whatever thread that is used by the
+ * corresponding suspending function, without mandating any specific threading policy.
+ * This in an appropriate choice for IO-intensive coroutines that do not consume CPU resources.
+ * * [CommonPool] -- immediately returns from the coroutine builder and schedules coroutine execution to
+ * a common pool of shared background threads.
+ * This is an appropriate choice for compute-intensive coroutines that consume a lot of CPU resources.
+ * * Private thread pools can be created with [newSingleThreadContext] and [newFixedThreadPoolContext].
+ * * [currentCoroutineContext] -- inherits the context of the parent coroutine,
+ * but throws [IllegalStateException] if used outside of coroutine. Use [currentCoroutineContextOrDefault]
+ * if a default is needed when outside of coroutine.
+ * This is an appropriate choice for libraries that need to inherit parent coroutine context.
+ * * There are context implementations for UI libraries like `Swing` and `JavaFx` in separate modules.
+ *
+ * This class ensures that [currentCoroutineContext] is correctly transferred to a new thread and that
+ * debugging facilities in [newCoroutineContext] function work properly.
*/
public abstract class CoroutineDispatcher :
AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CurrentCoroutineContext.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CurrentCoroutineContext.kt
index 3e0cde7..165e104 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CurrentCoroutineContext.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CurrentCoroutineContext.kt
@@ -3,6 +3,7 @@
import java.util.concurrent.atomic.AtomicLong
import kotlin.coroutines.AbstractCoroutineContextElement
import kotlin.coroutines.ContinuationInterceptor
+import kotlin.coroutines.ContinuationInterceptor.Key
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
@@ -24,6 +25,26 @@
}
/**
+ * Returns the context of the coroutine that this function is invoked in or throws
+ * [IllegalStateException] if not invoked inside a coroutine.
+ * This function can be used to inherit execution context of the parent coroutine if needed,
+ * like in `launch(currentCoroutineContext()) { ... }`.
+ * This function properly works only for coroutines that are created using [newCoroutineContext] function,
+ * as all coroutine builders in `kotlinx.coroutines` do.
+ */
+public val currentCoroutineContext: CoroutineContext
+ get() = CURRENT_CONTEXT.get() ?: throw IllegalStateException("Not inside a coroutine")
+
+
+/**
+ * Returns the context of the coroutine that this function is invoked in or a specified [default]
+ * if not invoked inside a coroutine. A [default] must be a singleton [CoroutineDispatcher] element.
+ * See [CoroutineDispatcher] for the standard implementations that are provided by `kotlinx.coroutines`.
+ */
+public fun currentCoroutineContextOrDefault(default: CoroutineDispatcher): CoroutineContext =
+ CURRENT_CONTEXT.get() ?: default
+
+/**
* Creates context for the new coroutine with user-specified overrides from [context] parameter.
* The [context] for the new coroutine must be explicitly specified and must include [CoroutineDispatcher] element.
* This function shall be used to start new coroutines.
@@ -40,8 +61,13 @@
* The string "coroutine" is used as a default name.
*/
public fun newCoroutineContext(context: CoroutineContext): CoroutineContext {
- validateContext(context)
- return ((CURRENT_CONTEXT.get() ?: EmptyCoroutineContext) + context).let {
+ val current = CURRENT_CONTEXT.get()
+ if (context !== current) {
+ check(context[ContinuationInterceptor] is CoroutineDispatcher) {
+ "Context of new coroutine must include CoroutineDispatcher"
+ }
+ }
+ return ((current ?: EmptyCoroutineContext) + context).let {
if (DEBUG) it + CoroutineId(COROUTINE_ID.incrementAndGet()) else it
}
}
@@ -49,7 +75,6 @@
/**
* Executes a block using a given default coroutine context.
* This context affects all new coroutines that are started withing the block.
- * The specified [context] is merged onto the current coroutine context (if any).
*/
internal inline fun <T> withDefaultCoroutineContext(context: CoroutineContext, block: () -> T): T {
val oldContext = CURRENT_CONTEXT.get()
@@ -61,12 +86,6 @@
}
}
-private fun validateContext(context: CoroutineContext) {
- check(context[ContinuationInterceptor] is CoroutineDispatcher) {
- "Context of new coroutine must include CoroutineDispatcher"
- }
-}
-
@PublishedApi
internal fun updateContext(oldContext: CoroutineContext?, newContext: CoroutineContext): String? {
if (newContext === oldContext) return null
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Deferred.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Deferred.kt
index 0b36030..020c449 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Deferred.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Deferred.kt
@@ -29,6 +29,7 @@
* Starts new coroutine and returns its result as an implementation of [Deferred].
* The running coroutine is cancelled when the resulting job is cancelled.
* The [context] for the new coroutine must be explicitly specified and must include [CoroutineDispatcher] element.
+ * See [CoroutineDispatcher] for the standard [context] implementations that are provided by `kotlinx.coroutines`.
* The specified context is added to the context of the parent running coroutine (if any) inside which this function
* is invoked. The [Job] of the resulting coroutine is a child of the job of the parent coroutine (if any).
*/