File tree Expand file tree Collapse file tree 2 files changed +57
-2
lines changed
common/kotlinx-coroutines-core-common Expand file tree Collapse file tree 2 files changed +57
-2
lines changed Original file line number Diff line number Diff line change @@ -32,8 +32,10 @@ public fun SupervisorJob(parent: Job? = null) : Job = SupervisorJobImpl(parent)
32
32
*
33
33
* A failure of a child does not cause this scope to fail and does not affect its other children,
34
34
* so a custom policy for handling failures of its children can be implemented. See [SupervisorJob] for details.
35
+ * A failure of the scope itself (exception thrown in the [block] or cancellation) fails the scope with all its children,
36
+ * but does not cancel parent job.
35
37
*/
36
- public suspend fun <R > supervisorScope (block : suspend CoroutineScope .() -> R ): R {
38
+ public suspend fun <R > supervisorScope (block : suspend CoroutineScope .() -> R ): R {
37
39
// todo: optimize implementation to a single allocated object
38
40
// todo: fix copy-and-paste with coroutineScope
39
41
val owner = SupervisorCoroutine <R >(coroutineContext)
@@ -62,6 +64,6 @@ private class SupervisorJobImpl(parent: Job?) : JobSupport(true) {
62
64
private class SupervisorCoroutine <R >(
63
65
parentContext : CoroutineContext
64
66
) : AbstractCoroutine<R>(parentContext, true ) {
65
- override val cancelsParent: Boolean get() = true
67
+ override val cancelsParent: Boolean get() = false
66
68
override fun childCancelled (cause : Throwable ): Boolean = false
67
69
}
Original file line number Diff line number Diff line change @@ -32,6 +32,8 @@ class SupervisorTest : TestBase() {
32
32
finish(5 )
33
33
assertTrue(job1.isCancelled)
34
34
assertTrue(job2.isCancelled)
35
+ assertFalse(supervisor.isCancelled)
36
+ assertFalse(supervisor.isCompleted)
35
37
}
36
38
37
39
@Test
@@ -53,6 +55,57 @@ class SupervisorTest : TestBase() {
53
55
assertEquals(" OK" , result)
54
56
}
55
57
58
+ @Test
59
+ fun testSupervisorScopeIsolation () = runTest(
60
+ unhandled = listOf (
61
+ { it -> it is TestException2 })
62
+ ) {
63
+ val result = supervisorScope {
64
+ expect(1 )
65
+ val job = launch {
66
+ expect(2 )
67
+ delay(Long .MAX_VALUE )
68
+ }
69
+
70
+ val failingJob = launch {
71
+ expect(3 )
72
+ throw TestException2 ()
73
+ }
74
+
75
+ failingJob.join()
76
+ yield ()
77
+ expect(4 )
78
+ assertTrue(job.isActive)
79
+ assertFalse(job.isCancelled)
80
+ job.cancel()
81
+ " OK"
82
+ }
83
+ assertEquals(" OK" , result)
84
+ finish(5 )
85
+ }
86
+
87
+ @Test
88
+ fun testThrowingSupervisorScope () = runTest {
89
+ try {
90
+ expect(1 )
91
+ supervisorScope {
92
+ async {
93
+ try {
94
+ delay(Long .MAX_VALUE )
95
+ } finally {
96
+ expect(3 )
97
+ }
98
+ }
99
+
100
+ expect(2 )
101
+ yield ()
102
+ throw TestException2 ()
103
+ }
104
+ } catch (e: Throwable ) {
105
+ finish(4 )
106
+ }
107
+ }
108
+
56
109
@Test
57
110
fun testSupervisorWithParentCancelNormally () {
58
111
val parent = Job ()
You can’t perform that action at this time.
0 commit comments