blob: 8411c5c65afcf27523febe9a5022ed1be3761ec0 [file] [log] [blame]
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:OptIn(ExperimentalContracts::class)
@file:Suppress("DEPRECATION_ERROR")
package kotlinx.coroutines
import kotlinx.coroutines.internal.*
import kotlinx.coroutines.intrinsics.*
import kotlin.contracts.*
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
import kotlin.jvm.*
/**
* Creates a _supervisor_ job object in an active state.
* Children of a supervisor job can fail independently of each other.
*
* A failure or cancellation of a child does not cause the supervisor job to fail and does not affect its other children,
* so a supervisor can implement a custom policy for handling failures of its children:
*
* * A failure of a child job that was created using [launch][CoroutineScope.launch] can be handled via [CoroutineExceptionHandler] in the context.
* * A failure of a child job that was created using [async][CoroutineScope.async] can be handled via [Deferred.await] on the resulting deferred value.
*
* If [parent] job is specified, then this supervisor job becomes a child job of its parent and is cancelled when its
* parent fails or is cancelled. All this supervisor's children are cancelled in this case, too. The invocation of
* [cancel][Job.cancel] with exception (other than [CancellationException]) on this supervisor job also cancels parent.
*
* @param parent an optional parent job.
*/
@Suppress("FunctionName")
public fun SupervisorJob(parent: Job? = null) : CompletableJob = SupervisorJobImpl(parent)
/** @suppress Binary compatibility only */
@Suppress("FunctionName")
@Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
@JvmName("SupervisorJob")
public fun SupervisorJob0(parent: Job? = null) : Job = SupervisorJob(parent)
/**
* Creates a [CoroutineScope] with [SupervisorJob] and calls the specified suspend block with this scope.
* The provided scope inherits its [coroutineContext][CoroutineScope.coroutineContext] from the outer scope, but overrides
* context's [Job] with [SupervisorJob].
* This function returns as soon as the given block and all its child coroutines are completed.
*
* Unlike [coroutineScope], a failure of a child does not cause this scope to fail and does not affect its other children,
* so a custom policy for handling failures of its children can be implemented. See [SupervisorJob] for additional details.
* A failure of the scope itself (exception thrown in the [block] or external cancellation) fails the scope with all its children,
* but does not cancel parent job.
*
* The method may throw a [CancellationException] if the current job was cancelled externally,
* or rethrow an exception thrown by the given [block].
*/
public suspend fun <R> supervisorScope(block: suspend CoroutineScope.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return suspendCoroutineUninterceptedOrReturn { uCont ->
val coroutine = SupervisorCoroutine(uCont.context, uCont)
coroutine.startUndispatchedOrReturn(coroutine, block)
}
}
private class SupervisorJobImpl(parent: Job?) : JobImpl(parent) {
override fun childCancelled(cause: Throwable): Boolean = false
}
private class SupervisorCoroutine<in T>(
context: CoroutineContext,
uCont: Continuation<T>
) : ScopeCoroutine<T>(context, uCont) {
override fun childCancelled(cause: Throwable): Boolean = false
}