include/boost/capy/quitter.hpp

100.0% Lines (213 / 213, 1 excl) 73.2% Functions (293 / 400)
quitter.hpp
f(x) Functions (400)
Function Calls Lines Blocks
boost::capy::detail::quitter_return_base<int>::return_value(int) :107 9x 100.0% 100.0% boost::capy::detail::quitter_return_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::return_value(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) :107 1x 100.0% 100.0% boost::capy::detail::quitter_return_base<std::error_code>::return_value(std::error_code) :107 0 0.0% 0.0% boost::capy::detail::quitter_return_base<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::return_value(std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >) :107 0 0.0% 0.0% boost::capy::detail::quitter_return_base<std::tuple<std::error_code, unsigned long> >::return_value(std::tuple<std::error_code, unsigned long>) :107 2x 100.0% 100.0% boost::capy::detail::quitter_return_base<std::tuple<std::error_code> >::return_value(std::tuple<std::error_code>) :107 5233x 100.0% 100.0% boost::capy::detail::quitter_return_base<int>::result() :112 4x 100.0% 100.0% boost::capy::detail::quitter_return_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::result() :112 1x 100.0% 100.0% boost::capy::detail::quitter_return_base<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::result() :112 0 0.0% 0.0% boost::capy::detail::quitter_return_base<std::tuple<std::error_code> >::result() :112 0 0.0% 0.0% boost::capy::detail::quitter_return_base<void>::return_void() :121 8x 100.0% 100.0% boost::capy::detail::stopped_value<int>::get() :136 8x 100.0% 80.0% boost::capy::detail::stopped_value<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::get() :136 0 0.0% 0.0% boost::capy::detail::stopped_value<void>::get() :136 21x 100.0% 80.0% boost::capy::detail::stopped_value<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::get() :157 2x 100.0% 100.0% boost::capy::detail::stopped_value<std::tuple<std::error_code, unsigned long> >::get() :157 5x 100.0% 100.0% boost::capy::detail::stopped_value<std::tuple<std::error_code> >::get() :157 4799x 100.0% 100.0% boost::capy::detail::stopped_value<std::error_code>::get() :166 1x 100.0% 100.0% boost::capy::detail::quitter_stop_pending(boost::capy::await_context const*) :182 20303x 100.0% 86.0% boost::capy::detail::quitter_segment::promise_type::~promise_type() :235 10090x 100.0% 100.0% boost::capy::detail::quitter_segment::promise_type::get_return_object() :251 10090x 100.0% 100.0% boost::capy::detail::quitter_segment::promise_type::initial_suspend() :257 10090x 100.0% 100.0% boost::capy::detail::quitter_segment::promise_type::handle() :262 10118x 100.0% 100.0% boost::capy::detail::quitter_segment::promise_type::stop() :269 4834x 100.0% 100.0% boost::capy::detail::quitter_segment::promise_type::decide() :274 14909x 100.0% 100.0% boost::capy::detail::quitter_hop::await_ready() const :301 14909x 100.0% 100.0% boost::capy::detail::quitter_hop::await_suspend(std::__n4861::coroutine_handle<boost::capy::detail::quitter_segment::promise_type>) :303 14909x 100.0% 100.0% boost::capy::detail::quitter_hop::await_resume() const :309 4824x 100.0% 100.0% boost::capy::detail::make_quitter_segment() :313 10090x 100.0% 50.0% boost::capy::quitter<int>::promise_type::open_gate() :481 14x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::promise_type::open_gate() :481 1x 100.0% 100.0% boost::capy::quitter<std::error_code>::promise_type::open_gate() :481 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::open_gate() :481 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::open_gate() :481 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::open_gate() :481 7x 100.0% 100.0% boost::capy::quitter<void>::promise_type::open_gate() :481 27x 100.0% 100.0% boost::capy::quitter<int>::promise_type::promise_type() :490 20x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::promise_type::promise_type() :490 1x 100.0% 100.0% boost::capy::quitter<std::error_code>::promise_type::promise_type() :490 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::promise_type() :490 2x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::promise_type() :490 7x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::promise_type() :490 10137x 100.0% 100.0% boost::capy::quitter<void>::promise_type::promise_type() :490 36x 100.0% 100.0% boost::capy::quitter<int>::promise_type::~promise_type() :493 20x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::promise_type::~promise_type() :493 1x 100.0% 100.0% boost::capy::quitter<std::error_code>::promise_type::~promise_type() :493 1x 75.0% 80.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::~promise_type() :493 2x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::~promise_type() :493 7x 75.0% 80.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::~promise_type() :493 10137x 100.0% 100.0% boost::capy::quitter<void>::promise_type::~promise_type() :493 36x 100.0% 100.0% boost::capy::quitter<int>::promise_type::exception() const :504 8x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::promise_type::exception() const :504 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::exception() const :504 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::exception() const :504 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::exception() const :504 9x 100.0% 100.0% boost::capy::quitter<int>::promise_type::stopped_result() :523 8x 100.0% 67.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::promise_type::stopped_result() :523 0 0.0% 0.0% boost::capy::quitter<std::error_code>::promise_type::stopped_result() :523 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::stopped_result() :523 2x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::stopped_result() :523 5x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::stopped_result() :523 4799x 100.0% 100.0% boost::capy::quitter<void>::promise_type::stopped_result() :523 21x 100.0% 100.0% boost::capy::quitter<int>::promise_type::launch_handle() :544 12x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::promise_type::launch_handle() :544 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::launch_handle() :544 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::launch_handle() :544 7x 100.0% 100.0% boost::capy::quitter<void>::promise_type::launch_handle() :544 27x 100.0% 100.0% boost::capy::quitter<int>::promise_type::get_return_object() :559 20x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::promise_type::get_return_object() :559 1x 100.0% 100.0% boost::capy::quitter<std::error_code>::promise_type::get_return_object() :559 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::get_return_object() :559 2x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::get_return_object() :559 7x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::get_return_object() :559 10137x 100.0% 100.0% boost::capy::quitter<void>::promise_type::get_return_object() :559 36x 100.0% 100.0% boost::capy::quitter<int>::promise_type::initial_suspend() :576 20x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::promise_type::initial_suspend() :576 1x 100.0% 100.0% boost::capy::quitter<std::error_code>::promise_type::initial_suspend() :576 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::initial_suspend() :576 2x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::initial_suspend() :576 7x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::initial_suspend() :576 10137x 100.0% 100.0% boost::capy::quitter<void>::promise_type::initial_suspend() :576 36x 100.0% 100.0% boost::capy::quitter<int>::promise_type::final_suspend() :614 12x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::promise_type::final_suspend() :614 1x 100.0% 100.0% boost::capy::quitter<std::error_code>::promise_type::final_suspend() :614 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::final_suspend() :614 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::final_suspend() :614 2x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::final_suspend() :614 5233x 100.0% 100.0% boost::capy::quitter<void>::promise_type::final_suspend() :614 9x 100.0% 100.0% boost::capy::quitter<int>::promise_type::unhandled_exception() :647 3x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::promise_type::unhandled_exception() :647 0 0.0% 0.0% boost::capy::quitter<std::error_code>::promise_type::unhandled_exception() :647 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::unhandled_exception() :647 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::unhandled_exception() :647 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::unhandled_exception() :647 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::unhandled_exception() :647 1x 100.0% 100.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::quitter_test::bool_resume_awaitable>::stops_on_sync_completion() :717 1x 100.0% 100.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::yield_awaitable>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<std::error_code>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::transform_awaiter<boost::capy::yield_awaitable>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::async_mutex::lock_guard_awaiter>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable<boost::capy::quitter<std::tuple<std::error_code> >, false, void> >::stops_on_sync_completion() :717 1x 100.0% 60.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::quitter<std::tuple<std::error_code> >, boost::capy::queuing_executor, false, void> >::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::quitter<std::tuple<std::error_code> >, boost::capy::thread_pool::executor_type, true, void> >::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::task<std::tuple<std::error_code> >, boost::capy::thread_pool::executor_type, true, void> >::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::park_awaitable>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::armed_wait>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::false_after_stop_awaitable>::stops_on_sync_completion() :717 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::inline_after_stop_awaitable>::stops_on_sync_completion() :717 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::task<std::tuple<std::error_code> > >::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::yield_awaitable>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::async_mutex::lock_guard_awaiter>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::park_awaitable>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::bool_park_awaitable>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::rmw_ready_awaitable>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::stop_then_return_self_awaitable>::stops_on_sync_completion() :717 1x 100.0% 100.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::stop_while_ready_awaitable>::stops_on_sync_completion() :717 1x 100.0% 100.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)0> >::stops_on_sync_completion() :717 3x 100.0% 100.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)1> >::stops_on_sync_completion() :717 1x 100.0% 93.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)2> >::stops_on_sync_completion() :717 2x 100.0% 100.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::stop_only_awaitable>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::task<void> >::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::test::stream::read_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer)::awaitable>::stops_on_sync_completion() :717 1x 100.0% 60.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::test::stream::write_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer)::awaitable>::stops_on_sync_completion() :717 1x 100.0% 60.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::yield_awaitable>::stops_on_sync_completion() :717 0 0.0% 0.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_ready() :752 6x 50.0% 70.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::quitter_test::bool_resume_awaitable>::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::yield_awaitable>::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<std::error_code>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_ready() :752 2x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::await_ready() :752 5x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::transform_awaiter<boost::capy::yield_awaitable>::await_ready() :752 3x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::async_mutex::lock_guard_awaiter>::await_ready() :752 2x 75.0% 80.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_ready() :752 13x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable<boost::capy::quitter<std::tuple<std::error_code> >, false, void> >::await_ready() :752 2x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::quitter<std::tuple<std::error_code> >, boost::capy::queuing_executor, false, void> >::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::quitter<std::tuple<std::error_code> >, boost::capy::thread_pool::executor_type, true, void> >::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::task<std::tuple<std::error_code> >, boost::capy::thread_pool::executor_type, true, void> >::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::park_awaitable>::await_ready() :752 2x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::armed_wait>::await_ready() :752 10000x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::false_after_stop_awaitable>::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::inline_after_stop_awaitable>::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::task<std::tuple<std::error_code> > >::await_ready() :752 2x 50.0% 70.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::yield_awaitable>::await_ready() :752 4x 75.0% 80.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::async_mutex::lock_guard_awaiter>::await_ready() :752 1x 50.0% 50.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_ready() :752 10x 50.0% 70.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::park_awaitable>::await_ready() :752 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::bool_park_awaitable>::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::await_ready() :752 4x 50.0% 70.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::rmw_ready_awaitable>::await_ready() :752 2x 50.0% 70.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::stop_then_return_self_awaitable>::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::stop_while_ready_awaitable>::await_ready() :752 1x 62.5% 80.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)0> >::await_ready() :752 3x 62.5% 80.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)1> >::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)2> >::await_ready() :752 2x 50.0% 70.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::stop_only_awaitable>::await_ready() :752 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::task<void> >::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::test::stream::read_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer)::awaitable>::await_ready() :752 1x 62.5% 80.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::test::stream::write_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer)::awaitable>::await_ready() :752 1x 50.0% 70.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::yield_awaitable>::await_ready() :752 0 0.0% 0.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::quitter_test::bool_resume_awaitable>::await_resume() :779 1x 100.0% 100.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::yield_awaitable>::await_resume() :779 1x 100.0% 100.0% boost::capy::quitter<std::error_code>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::transform_awaiter<boost::capy::yield_awaitable>::await_resume() :779 3x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::async_mutex::lock_guard_awaiter>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable<boost::capy::quitter<std::tuple<std::error_code> >, false, void> >::await_resume() :779 2x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::quitter<std::tuple<std::error_code> >, boost::capy::queuing_executor, false, void> >::await_resume() :779 1x 83.3% 67.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::quitter<std::tuple<std::error_code> >, boost::capy::thread_pool::executor_type, true, void> >::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::task<std::tuple<std::error_code> >, boost::capy::thread_pool::executor_type, true, void> >::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::park_awaitable>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::armed_wait>::await_resume() :779 5229x 83.3% 67.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::false_after_stop_awaitable>::await_resume() :779 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::inline_after_stop_awaitable>::await_resume() :779 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::task<std::tuple<std::error_code> > >::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::yield_awaitable>::await_resume() :779 1x 100.0% 100.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::async_mutex::lock_guard_awaiter>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::park_awaitable>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::bool_park_awaitable>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::rmw_ready_awaitable>::await_resume() :779 1x 100.0% 100.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::stop_then_return_self_awaitable>::await_resume() :779 1x 100.0% 100.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::stop_while_ready_awaitable>::await_resume() :779 1x 100.0% 100.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)0> >::await_resume() :779 2x 83.3% 89.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)1> >::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)2> >::await_resume() :779 1x 83.3% 89.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::stop_only_awaitable>::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::task<void> >::await_resume() :779 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::test::stream::read_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer)::awaitable>::await_resume() :779 1x 83.3% 89.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::test::stream::write_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer)::awaitable>::await_resume() :779 1x 83.3% 89.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::yield_awaitable>::await_resume() :779 0 0.0% 0.0% auto boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_suspend<boost::capy::quitter<int>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<int>::promise_type>) :817 6x 75.0% 65.0% auto boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::quitter_test::bool_resume_awaitable>::await_suspend<boost::capy::quitter<int>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<int>::promise_type>) :817 1x 72.7% 59.0% auto boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::await_suspend<boost::capy::quitter<int>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<int>::promise_type>) :817 1x 75.0% 65.0% auto boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::yield_awaitable>::await_suspend<boost::capy::quitter<int>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<int>::promise_type>) :817 1x 75.0% 65.0% auto boost::capy::quitter<std::error_code>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_suspend<boost::capy::quitter<std::error_code>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::error_code>::promise_type>) :817 1x 75.0% 65.0% auto boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_suspend<boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type>) :817 2x 75.0% 65.0% auto boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::await_suspend<boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type>) :817 5x 75.0% 65.0% auto boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::transform_awaiter<boost::capy::yield_awaitable>::await_suspend<boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type>) :817 3x 75.0% 65.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::async_mutex::lock_guard_awaiter>::await_suspend<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :817 2x 91.7% 88.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_suspend<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :817 13x 75.0% 65.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable<boost::capy::quitter<std::tuple<std::error_code> >, false, void> >::await_suspend<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :817 2x 83.3% 75.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::quitter<std::tuple<std::error_code> >, boost::capy::queuing_executor, false, void> >::await_suspend<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :817 1x 75.0% 60.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::quitter<std::tuple<std::error_code> >, boost::capy::thread_pool::executor_type, true, void> >::await_suspend<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :817 1x 75.0% 60.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::task<std::tuple<std::error_code> >, boost::capy::thread_pool::executor_type, true, void> >::await_suspend<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :817 1x 75.0% 60.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::park_awaitable>::await_suspend<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :817 2x 75.0% 65.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::armed_wait>::await_suspend<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :817 10000x 75.0% 65.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::false_after_stop_awaitable>::await_suspend<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :817 1x 72.7% 59.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::inline_after_stop_awaitable>::await_suspend<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :817 1x 75.0% 71.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::await_suspend<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :817 1x 75.0% 65.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::task<std::tuple<std::error_code> > >::await_suspend<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :817 2x 75.0% 60.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::yield_awaitable>::await_suspend<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :817 4x 91.7% 88.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::async_mutex::lock_guard_awaiter>::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 1x 50.0% 47.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 10x 75.0% 65.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::park_awaitable>::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 0 0.0% 0.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::bool_park_awaitable>::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 1x 72.7% 65.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 4x 75.0% 65.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::rmw_ready_awaitable>::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 2x 75.0% 65.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::stop_then_return_self_awaitable>::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 1x 75.0% 71.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::stop_while_ready_awaitable>::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 0 0.0% 0.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)0> >::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 1x 50.0% 47.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)1> >::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 1x 72.7% 59.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)2> >::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 2x 75.0% 71.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::stop_only_awaitable>::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 0 0.0% 0.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::task<void> >::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 1x 75.0% 65.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::test::stream::read_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer)::awaitable>::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 0 0.0% 0.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::test::stream::write_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer)::awaitable>::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 1x 72.7% 63.0% auto boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::yield_awaitable>::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :817 0 0.0% 0.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::quitter_test::bool_resume_awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 1x 60.0% 50.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<int>::promise_type::transform_awaiter<boost::capy::yield_awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<std::error_code>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::transform_awaiter<boost::capy::yield_awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::async_mutex::lock_guard_awaiter>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable<boost::capy::quitter<std::tuple<std::error_code> >, false, void> >::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 1x 60.0% 50.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::quitter<std::tuple<std::error_code> >, boost::capy::queuing_executor, false, void> >::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::quitter<std::tuple<std::error_code> >, boost::capy::thread_pool::executor_type, true, void> >::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::detail::run_awaitable_ex<boost::capy::task<std::tuple<std::error_code> >, boost::capy::thread_pool::executor_type, true, void> >::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::park_awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::armed_wait>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::false_after_stop_awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 1x 60.0% 50.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::inline_after_stop_awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 1x 60.0% 50.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::task<std::tuple<std::error_code> > >::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaiter<boost::capy::yield_awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::async_mutex::lock_guard_awaiter>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::async_waker::wait_awaiter>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::park_awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::bool_park_awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::parked_until_stop>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::rmw_ready_awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::stop_then_return_self_awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 1x 60.0% 50.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::stop_while_ready_awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)0> >::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)1> >::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 1x 80.0% 88.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)2> >::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 2x 100.0% 100.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::stop_only_awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::task<void> >::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::test::stream::read_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer)::awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::test::stream::write_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer)::awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 1x 60.0% 50.0% boost::capy::quitter<void>::promise_type::transform_awaiter<boost::capy::yield_awaitable>::continue_or_stop(std::__n4861::coroutine_handle<void>) :883 0 0.0% 0.0% boost::capy::quitter<int>::promise_type::join_awaiter<boost::capy::quitter<int> >::await_ready() const :913 3x 100.0% 100.0% boost::capy::quitter<int>::promise_type::join_awaiter<boost::capy::quitter<void> >::await_ready() const :913 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::join_awaiter<boost::capy::quitter<std::tuple<std::error_code> > >::await_ready() const :913 101x 100.0% 100.0% boost::capy::quitter<void>::promise_type::join_awaiter<boost::capy::quitter<void> >::await_ready() const :913 3x 100.0% 100.0% auto boost::capy::quitter<int>::promise_type::join_awaiter<boost::capy::quitter<int> >::await_suspend<boost::capy::quitter<int>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<int>::promise_type>) :928 3x 62.5% 57.0% auto boost::capy::quitter<int>::promise_type::join_awaiter<boost::capy::quitter<void> >::await_suspend<boost::capy::quitter<int>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<int>::promise_type>) :928 1x 62.5% 57.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::join_awaiter<boost::capy::quitter<std::tuple<std::error_code> > >::await_suspend<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :928 101x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::join_awaiter<boost::capy::quitter<void> >::await_suspend<boost::capy::quitter<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :928 3x 62.5% 57.0% boost::capy::quitter<int>::promise_type::join_awaiter<boost::capy::quitter<int> >::await_resume() :946 3x 100.0% 100.0% boost::capy::quitter<int>::promise_type::join_awaiter<boost::capy::quitter<void> >::await_resume() :946 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::promise_type::join_awaiter<boost::capy::quitter<std::tuple<std::error_code> > >::await_resume() :946 0 0.0% 0.0% boost::capy::quitter<void>::promise_type::join_awaiter<boost::capy::quitter<void> >::await_resume() :946 0 0.0% 0.0% auto boost::capy::quitter<int>::promise_type::transform_awaitable<boost::capy::async_waker::wait_awaiter>(boost::capy::async_waker::wait_awaiter&&) :965 6x 100.0% 100.0% auto boost::capy::quitter<int>::promise_type::transform_awaitable<boost::capy::quitter<int> >(boost::capy::quitter<int>&&) :965 3x 100.0% 100.0% auto boost::capy::quitter<int>::promise_type::transform_awaitable<boost::capy::quitter<void> >(boost::capy::quitter<void>&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<int>::promise_type::transform_awaitable<boost::capy::quitter_test::bool_resume_awaitable>(boost::capy::quitter_test::bool_resume_awaitable&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<int>::promise_type::transform_awaitable<boost::capy::quitter_test::parked_until_stop>(boost::capy::quitter_test::parked_until_stop&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<int>::promise_type::transform_awaitable<boost::capy::yield_awaitable>(boost::capy::yield_awaitable&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<std::error_code>::promise_type::transform_awaitable<boost::capy::async_waker::wait_awaiter>(boost::capy::async_waker::wait_awaiter&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::transform_awaitable<boost::capy::async_waker::wait_awaiter>(boost::capy::async_waker::wait_awaiter&&) :965 2x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::transform_awaitable<boost::capy::quitter_test::parked_until_stop>(boost::capy::quitter_test::parked_until_stop&&) :965 5x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type::transform_awaitable<boost::capy::yield_awaitable>(boost::capy::yield_awaitable&&) :965 3x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaitable<boost::capy::async_mutex::lock_guard_awaiter>(boost::capy::async_mutex::lock_guard_awaiter&&) :965 2x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaitable<boost::capy::async_waker::wait_awaiter>(boost::capy::async_waker::wait_awaiter&&) :965 13x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaitable<boost::capy::detail::run_awaitable<boost::capy::quitter<std::tuple<std::error_code> >, false, void> >(boost::capy::detail::run_awaitable<boost::capy::quitter<std::tuple<std::error_code> >, false, void>&&) :965 2x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaitable<boost::capy::detail::run_awaitable_ex<boost::capy::quitter<std::tuple<std::error_code> >, boost::capy::queuing_executor, false, void> >(boost::capy::detail::run_awaitable_ex<boost::capy::quitter<std::tuple<std::error_code> >, boost::capy::queuing_executor, false, void>&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaitable<boost::capy::detail::run_awaitable_ex<boost::capy::quitter<std::tuple<std::error_code> >, boost::capy::thread_pool::executor_type, true, void> >(boost::capy::detail::run_awaitable_ex<boost::capy::quitter<std::tuple<std::error_code> >, boost::capy::thread_pool::executor_type, true, void>&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaitable<boost::capy::detail::run_awaitable_ex<boost::capy::task<std::tuple<std::error_code> >, boost::capy::thread_pool::executor_type, true, void> >(boost::capy::detail::run_awaitable_ex<boost::capy::task<std::tuple<std::error_code> >, boost::capy::thread_pool::executor_type, true, void>&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaitable<boost::capy::park_awaitable>(boost::capy::park_awaitable&&) :965 2x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaitable<boost::capy::quitter<std::tuple<std::error_code> > >(boost::capy::quitter<std::tuple<std::error_code> >&&) :965 101x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaitable<boost::capy::quitter_test::armed_wait>(boost::capy::quitter_test::armed_wait&&) :965 10000x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaitable<boost::capy::quitter_test::false_after_stop_awaitable>(boost::capy::quitter_test::false_after_stop_awaitable&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaitable<boost::capy::quitter_test::inline_after_stop_awaitable>(boost::capy::quitter_test::inline_after_stop_awaitable&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaitable<boost::capy::quitter_test::parked_until_stop>(boost::capy::quitter_test::parked_until_stop&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaitable<boost::capy::task<std::tuple<std::error_code> > >(boost::capy::task<std::tuple<std::error_code> >&&) :965 2x 100.0% 100.0% auto boost::capy::quitter<std::tuple<std::error_code> >::promise_type::transform_awaitable<boost::capy::yield_awaitable>(boost::capy::yield_awaitable&&) :965 4x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::async_mutex::lock_guard_awaiter>(boost::capy::async_mutex::lock_guard_awaiter&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::async_waker::wait_awaiter>(boost::capy::async_waker::wait_awaiter&&) :965 10x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::park_awaitable>(boost::capy::park_awaitable&&) :965 0 0.0% 0.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::quitter<void> >(boost::capy::quitter<void>&&) :965 3x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::quitter_test::bool_park_awaitable>(boost::capy::quitter_test::bool_park_awaitable&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::quitter_test::parked_until_stop>(boost::capy::quitter_test::parked_until_stop&&) :965 4x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::quitter_test::rmw_ready_awaitable>(boost::capy::quitter_test::rmw_ready_awaitable&&) :965 2x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::quitter_test::stop_then_return_self_awaitable>(boost::capy::quitter_test::stop_then_return_self_awaitable&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::quitter_test::stop_while_ready_awaitable>(boost::capy::quitter_test::stop_while_ready_awaitable&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)0> >(boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)0>&&) :965 3x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)1> >(boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)1>&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)2> >(boost::capy::quitter_test::sync_results_awaitable<(boost::capy::quitter_test::completes)2>&&) :965 2x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::stop_only_awaitable>(boost::capy::stop_only_awaitable&&) :965 0 0.0% 0.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::task<void> >(boost::capy::task<void>&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::test::stream::read_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer)::awaitable>(boost::capy::test::stream::read_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer)::awaitable&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::test::stream::write_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer)::awaitable>(boost::capy::test::stream::write_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer)::awaitable&&) :965 1x 100.0% 100.0% auto boost::capy::quitter<void>::promise_type::transform_awaitable<boost::capy::yield_awaitable>(boost::capy::yield_awaitable&&) :965 0 0.0% 0.0% boost::capy::quitter<int>::~quitter() :1003 40x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::~quitter() :1003 2x 100.0% 100.0% boost::capy::quitter<std::error_code>::~quitter() :1003 2x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::~quitter() :1003 4x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::~quitter() :1003 26x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::~quitter() :1003 30311x 100.0% 100.0% boost::capy::quitter<void>::~quitter() :1003 52x 100.0% 100.0% boost::capy::quitter<int>::await_ready() const :1015 4x 100.0% 100.0% boost::capy::quitter<std::error_code>::await_ready() const :1015 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::await_ready() const :1015 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::await_ready() const :1015 7x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::await_ready() const :1015 10033x 100.0% 100.0% boost::capy::quitter<void>::await_ready() const :1015 5x 100.0% 100.0% boost::capy::quitter<int>::await_resume() :1031 6x 100.0% 93.0% boost::capy::quitter<std::error_code>::await_resume() :1031 1x 50.0% 29.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::await_resume() :1031 1x 50.0% 29.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::await_resume() :1031 7x 87.5% 71.0% boost::capy::quitter<std::tuple<std::error_code> >::await_resume() :1031 10027x 87.5% 71.0% boost::capy::quitter<void>::await_resume() :1031 3x 85.7% 58.0% boost::capy::quitter<int>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::await_context const*) :1069 3x 100.0% 100.0% boost::capy::quitter<std::error_code>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::await_context const*) :1069 1x 90.5% 92.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::await_context const*) :1069 1x 90.5% 92.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::await_context const*) :1069 7x 90.5% 92.0% boost::capy::quitter<std::tuple<std::error_code> >::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::await_context const*) :1069 10029x 100.0% 100.0% boost::capy::quitter<void>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::await_context const*) :1069 3x 90.5% 92.0% boost::capy::quitter<int>::handle() const :1124 17x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::handle() const :1124 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::handle() const :1124 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::handle() const :1124 17x 100.0% 100.0% boost::capy::quitter<void>::handle() const :1124 29x 100.0% 100.0% boost::capy::quitter<int>::release() :1141 14x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::release() :1141 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::release() :1141 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::release() :1141 7x 100.0% 100.0% boost::capy::quitter<void>::release() :1141 27x 100.0% 100.0% boost::capy::quitter<int>::quitter(boost::capy::quitter<int>&&) :1170 20x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::quitter(boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&) :1170 1x 100.0% 100.0% boost::capy::quitter<std::error_code>::quitter(boost::capy::quitter<std::error_code>&&) :1170 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::quitter(boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&&) :1170 2x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::quitter(boost::capy::quitter<std::tuple<std::error_code, unsigned long> >&&) :1170 19x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::quitter(boost::capy::quitter<std::tuple<std::error_code> >&&) :1170 20174x 100.0% 100.0% boost::capy::quitter<void>::quitter(boost::capy::quitter<void>&&) :1170 16x 100.0% 100.0% boost::capy::quitter<void>::operator=(boost::capy::quitter<void>&&) :1193 1x 100.0% 100.0% boost::capy::quitter<int>::quitter(std::__n4861::coroutine_handle<boost::capy::quitter<int>::promise_type>) :1208 20x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::quitter(std::__n4861::coroutine_handle<boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::promise_type>) :1208 1x 100.0% 100.0% boost::capy::quitter<std::error_code>::quitter(std::__n4861::coroutine_handle<boost::capy::quitter<std::error_code>::promise_type>) :1208 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::quitter(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type>) :1208 2x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::quitter(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::promise_type>) :1208 7x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::quitter(std::__n4861::coroutine_handle<boost::capy::quitter<std::tuple<std::error_code> >::promise_type>) :1208 10137x 100.0% 100.0% boost::capy::quitter<void>::quitter(std::__n4861::coroutine_handle<boost::capy::quitter<void>::promise_type>) :1208 36x 100.0% 100.0% boost::capy::quitter<int>::release_top(boost::capy::detail::quitter_opener&) :1215 1x 100.0% 100.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::release_top(boost::capy::detail::quitter_opener&) :1215 0 0.0% 0.0% boost::capy::quitter<std::error_code>::release_top(boost::capy::detail::quitter_opener&) :1215 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::release_top(boost::capy::detail::quitter_opener&) :1215 1x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::release_top(boost::capy::detail::quitter_opener&) :1215 5x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::release_top(boost::capy::detail::quitter_opener&) :1215 4793x 100.0% 100.0% boost::capy::quitter<void>::release_top(boost::capy::detail::quitter_opener&) :1215 3x 100.0% 100.0% boost::capy::quitter<int>::join(std::__n4861::coroutine_handle<void>, boost::capy::detail::quitter_segment::promise_type*, boost::capy::await_context const*) :1221 3x 100.0% 100.0% boost::capy::quitter<std::tuple<std::error_code> >::join(std::__n4861::coroutine_handle<void>, boost::capy::detail::quitter_segment::promise_type*, boost::capy::await_context const*) :1221 100x 100.0% 100.0% boost::capy::quitter<void>::join(std::__n4861::coroutine_handle<void>, boost::capy::detail::quitter_segment::promise_type*, boost::capy::await_context const*) :1221 4x 100.0% 100.0% boost::capy::quitter<int>::destroy_frame() :1234 40x 81.8% 56.0% boost::capy::quitter<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::destroy_frame() :1234 2x 45.5% 19.0% boost::capy::quitter<std::error_code>::destroy_frame() :1234 2x 63.6% 33.0% boost::capy::quitter<std::tuple<std::error_code, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::destroy_frame() :1234 4x 63.6% 33.0% boost::capy::quitter<std::tuple<std::error_code, unsigned long> >::destroy_frame() :1234 26x 81.8% 56.0% boost::capy::quitter<std::tuple<std::error_code> >::destroy_frame() :1234 30311x 100.0% 93.0% boost::capy::quitter<void>::destroy_frame() :1234 53x 100.0% 93.0%
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Michael Vandeberg
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/capy
8 //
9
10 #ifndef BOOST_CAPY_QUITTER_HPP
11 #define BOOST_CAPY_QUITTER_HPP
12
13 #include <boost/capy/detail/config.hpp>
14 #include <boost/capy/concept/executor.hpp>
15 #include <boost/capy/concept/context_awaitable.hpp>
16 #include <boost/capy/cond.hpp>
17 #include <boost/capy/continuation.hpp>
18 #include <boost/capy/error.hpp>
19 #include <boost/capy/ex/abandon.hpp>
20 #include <boost/capy/ex/context_awaitable_promise_base.hpp>
21 #include <boost/capy/ex/await_context.hpp>
22 #include <boost/capy/ex/frame_alloc_mixin.hpp>
23 #include <boost/capy/ex/frame_allocator.hpp>
24 #include <boost/capy/detail/await_suspend_helper.hpp>
25 #include <boost/capy/detail/quitter_stopped.hpp>
26 #include <boost/capy/results.hpp>
27
28 #include <coroutine>
29 #include <exception>
30 #include <optional>
31 #include <system_error>
32 #include <type_traits>
33 #include <utility>
34
35 /* Stop-aware coroutine task.
36
37 quitter<T> is task<T>, except that a stop request ends its frames
38 by abandonment instead of resuming them. Nothing in the body runs
39 after the stop, so nothing can intercept it, and no exception is
40 thrown inside the quitter.
41
42 Segment. A quitter awaited by anything other than a quitter opens a
43 segment in its await_suspend. The segment is one coroutine frame,
44 quitter_segment, that is both the segment's owner (its chain_owner is
45 the await_context::owner every frame in the segment sees) and the
46 gate. A quitter awaited by a quitter joins the parent's segment. A
47 quitter started directly by a launcher (run_async, run(ex)) runs in
48 the launcher's segment; it still gets a gate, and the launcher's
49 chain_owner is the one the gate abandons. The launcher creates the
50 gate with launch_handle() and resumes the gate, not the quitter, so
51 the gate checks the stop before the body starts. A launcher that
52 resumes the quitter's own handle instead gets a gate when the body
53 starts, with no such check.
54
55 Gate. A quitter frame never hands its own handle to an operation. Its
56 transform_awaiter records the frame as the gate's target and passes
57 the gate's handle instead, so an operation completes into the gate.
58 The gate then resumes the target, or, if a stop was requested,
59 abandons the segment with chain_owner::abandon_for_stop. The
60 operation has finished with the frame by then (the corosio rule: no
61 frame is destroyed while an operation holds its continuation).
62
63 Synchronous completions. The stop is checked before the
64 inner await_ready, so a pending stop starts no work. An inner
65 awaitable that completes without going through the gate (ready,
66 await_suspend returning false or the gate's own handle) always has
67 its await_resume called, so anything it acquired is handed over; the
68 stop takes effect at the next suspension. The exception is a
69 results<> holding cond::canceled while our stop is pending: the
70 inner awaitable saw the stop first and acquired nothing (async_mutex,
71 async_event and async_waker all answer a stop that lands between our
72 check and theirs this way), so the segment is abandoned there. That
73 result is taken early and kept in the awaiter, because await_resume
74 runs in the resumed body, too late to abandon.
75
76 Unwind. When the segment's owner is resumed after an abandon, it
77 releases the opening quitter's handle and destroys the top frame,
78 which destroys the frames below it. After a stop it then resumes the
79 parent, whose co_await yields the stopped value (stopped_value<T>).
80 After a teardown it abandons the parent, as run's boundary_trampoline
81 does. A segment frame destroyed instead of resumed (posted to a
82 closed executor) unwinds as teardown from its destructor.
83
84 Why the gate is never resumed while it runs. Its body is
85 `for(;;) co_await hop{}`, and every decision is made in
86 hop::await_suspend, after the frame has suspended. Its handle is
87 reachable only from the one operation a quitter frame of the segment
88 is waiting on, and from the owner's post, which happens only when no
89 operation holds it. Once await_suspend has handed the handle on, by
90 returning it, resuming a target inline or posting, it touches nothing
91 of the frame again, because another thread may already be running or
92 destroying it. */
93
94 namespace boost {
95 namespace capy {
96
97 template<typename T>
98 struct quitter;
99
100 namespace detail {
101
102 template<typename T>
103 struct quitter_return_base
104 {
105 std::optional<T> result_;
106
107 5245x void return_value(T value)
108 {
109 5245x result_ = std::move(value);
110 5245x }
111
112 5x T&& result() noexcept
113 {
114 5x return std::move(*result_);
115 }
116 };
117
118 template<>
119 struct quitter_return_base<void>
120 {
121 8x void return_void()
122 {
123 8x }
124 };
125
126 /* What a stopped quitter<T> delivers to its parent.
127
128 results<Ts...>: canceled, with each payload value-initialized.
129 std::error_code: canceled.
130 Any other T, void included: quitter_stopped, a std::system_error
131 with canceled, thrown at the boundary. A void return would read as
132 success. */
133 template<class T>
134 struct stopped_value
135 {
136 29x static T get()
137 {
138 #if defined(__cpp_exceptions)
139 29x throw quitter_stopped();
140 #else
141 // sizeof(T*): T may be void.
142 static_assert(sizeof(T*) == 0,
143 "a stopped quitter<T> for a T other than results or "
144 "std::error_code reports the stop by throwing, "
145 "which needs exceptions");
146 #endif
147 }
148 };
149
150 template<class... Ts>
151 struct stopped_value<results<Ts...>>
152 {
153 static_assert(
154 (std::is_default_constructible_v<Ts> && ...),
155 "a stopped quitter<results<Ts...>> value-initializes every Ts");
156
157 4806x static results<Ts...> get()
158 {
159 4806x return results<Ts...>(make_error_code(error::canceled), Ts{}...);
160 }
161 };
162
163 template<>
164 struct stopped_value<std::error_code>
165 {
166 1x static std::error_code get() noexcept
167 {
168 1x return make_error_code(error::canceled);
169 }
170 };
171
172 template<class T>
173 struct is_quitter : std::false_type {};
174
175 template<class T>
176 struct is_quitter<quitter<T>> : std::true_type {};
177
178 // A stop that can be carried out: requested, with an owner to abandon.
179 // With no owner a quitter cannot stop, and runs on as a task would; a
180 // launcher that runs quitters must bind a chain_owner.
181 inline bool
182 20303x quitter_stop_pending(await_context const* env) noexcept
183 {
184 20303x if(!env->stop_token.stop_requested())
185 15467x return false;
186 4836x BOOST_CAPY_ASSERT(env->owner &&
187 "a quitter's environment needs an owner to stop");
188 4836x return env->owner != nullptr;
189 }
190
191 struct quitter_opener;
192
193 // One per segment: the owner and the gate in one coroutine frame.
194 struct quitter_segment
195 {
196 struct promise_type;
197
198 std::coroutine_handle<promise_type> h_;
199 };
200
201 // The part of a quitter that opened a segment, without its T.
202 struct quitter_opener
203 {
204 // Takes the quitter's frame handle, leaving the quitter empty.
205 std::coroutine_handle<> (*release_top_)(quitter_opener&) noexcept =
206 nullptr;
207 quitter_segment seg_{};
208 bool stopped_ = false;
209 // Set while a parent is suspended awaiting the quitter.
210 bool lent_ = false;
211 };
212
213 // Not the chain's frame allocator: after a teardown this frame is freed
214 // once the parent has been abandoned, when that allocator may be gone.
215 // run's boundary_trampoline does the same.
216 struct quitter_segment::promise_type
217 : process_frame_mixin
218 {
219 // The segment's owner, when a quitter opened the segment.
220 chain_owner owner_;
221 // The environment of the segment's frames, when a quitter opened it.
222 await_context env_;
223 // The environment the frames run in: env_, or the launcher's.
224 await_context const* frame_env_ = nullptr;
225 // The awaiting coroutine, and its own owner for a teardown.
226 continuation parent_;
227 // The quitter frame waiting in the gate.
228 std::coroutine_handle<> target_;
229 // The quitter that opened the segment; null for a gate only.
230 quitter_opener* opener_ = nullptr;
231 // An unwind is still owed. Cleared when the top frame completes,
232 // when the unwind runs, and by the quitter when it destroys this.
233 bool active_ = false;
234
235 10090x ~promise_type()
236 {
237 // Destroyed instead of resumed: a closed executor discarded the
238 // owner's post. That is teardown, whatever the cause.
239 10090x if(active_)
240 {
241 1x active_ = false;
242 // This frame is going away; the quitter must not destroy it
243 // again when the parent's unwind reaches it.
244 1x opener_->seg_.h_ = nullptr;
245 1x opener_->release_top_(*opener_).destroy();
246 1x auto parent = parent_;
247 1x capy::abandon(parent);
248 }
249 10090x }
250
251 10090x quitter_segment get_return_object() noexcept
252 {
253 return quitter_segment{
254 10090x std::coroutine_handle<promise_type>::from_promise(*this)};
255 }
256
257 10090x std::suspend_always initial_suspend() noexcept { return {}; }
258 std::suspend_always final_suspend() noexcept { return {}; } // LCOV_EXCL_LINE the body never ends
259 void return_void() noexcept {} // LCOV_EXCL_LINE the body never ends
260 void unhandled_exception() noexcept { std::terminate(); } // LCOV_EXCL_LINE the body never throws
261
262 10118x std::coroutine_handle<> handle() noexcept
263 {
264 10118x return std::coroutine_handle<promise_type>::from_promise(*this);
265 }
266
267 // Abandon the segment for a stop. The caller holds the waiting
268 // frame and touches nothing of it afterwards.
269 4834x void stop() noexcept
270 {
271 4834x frame_env_->owner->abandon_for_stop();
272 4834x }
273
274 14909x std::coroutine_handle<> decide() noexcept
275 {
276 14909x if(opener_ && owner_.abandoned())
277 {
278 4803x active_ = false;
279 4803x auto* op = opener_;
280 4803x op->release_top_(*op).destroy();
281 4803x if(owner_.stopped())
282 {
283 4801x op->stopped_ = true;
284 4801x return parent_.h;
285 }
286 2x auto parent = parent_;
287 2x capy::abandon(parent);
288 2x return std::noop_coroutine();
289 }
290 10106x if(quitter_stop_pending(frame_env_))
291 {
292 4825x stop();
293 4825x return std::noop_coroutine();
294 }
295 5281x return target_;
296 }
297 };
298
299 struct quitter_hop
300 {
301 14909x bool await_ready() const noexcept { return false; }
302
303 14909x auto await_suspend(
304 std::coroutine_handle<quitter_segment::promise_type> h) noexcept
305 {
306 14909x return detail::symmetric_transfer(h.promise().decide());
307 }
308
309 4824x void await_resume() const noexcept {}
310 };
311
312 inline quitter_segment
313 10090x make_quitter_segment()
314 {
315 for(;;)
316 co_await quitter_hop{};
317 20180x }
318
319 } // namespace detail
320
321 /** Defers a coroutine body until awaited, and ends it on a stop request without resuming it.
322
323 A `quitter` is a @ref task whose author has chosen that a stop
324 request ends it. When the stop token fires, the quitter's frames are
325 not resumed: they are destroyed, from the top down, as an abandoned
326 chain is (see @ref abandon). Only destructors run. Nothing in the
327 body can observe or intercept the stop, not even `catch(...)`, and no
328 exception is thrown inside the quitter. The stop is reported to the
329 first coroutine above that is not a quitter, as a value: see
330 Await-returns.
331
332 A quitter stops only quitter frames. A @ref task below a quitter
333 receives the stop request as usual, and returns through its own code
334 before the quitter is destroyed. A task above a quitter receives the
335 stopped value from `co_await`. A quitter awaited by a quitter is
336 stopped together with it.
337
338 Everything else (frame allocation, environment propagation,
339 symmetric transfer, move semantics) is as for @ref task.
340
341 @par Await-effects
342
343 Let `q` be a `quitter<T>`. If the stop token in the awaiting
344 environment has already been triggered, `co_await q` does not start
345 the body, and await-returns the stopped value. Otherwise it suspends
346 the awaiting coroutine and transfers control directly into the
347 quitter's body on the current thread; no executor operation is
348 posted. The quitter propagates the caller's executor, stop token and
349 frame allocator to every `co_await` inside the body.
350
351 At every `co_await` in the body, the stop token is checked before
352 the awaited operation is started. An operation that completes
353 asynchronously does not resume the body directly: the stop token is
354 checked again first. If either check finds a stop, the body is not
355 resumed. The quitter's frames are destroyed on the executor, and
356 the coroutine that awaited the quitter is resumed with the stopped
357 value. When `run_async` started the quitter, it reports the stop to
358 its handlers instead, as Await-returns describes.
359
360 An operation that completes without suspending always has
361 its `await_resume` called, because its `await_ready` or
362 `await_suspend` may already have acquired a resource, such as
363 `async_mutex`'s lock, that only its `await_resume` hands over. If
364 that result is a @ref results holding `cond::canceled` while a stop
365 is pending, the operation saw the stop first and acquired nothing,
366 so the quitter is stopped at that `co_await`. Any other result is
367 handed to the body, and the stop takes effect at the next
368 suspension. An operation whose result is not a @ref results can
369 therefore hand the body one result it produced after seeing the
370 stop.
371
372 When the body returns or exits via an exception, control transfers
373 directly back to the awaiting coroutine.
374
375 @par Await-returns
376
377 The value the body passed to `co_return`, moved out of the quitter,
378 or nothing when `T` is `void`. If the body exits via an unhandled
379 exception, that exception is rethrown instead.
380
381 If the quitter was stopped, the stopped value instead:
382
383 @li for `results<Ts...>`: `make_error_code(error::canceled)` with
384 each `Ts` value-initialized; it compares equal to
385 `cond::canceled`. Every `Ts` must be default-constructible.
386 @li for `std::error_code`: `make_error_code(error::canceled)`.
387 @li for any other `T`, `void` included: no value; an exception of
388 an unspecified type derived from `std::system_error`, whose
389 `code()` compares equal to `cond::canceled`, is thrown. A `void`
390 return would read as success. Such a `quitter<T>` cannot be used
391 where exceptions are disabled: use `quitter<results<>>` there.
392
393 `co_await run(ex)(q)`, and the other @ref run overloads, yield the
394 same stopped value. A quitter started by `run_async` reports a stop
395 the same way. For `results<Ts...>` and `std::error_code`, the value
396 handler receives the stopped value. For any other `T`, the error
397 handler receives the exception. With no error handler, no handler
398 is called and the stop is discarded. This also holds when the
399 exception escapes a @ref task that awaited the quitter: the task is
400 unwound, and with no error handler `run_async` discards the stop.
401 Any other exception, a `std::system_error` with `cond::canceled`
402 included, still calls `std::terminate`. That includes a
403 `std::system_error` copy of the stop that a task throws.
404
405 @par Await-postcondition
406 The quitter's coroutine has completed, has been destroyed by a
407 stop, or, when the stop was requested before it was awaited, was
408 never started. A quitter must not be awaited twice.
409
410 @par Remarks
411 Supports _ContextAwaitable cancellation_. A quitter stops through the
412 owner of its segment (@ref await_context::owner). A launcher that
413 starts a quitter in an environment with no owner cannot stop it: a
414 debug build asserts, and otherwise the quitter runs on as a
415 @ref task would. A stop that arrives while
416 the execution context is being shut down may end the quitter as a
417 teardown instead, with nothing delivered. Stop the work, wait for it
418 to finish, and only then destroy the context.
419
420 A stop destroys quitter frames that are suspended at a `co_await`.
421 GCC 15.2, and GCC 16 before 2026-07-02, at `-O0`, miscompile such a
422 destruction when the `co_await` initializes a structured binding
423 with an element that is not trivially destructible: the destructor
424 of the never-constructed binding runs (GCC PR c++/124584). Bind the
425 result to a named variable, and destructure it after the
426 `co_await`:
427
428 @code
429 auto r = co_await mtx.scoped_lock();
430 auto& [ec, guard] = r;
431 @endcode
432
433 @tparam T The result type. Use `quitter<>` for `quitter<void>`.
434
435 @see @ref task, @ref ContextRunnable, @ref ContextAwaitable,
436 @ref chain_owner
437 */
438 template<typename T = void>
439 struct [[nodiscard]] BOOST_CAPY_CORO_AWAIT_ELIDABLE
440 quitter
441 : private detail::quitter_opener
442 {
443 /** Stores `quitter<T>`'s result and routes its awaits through the segment's gate.
444
445 This is the promise object the compiler associates with a
446 `quitter<T>` coroutine. It satisfies the coroutine promise
447 requirements and participates in the I/O awaitable protocol via
448 @ref context_awaitable_promise_base. Unlike @ref task::promise_type,
449 its `transform_awaitable` checks the stop token before each
450 awaited operation starts. It hands the operation the segment's
451 gate as the continuation, not this coroutine. It is part of
452 the coroutine machinery and is not intended to be used directly
453 by callers.
454
455 Result storage and `return_value`/`return_void` are provided by
456 `detail::quitter_return_base<T>`.
457
458 @see @ref context_awaitable_promise_base, @ref ContextRunnable
459 */
460 struct promise_type
461 : context_awaitable_promise_base<promise_type>
462 , detail::quitter_return_base<T>
463 {
464 private:
465 friend quitter;
466
467 template<class>
468 friend struct quitter;
469
470 std::exception_ptr ep_;
471
472 // The gate of the segment this frame runs in.
473 detail::quitter_segment::promise_type* seg_ = nullptr;
474
475 // The gate this frame owns, when a launcher started it.
476 detail::quitter_segment own_gate_{};
477
478 // This frame opened its segment.
479 bool top_ = false;
480
481 50x void open_gate()
482 {
483 50x own_gate_ = detail::make_quitter_segment();
484 50x seg_ = &own_gate_.h_.promise();
485 50x seg_->frame_env_ = this->environment();
486 50x }
487
488 public:
489 /// Construct the promise.
490 10204x promise_type() noexcept = default;
491
492 /// Destroy the promise, and the gate it owns, if any.
493 10204x ~promise_type()
494 {
495 10204x if(own_gate_.h_)
496 50x own_gate_.h_.destroy();
497 10204x }
498
499 /** Return the exception the body exited with, if any.
500
501 @return The stored exception if the coroutine exited via an
502 exception, otherwise a null `std::exception_ptr`.
503 */
504 18x std::exception_ptr exception() const noexcept
505 {
506 18x return ep_;
507 }
508
509 /** Return what a stopped `quitter<T>` delivers.
510
511 Launchers that start a quitter directly call this when its
512 segment was abandoned for a stop: see
513 @ref chain_owner::stopped. Its result, or the exception it
514 throws, is reported in place of the coroutine's own result.
515
516 @return `make_error_code(error::canceled)` with value-initialized
517 payloads for `results<Ts...>`, or
518 `make_error_code(error::canceled)` for `std::error_code`.
519
520 @throws std::system_error For any other `T`, `void` included,
521 with a `code()` that compares equal to `cond::canceled`.
522 */
523 4836x static T stopped_result()
524 {
525 4836x return detail::stopped_value<T>::get();
526 }
527
528 /** Return the handle a launcher resumes to start the quitter.
529
530 Launchers that start a quitter directly resume this handle,
531 not the coroutine's own, so the stop is checked when the body
532 would start rather than when the launcher was called. The
533 handle is the quitter's gate, which either starts the body
534 or, if a stop was requested by then, abandons the segment for
535 the stop: see @ref chain_owner::abandon_for_stop.
536
537 @par Preconditions
538 The coroutine has not started, and its environment is set.
539
540 @return The handle of the quitter's gate.
541
542 @throws std::bad_alloc If the gate cannot be allocated.
543 */
544 48x std::coroutine_handle<> launch_handle()
545 {
546 48x open_gate();
547 48x seg_->target_ =
548 48x std::coroutine_handle<promise_type>::from_promise(*this);
549 48x return seg_->handle();
550 }
551
552 /** Return the owning `quitter` for this coroutine.
553
554 Called by the compiler to produce the object returned to the
555 caller when the coroutine is created.
556
557 @return A `quitter` owning the coroutine frame.
558 */
559 10204x quitter get_return_object()
560 {
561 return quitter{
562 10204x std::coroutine_handle<promise_type>::from_promise(*this)};
563 }
564
565 /** Return the initial-suspend awaiter.
566
567 The coroutine always suspends at the initial suspend point,
568 so the body does not start until the quitter is awaited or
569 started. When the body is resumed, the awaiter restores the
570 thread-local frame allocator. A quitter started directly by a
571 launcher that did not call @ref launch_handle creates its
572 gate at that point.
573
574 @return An awaiter that suspends unconditionally.
575 */
576 10204x auto initial_suspend() noexcept
577 {
578 struct awaiter
579 {
580 promise_type* p_;
581
582 bool await_ready() const noexcept
583 {
584 return false;
585 }
586
587 void await_suspend(std::coroutine_handle<>) const noexcept
588 {
589 }
590
591 // Allocates the gate of a quitter that a launcher started
592 // without launch_handle(); a failure is reported as the
593 // body's exception.
594 void await_resume() const
595 {
596 set_current_frame_allocator(
597 p_->environment()->frame_allocator);
598 if(!p_->seg_)
599 p_->open_gate();
600 }
601 };
602 10204x return awaiter{this};
603 }
604
605 /** Return the final-suspend awaiter.
606
607 The coroutine always suspends at the final suspend point. The
608 awaiter's `await_suspend` performs symmetric transfer to the
609 stored continuation, resuming the awaiting coroutine.
610
611 @return An awaiter that suspends and transfers to the
612 continuation.
613 */
614 5257x auto final_suspend() noexcept
615 {
616 struct awaiter
617 {
618 promise_type* p_;
619
620 bool await_ready() const noexcept
621 {
622 return false;
623 }
624
625 std::coroutine_handle<> await_suspend(
626 std::coroutine_handle<>) const noexcept
627 {
628 // The top frame completed: its segment owes no
629 // unwind.
630 if(p_->top_)
631 p_->seg_->active_ = false;
632 return p_->continuation();
633 }
634
635 void await_resume() const noexcept {} // LCOV_EXCL_LINE final_suspend awaiter, never resumed
636 };
637 5257x return awaiter{this};
638 }
639
640 /** Capture the in-flight exception from the coroutine body.
641
642 Called by the compiler when the coroutine body exits via an
643 unhandled exception. The exception is rethrown when the
644 quitter is awaited, or routed to the error handler when it is
645 run.
646 */
647 4x void unhandled_exception() noexcept
648 {
649 4x ep_ = std::current_exception();
650 4x }
651
652 /** Awaiter wrapping a nested `co_await` of an @ref ContextAwaitable.
653
654 Forwards the environment to the inner awaitable's
655 environment-taking `await_suspend`, and restores the
656 thread-local frame allocator before the body resumes. Unlike
657 `task`'s, it checks the stop token before the inner awaitable
658 is touched. It passes the inner awaitable the segment's gate
659 as the continuation, not this coroutine.
660
661 @tparam Awaitable The awaitable being transformed.
662 */
663 template<class Awaitable>
664 struct transform_awaiter
665 {
666 /// The wrapped awaitable, decayed and stored by value.
667 std::decay_t<Awaitable> a_;
668
669 /// The promise of the coroutine performing the `co_await`.
670 promise_type* p_;
671
672 /// The wrapped awaitable's await-result type.
673 using result_type = decltype(
674 std::declval<std::decay_t<Awaitable>&>().await_resume());
675
676 /// True when the await-result is a @ref results, which is
677 /// checked for a canceled stop after a synchronous completion.
678 static constexpr bool checks_canceled =
679 detail::is_results_v<result_type>;
680
681 /// True when the checks that may call the wrapped awaitable's
682 /// `await_resume` early cannot throw.
683 static constexpr bool checks_noexcept =
684 !checks_canceled || noexcept(
685 std::declval<std::decay_t<Awaitable>&>().await_resume());
686
687 /// Empty stand-in for @ref result_ when nothing is checked.
688 struct no_result {};
689
690 /// The result of a synchronous completion, taken early by
691 /// @ref stops_on_sync_completion and handed over by
692 /// @ref await_resume.
693 std::conditional_t<checks_canceled,
694 std::optional<result_type>, no_result> result_{};
695
696 /// True when the stop takes effect at this `co_await` without
697 /// suspending: a stop was pending before the wrapped awaitable
698 /// was touched, or it completed synchronously with a result
699 /// canceled by that stop.
700 bool stop_here_ = false;
701
702 /** Take the result of a synchronous completion, and report
703 whether the stop takes effect here instead.
704
705 The wrapped awaitable's `await_resume` is always called,
706 because its `await_ready` or `await_suspend` may already
707 have acquired something that only `await_resume` hands
708 over. A @ref results holding `cond::canceled` while our
709 stop is pending saw the stop first and acquired nothing,
710 so the quitter can be abandoned. Any other result is kept
711 for @ref await_resume. A result that is not a
712 @ref results is not taken early.
713
714 @return `true` if the quitter is abandoned at this
715 `co_await`.
716 */
717 14x bool stops_on_sync_completion() noexcept(checks_noexcept)
718 {
719 if constexpr (checks_canceled)
720 {
721 9x result_.emplace(a_.await_resume());
722 // The stop check first: comparing with
723 // cond::canceled goes through the error category's
724 // virtual calls, and a stop is rarely pending.
725 14x return detail::quitter_stop_pending(p_->environment()) &&
726 14x std::get<0>(*result_) == cond::canceled;
727 }
728 else
729 {
730 5x return false;
731 }
732 }
733
734 /** Report whether the `co_await` can continue without
735 suspending.
736
737 The stop token is checked first. If a stop is pending, the
738 wrapped awaitable is never touched: this returns `false`,
739 and @ref await_suspend ends the quitter. Otherwise the
740 wrapped awaitable's own `await_ready` decides. A `true`
741 result means it completed synchronously. Its
742 `await_resume` then hands over its result, even if a stop
743 arrives afterwards, unless that result is a @ref results
744 canceled by the stop (see @ref stops_on_sync_completion).
745
746 Where `BOOST_CAPY_SYMMETRIC_TRANSFER_WORKAROUND` is on,
747 this always returns `false`, and @ref await_suspend does both
748 steps instead. See `detail::await_ready_then_suspend`.
749
750 @return `true` if no suspension is needed.
751 */
752 10080x bool await_ready() noexcept(checks_noexcept)
753 {
754 #if BOOST_CAPY_SYMMETRIC_TRANSFER_WORKAROUND
755 return false;
756 #else
757 10080x if(detail::quitter_stop_pending(p_->environment()))
758 {
759 5x stop_here_ = true;
760 5x return false;
761 }
762 10075x if(!a_.await_ready())
763 10070x return false;
764 5x stop_here_ = stops_on_sync_completion();
765 5x return !stop_here_;
766 #endif
767 }
768
769 /** Restore the frame allocator, then return the wrapped
770 awaitable's result.
771
772 The body is resumed only when the wrapped awaitable
773 completed synchronously, or completed through the gate
774 with no stop requested.
775
776 @return The wrapped awaitable's await-result, forwarded
777 unchanged, or the result already taken from it.
778 */
779 5248x decltype(auto) await_resume()
780 {
781 5248x set_current_frame_allocator(
782 5248x p_->environment()->frame_allocator);
783 if constexpr (checks_canceled)
784 {
785 5237x if(result_)
786 6x return result_type(std::move(*result_));
787 }
788 5242x return a_.await_resume();
789 }
790
791 /** Start the wrapped awaitable with the gate as its
792 continuation, or end the quitter on a pending stop.
793
794 If a stop is pending, the segment is abandoned for the
795 stop and this coroutine stays suspended until it is
796 destroyed. Otherwise this coroutine becomes the gate's
797 target, and the wrapped awaitable's @ref ContextAwaitable
798 overload is called with the gate's handle and the
799 promise's environment. If that call completes without
800 suspending (returning `false`, or the gate's own handle),
801 this coroutine continues to @ref await_resume without
802 passing through the gate, unless its result is a
803 @ref results canceled by the stop (see
804 @ref stops_on_sync_completion).
805
806 @param h The coroutine performing the `co_await`.
807
808 @return Where the workaround is off, the handle to resume:
809 `h` to continue, a handle the wrapped awaitable returned,
810 or `std::noop_coroutine()`. Where
811 `BOOST_CAPY_SYMMETRIC_TRANSFER_WORKAROUND` is on, `false`
812 to continue and `true` to stay suspended; the stop check
813 and the wrapped awaitable's `await_ready` both run here,
814 through `detail::await_ready_then_suspend`.
815 */
816 template<class Promise>
817 10076x auto await_suspend(
818 std::coroutine_handle<Promise> h) noexcept(checks_noexcept)
819 {
820 // After the wrapped awaitable's await_suspend, the gate
821 // may already have run and destroyed this frame on
822 // another thread: only locals are used from then on,
823 // except after a synchronous completion, which leaves
824 // the frame to us.
825 10076x auto* seg = p_->seg_;
826 10076x auto const* env = p_->environment();
827 #if BOOST_CAPY_SYMMETRIC_TRANSFER_WORKAROUND
828 if(detail::quitter_stop_pending(env))
829 {
830 seg->stop();
831 return true;
832 }
833 seg->target_ = h;
834 if(detail::await_ready_then_suspend(
835 a_, seg->handle(), env))
836 return true;
837 if(stops_on_sync_completion())
838 {
839 seg->stop();
840 return true;
841 }
842 return false;
843 #else
844 10076x if(stop_here_)
845 {
846 6x seg->stop();
847 6x return std::coroutine_handle<>(std::noop_coroutine());
848 }
849 10070x seg->target_ = h;
850 10070x std::coroutine_handle<> gate = seg->handle();
851 using R = decltype(a_.await_suspend(gate, env));
852 if constexpr (std::is_same_v<R, bool>)
853 {
854 5x if(!a_.await_suspend(gate, env))
855 4x return continue_or_stop(h);
856 1x return std::coroutine_handle<>(std::noop_coroutine());
857 }
858 else if constexpr (std::is_void_v<R>)
859 {
860 a_.await_suspend(gate, env);
861 return std::coroutine_handle<>(std::noop_coroutine());
862 }
863 else
864 {
865 10065x std::coroutine_handle<> r = a_.await_suspend(gate, env);
866 10065x if(r == gate)
867 5x return continue_or_stop(h);
868 10060x return r;
869 }
870 #endif
871 }
872
873 #if !BOOST_CAPY_SYMMETRIC_TRANSFER_WORKAROUND
874 /** After a synchronous completion in @ref await_suspend,
875 continue to @ref await_resume, or end the quitter.
876
877 @param h The coroutine performing the `co_await`.
878
879 @return `h`, or `std::noop_coroutine()` when the quitter is
880 abandoned here (see @ref stops_on_sync_completion).
881 */
882 std::coroutine_handle<>
883 9x continue_or_stop(std::coroutine_handle<> h)
884 noexcept(checks_noexcept)
885 {
886 9x if(!stops_on_sync_completion())
887 7x return h;
888 2x p_->seg_->stop();
889 2x return std::noop_coroutine();
890 }
891 #endif
892 };
893
894 /** Awaiter for a nested `co_await` of a quitter.
895
896 The awaited quitter joins this coroutine's segment instead of
897 opening one: it runs in the same environment and gate, and a
898 stop ends both together. Its completion transfers straight
899 back to this coroutine.
900
901 @tparam Q The awaited quitter type.
902 */
903 template<class Q>
904 struct join_awaiter
905 {
906 /// The awaited quitter, stored by value.
907 Q q_;
908
909 /// The promise of the coroutine performing the `co_await`.
910 promise_type* p_;
911
912 /// Return `false`; the joined quitter has not started.
913 108x bool await_ready() const noexcept
914 {
915 108x return false;
916 }
917
918 /** Start the joined quitter, or end the segment on a pending
919 stop.
920
921 @param h The coroutine performing the `co_await`.
922
923 @return The joined quitter's handle, for symmetric
924 transfer, or `std::noop_coroutine()` after a stop. Where
925 the workaround is on, `void`.
926 */
927 template<class Promise>
928 108x auto await_suspend(std::coroutine_handle<Promise> h) noexcept
929 {
930 108x auto const* env = p_->environment();
931 108x if(detail::quitter_stop_pending(env))
932 {
933 1x p_->seg_->stop();
934 1x return detail::symmetric_transfer(
935 2x std::noop_coroutine());
936 }
937 107x return detail::symmetric_transfer(
938 214x q_.join(h, p_->seg_, env));
939 }
940
941 /** Restore the frame allocator, then return the joined
942 quitter's result.
943
944 @return The joined quitter's await-result.
945 */
946 4x decltype(auto) await_resume()
947 {
948 4x set_current_frame_allocator(
949 4x p_->environment()->frame_allocator);
950 4x return q_.await_resume();
951 }
952 };
953
954 /** Transform a nested awaitable before `co_await`.
955
956 A quitter is wrapped in a @ref join_awaiter. Any other
957 @ref ContextAwaitable is wrapped in a @ref transform_awaiter.
958 A diagnostic is emitted for anything else.
959
960 @param a The awaitable expression from `co_await a`.
961
962 @return The awaiter wrapping `a`.
963 */
964 template<class Awaitable>
965 10188x auto transform_awaitable(Awaitable&& a)
966 {
967 using A = std::decay_t<Awaitable>;
968 if constexpr (detail::is_quitter<A>::value)
969 {
970 216x return join_awaiter<A>{std::forward<Awaitable>(a), this};
971 }
972 else if constexpr (ContextAwaitable<A>)
973 {
974 return transform_awaiter<Awaitable>{
975 20147x std::forward<Awaitable>(a), this};
976 }
977 else
978 {
979 static_assert(sizeof(A) == 0,
980 "requires ContextAwaitable");
981 }
982 10169x }
983 };
984
985 /** Handle to the owned coroutine frame.
986
987 Null when the quitter is empty (for example after a move, after
988 @ref release, or once a stop has destroyed the frame). Prefer
989 @ref handle to read this; the member is public for use by the
990 coroutine machinery.
991 */
992 std::coroutine_handle<promise_type> h_;
993
994 /** Destroy the quitter and its coroutine frame if owned.
995
996 @par Preconditions
997 The frame is not lent: no parent is suspended awaiting it,
998 unless its chain is being unwound after an @ref abandon.
999 Destroying a lent frame otherwise calls `std::terminate`; end
1000 a running chain by requesting stop, or by destroying its
1001 execution context.
1002 */
1003 30437x ~quitter()
1004 {
1005 30437x destroy_frame();
1006 30437x }
1007
1008 /** Return false; quitters are never immediately ready.
1009
1010 A quitter is lazy and has not started when it is awaited, so the
1011 awaiting coroutine always suspends.
1012
1013 @return `false`.
1014 */
1015 10051x bool await_ready() const noexcept
1016 {
1017 10051x return false;
1018 }
1019
1020 /** Return the result, rethrow the body's exception, or deliver the stopped value.
1021
1022 @return The result value for non-void `T`, moved out of the
1023 quitter, or the stopped value if the quitter was stopped.
1024
1025 @par Exception Safety
1026 If the body exited via an exception, that exception is rethrown.
1027 If the quitter was stopped and `T` is not `results<Ts...>` or
1028 `std::error_code`, a `std::system_error` whose `code()`
1029 compares equal to `cond::canceled` is thrown.
1030 */
1031 10045x T await_resume()
1032 {
1033 10045x lent_ = false;
1034 10045x if(stopped_)
1035 4805x return promise_type::stopped_result();
1036 5240x auto& p = h_.promise();
1037 5240x if(p.ep_)
1038 1x std::rethrow_exception(p.ep_);
1039 if constexpr (! std::is_void_v<T>)
1040 5238x return std::move(*p.result_);
1041 }
1042
1043 /** Open a segment and start the quitter with the caller's context.
1044
1045 If the stop token in `env` has already been triggered, the body
1046 is not started. `cont` is returned, so the caller resumes at once
1047 with the stopped value.
1048
1049 Otherwise the quitter opens a segment of its own. The segment's
1050 owner destroys the quitter's frames if the segment is abandoned.
1051 Its gate is what the quitter's awaits complete through. The body
1052 runs with `env`'s executor, stop token and frame allocator, and
1053 the segment's owner. Control then transfers into the body.
1054
1055 @param cont The awaiting coroutine to resume when the quitter
1056 completes or is stopped.
1057
1058 @param env The execution environment. It must outlive the
1059 quitter.
1060
1061 @return The quitter's coroutine handle for symmetric transfer, or
1062 `cont`.
1063
1064 @throws std::bad_alloc If the segment's frame cannot be
1065 allocated. When the awaiting coroutine is a @ref task, its
1066 awaiter's `await_suspend` is `noexcept`, so `std::terminate` is
1067 called instead.
1068 */
1069 10044x std::coroutine_handle<> await_suspend(
1070 std::coroutine_handle<> cont,
1071 await_context const* env)
1072 {
1073 10044x if(env->stop_token.stop_requested())
1074 {
1075 4x stopped_ = true;
1076 4x return cont;
1077 }
1078 10040x seg_ = detail::make_quitter_segment();
1079 10040x auto& sp = seg_.h_.promise();
1080 10040x sp.owner_.bind(seg_.h_, env->executor);
1081 10040x sp.env_ = *env;
1082 10040x sp.env_.owner = &sp.owner_;
1083 10040x sp.frame_env_ = &sp.env_;
1084 10040x sp.parent_.h = cont;
1085 10040x sp.parent_.owner = env->owner;
1086 10040x sp.opener_ = this;
1087 10040x sp.active_ = true;
1088 10040x auto& p = h_.promise();
1089 10040x p.seg_ = &sp;
1090 10040x p.top_ = true;
1091 10040x p.set_environment(&sp.env_);
1092 10040x p.set_continuation(cont);
1093 10040x lent_ = true;
1094 10040x return h_;
1095 }
1096
1097 /** Return the coroutine handle.
1098
1099 @note Do not call `destroy()` on the returned handle while the
1100 quitter is being awaited: the awaiting frame still holds it and
1101 destroys it again, which has undefined behavior. A holder that
1102 gives the coroutine up passes its continuation to @ref abandon
1103 instead. (Destroying or
1104 move-assigning over the quitter object itself while its frame is
1105 lent is a different operation, and calls `std::terminate`.)
1106 The quitter's lifetime is normally managed by `run_async`, `run`,
1107 or the awaiting parent.
1108
1109 @note The operation, queue or primitive holding a suspended
1110 coroutine gives it up by passing the continuation it keeps to
1111 @ref abandon. `handle()` belongs to the owning quitter object.
1112
1113 @note To run the quitter for an awaiting coroutine, call its
1114 `await_suspend`, which opens a segment for it. Do not resume
1115 this handle with the awaiting coroutine's environment: a stop
1116 then abandons the awaiting coroutine's segment, and a @ref task
1117 chain in it is torn down with no handler called. When
1118 `run_async` or `run` owns that segment, a debug build asserts.
1119 A launcher that resumes the handle itself must own the segment:
1120 see @ref await_context::owner.
1121
1122 @return The coroutine handle.
1123 */
1124 65x std::coroutine_handle<promise_type> handle() const noexcept
1125 {
1126 65x return h_;
1127 }
1128
1129 /** Release ownership of the coroutine frame.
1130
1131 @note The caller may call `destroy()` on the released handle
1132 only when the quitter has not started or has fully completed.
1133 Destroying the released handle of a quitter that is being
1134 awaited is not supported and has undefined behavior.
1135
1136 @par Postconditions
1137 `handle()` returns a null handle. Callers needing the
1138 original handle must save it, via @ref handle, before
1139 calling this.
1140 */
1141 50x void release() noexcept
1142 {
1143 50x h_ = nullptr;
1144 50x }
1145
1146 /** Copy construction is disabled; a quitter uniquely owns its frame.
1147
1148 @param other The quitter that would be copied.
1149 */
1150 quitter(quitter const& other) = delete;
1151
1152 /** Copy assignment is disabled; a quitter uniquely owns its frame.
1153
1154 @param other The quitter that would be assigned from.
1155
1156 @return A reference to `*this`.
1157 */
1158 quitter& operator=(quitter const& other) = delete;
1159
1160 /** Construct by moving, transferring ownership.
1161
1162 @par Preconditions
1163 `other` is not being awaited.
1164
1165 @par Postconditions
1166 `other` is empty and must not be awaited.
1167
1168 @param other The quitter to move from.
1169 */
1170 20233x quitter(quitter&& other) noexcept
1171 20233x : h_(std::exchange(other.h_, nullptr))
1172 {
1173 20233x release_top_ = other.release_top_;
1174 20233x }
1175
1176 /** Assign by moving, transferring ownership.
1177
1178 If this quitter already owns a coroutine frame, that frame is
1179 destroyed first. Self-assignment is a no-op.
1180
1181 @par Preconditions
1182 The frame being replaced is not lent: no parent is suspended
1183 awaiting it. Replacing a lent frame calls `std::terminate`.
1184 `other` is not being awaited.
1185
1186 @par Postconditions
1187 `other` is empty and must not be awaited.
1188
1189 @param other The quitter to move from.
1190
1191 @return A reference to `*this`.
1192 */
1193 1x quitter& operator=(quitter&& other) noexcept
1194 {
1195 1x if(this != &other)
1196 {
1197 1x destroy_frame();
1198 1x h_ = std::exchange(other.h_, nullptr);
1199 1x stopped_ = false;
1200 }
1201 1x return *this;
1202 }
1203
1204 private:
1205 template<class>
1206 friend struct quitter;
1207
1208 10204x explicit quitter(std::coroutine_handle<promise_type> h)
1209 10204x : h_(h)
1210 {
1211 10204x release_top_ = &release_top;
1212 10204x }
1213
1214 static std::coroutine_handle<>
1215 4804x release_top(detail::quitter_opener& o) noexcept
1216 {
1217 4804x return std::exchange(static_cast<quitter&>(o).h_, nullptr);
1218 }
1219
1220 // Start as a quitter joining the segment of the quitter `parent`.
1221 107x std::coroutine_handle<> join(
1222 std::coroutine_handle<> parent,
1223 detail::quitter_segment::promise_type* seg,
1224 await_context const* env) noexcept
1225 {
1226 107x auto& p = h_.promise();
1227 107x p.seg_ = seg;
1228 107x p.set_environment(env);
1229 107x p.set_continuation(parent);
1230 107x lent_ = true;
1231 107x return h_;
1232 }
1233
1234 30438x void destroy_frame() noexcept
1235 {
1236 30438x if(h_)
1237 {
1238 5350x if(lent_ && !h_.done())
1239 {
1240 // Only the unwind of an abandoned chain destroys a frame
1241 // that is still awaited.
1242 103x auto* owner = h_.promise().environment()->owner;
1243 103x if(!owner || !owner->abandoned())
1244 − std::terminate(); // LCOV_EXCL_LINE reached only in a death test's child process
1245 }
1246 5350x std::exchange(h_, nullptr).destroy();
1247 }
1248 30438x if(seg_.h_)
1249 {
1250 10039x seg_.h_.promise().active_ = false;
1251 10039x std::exchange(seg_.h_, nullptr).destroy();
1252 }
1253 30438x lent_ = false;
1254 30438x }
1255 };
1256
1257 } // namespace capy
1258 } // namespace boost
1259
1260 #endif
1261