File tree 5 files changed +45
-3
lines changed
kotlinx-coroutines-core/common
5 files changed +45
-3
lines changed Original file line number Diff line number Diff line change @@ -477,7 +477,14 @@ internal abstract class AbstractSendChannel<E>(
477
477
override val pollResult: Any? get() = element
478
478
override fun tryResumeSend (otherOp : PrepareOp ? ): Symbol ? = RESUME_TOKEN .also { otherOp?.finishPrepare() }
479
479
override fun completeResumeSend () {}
480
- override fun resumeSendClosed (closed : Closed <* >) {}
480
+
481
+ /* *
482
+ * This method should be never called, see special logic in [LinkedListChannel.onCancelIdempotentList].
483
+ */
484
+ override fun resumeSendClosed (closed : Closed <* >) {
485
+ assert { false }
486
+ }
487
+
481
488
override fun toString (): String = " SendBuffered@$hexAddress ($element )"
482
489
}
483
490
}
@@ -669,6 +676,13 @@ internal abstract class AbstractChannel<E>(
669
676
// Add to the list only **after** successful removal
670
677
list + = previous as Send
671
678
}
679
+ onCancelIdempotentList(list, closed)
680
+ }
681
+
682
+ /* *
683
+ * This method is overridden by [LinkedListChannel] to handle cancellation of [SendBuffered] elements from the list.
684
+ */
685
+ protected open fun onCancelIdempotentList (list : InlineList <Send >, closed : Closed <* >) {
672
686
list.forEachReversed { it.resumeSendClosed(closed) }
673
687
}
674
688
Original file line number Diff line number Diff line change @@ -298,7 +298,7 @@ internal open class ArrayChannel<E>(
298
298
}
299
299
// then clean all queued senders
300
300
super .onCancelIdempotent(wasClosed)
301
- undeliveredElementException?.let { throw it } // throw cancel exception at the end if there was one
301
+ undeliveredElementException?.let { throw it } // throw UndeliveredElementException at the end if there was one
302
302
}
303
303
304
304
// ------ debug ------
Original file line number Diff line number Diff line change @@ -120,7 +120,7 @@ internal open class ConflatedChannel<E>(onUndeliveredElement: OnUndeliveredEleme
120
120
undeliveredElementException = updateValueLocked(EMPTY )
121
121
}
122
122
super .onCancelIdempotent(wasClosed)
123
- undeliveredElementException?.let { throw it } // throw exception at the end if there was one
123
+ undeliveredElementException?.let { throw it } // throw UndeliveredElementException at the end if there was one
124
124
}
125
125
126
126
private fun updateValueLocked (element : Any? ): UndeliveredElementException ? {
Original file line number Diff line number Diff line change @@ -58,5 +58,19 @@ internal open class LinkedListChannel<E>(onUndeliveredElement: OnUndeliveredElem
58
58
}
59
59
}
60
60
}
61
+
62
+ override fun onCancelIdempotentList (list : InlineList <Send >, closed : Closed <* >) {
63
+ var undeliveredElementException: UndeliveredElementException ? = null
64
+ list.forEachReversed {
65
+ when (it) {
66
+ is SendBuffered <* > -> {
67
+ @Suppress(" UNCHECKED_CAST" )
68
+ undeliveredElementException = onUndeliveredElement?.callUndeliveredElementCatchingException(it.element as E , undeliveredElementException)
69
+ }
70
+ else -> it.resumeSendClosed(closed)
71
+ }
72
+ }
73
+ undeliveredElementException?.let { throw it } // throw UndeliveredElementException at the end if there was one
74
+ }
61
75
}
62
76
Original file line number Diff line number Diff line change @@ -50,6 +50,20 @@ class ChannelUndeliveredElementTest : TestBase() {
50
50
assertTrue(resA.isCancelled) // now cancelled in buffer
51
51
}
52
52
53
+ @Test
54
+ fun testUnlimitedChannelCancelled () = runTest {
55
+ val channel = Channel <Resource >(Channel .UNLIMITED ) { it.cancel() }
56
+ val resA = Resource (" A" )
57
+ val resB = Resource (" B" )
58
+ channel.send(resA) // goes to buffer
59
+ channel.send(resB) // goes to buffer
60
+ assertFalse(resA.isCancelled) // it is in buffer, not cancelled
61
+ assertFalse(resB.isCancelled) // it is in buffer, not cancelled
62
+ channel.cancel() // now cancel the channel
63
+ assertTrue(resA.isCancelled) // now cancelled in buffer
64
+ assertTrue(resB.isCancelled) // now cancelled in buffer
65
+ }
66
+
53
67
@Test
54
68
fun testConflatedResourceCancelled () = runTest {
55
69
val channel = Channel <Resource >(Channel .CONFLATED ) { it.cancel() }
You can’t perform that action at this time.
0 commit comments