From 778656934f488d56409f26285e88f208ccf11930 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Sat, 6 Feb 2016 13:34:10 +0100 Subject: [PATCH] captured_context renamed to execution_context (v2) - execution_context (v2) is enabled per default - execution_context (v1) is used for segmented stacks --- include/boost/fiber/context.hpp | 144 +++++++++++++--------------- include/boost/fiber/detail/wrap.hpp | 82 ++++++++-------- include/boost/fiber/scheduler.hpp | 12 +-- src/context.cpp | 92 +++++++++--------- src/scheduler.cpp | 25 +++-- 5 files changed, 173 insertions(+), 182 deletions(-) diff --git a/include/boost/fiber/context.hpp b/include/boost/fiber/context.hpp index f8e80a30..d23f64c3 100644 --- a/include/boost/fiber/context.hpp +++ b/include/boost/fiber/context.hpp @@ -18,11 +18,7 @@ #include #include #include -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) -# include -#else -# include -#endif +#include #include #include #include @@ -161,7 +157,22 @@ private: } }; -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) +#if (BOOST_EXECUTION_CONTEXT==1) + struct data_t { + detail::spinlock_lock * lk{ nullptr }; + context * ctx{ nullptr }; + + constexpr data_t() noexcept = default; + + explicit data_t( detail::spinlock_lock * lk_) noexcept : + lk{ lk_ } { + } + + explicit data_t( context * ctx_) noexcept : + ctx{ ctx_ } { + } + }; +#else struct data_t { detail::spinlock_lock * lk{ nullptr }; context * ctx{ nullptr }; @@ -183,21 +194,6 @@ private: from{ from_ } { } }; -#else - struct data_t { - detail::spinlock_lock * lk{ nullptr }; - context * ctx{ nullptr }; - - constexpr data_t() noexcept = default; - - explicit data_t( detail::spinlock_lock * lk_) noexcept : - lk{ lk_ } { - } - - explicit data_t( context * ctx_) noexcept : - ctx{ ctx_ } { - } - }; #endif typedef std::map< uintptr_t, fss_data > fss_data_t; @@ -212,36 +208,12 @@ private: int flags_; #endif scheduler * scheduler_{ nullptr }; -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) - boost::context::captured_context ctx_; -#else boost::context::execution_context ctx_; -#endif void resume_( data_t &) noexcept; void set_ready_( context *) noexcept; -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) - template< typename Fn, typename Tpl > - boost::context::captured_context - run_( boost::context::captured_context ctx, Fn && fn_, Tpl && tpl_, data_t * dp) noexcept { - try { - typename std::decay< Fn >::type fn = std::forward< Fn >( fn_); - typename std::decay< Tpl >::type tpl = std::forward< Tpl >( tpl_); - // update captured_context of calling fiber - dp->from->ctx_ = std::move( ctx); - if ( nullptr != dp->lk) { - dp->lk->unlock(); - } else if ( nullptr != dp->ctx) { - active_->set_ready_( dp->ctx); - } - boost::context::detail::apply( std::move( fn), std::move( tpl) ); - } catch ( fiber_interrupted const&) { - } - // terminate context - return set_terminated(); - } -#else +#if (BOOST_EXECUTION_CONTEXT==1) template< typename Fn, typename Tpl > void run_( Fn && fn_, Tpl && tpl_, data_t * dp) noexcept { try { @@ -259,6 +231,26 @@ private: set_terminated(); BOOST_ASSERT_MSG( false, "fiber already terminated"); } +#else + template< typename Fn, typename Tpl > + boost::context::execution_context + run_( boost::context::execution_context ctx, Fn && fn_, Tpl && tpl_, data_t * dp) noexcept { + try { + typename std::decay< Fn >::type fn = std::forward< Fn >( fn_); + typename std::decay< Tpl >::type tpl = std::forward< Tpl >( tpl_); + // update execution_context of calling fiber + dp->from->ctx_ = std::move( ctx); + if ( nullptr != dp->lk) { + dp->lk->unlock(); + } else if ( nullptr != dp->ctx) { + active_->set_ready_( dp->ctx); + } + boost::context::detail::apply( std::move( fn), std::move( tpl) ); + } catch ( fiber_interrupted const&) { + } + // terminate context + return set_terminated(); + } #endif public: @@ -357,25 +349,7 @@ public: Fn && fn, Tpl && tpl) : use_count_{ 1 }, // fiber instance or scheduler owner flags_{ flag_worker_context }, -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) -# if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) - ctx_{ std::allocator_arg, palloc, salloc, - detail::wrap( - [this]( typename std::decay< Fn >::type & fn, typename std::decay< Tpl >::type & tpl, - boost::context::captured_context ctx, void * vp) mutable noexcept { - return run_( std::move( ctx), std::move( fn), std::move( tpl), static_cast< data_t * >( vp) ); - }, - std::forward< Fn >( fn), - std::forward< Tpl >( tpl) )} - -# else - ctx_{ std::allocator_arg, palloc, salloc, - [this,fn=detail::decay_copy( std::forward< Fn >( fn) ),tpl=std::forward< Tpl >( tpl)] - (boost::context::captured_context ctx, void * vp) mutable noexcept { - return run_( std::move( ctx), std::move( fn), std::move( tpl), static_cast< data_t * >( vp) ); - }} -# endif -#else +#if (BOOST_EXECUTION_CONTEXT==1) # if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) ctx_{ std::allocator_arg, palloc, salloc, detail::wrap( @@ -394,6 +368,24 @@ public: run_( std::move( fn), std::move( tpl), static_cast< data_t * >( vp) ); }} # endif +#else +# if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) + ctx_{ std::allocator_arg, palloc, salloc, + detail::wrap( + [this]( typename std::decay< Fn >::type & fn, typename std::decay< Tpl >::type & tpl, + boost::context::execution_context ctx, void * vp) mutable noexcept { + return run_( std::move( ctx), std::move( fn), std::move( tpl), static_cast< data_t * >( vp) ); + }, + std::forward< Fn >( fn), + std::forward< Tpl >( tpl) )} + +# else + ctx_{ std::allocator_arg, palloc, salloc, + [this,fn=detail::decay_copy( std::forward< Fn >( fn) ),tpl=std::forward< Tpl >( tpl)] + (boost::context::execution_context ctx, void * vp) mutable noexcept { + return run_( std::move( ctx), std::move( fn), std::move( tpl), static_cast< data_t * >( vp) ); + }} +# endif #endif {} @@ -413,11 +405,11 @@ public: void suspend() noexcept; void suspend( detail::spinlock_lock &) noexcept; -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) - boost::context::captured_context suspend_with_cc() noexcept; - boost::context::captured_context set_terminated() noexcept; -#else +#if (BOOST_EXECUTION_CONTEXT==1) void set_terminated() noexcept; +#else + boost::context::execution_context suspend_with_cc() noexcept; + boost::context::execution_context set_terminated() noexcept; #endif void join(); @@ -541,17 +533,17 @@ public: friend void intrusive_ptr_release( context * ctx) noexcept { BOOST_ASSERT( nullptr != ctx); if ( 0 == --ctx->use_count_) { -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) - boost::context::captured_context cc( std::move( ctx->ctx_) ); - // destruct context - ctx->~context(); - // deallocated stack - cc(); -#else +#if (BOOST_EXECUTION_CONTEXT==1) boost::context::execution_context ec( ctx->ctx_); // destruct context // deallocates stack (execution_context is ref counted) ctx->~context(); +#else + boost::context::execution_context cc( std::move( ctx->ctx_) ); + // destruct context + ctx->~context(); + // deallocated stack + cc(); #endif } } diff --git a/include/boost/fiber/detail/wrap.hpp b/include/boost/fiber/detail/wrap.hpp index a0bbff9b..cf3b062a 100644 --- a/include/boost/fiber/detail/wrap.hpp +++ b/include/boost/fiber/detail/wrap.hpp @@ -11,11 +11,7 @@ #include #include -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) -# include -#else -# include -#endif +#include #include @@ -27,44 +23,7 @@ namespace boost { namespace fibers { namespace detail { -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) -template< typename Fn1, typename Fn2, typename Tpl > -class wrapper { -private: - typename std::decay< Fn1 >::type fn1_; - typename std::decay< Fn2 >::type fn2_; - typename std::decay< Tpl >::type tpl_; - -public: - wrapper( Fn1 && fn1, Fn2 && fn2, Tpl && tpl) : - fn1_( std::move( fn1) ), - fn2_( std::move( fn2) ), - tpl_( std::move( tpl) ) { - } - - wrapper( wrapper const&) = delete; - wrapper & operator=( wrapper const&) = delete; - - wrapper( wrapper && other) = default; - wrapper & operator=( wrapper && other) = default; - - boost::context::captured_context - operator()( boost::context::captured_context ctx, void * vp) { - return boost::context::detail::invoke( - std::move( fn1_), - fn2_, tpl_, std::move( ctx), vp); - } -}; - -template< typename Fn1, typename Fn2, typename Tpl > -wrapper< Fn1, Fn2, Tpl > -wrap( Fn1 && fn1, Fn2 && fn2, Tpl && tpl) { - return wrapper< Fn1, Fn2, Tpl >( - std::forward< Fn1 >( fn1), - std::forward< Fn2 >( fn2), - std::forward< Tpl >( tpl) ); -} -#else +#if (BOOST_EXECUTION_CONTEXT==1) template< typename Fn1, typename Fn2, typename Tpl > class wrapper { private: @@ -105,6 +64,43 @@ wrap( Fn1 && fn1, Fn2 && fn2, Tpl && tpl, std::forward< Tpl >( tpl), ctx); } +#else +template< typename Fn1, typename Fn2, typename Tpl > +class wrapper { +private: + typename std::decay< Fn1 >::type fn1_; + typename std::decay< Fn2 >::type fn2_; + typename std::decay< Tpl >::type tpl_; + +public: + wrapper( Fn1 && fn1, Fn2 && fn2, Tpl && tpl) : + fn1_( std::move( fn1) ), + fn2_( std::move( fn2) ), + tpl_( std::move( tpl) ) { + } + + wrapper( wrapper const&) = delete; + wrapper & operator=( wrapper const&) = delete; + + wrapper( wrapper && other) = default; + wrapper & operator=( wrapper && other) = default; + + boost::context::execution_context + operator()( boost::context::execution_context ctx, void * vp) { + return boost::context::detail::invoke( + std::move( fn1_), + fn2_, tpl_, std::move( ctx), vp); + } +}; + +template< typename Fn1, typename Fn2, typename Tpl > +wrapper< Fn1, Fn2, Tpl > +wrap( Fn1 && fn1, Fn2 && fn2, Tpl && tpl) { + return wrapper< Fn1, Fn2, Tpl >( + std::forward< Fn1 >( fn1), + std::forward< Fn2 >( fn2), + std::forward< Tpl >( tpl) ); +} #endif }}} diff --git a/include/boost/fiber/scheduler.hpp b/include/boost/fiber/scheduler.hpp index 44d97c9d..75998f75 100644 --- a/include/boost/fiber/scheduler.hpp +++ b/include/boost/fiber/scheduler.hpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include @@ -104,14 +104,14 @@ public: void set_remote_ready( context *) noexcept; -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) - boost::context::captured_context dispatch() noexcept; - - boost::context::captured_context set_terminated( context *) noexcept; -#else +#if (BOOST_EXECUTION_CONTEXT==1) void dispatch() noexcept; void set_terminated( context *) noexcept; +#else + boost::context::execution_context dispatch() noexcept; + + boost::context::execution_context set_terminated( context *) noexcept; #endif void yield( context *) noexcept; diff --git a/src/context.cpp b/src/context.cpp index 6401dd70..c9fe6826 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -134,7 +134,7 @@ context_initializer::~context_initializer() { context * context::active() noexcept { -#if defined(BOOST_USE_EXECUTION_CONTEXT) +#if (BOOST_EXECUTION_CONTEXT==1) // initialized the first time control passes; per thread thread_local static boost::context::detail::activation_record_initializer rec_initializer; #endif @@ -148,7 +148,17 @@ context::reset_active() noexcept { active_ = nullptr; } -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) +#if (BOOST_EXECUTION_CONTEXT==1) +void +context::resume_( data_t & d) noexcept { + data_t * dp = static_cast< data_t * >( ctx_( & d) ); + if ( nullptr != dp->lk) { + dp->lk->unlock(); + } else if ( nullptr != dp->ctx) { + active_->set_ready_( dp->ctx); + } +} +#else void context::resume_( data_t & d) noexcept { auto result = ctx_( & d); @@ -162,16 +172,6 @@ context::resume_( data_t & d) noexcept { } } } -#else -void -context::resume_( data_t & d) noexcept { - data_t * dp = static_cast< data_t * >( ctx_( & d) ); - if ( nullptr != dp->lk) { - dp->lk->unlock(); - } else if ( nullptr != dp->ctx) { - active_->set_ready_( dp->ctx); - } -} #endif void @@ -183,10 +183,10 @@ context::set_ready_( context * ctx) noexcept { context::context( main_context_t) noexcept : use_count_{ 1 }, // allocated on main- or thread-stack flags_{ flag_main_context }, -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) - ctx_() { -#else +#if (BOOST_EXECUTION_CONTEXT==1) ctx_{ boost::context::execution_context::current() } { +#else + ctx_() { #endif } @@ -194,21 +194,7 @@ context::context( main_context_t) noexcept : context::context( dispatcher_context_t, boost::context::preallocated const& palloc, default_stack const& salloc, scheduler * sched) : flags_{ flag_dispatcher_context }, -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) - ctx_{ std::allocator_arg, palloc, salloc, - [this,sched](boost::context::captured_context ctx, void * vp) noexcept { - data_t * dp = static_cast< data_t * >( vp); - // update captured_context of calling fiber - dp->from->ctx_ = std::move( ctx); - if ( nullptr != dp->lk) { - dp->lk->unlock(); - } else if ( nullptr != dp->ctx) { - active_->set_ready_( dp->ctx); - } - // execute scheduler::dispatch() - return sched->dispatch(); - }} -#else +#if (BOOST_EXECUTION_CONTEXT==1) ctx_{ std::allocator_arg, palloc, salloc, [this,sched](void * vp) noexcept { data_t * dp = static_cast< data_t * >( vp); @@ -222,6 +208,20 @@ context::context( dispatcher_context_t, boost::context::preallocated const& pall // dispatcher context should never return from scheduler::dispatch() BOOST_ASSERT_MSG( false, "disatcher fiber already terminated"); }} +#else + ctx_{ std::allocator_arg, palloc, salloc, + [this,sched](boost::context::execution_context ctx, void * vp) noexcept { + data_t * dp = static_cast< data_t * >( vp); + // update execution_context of calling fiber + dp->from->ctx_ = std::move( ctx); + if ( nullptr != dp->lk) { + dp->lk->unlock(); + } else if ( nullptr != dp->ctx) { + active_->set_ready_( dp->ctx); + } + // execute scheduler::dispatch() + return sched->dispatch(); + }} #endif {} @@ -249,10 +249,10 @@ context::resume() noexcept { // active_ will point to `this` // prev will point to previous active context std::swap( active_, prev); -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) - data_t d{ prev }; -#else +#if (BOOST_EXECUTION_CONTEXT==1) data_t d{}; +#else + data_t d{ prev }; #endif resume_( d); } @@ -263,10 +263,10 @@ context::resume( detail::spinlock_lock & lk) noexcept { // active_ will point to `this` // prev will point to previous active context std::swap( active_, prev); -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) - data_t d{ & lk, prev }; -#else +#if (BOOST_EXECUTION_CONTEXT==1) data_t d{ & lk }; +#else + data_t d{ & lk, prev }; #endif resume_( d); } @@ -277,10 +277,10 @@ context::resume( context * ready_ctx) noexcept { // active_ will point to `this` // prev will point to previous active context std::swap( active_, prev); -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) - data_t d{ ready_ctx, prev }; -#else +#if (BOOST_EXECUTION_CONTEXT==1) data_t d{ ready_ctx }; +#else + data_t d{ ready_ctx, prev }; #endif resume_( d); } @@ -327,8 +327,8 @@ context::yield() noexcept { scheduler_->yield( context::active() ); } -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) -boost::context::captured_context +#if (BOOST_EXECUTION_CONTEXT>1) +boost::context::execution_context context::suspend_with_cc() noexcept { context * prev = this; // active_ will point to `this` @@ -340,10 +340,10 @@ context::suspend_with_cc() noexcept { } #endif -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) -boost::context::captured_context -#else +#if (BOOST_EXECUTION_CONTEXT==1) void +#else +boost::context::execution_context #endif context::set_terminated() noexcept { // protect for concurrent access @@ -365,7 +365,11 @@ context::set_terminated() noexcept { } fss_data_.clear(); // switch to another context +#if (BOOST_EXECUTION_CONTEXT==1) + scheduler_->set_terminated( this); +#else return scheduler_->set_terminated( this); +#endif } bool diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 78cd1b05..cc32510f 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -125,11 +125,11 @@ scheduler::~scheduler() { main_ctx_ = nullptr; } -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) -boost::context::captured_context +#if (BOOST_EXECUTION_CONTEXT==1) +void scheduler::dispatch() noexcept { #else -void +boost::context::execution_context scheduler::dispatch() noexcept { #endif BOOST_ASSERT( context::active() == dispatcher_ctx_); @@ -191,10 +191,10 @@ scheduler::dispatch() noexcept { // release termianted context' release_terminated_(); // return to main-context -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) - return main_ctx_->suspend_with_cc(); -#else +#if (BOOST_EXECUTION_CONTEXT==1) main_ctx_->resume(); +#else + return main_ctx_->suspend_with_cc(); #endif } @@ -242,11 +242,11 @@ scheduler::set_remote_ready( context * ctx) noexcept { sched_algo_->notify(); } -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) -boost::context::captured_context +#if (BOOST_EXECUTION_CONTEXT==1) +void scheduler::set_terminated( context * active_ctx) noexcept { #else -void +boost::context::execution_context scheduler::set_terminated( context * active_ctx) noexcept { #endif BOOST_ASSERT( nullptr != active_ctx); @@ -263,11 +263,10 @@ scheduler::set_terminated( context * active_ctx) noexcept { // intrusive_ptr_release( ctx); active_ctx->terminated_link( terminated_queue_); // resume another fiber -#if ! defined(BOOST_USE_EXECUTION_CONTEXT) - return get_next_()->suspend_with_cc(); -#else - // resume another fiber +#if (BOOST_EXECUTION_CONTEXT==1) get_next_()->resume(); +#else + return get_next_()->suspend_with_cc(); #endif }