Skip to content

Commit

Permalink
SupervisorJob & supervisorScope
Browse files Browse the repository at this point in the history
Tentative implementation and name, no docs yet

Fixes #576
  • Loading branch information
elizarov committed Sep 21, 2018
1 parent 73a2583 commit 5d1a76e
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,12 @@ public final class kotlinx/coroutines/experimental/ScheduledKt {
public static synthetic fun withTimeoutOrNull$default (JLjava/util/concurrent/TimeUnit;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/experimental/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
}

public final class kotlinx/coroutines/experimental/SupervisorKt {
public static final fun SupervisorJob (Lkotlinx/coroutines/experimental/Job;)Lkotlinx/coroutines/experimental/Job;
public static synthetic fun SupervisorJob$default (Lkotlinx/coroutines/experimental/Job;ILjava/lang/Object;)Lkotlinx/coroutines/experimental/Job;
public static final fun supervisorScope (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object;
}

public abstract interface class kotlinx/coroutines/experimental/ThreadContextElement : kotlin/coroutines/experimental/CoroutineContext$Element {
public abstract fun restoreThreadContext (Lkotlin/coroutines/experimental/CoroutineContext;Ljava/lang/Object;)V
public abstract fun updateThreadContext (Lkotlin/coroutines/experimental/CoroutineContext;)Ljava/lang/Object;
Expand Down
41 changes: 41 additions & 0 deletions common/kotlinx-coroutines-core-common/src/Supervisor.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.coroutines.experimental

import kotlin.coroutines.experimental.*

@Suppress("FunctionName")
public fun SupervisorJob(parent: Job? = null) : Job = SupervisorJobImpl(parent)

public suspend fun <R> supervisorScope(block: suspend CoroutineScope.() -> R): R {
// todo: optimize implementation to a single allocated object
// todo: fix copy-and-paste with coroutineScope
val owner = SupervisorCoroutine<R>(coroutineContext)
owner.start(CoroutineStart.UNDISPATCHED, owner, block)
owner.join()
if (owner.isCancelled) {
throw owner.getCancellationException().let { it.cause ?: it }
}
val state = owner.state
if (state is CompletedExceptionally) {
throw state.cause
}
@Suppress("UNCHECKED_CAST")
return state as R

}

private class SupervisorJobImpl(parent: Job?) : JobSupport(true) {
init { initParentJobInternal(parent) }
override val onFailComplete get() = true
override val handlesException: Boolean get() = false
override fun childFailed(cause: Throwable): Boolean = false
}

private class SupervisorCoroutine<R>(
parentContext: CoroutineContext
) : AbstractCoroutine<R>(parentContext, true) {
override fun childFailed(cause: Throwable): Boolean = false
}
58 changes: 58 additions & 0 deletions common/kotlinx-coroutines-core-common/test/SupervisorTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

@file:Suppress("NAMED_ARGUMENTS_NOT_ALLOWED") // KT-21913

package kotlinx.coroutines.experimental

import kotlin.test.*

class SupervisorTest : TestBase() {
@Test
fun testSupervisorJob() = runTest(
unhandled = listOf(
{ it -> it is TestException2 },
{ it -> it is TestException1 }
)
) {
expect(1)
val supervisor = SupervisorJob()
val job1 = launch(supervisor + CoroutineName("job1")) {
expect(2)
yield() // to second child
expect(4)
throw TestException1()
}
val job2 = launch(supervisor + CoroutineName("job2")) {
expect(3)
throw TestException2()
}
joinAll(job1, job2)
finish(5)
assertTrue(job1.isFailed)
assertTrue(job2.isFailed)
}

@Test
fun testSupervisorScope() = runTest(
unhandled = listOf(
{ it -> it is TestException1 },
{ it -> it is TestException2 }
)
) {
val result = supervisorScope {
launch {
throw TestException1()
}
launch {
throw TestException2()
}
"OK"
}
assertEquals("OK", result)
}

private class TestException1 : Exception()
private class TestException2 : Exception()
}
1 change: 0 additions & 1 deletion core/kotlinx-coroutines-core/test/TestBase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ public actual open class TestBase actual constructor() {
!unhandled[exCount - 1](e) ->
printError("Unhandled exception was unexpected: $e", e)
}
context[Job]?.cancel(e)
})
} catch (e: Throwable) {
ex = e
Expand Down
1 change: 0 additions & 1 deletion js/kotlinx-coroutines-core-js/test/TestBase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ public actual open class TestBase actual constructor() {
!unhandled[exCount - 1](e) ->
printError("Unhandled exception was unexpected: $e", e)
}
context[Job]?.cancel(e)
}).catch { e ->
ex = e
if (expected != null) {
Expand Down
1 change: 0 additions & 1 deletion native/kotlinx-coroutines-core-native/test/TestBase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ public actual open class TestBase actual constructor() {
!unhandled[exCount - 1](e) ->
printError("Unhandled exception was unexpected: $e", e)
}
context[Job]?.cancel(e)
})
} catch (e: Throwable) {
ex = e
Expand Down

0 comments on commit 5d1a76e

Please sign in to comment.