Support leak-free closeable resources transfer via channel #1936
Description
The change in #1813 removes support for "atomic cancellation", making it impossible to transfer a resource via a channel from one coroutine to another. When a closeable resource (like open file or a handle to another native resource) is transferred via channel from one coroutine to another it can be lost if either send or receive operation are cancelled in transit.
We introduce the following replacement. A Channel()
constructor function gets and additional optional parameter: onUndeliveredElement: ((E) -> Unit)? = null
When onUndeliveredElement
option parameter is set, the corresponding function is called once for each element that was sent to the channel and is being lost due to cancellation, which can happen in the following cases:
send
operation was cancelled before it had a chance to actually send the element.receive
operation retrieved the element from the channel but was cancelled when trying to return it the caller.- The channel was cancelled, in which case
onUndeliveredElement
is called on every remaining element in the channel's buffer.
Note, that onUndeliveredElement
is called synchronously in an arbitrary context. It should be fast, non-blocking, and should not throw exceptions. Any exception thrown by onUndeliveredElement
is wrapped into an internal runtime exception which is either rethrown or handed off to the exception handler in the current context (CoroutineExceptionHandler
) when one is available.
UPDATE: The final name of the parameter is onUndeliveredElement
.