Skip to content

Commit 90b01ea

Browse files
committed
SupervisorJob & supervisorScope
Tentative implementation and name, no docs yet Fixes #576
1 parent 309afa2 commit 90b01ea

File tree

6 files changed

+105
-3
lines changed

6 files changed

+105
-3
lines changed

binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt

+6
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,12 @@ public final class kotlinx/coroutines/ScheduledKt {
490490
public static synthetic fun withTimeoutOrNull$default (JLjava/util/concurrent/TimeUnit;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
491491
}
492492

493+
public final class kotlinx/coroutines/experimental/SupervisorKt {
494+
public static final fun SupervisorJob (Lkotlinx/coroutines/experimental/Job;)Lkotlinx/coroutines/experimental/Job;
495+
public static synthetic fun SupervisorJob$default (Lkotlinx/coroutines/experimental/Job;ILjava/lang/Object;)Lkotlinx/coroutines/experimental/Job;
496+
public static final fun supervisorScope (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object;
497+
}
498+
493499
public abstract interface class kotlinx/coroutines/ThreadContextElement : kotlin/coroutines/CoroutineContext$Element {
494500
public abstract fun restoreThreadContext (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Object;)V
495501
public abstract fun updateThreadContext (Lkotlin/coroutines/CoroutineContext;)Ljava/lang/Object;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.coroutines.experimental
6+
7+
import kotlin.coroutines.experimental.*
8+
9+
@Suppress("FunctionName")
10+
public fun SupervisorJob(parent: Job? = null) : Job = SupervisorJobImpl(parent)
11+
12+
public suspend fun <R> supervisorScope(block: suspend CoroutineScope.() -> R): R {
13+
// todo: optimize implementation to a single allocated object
14+
// todo: fix copy-and-paste with coroutineScope
15+
val owner = SupervisorCoroutine<R>(coroutineContext)
16+
owner.start(CoroutineStart.UNDISPATCHED, owner, block)
17+
owner.join()
18+
if (owner.isCancelled) {
19+
throw owner.getCancellationException().let { it.cause ?: it }
20+
}
21+
val state = owner.state
22+
if (state is CompletedExceptionally) {
23+
throw state.cause
24+
}
25+
@Suppress("UNCHECKED_CAST")
26+
return state as R
27+
28+
}
29+
30+
private class SupervisorJobImpl(parent: Job?) : JobSupport(true) {
31+
init { initParentJobInternal(parent) }
32+
override val onFailComplete get() = true
33+
override val handlesException: Boolean get() = false
34+
override fun childFailed(cause: Throwable): Boolean = false
35+
}
36+
37+
private class SupervisorCoroutine<R>(
38+
parentContext: CoroutineContext
39+
) : AbstractCoroutine<R>(parentContext, true) {
40+
override fun childFailed(cause: Throwable): Boolean = false
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
@file:Suppress("NAMED_ARGUMENTS_NOT_ALLOWED") // KT-21913
6+
7+
package kotlinx.coroutines.experimental
8+
9+
import kotlin.test.*
10+
11+
class SupervisorTest : TestBase() {
12+
@Test
13+
fun testSupervisorJob() = runTest(
14+
unhandled = listOf(
15+
{ it -> it is TestException2 },
16+
{ it -> it is TestException1 }
17+
)
18+
) {
19+
expect(1)
20+
val supervisor = SupervisorJob()
21+
val job1 = launch(supervisor + CoroutineName("job1")) {
22+
expect(2)
23+
yield() // to second child
24+
expect(4)
25+
throw TestException1()
26+
}
27+
val job2 = launch(supervisor + CoroutineName("job2")) {
28+
expect(3)
29+
throw TestException2()
30+
}
31+
joinAll(job1, job2)
32+
finish(5)
33+
assertTrue(job1.isFailed)
34+
assertTrue(job2.isFailed)
35+
}
36+
37+
@Test
38+
fun testSupervisorScope() = runTest(
39+
unhandled = listOf(
40+
{ it -> it is TestException1 },
41+
{ it -> it is TestException2 }
42+
)
43+
) {
44+
val result = supervisorScope {
45+
launch {
46+
throw TestException1()
47+
}
48+
launch {
49+
throw TestException2()
50+
}
51+
"OK"
52+
}
53+
assertEquals("OK", result)
54+
}
55+
56+
private class TestException1 : Exception()
57+
private class TestException2 : Exception()
58+
}

core/kotlinx-coroutines-core/test/TestBase.kt

-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ public actual open class TestBase actual constructor() {
146146
!unhandled[exCount - 1](e) ->
147147
printError("Unhandled exception was unexpected: $e", e)
148148
}
149-
context[Job]?.cancel(e)
150149
})
151150
} catch (e: Throwable) {
152151
ex = e

js/kotlinx-coroutines-core-js/test/TestBase.kt

-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ public actual open class TestBase actual constructor() {
8181
!unhandled[exCount - 1](e) ->
8282
printError("Unhandled exception was unexpected: $e", e)
8383
}
84-
context[Job]?.cancel(e)
8584
}).catch { e ->
8685
ex = e
8786
if (expected != null) {

native/kotlinx-coroutines-core-native/test/TestBase.kt

-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ public actual open class TestBase actual constructor() {
7676
!unhandled[exCount - 1](e) ->
7777
printError("Unhandled exception was unexpected: $e", e)
7878
}
79-
context[Job]?.cancel(e)
8079
})
8180
} catch (e: Throwable) {
8281
ex = e

0 commit comments

Comments
 (0)