summaryrefslogtreecommitdiff
path: root/boost/fiber/context.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/fiber/context.hpp')
-rw-r--r--boost/fiber/context.hpp263
1 files changed, 79 insertions, 184 deletions
diff --git a/boost/fiber/context.hpp b/boost/fiber/context.hpp
index 773528e3a1..e2d1aeff5f 100644
--- a/boost/fiber/context.hpp
+++ b/boost/fiber/context.hpp
@@ -7,11 +7,12 @@
#ifndef BOOST_FIBERS_CONTEXT_H
#define BOOST_FIBERS_CONTEXT_H
-#include <iostream>
#include <atomic>
#include <chrono>
+#include <cstdint>
#include <exception>
#include <functional>
+#include <iostream>
#include <map>
#include <memory>
#include <tuple>
@@ -22,11 +23,7 @@
#if defined(BOOST_NO_CXX17_STD_APPLY)
#include <boost/context/detail/apply.hpp>
#endif
-#if (BOOST_EXECUTION_CONTEXT==1)
-# include <boost/context/execution_context.hpp>
-#else
-# include <boost/context/continuation.hpp>
-#endif
+#include <boost/context/continuation.hpp>
#include <boost/context/stack_context.hpp>
#include <boost/intrusive/list.hpp>
#include <boost/intrusive/parent_from_member.hpp>
@@ -39,7 +36,6 @@
#include <boost/fiber/detail/decay_copy.hpp>
#include <boost/fiber/detail/fss.hpp>
#include <boost/fiber/detail/spinlock.hpp>
-#include <boost/fiber/detail/wrap.hpp>
#include <boost/fiber/exceptions.hpp>
#include <boost/fiber/fixedsize_stack.hpp>
#include <boost/fiber/policy.hpp>
@@ -66,10 +62,10 @@ class scheduler;
namespace detail {
struct wait_tag;
-typedef intrusive::slist_member_hook<
+typedef intrusive::list_member_hook<
intrusive::tag< wait_tag >,
intrusive::link_mode<
- intrusive::safe_link
+ intrusive::auto_unlink
>
> wait_hook;
// declaration of the functor that converts between
@@ -132,25 +128,18 @@ typedef intrusive::slist_member_hook<
}
-struct main_context_t {};
-const main_context_t main_context{};
-
-struct dispatcher_context_t {};
-const dispatcher_context_t dispatcher_context{};
-
-struct worker_context_t {};
-const worker_context_t worker_context{};
-
class BOOST_FIBERS_DECL context {
public:
- typedef intrusive::slist<
+ typedef intrusive::list<
context,
intrusive::function_hook< detail::wait_functor >,
- intrusive::linear< true >,
- intrusive::cache_last< true >
+ intrusive::constant_time_size< false >
> wait_queue_t;
private:
+ friend class dispatcher_context;
+ friend class main_context;
+ template< typename Fn, typename ... Arg > friend class worker_context;
friend class scheduler;
struct fss_data {
@@ -175,88 +164,39 @@ private:
typedef std::map< uintptr_t, fss_data > fss_data_t;
#if ! defined(BOOST_FIBERS_NO_ATOMICS)
- alignas(cache_alignment) std::atomic< std::size_t > use_count_{ 0 };
+ std::atomic< std::size_t > use_count_;
#else
- alignas(cache_alignment) std::size_t use_count_{ 0 };
+ std::size_t use_count_;
#endif
#if ! defined(BOOST_FIBERS_NO_ATOMICS)
- alignas(cache_alignment) detail::remote_ready_hook remote_ready_hook_{};
- std::atomic< context * > remote_nxt_{ nullptr };
+ detail::remote_ready_hook remote_ready_hook_{};
#endif
- alignas(cache_alignment) detail::spinlock splk_{};
+ detail::spinlock splk_{};
bool terminated_{ false };
wait_queue_t wait_queue_{};
public:
detail::wait_hook wait_hook_{};
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+ std::atomic< std::intptr_t > twstatus{ 0 };
+#endif
private:
- alignas(cache_alignment) scheduler * scheduler_{ nullptr };
+ scheduler * scheduler_{ nullptr };
fss_data_t fss_data_{};
detail::sleep_hook sleep_hook_{};
detail::ready_hook ready_hook_{};
detail::terminated_hook terminated_hook_{};
detail::worker_hook worker_hook_{};
-#if (BOOST_EXECUTION_CONTEXT==1)
- boost::context::execution_context ctx_;
-#else
- boost::context::continuation c_;
-#endif
fiber_properties * properties_{ nullptr };
std::chrono::steady_clock::time_point tp_{ (std::chrono::steady_clock::time_point::max)() };
+ boost::context::continuation c_{};
type type_;
launch policy_;
- void resume_( detail::data_t &) noexcept;
- void schedule_( context *) noexcept;
-
-#if (BOOST_EXECUTION_CONTEXT==1)
- template< typename Fn, typename Tpl >
- void run_( Fn && fn_, Tpl && tpl_, detail::data_t * dp) noexcept {
- {
- // fn and tpl must be destroyed before calling terminate()
- typename std::decay< Fn >::type fn = std::forward< Fn >( fn_);
- typename std::decay< Tpl >::type tpl = std::forward< Tpl >( tpl_);
- if ( nullptr != dp->lk) {
- dp->lk->unlock();
- } else if ( nullptr != dp->ctx) {
- active()->schedule_( dp->ctx);
- }
-#if defined(BOOST_NO_CXX17_STD_APPLY)
- boost::context::detail::apply( std::move( fn), std::move( tpl) );
-#else
- std::apply( std::move( fn), std::move( tpl) );
-#endif
- }
- // terminate context
- terminate();
- BOOST_ASSERT_MSG( false, "fiber already terminated");
- }
-#else
- template< typename Fn, typename Tpl >
- boost::context::continuation
- run_( boost::context::continuation && c, Fn && fn_, Tpl && tpl_) noexcept {
- {
- // fn and tpl must be destroyed before calling terminate()
- typename std::decay< Fn >::type fn = std::forward< Fn >( fn_);
- typename std::decay< Tpl >::type tpl = std::forward< Tpl >( tpl_);
- c = c.resume();
- detail::data_t * dp = c.get_data< detail::data_t * >();
- // update contiunation of calling fiber
- dp->from->c_ = std::move( c);
- if ( nullptr != dp->lk) {
- dp->lk->unlock();
- } else if ( nullptr != dp->ctx) {
- active()->schedule_( dp->ctx);
- }
-#if defined(BOOST_NO_CXX17_STD_APPLY)
- boost::context::detail::apply( std::move( fn), std::move( tpl) );
-#else
- std::apply( std::move( fn), std::move( tpl) );
-#endif
- }
- // terminate context
- return terminate();
+ context( std::size_t initial_count, type t, launch policy) noexcept :
+ use_count_{ initial_count },
+ type_{ t },
+ policy_{ policy } {
}
-#endif
public:
class id {
@@ -317,73 +257,6 @@ public:
static void reset_active() noexcept;
- // main fiber context
- explicit context( main_context_t) noexcept;
-
- // dispatcher fiber context
- context( dispatcher_context_t, boost::context::preallocated const&,
- default_stack const&, scheduler *);
-
- // worker fiber context
- template< typename StackAlloc,
- typename Fn,
- typename Tpl
- >
- context( worker_context_t,
- launch policy,
- boost::context::preallocated palloc, StackAlloc salloc,
- Fn && fn, Tpl && tpl) :
- use_count_{ 1 }, // fiber instance or scheduler owner
-#if (BOOST_EXECUTION_CONTEXT==1)
-# 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 {
- run_( std::move( fn), std::move( tpl), static_cast< detail::data_t * >( vp) );
- },
- std::forward< Fn >( fn),
- std::forward< Tpl >( tpl),
- boost::context::execution_context::current() )
- },
- type_{ type::worker_context },
- policy_{ policy }
-# else
- ctx_{ std::allocator_arg, palloc, salloc,
- [this,fn=detail::decay_copy( std::forward< Fn >( fn) ),tpl=std::forward< Tpl >( tpl),
- ctx=boost::context::execution_context::current()] (void * vp) mutable noexcept {
- run_( std::move( fn), std::move( tpl), static_cast< detail::data_t * >( vp) );
- }},
- type_{ type::worker_context },
- policy_{ policy }
-# endif
- {}
-#else
- c_{},
- type_{ type::worker_context },
- policy_{ policy }
- {
-# if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
- c_ = boost::context::callcc(
- std::allocator_arg, palloc, salloc,
- detail::wrap(
- [this]( typename std::decay< Fn >::type & fn, typename std::decay< Tpl >::type & tpl,
- boost::context::continuation && c) mutable noexcept {
- return run_( std::forward< boost::context::continuation >( c), std::move( fn), std::move( tpl) );
- },
- std::forward< Fn >( fn),
- std::forward< Tpl >( tpl) ) );
-# else
- c_ = boost::context::callcc(
- std::allocator_arg, palloc, salloc,
- [this,fn=detail::decay_copy( std::forward< Fn >( fn) ),tpl=std::forward< Tpl >( tpl)]
- (boost::context::continuation && c) mutable noexcept {
- return run_( std::forward< boost::context::continuation >( c), std::move( fn), std::move( tpl) );
- });
-# endif
- }
-#endif
-
context( context const&) = delete;
context & operator=( context const&) = delete;
@@ -412,12 +285,9 @@ public:
void suspend() noexcept;
void suspend( detail::spinlock_lock &) noexcept;
-#if (BOOST_EXECUTION_CONTEXT==1)
- void terminate() noexcept;
-#else
boost::context::continuation suspend_with_cc() noexcept;
boost::context::continuation terminate() noexcept;
-#endif
+
void join();
void yield() noexcept;
@@ -510,6 +380,8 @@ public:
void sleep_unlink() noexcept;
+ void wait_unlink() noexcept;
+
void detach() noexcept;
void attach( context *) noexcept;
@@ -523,18 +395,11 @@ public:
BOOST_ASSERT( nullptr != ctx);
if ( 1 == ctx->use_count_.fetch_sub( 1, std::memory_order_release) ) {
std::atomic_thread_fence( std::memory_order_acquire);
-#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::continuation c = std::move( ctx->c_);
// destruct context
ctx->~context();
// deallocated stack
- c.resume( nullptr);
-#endif
+ c.resume();
}
}
};
@@ -544,36 +409,66 @@ bool operator<( context const& l, context const& r) noexcept {
return l.get_id() < r.get_id();
}
-template< typename StackAlloc, typename Fn, typename ... Args >
+template< typename Fn, typename ... Arg >
+class worker_context final : public context {
+private:
+ typename std::decay< Fn >::type fn_;
+ std::tuple< Arg ... > arg_;
+
+ boost::context::continuation
+ run_( boost::context::continuation && c) {
+ {
+ // fn and tpl must be destroyed before calling terminate()
+ auto fn = std::move( fn_);
+ auto arg = std::move( arg_);
+ c.resume();
+#if defined(BOOST_NO_CXX17_STD_APPLY)
+ boost::context::detail::apply( std::move( fn_), std::move( arg_) );
+#else
+ std::apply( std::move( fn_), std::move( arg_) );
+#endif
+ }
+ // terminate context
+ return terminate();
+ }
+
+public:
+ template< typename StackAlloc >
+ worker_context( launch policy,
+ boost::context::preallocated const& palloc, StackAlloc const& salloc,
+ Fn && fn, Arg ... arg) :
+ context{ 1, type::worker_context, policy },
+ fn_( std::forward< Fn >( fn) ),
+ arg_( std::forward< Arg >( arg) ... ) {
+ c_ = boost::context::callcc(
+ std::allocator_arg, palloc, salloc,
+ std::bind( & worker_context::run_, this, std::placeholders::_1) );
+ }
+};
+
+
+template< typename StackAlloc, typename Fn, typename ... Arg >
static intrusive_ptr< context > make_worker_context( launch policy,
StackAlloc salloc,
- Fn && fn, Args && ... args) {
- boost::context::stack_context sctx = salloc.allocate();
-#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
+ Fn && fn, Arg ... arg) {
+ typedef worker_context< Fn, Arg ... > context_t;
+
+ auto sctx = salloc.allocate();
// reserve space for control structure
- const std::size_t size = sctx.size - sizeof( context);
- void * sp = static_cast< char * >( sctx.sp) - sizeof( context);
-#else
- constexpr std::size_t func_alignment = 64; // alignof( context);
- constexpr std::size_t func_size = sizeof( context);
- // reserve space on stack
- void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
- // align sp pointer
- std::size_t space = func_size + func_alignment;
- sp = std::align( func_alignment, func_size, sp, space);
- BOOST_ASSERT( nullptr != sp);
- // calculate remaining size
- const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
-#endif
+ void * storage = reinterpret_cast< void * >(
+ ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( context_t) ) )
+ & ~ static_cast< uintptr_t >( 0xff) );
+ void * stack_bottom = reinterpret_cast< void * >(
+ reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) );
+ const std::size_t size = reinterpret_cast< uintptr_t >( storage) - reinterpret_cast< uintptr_t >( stack_bottom);
// placement new of context on top of fiber's stack
return intrusive_ptr< context >{
- ::new ( sp) context{
- worker_context,
+ new ( storage) context_t{
policy,
- boost::context::preallocated{ sp, size, sctx },
+ boost::context::preallocated{ storage, size, sctx },
salloc,
std::forward< Fn >( fn),
- std::make_tuple( std::forward< Args >( args) ... ) } };
+ std::forward< Arg >( arg) ... } };
}
namespace detail {