-
Notifications
You must be signed in to change notification settings - Fork 11
Description
Summary
All four scheduler backends (IOCP, epoll, kqueue, select) leak coroutine frames during shutdown instead of properly destroying them. This is a workaround for a circular dependency in capy's io_awaitable_promise_base where destroying a child coroutine triggers destruction of the parent continuation, causing re-entrant destruction and stack overflow.
Current behavior
IOCP (win_scheduler::shutdown)
- Drains completed ops but abandons coroutine handles (
h_ = {}instead ofh_.destroy()) - Forces
outstanding_work_ = 0at the end
epoll / kqueue / select (shutdown)
- Calls
scheduler_op::destroy()on queued ops, butpost_handler::destroy()only doesdelete this— the storedcoroutine_handle<> h_is silently dropped without callingh_.destroy() - Forces
outstanding_work_ = 0at the end
Timer service (timer_service::shutdown)
- Abandons waiter handles (
w->h_ = {}) instead of destroying them
Root cause
The circular dependency lives in capy's io_awaitable_promise_base:
~io_awaitable_promise_base()
{
// Abnormal teardown: destroy orphaned continuation
if(cont_ != std::noop_coroutine())
cont_.destroy();
}During normal execution, final_suspend() calls continuation() which atomically swaps cont_ to noop_coroutine() before the frame is destroyed — no cycle. But during shutdown, final_suspend is never reached. The destructor tries to destroy the parent continuation, which owns the child, causing recursive destruction.
Expected behavior
All coroutine frames should be properly destroyed during shutdown without leaking memory. Boost.Asio accomplishes this during its shutdown/cleanup — we should investigate their approach (possibly deferred destruction or breaking the ownership cycle before destroying).
Affected files
include/boost/corosio/native/detail/iocp/win_scheduler.hpp—shutdown()include/boost/corosio/native/detail/epoll/epoll_scheduler.hpp—shutdown(),post_handler::destroy()include/boost/corosio/native/detail/kqueue/kqueue_scheduler.hpp—shutdown(),post_handler::destroy()include/boost/corosio/native/detail/select/select_scheduler.hpp—shutdown(),post_handler::destroy()include/boost/corosio/detail/timer_service.hpp—shutdown()- Upstream:
capy/ex/io_awaitable_promise_base.hpp— destructor circular dependency