diff --git a/include/boost/coroutine2/detail/pull_control_block_cc.hpp b/include/boost/coroutine2/detail/pull_control_block_cc.hpp index b8c90cf..4fd72a3 100644 --- a/include/boost/coroutine2/detail/pull_control_block_cc.hpp +++ b/include/boost/coroutine2/detail/pull_control_block_cc.hpp @@ -25,13 +25,15 @@ namespace detail { template< typename T > struct pull_coroutine< T >::control_block { - typename push_coroutine< T >::control_block * other; boost::context::captured_context ctx; + typename push_coroutine< T >::control_block * other; state_t state; std::exception_ptr except; bool bvalid; typename std::aligned_storage< sizeof( T), alignof( T) >::type storage; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); @@ -42,6 +44,8 @@ struct pull_coroutine< T >::control_block { control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume(); void set( T *); @@ -53,22 +57,24 @@ struct pull_coroutine< T >::control_block { template< typename T > struct pull_coroutine< T & >::control_block { - typename push_coroutine< T & >::control_block * other; boost::context::captured_context ctx; + typename push_coroutine< T & >::control_block * other; state_t state; std::exception_ptr except; T * t; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); control_block( typename push_coroutine< T & >::control_block *, boost::context::captured_context &) noexcept; - ~control_block(); - control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume(); T & get() noexcept; @@ -77,21 +83,23 @@ struct pull_coroutine< T & >::control_block { }; struct pull_coroutine< void >::control_block { - push_coroutine< void >::control_block * other; boost::context::captured_context ctx; + push_coroutine< void >::control_block * other; state_t state; std::exception_ptr except; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); control_block( push_coroutine< void >::control_block *, boost::context::captured_context &) noexcept; - ~control_block(); - control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume(); bool valid() const noexcept; diff --git a/include/boost/coroutine2/detail/pull_control_block_cc.ipp b/include/boost/coroutine2/detail/pull_control_block_cc.ipp index 07972cf..1933030 100644 --- a/include/boost/coroutine2/detail/pull_control_block_cc.ipp +++ b/include/boost/coroutine2/detail/pull_control_block_cc.ipp @@ -30,11 +30,20 @@ namespace detail { // pull_coroutine< T > +template< typename T > +void +pull_coroutine< T >::control_block::destroy( control_block * cb) noexcept { + boost::context::captured_context ctx = std::move( cb->ctx); + // destroy control structure + cb->~control_block(); + // destroy coroutine's stack + ctx(); +} + template< typename T > template< typename StackAllocator, typename Fn > pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) : - other{ nullptr }, #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) ctx{ std::allocator_arg, palloc, salloc, std::move( @@ -89,6 +98,7 @@ pull_coroutine< T >::control_block::control_block( context::preallocated palloc, return std::move( other->ctx); }}, #endif + other{ nullptr }, state{ state_t::unwind }, except{}, bvalid{ false }, @@ -102,8 +112,8 @@ pull_coroutine< T >::control_block::control_block( context::preallocated palloc, template< typename T > pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb, boost::context::captured_context & ctx_) noexcept : - other{ cb }, ctx{ std::move( ctx_) }, + other{ cb }, state{ state_t::none }, except{}, bvalid{ false }, @@ -116,9 +126,13 @@ pull_coroutine< T >::control_block::~control_block() { if ( bvalid) { reinterpret_cast< T * >( std::addressof( storage) )->~T(); } +} + +template< typename T > +void +pull_coroutine< T >::control_block::deallocate() noexcept { if ( state_t::none != ( state & state_t::unwind) ) { - // unwind coroutine stack - ctx(); + destroy( this); } } @@ -163,11 +177,20 @@ pull_coroutine< T >::control_block::valid() const noexcept { // pull_coroutine< T & > +template< typename T > +void +pull_coroutine< T & >::control_block::destroy( control_block * cb) noexcept { + boost::context::captured_context ctx = std::move( cb->ctx); + // destroy control structure + cb->~control_block(); + // destroy coroutine's stack + ctx(); +} + template< typename T > template< typename StackAllocator, typename Fn > pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) : - other{ nullptr }, #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) ctx{ std::allocator_arg, palloc, salloc, std::move( @@ -222,6 +245,7 @@ pull_coroutine< T & >::control_block::control_block( context::preallocated pallo return std::move( other->ctx); }}, #endif + other{ nullptr }, state{ state_t::unwind }, except{}, t{ nullptr } { @@ -234,18 +258,18 @@ pull_coroutine< T & >::control_block::control_block( context::preallocated pallo template< typename T > pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb, boost::context::captured_context & ctx_) noexcept : - other{ cb }, ctx{ std::move( ctx_) }, + other{ cb }, state{ state_t::none }, except{}, t{ nullptr } { } template< typename T > -pull_coroutine< T & >::control_block::~control_block() { +void +pull_coroutine< T & >::control_block::deallocate() noexcept { if ( state_t::none != ( state & state_t::unwind) ) { - // unwind coroutine stack - ctx(); + destroy( this); } } @@ -275,10 +299,19 @@ pull_coroutine< T & >::control_block::valid() const noexcept { // pull_coroutine< void > +inline +void +pull_coroutine< void >::control_block::destroy( control_block * cb) noexcept { + boost::context::captured_context ctx = std::move( cb->ctx); + // destroy control structure + cb->~control_block(); + // destroy coroutine's stack + ctx(); +} + template< typename StackAllocator, typename Fn > pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) : - other{ nullptr }, #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) ctx{ std::allocator_arg, palloc, salloc, std::move( @@ -333,6 +366,7 @@ pull_coroutine< void >::control_block::control_block( context::preallocated pall return std::move( other->ctx); }}, #endif + other{ nullptr }, state{ state_t::unwind }, except{} { // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns @@ -343,17 +377,17 @@ pull_coroutine< void >::control_block::control_block( context::preallocated pall inline pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb, boost::context::captured_context & ctx_) noexcept : - other{ cb }, ctx{ std::move( ctx_) }, + other{ cb }, state{ state_t::none }, except{} { } inline -pull_coroutine< void >::control_block::~control_block() { +void +pull_coroutine< void >::control_block::deallocate() noexcept { if ( state_t::none != ( state & state_t::unwind) ) { - // unwind coroutine stack - ctx(); + destroy( this); } } diff --git a/include/boost/coroutine2/detail/pull_control_block_ec.hpp b/include/boost/coroutine2/detail/pull_control_block_ec.hpp index 31af766..203a200 100644 --- a/include/boost/coroutine2/detail/pull_control_block_ec.hpp +++ b/include/boost/coroutine2/detail/pull_control_block_ec.hpp @@ -26,13 +26,15 @@ namespace detail { template< typename T > struct pull_coroutine< T >::control_block { - typename push_coroutine< T >::control_block * other; boost::context::execution_context ctx; + typename push_coroutine< T >::control_block * other; state_t state; std::exception_ptr except; bool bvalid; typename std::aligned_storage< sizeof( T), alignof( T) >::type storage; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); @@ -43,6 +45,8 @@ struct pull_coroutine< T >::control_block { control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume(); void set( T *); @@ -54,12 +58,14 @@ struct pull_coroutine< T >::control_block { template< typename T > struct pull_coroutine< T & >::control_block { - typename push_coroutine< T & >::control_block * other; boost::context::execution_context ctx; + typename push_coroutine< T & >::control_block * other; state_t state; std::exception_ptr except; T * t; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); @@ -70,6 +76,8 @@ struct pull_coroutine< T & >::control_block { control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume(); T & get() noexcept; @@ -78,11 +86,13 @@ struct pull_coroutine< T & >::control_block { }; struct pull_coroutine< void >::control_block { - push_coroutine< void >::control_block * other; boost::context::execution_context ctx; + push_coroutine< void >::control_block * other; state_t state; std::exception_ptr except; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); @@ -93,6 +103,8 @@ struct pull_coroutine< void >::control_block { control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume(); bool valid() const noexcept; diff --git a/include/boost/coroutine2/detail/pull_control_block_ec.ipp b/include/boost/coroutine2/detail/pull_control_block_ec.ipp index 481601d..f271e79 100644 --- a/include/boost/coroutine2/detail/pull_control_block_ec.ipp +++ b/include/boost/coroutine2/detail/pull_control_block_ec.ipp @@ -31,11 +31,18 @@ namespace detail { // pull_coroutine< T > +template< typename T > +void +pull_coroutine< T >::control_block::destroy( control_block * cb) noexcept { + boost::context::execution_context ctx = cb->ctx; + // destroy control structure + cb->~control_block(); +} + template< typename T > template< typename StackAllocator, typename Fn > pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) : - other{ nullptr }, #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) ctx{ std::allocator_arg, palloc, salloc, std::move( @@ -88,6 +95,7 @@ pull_coroutine< T >::control_block::control_block( context::preallocated palloc, BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); }}, #endif + other{ nullptr }, state{ state_t::unwind }, except{}, bvalid{ false }, @@ -99,8 +107,8 @@ pull_coroutine< T >::control_block::control_block( context::preallocated palloc, template< typename T > pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb, boost::context::execution_context const& ctx_) noexcept : - other{ cb }, ctx{ ctx_ }, + other{ cb }, state{ state_t::none }, except{}, bvalid{ false }, @@ -120,6 +128,14 @@ pull_coroutine< T >::control_block::~control_block() { } } +template< typename T > +void +pull_coroutine< T >::control_block::deallocate() noexcept { + if ( state_t::none != ( state & state_t::unwind) ) { + destroy( this); + } +} + template< typename T > void pull_coroutine< T >::control_block::resume() { @@ -160,11 +176,18 @@ pull_coroutine< T >::control_block::valid() const noexcept { // pull_coroutine< T & > +template< typename T > +void +pull_coroutine< T & >::control_block::destroy( control_block * cb) noexcept { + boost::context::execution_context ctx = cb->ctx; + // destroy control structure + cb->~control_block(); +} + template< typename T > template< typename StackAllocator, typename Fn > pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) : - other{ nullptr }, #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) ctx{ std::allocator_arg, palloc, salloc, std::move( @@ -217,6 +240,7 @@ pull_coroutine< T & >::control_block::control_block( context::preallocated pallo BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); }}, #endif + other{ nullptr }, state{ state_t::unwind }, except{}, t{ nullptr } { @@ -227,15 +251,15 @@ pull_coroutine< T & >::control_block::control_block( context::preallocated pallo template< typename T > pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb, boost::context::execution_context const& ctx_) noexcept : - other{ cb }, ctx{ ctx_ }, + other{ cb }, state{ state_t::none }, except{}, t( nullptr) { } template< typename T > -pull_coroutine< T & >::control_block::~control_block() noexcept { +pull_coroutine< T & >::control_block::~control_block() { if ( state_t::none == ( state & state_t::complete) && state_t::none != ( state & state_t::unwind) ) { // unwind coroutine stack @@ -243,6 +267,14 @@ pull_coroutine< T & >::control_block::~control_block() noexcept { } } +template< typename T > +void +pull_coroutine< T & >::control_block::deallocate() noexcept { + if ( state_t::none != ( state & state_t::unwind) ) { + destroy( this); + } +} + template< typename T > void pull_coroutine< T & >::control_block::resume() { @@ -268,10 +300,17 @@ pull_coroutine< T & >::control_block::valid() const noexcept { // pull_coroutine< void > +inline +void +pull_coroutine< void >::control_block::destroy( control_block * cb) noexcept { + boost::context::execution_context ctx = cb->ctx; + // destroy control structure + cb->~control_block(); +} + template< typename StackAllocator, typename Fn > pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) : - other{ nullptr }, #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) ctx{ std::allocator_arg, palloc, salloc, std::move( @@ -324,6 +363,7 @@ pull_coroutine< void >::control_block::control_block( context::preallocated pall BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); }}, #endif + other{ nullptr }, state{ state_t::unwind }, except{} { // enter coroutine-fn in order to have first value available after ctor returns @@ -333,14 +373,14 @@ pull_coroutine< void >::control_block::control_block( context::preallocated pall inline pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb, boost::context::execution_context const& ctx_) noexcept : - other{ cb }, ctx{ ctx_ }, + other{ cb }, state{ state_t::none }, except{} { } inline -pull_coroutine< void >::control_block::~control_block() noexcept { +pull_coroutine< void >::control_block::~control_block() { if ( state_t::none == ( state & state_t::complete) && state_t::none != ( state & state_t::unwind) ) { // unwind coroutine stack @@ -348,6 +388,14 @@ pull_coroutine< void >::control_block::~control_block() noexcept { } } +inline +void +pull_coroutine< void >::control_block::deallocate() noexcept { + if ( state_t::none != ( state & state_t::unwind) ) { + destroy( this); + } +} + inline void pull_coroutine< void >::control_block::resume() { diff --git a/include/boost/coroutine2/detail/pull_coroutine.ipp b/include/boost/coroutine2/detail/pull_coroutine.ipp index a6c45fd..58fe845 100644 --- a/include/boost/coroutine2/detail/pull_coroutine.ipp +++ b/include/boost/coroutine2/detail/pull_coroutine.ipp @@ -53,7 +53,7 @@ template< typename StackAllocator, typename Fn > pull_coroutine< T >::pull_coroutine( StackAllocator salloc, Fn && fn) : cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } { if ( ! cb_->valid() ) { - cb_->~control_block(); + cb_->deallocate(); cb_ = nullptr; } } @@ -61,7 +61,7 @@ pull_coroutine< T >::pull_coroutine( StackAllocator salloc, Fn && fn) : template< typename T > pull_coroutine< T >::~pull_coroutine() noexcept { if ( nullptr != cb_) { - cb_->~control_block(); + cb_->deallocate(); } } @@ -122,7 +122,7 @@ template< typename StackAllocator, typename Fn > pull_coroutine< T & >::pull_coroutine( StackAllocator salloc, Fn && fn) : cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } { if ( ! cb_->valid() ) { - cb_->~control_block(); + cb_->deallocate(); cb_ = nullptr; } } @@ -130,7 +130,7 @@ pull_coroutine< T & >::pull_coroutine( StackAllocator salloc, Fn && fn) : template< typename T > pull_coroutine< T & >::~pull_coroutine() noexcept { if ( nullptr != cb_) { - cb_->~control_block(); + cb_->deallocate(); } } @@ -183,7 +183,7 @@ template< typename StackAllocator, typename Fn > pull_coroutine< void >::pull_coroutine( StackAllocator salloc, Fn && fn) : cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } { if ( ! cb_->valid() ) { - cb_->~control_block(); + cb_->deallocate(); cb_ = nullptr; } } @@ -191,7 +191,7 @@ pull_coroutine< void >::pull_coroutine( StackAllocator salloc, Fn && fn) : inline pull_coroutine< void >::~pull_coroutine() noexcept { if ( nullptr != cb_) { - cb_->~control_block(); + cb_->deallocate(); } } diff --git a/include/boost/coroutine2/detail/push_control_block_cc.hpp b/include/boost/coroutine2/detail/push_control_block_cc.hpp index fb43688..ac4ab61 100644 --- a/include/boost/coroutine2/detail/push_control_block_cc.hpp +++ b/include/boost/coroutine2/detail/push_control_block_cc.hpp @@ -24,21 +24,23 @@ namespace detail { template< typename T > struct push_coroutine< T >::control_block { - typename pull_coroutine< T >::control_block * other; boost::context::captured_context ctx; + typename pull_coroutine< T >::control_block * other; state_t state; std::exception_ptr except; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); control_block( typename pull_coroutine< T >::control_block *, boost::context::captured_context &) noexcept; - ~control_block(); - control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume( T const&); void resume( T &&); @@ -48,42 +50,46 @@ struct push_coroutine< T >::control_block { template< typename T > struct push_coroutine< T & >::control_block { - typename pull_coroutine< T & >::control_block * other; boost::context::captured_context ctx; + typename pull_coroutine< T & >::control_block * other; state_t state; std::exception_ptr except; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); control_block( typename pull_coroutine< T & >::control_block *, boost::context::captured_context &) noexcept; - ~control_block(); - control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume( T &); bool valid() const noexcept; }; struct push_coroutine< void >::control_block { - pull_coroutine< void >::control_block * other; boost::context::captured_context ctx; + pull_coroutine< void >::control_block * other; state_t state; std::exception_ptr except; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); control_block( pull_coroutine< void >::control_block *, boost::context::captured_context &) noexcept; - ~control_block(); - control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume(); bool valid() const noexcept; diff --git a/include/boost/coroutine2/detail/push_control_block_cc.ipp b/include/boost/coroutine2/detail/push_control_block_cc.ipp index b51352e..78a6394 100644 --- a/include/boost/coroutine2/detail/push_control_block_cc.ipp +++ b/include/boost/coroutine2/detail/push_control_block_cc.ipp @@ -29,11 +29,20 @@ namespace detail { // push_coroutine< T > +template< typename T > +void +push_coroutine< T >::control_block::destroy( control_block * cb) noexcept { + boost::context::captured_context ctx = std::move( cb->ctx); + // destroy control structure + cb->~control_block(); + // destroy coroutine's stack + ctx(); +} + template< typename T > template< typename StackAllocator, typename Fn > push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) : - other{ nullptr }, #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) ctx{ std::allocator_arg, palloc, salloc, std::move( @@ -92,6 +101,7 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc, return std::move( other->ctx); }}, #endif + other{ nullptr }, state{ state_t::unwind }, except{} { } @@ -99,17 +109,17 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc, template< typename T > push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb, boost::context::captured_context & ctx_) noexcept : - other{ cb }, ctx{ std::move( ctx_) }, + other{ cb }, state{ state_t::none }, except{} { } template< typename T > -push_coroutine< T >::control_block::~control_block() { +void +push_coroutine< T >::control_block::deallocate() noexcept { if ( state_t::none != ( state & state_t::unwind) ) { - // unwind coroutine stack - ctx(); + destroy( this); } } @@ -144,11 +154,20 @@ push_coroutine< T >::control_block::valid() const noexcept { // push_coroutine< T & > +template< typename T > +void +push_coroutine< T & >::control_block::destroy( control_block * cb) noexcept { + boost::context::captured_context ctx = std::move( cb->ctx); + // destroy control structure + cb->~control_block(); + // destroy coroutine's stack + ctx(); +} + template< typename T > template< typename StackAllocator, typename Fn > push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) : - other{ nullptr }, #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) ctx{ std::allocator_arg, palloc, salloc, std::move( @@ -207,6 +226,7 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo return std::move( other->ctx); }}, #endif + other{ nullptr }, state{ state_t::unwind }, except{} { } @@ -214,17 +234,17 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo template< typename T > push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb, boost::context::captured_context & ctx_) noexcept : - other{ cb }, ctx{ std::move( ctx_) }, + other{ cb }, state{ state_t::none }, except{} { } template< typename T > -push_coroutine< T & >::control_block::~control_block() { +void +push_coroutine< T & >::control_block::deallocate() noexcept { if ( state_t::none != ( state & state_t::unwind) ) { - // unwind coroutine stack - ctx(); + destroy( this); } } @@ -248,9 +268,18 @@ push_coroutine< T & >::control_block::valid() const noexcept { // push_coroutine< void > +inline +void +push_coroutine< void >::control_block::destroy( control_block * cb) noexcept { + boost::context::captured_context ctx = std::move( cb->ctx); + // destroy control structure + cb->~control_block(); + // destroy coroutine's stack + ctx(); +} + template< typename StackAllocator, typename Fn > push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) : - other{ nullptr }, #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) ctx{ std::allocator_arg, palloc, salloc, std::move( @@ -305,6 +334,7 @@ push_coroutine< void >::control_block::control_block( context::preallocated pall return std::move( other->ctx); }}, #endif + other{ nullptr }, state{ state_t::unwind }, except{} { } @@ -312,17 +342,17 @@ push_coroutine< void >::control_block::control_block( context::preallocated pall inline push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb, boost::context::captured_context & ctx_) noexcept : - other{ cb }, ctx{ std::move( ctx_) }, + other{ cb }, state{ state_t::none }, except{} { } inline -push_coroutine< void >::control_block::~control_block() { +void +push_coroutine< void >::control_block::deallocate() noexcept { if ( state_t::none != ( state & state_t::unwind) ) { - // unwind coroutine stack - ctx(); + destroy( this); } } diff --git a/include/boost/coroutine2/detail/push_control_block_ec.hpp b/include/boost/coroutine2/detail/push_control_block_ec.hpp index e5127bf..f93215d 100644 --- a/include/boost/coroutine2/detail/push_control_block_ec.hpp +++ b/include/boost/coroutine2/detail/push_control_block_ec.hpp @@ -25,21 +25,25 @@ namespace detail { template< typename T > struct push_coroutine< T >::control_block { - typename pull_coroutine< T >::control_block * other; boost::context::execution_context ctx; + typename pull_coroutine< T >::control_block * other; state_t state; std::exception_ptr except; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); control_block( typename pull_coroutine< T >::control_block *, boost::context::execution_context const&) noexcept; - ~control_block() noexcept; + ~control_block(); control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume( T const&); void resume( T &&); @@ -49,42 +53,50 @@ struct push_coroutine< T >::control_block { template< typename T > struct push_coroutine< T & >::control_block { - typename pull_coroutine< T & >::control_block * other; boost::context::execution_context ctx; + typename pull_coroutine< T & >::control_block * other; state_t state; std::exception_ptr except; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); control_block( typename pull_coroutine< T & >::control_block *, boost::context::execution_context const&) noexcept; - ~control_block() noexcept; + ~control_block(); control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume( T &); bool valid() const noexcept; }; struct push_coroutine< void >::control_block { - pull_coroutine< void >::control_block * other; boost::context::execution_context ctx; + pull_coroutine< void >::control_block * other; state_t state; std::exception_ptr except; + static void destroy( control_block * cb) noexcept; + template< typename StackAllocator, typename Fn > control_block( context::preallocated, StackAllocator, Fn &&); control_block( pull_coroutine< void >::control_block *, boost::context::execution_context const&) noexcept; - ~control_block() noexcept; + ~control_block(); control_block( control_block &) = delete; control_block & operator=( control_block &) = delete; + void deallocate() noexcept; + void resume(); bool valid() const noexcept; diff --git a/include/boost/coroutine2/detail/push_control_block_ec.ipp b/include/boost/coroutine2/detail/push_control_block_ec.ipp index dc1be36..adefe07 100644 --- a/include/boost/coroutine2/detail/push_control_block_ec.ipp +++ b/include/boost/coroutine2/detail/push_control_block_ec.ipp @@ -32,11 +32,18 @@ namespace detail { // push_coroutine< T > +template< typename T > +void +push_coroutine< T >::control_block::destroy( control_block * cb) noexcept { + boost::context::execution_context ctx = cb->ctx; + // destroy control structure + cb->~control_block(); +} + template< typename T > template< typename StackAllocator, typename Fn > push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) : - other{ nullptr }, #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) ctx{ std::allocator_arg, palloc, salloc, std::move( @@ -97,6 +104,7 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc, BOOST_ASSERT_MSG( false, "push_coroutine is complete"); }}, #endif + other{ nullptr }, state{ state_t::unwind }, except{} { // enter coroutine-fn in order to get other set @@ -106,14 +114,14 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc, template< typename T > push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb, boost::context::execution_context const& ctx_) noexcept : - other{ cb }, ctx{ ctx_ }, + other{ cb }, state{ state_t::none }, except{} { } template< typename T > -push_coroutine< T >::control_block::~control_block() noexcept { +push_coroutine< T >::control_block::~control_block() { if ( state_t::none == ( state & state_t::complete) && state_t::none != ( state & state_t::unwind) ) { // unwind coroutine stack @@ -121,6 +129,14 @@ push_coroutine< T >::control_block::~control_block() noexcept { } } +template< typename T > +void +push_coroutine< T >::control_block::deallocate() noexcept { + if ( state_t::none != ( state & state_t::unwind) ) { + destroy( this); + } +} + template< typename T > void push_coroutine< T >::control_block::resume( T const& t) { @@ -152,11 +168,18 @@ push_coroutine< T >::control_block::valid() const noexcept { // push_coroutine< T & > +template< typename T > +void +push_coroutine< T & >::control_block::destroy( control_block * cb) noexcept { + boost::context::execution_context ctx = cb->ctx; + // destroy control structure + cb->~control_block(); +} + template< typename T > template< typename StackAllocator, typename Fn > push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) : - other{ nullptr }, #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) ctx{ std::allocator_arg, palloc, salloc, std::move( @@ -217,6 +240,7 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo BOOST_ASSERT_MSG( false, "push_coroutine is complete"); }}, #endif + other{ nullptr }, state{ state_t::unwind }, except{} { // enter coroutine-fn in order to get other set @@ -226,14 +250,14 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo template< typename T > push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb, boost::context::execution_context const& ctx_) noexcept : - other{ cb }, ctx{ ctx_ }, + other{ cb }, state{ state_t::none }, except{} { } template< typename T > -push_coroutine< T & >::control_block::~control_block() noexcept { +push_coroutine< T & >::control_block::~control_block() { if ( state_t::none == ( state & state_t::complete) && state_t::none != ( state & state_t::unwind) ) { // unwind coroutine stack @@ -241,6 +265,14 @@ push_coroutine< T & >::control_block::~control_block() noexcept { } } +template< typename T > +void +push_coroutine< T & >::control_block::deallocate() noexcept { + if ( state_t::none != ( state & state_t::unwind) ) { + destroy( this); + } +} + template< typename T > void push_coroutine< T & >::control_block::resume( T & t) { @@ -261,9 +293,16 @@ push_coroutine< T & >::control_block::valid() const noexcept { // push_coroutine< void > +inline +void +push_coroutine< void >::control_block::destroy( control_block * cb) noexcept { + boost::context::execution_context ctx = cb->ctx; + // destroy control structure + cb->~control_block(); +} + template< typename StackAllocator, typename Fn > push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) : - other{ nullptr }, #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) ctx{ std::allocator_arg, palloc, salloc, std::move( @@ -321,6 +360,7 @@ push_coroutine< void >::control_block::control_block( context::preallocated pall BOOST_ASSERT_MSG( false, "push_coroutine is complete"); }}, #endif + other{ nullptr }, state{ state_t::unwind }, except{} { // enter coroutine-fn in order to get other set @@ -330,14 +370,14 @@ push_coroutine< void >::control_block::control_block( context::preallocated pall inline push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb, boost::context::execution_context const& ctx_) noexcept : - other{ cb }, ctx{ ctx_ }, + other{ cb }, state{ state_t::none }, except{} { } inline -push_coroutine< void >::control_block::~control_block() noexcept { +push_coroutine< void >::control_block::~control_block() { if ( state_t::none == ( state & state_t::complete) && state_t::none != ( state & state_t::unwind) ) { // unwind coroutine stack @@ -345,6 +385,14 @@ push_coroutine< void >::control_block::~control_block() noexcept { } } +inline +void +push_coroutine< void >::control_block::deallocate() noexcept { + if ( state_t::none != ( state & state_t::unwind) ) { + destroy( this); + } +} + inline void push_coroutine< void >::control_block::resume() { diff --git a/include/boost/coroutine2/detail/push_coroutine.ipp b/include/boost/coroutine2/detail/push_coroutine.ipp index df54d69..304e077 100644 --- a/include/boost/coroutine2/detail/push_coroutine.ipp +++ b/include/boost/coroutine2/detail/push_coroutine.ipp @@ -50,7 +50,7 @@ push_coroutine< T >::push_coroutine( StackAllocator salloc, Fn && fn) : template< typename T > push_coroutine< T >::~push_coroutine() noexcept { if ( nullptr != cb_) { - cb_->~control_block(); + cb_->deallocate(); } } @@ -110,7 +110,7 @@ push_coroutine< T & >::push_coroutine( StackAllocator salloc, Fn && fn) : template< typename T > push_coroutine< T & >::~push_coroutine() noexcept { if ( nullptr != cb_) { - cb_->~control_block(); + cb_->deallocate(); } } @@ -161,7 +161,7 @@ push_coroutine< void >::push_coroutine( StackAllocator salloc, Fn && fn) : inline push_coroutine< void >::~push_coroutine() noexcept { if ( nullptr != cb_) { - cb_->~control_block(); + cb_->deallocate(); } }