Closed invexed closed 4 years ago
The design of asio's awaitable type is what I'd call "conditionally awaitable", which means that it's only awaitable in particular contexts.
The asio awaitable type is currently only awaitable within other asio awaitable coroutines.
The reason for this, I believe, is to support the ability to destroy an entire stack of coroutines from the root in the event that some an executor/async op decides to drop/destroy the completion handler without invoking it. To support this, the asio awaitable coroutine type needs to keep track of the top level coroutine so that when the leaf-level operation destroys the continuation handler that it can call .destroy() on the top level coroutine.
This requires cooperation between caller and callee to coordinate this kind of shutdown/ownership.
This approach is incompatible with the model that cppcoro adopts for coroutines, however, where cancellation is propagated by resuming from the leaf with a cancellation result and letting this propagate up towards the root rather than by destroying the stack from the root and letting the destruction propagate down towards the leaf.
The asio awaitable model integrates well with asio but is more limited. eg the asio model doesn't handle multiple concurrent child tasks, like those created with when_all(), since ownership of the coroutine stack/graph would be shared by all leaf operations and so we cannot just destroy the root coroutine when one of the leaf operations is dropped.
So, despite the name, asio awaitable doesn't actually satisfy the awaitable concept as far as cppcoro is concerned.
I hope that helps.
Thanks for such a comprehensive answer. That helps a lot.
is being triggered, I presume due to
boost::asio::awaitable<T>::await_suspend
having the following signature:Is the
Awaiter<T>
concept over-constrained, or is this incompatibility the fault of ASIO? It would be great if it were compatible withcppcoro::when_all
, for example.