override fun onCancellation()

in kotlinx-coroutines-core/common/src/channels/BufferedChannel.kt [2869:2931]


    override fun onCancellation(index: Int, cause: Throwable?, context: CoroutineContext) {
        // To distinguish cancelled senders and receivers, senders equip the index value with
        // an additional marker, adding `SEGMENT_SIZE` to the value.
        val isSender = index >= SEGMENT_SIZE
        // Unwrap the index.
        @Suppress("NAME_SHADOWING") val index = if (isSender) index - SEGMENT_SIZE else index
        // Read the element, which may be needed further to call `onUndeliveredElement`.
        val element = getElement(index)
        // Update the cell state.
        while (true) {
            // CAS-loop
            // Read the current state of the cell.
            val cur = getState(index)
            when {
                // The cell stores a waiter.
                cur is Waiter || cur is WaiterEB -> {
                    // The cancelled request is either send or receive.
                    // Update the cell state correspondingly.
                    val update = if (isSender) INTERRUPTED_SEND else INTERRUPTED_RCV
                    if (casState(index, cur, update)) {
                        // The waiter has been successfully cancelled.
                        // Clean the element slot and invoke `onSlotCleaned()`,
                        // which may cause deleting the whole segment from the linked list.
                        // In case the cancelled request is receiver, it is critical to ensure
                        // that the `expandBuffer()` attempt that processes this cell is completed,
                        // so `onCancelledRequest(..)` waits for its completion before invoking `onSlotCleaned()`.
                        cleanElement(index)
                        onCancelledRequest(index, !isSender)
                        // Call `onUndeliveredElement` if needed.
                        if (isSender) {
                            channel.onUndeliveredElement?.callUndeliveredElement(element, context)
                        }
                        return
                    }
                }
                // The cell already indicates that the operation is cancelled.
                cur === INTERRUPTED_SEND || cur === INTERRUPTED_RCV -> {
                    // Clean the element slot to avoid memory leaks,
                    // invoke `onUndeliveredElement` if needed, and finish
                    cleanElement(index)
                    // Call `onUndeliveredElement` if needed.
                    if (isSender) {
                        channel.onUndeliveredElement?.callUndeliveredElement(element, context)
                    }
                    return
                }
                // An opposite operation is resuming this request;
                // wait until the cell state updates.
                // It is possible that an opposite operation has already
                // resumed this request, which will result in updating
                // the cell state to `DONE_RCV` or `BUFFERED`, while the
                // current cancellation is caused by prompt cancellation.
                cur === RESUMING_BY_EB || cur === RESUMING_BY_RCV -> continue
                // This request was successfully resumed, so this cancellation
                // is caused by the prompt cancellation feature and should be ignored.
                cur === DONE_RCV || cur === BUFFERED -> return
                // The cell state indicates that the channel is closed;
                // this cancellation should be ignored.
                cur === CHANNEL_CLOSED -> return
                else -> error("unexpected state: $cur")
            }
        }
    }