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)
3232 *
3333 * A failure of a child does not cause this scope to fail and does not affect its other children,
3434 * 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.
3537 */
36- public suspend fun <R > supervisorScope (block : suspend CoroutineScope .() -> R ): R {
38+ public suspend fun <R > supervisorScope (block : suspend CoroutineScope .() -> R ): R {
3739 // todo: optimize implementation to a single allocated object
3840 // todo: fix copy-and-paste with coroutineScope
3941 val owner = SupervisorCoroutine <R >(coroutineContext)
@@ -62,6 +64,6 @@ private class SupervisorJobImpl(parent: Job?) : JobSupport(true) {
6264private class SupervisorCoroutine <R >(
6365 parentContext : CoroutineContext
6466) : AbstractCoroutine<R>(parentContext, true ) {
65- override val cancelsParent: Boolean get() = true
67+ override val cancelsParent: Boolean get() = false
6668 override fun childCancelled (cause : Throwable ): Boolean = false
6769}
Original file line number Diff line number Diff line change @@ -32,6 +32,8 @@ class SupervisorTest : TestBase() {
3232 finish(5 )
3333 assertTrue(job1.isCancelled)
3434 assertTrue(job2.isCancelled)
35+ assertFalse(supervisor.isCancelled)
36+ assertFalse(supervisor.isCompleted)
3537 }
3638
3739 @Test
@@ -53,6 +55,57 @@ class SupervisorTest : TestBase() {
5355 assertEquals(" OK" , result)
5456 }
5557
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+
56109 @Test
57110 fun testSupervisorWithParentCancelNormally () {
58111 val parent = Job ()
You can’t perform that action at this time.
0 commit comments