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.hpp267
1 files changed, 156 insertions, 111 deletions
diff --git a/boost/fiber/context.hpp b/boost/fiber/context.hpp
index d873343538..773528e3a1 100644
--- a/boost/fiber/context.hpp
+++ b/boost/fiber/context.hpp
@@ -7,23 +7,32 @@
#ifndef BOOST_FIBERS_CONTEXT_H
#define BOOST_FIBERS_CONTEXT_H
+#include <iostream>
#include <atomic>
#include <chrono>
#include <exception>
#include <functional>
#include <map>
#include <memory>
+#include <tuple>
#include <type_traits>
#include <boost/assert.hpp>
#include <boost/config.hpp>
+#if defined(BOOST_NO_CXX17_STD_APPLY)
#include <boost/context/detail/apply.hpp>
-#include <boost/context/execution_context.hpp>
+#endif
+#if (BOOST_EXECUTION_CONTEXT==1)
+# include <boost/context/execution_context.hpp>
+#else
+# include <boost/context/continuation.hpp>
+#endif
#include <boost/context/stack_context.hpp>
#include <boost/intrusive/list.hpp>
#include <boost/intrusive/parent_from_member.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/intrusive/set.hpp>
+#include <boost/intrusive/slist.hpp>
#include <boost/fiber/detail/config.hpp>
#include <boost/fiber/detail/data.hpp>
@@ -57,10 +66,10 @@ class scheduler;
namespace detail {
struct wait_tag;
-typedef intrusive::list_member_hook<
+typedef intrusive::slist_member_hook<
intrusive::tag< wait_tag >,
intrusive::link_mode<
- intrusive::auto_unlink
+ intrusive::safe_link
>
> wait_hook;
// declaration of the functor that converts between
@@ -97,21 +106,29 @@ typedef intrusive::set_member_hook<
>
> sleep_hook;
-struct terminated_tag;
+struct worker_tag;
typedef intrusive::list_member_hook<
- intrusive::tag< terminated_tag >,
+ intrusive::tag< worker_tag >,
intrusive::link_mode<
intrusive::auto_unlink
>
+> worker_hook;
+
+struct terminated_tag;
+typedef intrusive::slist_member_hook<
+ intrusive::tag< terminated_tag >,
+ intrusive::link_mode<
+ intrusive::safe_link
+ >
> terminated_hook;
-struct worker_tag;
-typedef intrusive::list_member_hook<
- intrusive::tag< worker_tag >,
+struct remote_ready_tag;
+typedef intrusive::slist_member_hook<
+ intrusive::tag< remote_ready_tag >,
intrusive::link_mode<
- intrusive::auto_unlink
+ intrusive::safe_link
>
-> worker_hook;
+> remote_ready_hook;
}
@@ -125,13 +142,17 @@ struct worker_context_t {};
const worker_context_t worker_context{};
class BOOST_FIBERS_DECL context {
+public:
+ typedef intrusive::slist<
+ context,
+ intrusive::function_hook< detail::wait_functor >,
+ intrusive::linear< true >,
+ intrusive::cache_last< true >
+ > wait_queue_t;
+
private:
friend class scheduler;
- enum flag_t {
- flag_terminated = 1 << 1
- };
-
struct fss_data {
void * vp{ nullptr };
detail::fss_cleanup_function::ptr_t cleanup_function{};
@@ -151,100 +172,102 @@ private:
}
};
- typedef std::map< uintptr_t, fss_data > fss_data_t;
+ typedef std::map< uintptr_t, fss_data > fss_data_t;
#if ! defined(BOOST_FIBERS_NO_ATOMICS)
- std::atomic< std::size_t > use_count_{ 0 };
- std::atomic< unsigned int > flags_;
- std::atomic< type > type_;
- std::atomic< scheduler * > scheduler_{ nullptr };
+ alignas(cache_alignment) std::atomic< std::size_t > use_count_{ 0 };
#else
- std::size_t use_count_{ 0 };
- unsigned int flags_;
- type type_;
- scheduler * scheduler_{ nullptr };
+ alignas(cache_alignment) std::size_t use_count_{ 0 };
+#endif
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+ alignas(cache_alignment) detail::remote_ready_hook remote_ready_hook_{};
+ std::atomic< context * > remote_nxt_{ nullptr };
#endif
- launch policy_{ launch::post };
+ alignas(cache_alignment) detail::spinlock splk_{};
+ bool terminated_{ false };
+ wait_queue_t wait_queue_{};
+public:
+ detail::wait_hook wait_hook_{};
+private:
+ alignas(cache_alignment) 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_;
+ boost::context::execution_context ctx_;
#else
- boost::context::execution_context< detail::data_t * > ctx_;
+ boost::context::continuation c_;
#endif
+ fiber_properties * properties_{ nullptr };
+ std::chrono::steady_clock::time_point tp_{ (std::chrono::steady_clock::time_point::max)() };
+ type type_;
+ launch policy_;
void resume_( detail::data_t &) noexcept;
- void set_ready_( context *) 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 set_terminated()
+ // 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()->set_ready_( 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
- set_terminated();
+ terminate();
BOOST_ASSERT_MSG( false, "fiber already terminated");
}
#else
template< typename Fn, typename Tpl >
- boost::context::execution_context< detail::data_t * >
- run_( boost::context::execution_context< detail::data_t * > && ctx, Fn && fn_, Tpl && tpl_, detail::data_t * dp) noexcept {
+ boost::context::continuation
+ run_( boost::context::continuation && c, Fn && fn_, Tpl && tpl_) noexcept {
{
- // fn and tpl must be destroyed before calling set_terminated()
+ // 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_);
- // update execution_context of calling fiber
- dp->from->ctx_ = std::move( ctx);
+ 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()->set_ready_( 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 set_terminated();
+ return terminate();
}
#endif
public:
- detail::ready_hook ready_hook_{};
- detail::sleep_hook sleep_hook_{};
- detail::terminated_hook terminated_hook_{};
- detail::wait_hook wait_hook_{};
- detail::worker_hook worker_hook_{};
- std::atomic< context * > remote_nxt_{ nullptr };
- std::chrono::steady_clock::time_point tp_{ (std::chrono::steady_clock::time_point::max)() };
-
- typedef intrusive::list<
- context,
- intrusive::function_hook< detail::wait_functor >,
- intrusive::constant_time_size< false > > wait_queue_t;
-
-private:
- fss_data_t fss_data_{};
- wait_queue_t wait_queue_{};
- detail::spinlock splk_{};
- fiber_properties * properties_{ nullptr };
-
-public:
class id {
private:
context * impl_{ nullptr };
public:
- id() noexcept {
- }
+ id() = default;
explicit id( context * impl) noexcept :
- impl_( impl) {
+ impl_{ impl } {
}
bool operator==( id const& other) const noexcept {
@@ -311,9 +334,6 @@ public:
boost::context::preallocated palloc, StackAlloc salloc,
Fn && fn, Tpl && tpl) :
use_count_{ 1 }, // fiber instance or scheduler owner
- flags_{ 0 },
- type_{ type::worker_context },
- policy_{ policy },
#if (BOOST_EXECUTION_CONTEXT==1)
# if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
ctx_{ std::allocator_arg, palloc, salloc,
@@ -325,50 +345,66 @@ public:
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)
- 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< detail::data_t * > && ctx, detail::data_t * dp) mutable noexcept {
- return run_( std::forward< boost::context::execution_context< detail::data_t * > >( ctx), std::move( fn), std::move( tpl), dp);
- },
- std::forward< Fn >( fn),
- std::forward< Tpl >( tpl) )}
-
+ 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
- ctx_{ std::allocator_arg, palloc, salloc,
- [this,fn=detail::decay_copy( std::forward< Fn >( fn) ),tpl=std::forward< Tpl >( tpl)]
- (boost::context::execution_context< detail::data_t * > && ctx, detail::data_t * dp) mutable noexcept {
- return run_( std::forward< boost::context::execution_context< detail::data_t * > >( ctx), std::move( fn), std::move( tpl), dp);
- }}
+ 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;
+ friend bool
+ operator==( context const& lhs, context const& rhs) noexcept {
+ return & lhs == & rhs;
+ }
+
virtual ~context();
scheduler * get_scheduler() const noexcept {
-#if ! defined(BOOST_FIBERS_NO_ATOMICS)
- return scheduler_.load( std::memory_order_relaxed);
-#else
return scheduler_;
-#endif
}
id get_id() const noexcept;
+ bool is_resumable() const noexcept {
+ if ( c_) return true;
+ else return false;
+ }
+
void resume() noexcept;
void resume( detail::spinlock_lock &) noexcept;
void resume( context *) noexcept;
@@ -377,10 +413,10 @@ public:
void suspend( detail::spinlock_lock &) noexcept;
#if (BOOST_EXECUTION_CONTEXT==1)
- void set_terminated() noexcept;
+ void terminate() noexcept;
#else
- boost::context::execution_context< detail::data_t * > suspend_with_cc() noexcept;
- boost::context::execution_context< detail::data_t * > set_terminated() noexcept;
+ boost::context::continuation suspend_with_cc() noexcept;
+ boost::context::continuation terminate() noexcept;
#endif
void join();
@@ -390,16 +426,12 @@ public:
bool wait_until( std::chrono::steady_clock::time_point const&,
detail::spinlock_lock &) noexcept;
- void set_ready( context *) noexcept;
+ void schedule( context *) noexcept;
bool is_context( type t) const noexcept {
return type::none != ( type_ & t);
}
- bool is_terminated() const noexcept {
- return 0 != ( flags_ & flag_terminated);
- }
-
void * get_fss_data( void const * vp) const;
void set_fss_data(
@@ -418,77 +450,90 @@ public:
return policy_;
}
+ bool worker_is_linked() const noexcept;
+
bool ready_is_linked() const noexcept;
+ bool remote_ready_is_linked() const noexcept;
+
bool sleep_is_linked() const noexcept;
bool terminated_is_linked() const noexcept;
bool wait_is_linked() const noexcept;
- bool worker_is_linked() const noexcept;
+ template< typename List >
+ void worker_link( List & lst) noexcept {
+ static_assert( std::is_same< typename List::value_traits::hook_type, detail::worker_hook >::value, "not a worker-queue");
+ BOOST_ASSERT( ! worker_is_linked() );
+ lst.push_back( * this);
+ }
template< typename List >
void ready_link( List & lst) noexcept {
static_assert( std::is_same< typename List::value_traits::hook_type, detail::ready_hook >::value, "not a ready-queue");
+ BOOST_ASSERT( ! ready_is_linked() );
+ lst.push_back( * this);
+ }
+
+ template< typename List >
+ void remote_ready_link( List & lst) noexcept {
+ static_assert( std::is_same< typename List::value_traits::hook_type, detail::remote_ready_hook >::value, "not a remote-ready-queue");
+ BOOST_ASSERT( ! remote_ready_is_linked() );
lst.push_back( * this);
}
template< typename Set >
void sleep_link( Set & set) noexcept {
static_assert( std::is_same< typename Set::value_traits::hook_type,detail::sleep_hook >::value, "not a sleep-queue");
+ BOOST_ASSERT( ! sleep_is_linked() );
set.insert( * this);
}
template< typename List >
void terminated_link( List & lst) noexcept {
static_assert( std::is_same< typename List::value_traits::hook_type, detail::terminated_hook >::value, "not a terminated-queue");
+ BOOST_ASSERT( ! terminated_is_linked() );
lst.push_back( * this);
}
template< typename List >
void wait_link( List & lst) noexcept {
static_assert( std::is_same< typename List::value_traits::hook_type, detail::wait_hook >::value, "not a wait-queue");
+ BOOST_ASSERT( ! wait_is_linked() );
lst.push_back( * this);
}
- template< typename List >
- void worker_link( List & lst) noexcept {
- static_assert( std::is_same< typename List::value_traits::hook_type, detail::worker_hook >::value, "not a worker-queue");
- lst.push_back( * this);
- }
+ void worker_unlink() noexcept;
void ready_unlink() noexcept;
void sleep_unlink() noexcept;
- void wait_unlink() noexcept;
-
- void worker_unlink() noexcept;
-
void detach() noexcept;
void attach( context *) noexcept;
friend void intrusive_ptr_add_ref( context * ctx) noexcept {
BOOST_ASSERT( nullptr != ctx);
- ++ctx->use_count_;
+ ctx->use_count_.fetch_add( 1, std::memory_order_relaxed);
}
friend void intrusive_ptr_release( context * ctx) noexcept {
BOOST_ASSERT( nullptr != ctx);
- if ( 0 == --ctx->use_count_) {
+ 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_);
+ boost::context::execution_context ec = ctx->ctx_;
// destruct context
// deallocates stack (execution_context is ref counted)
ctx->~context();
#else
- boost::context::execution_context< detail::data_t * > cc( std::move( ctx->ctx_) );
+ boost::context::continuation c = std::move( ctx->c_);
// destruct context
ctx->~context();
// deallocated stack
- cc( nullptr);
+ c.resume( nullptr);
#endif
}
}
@@ -521,14 +566,14 @@ static intrusive_ptr< context > make_worker_context( launch policy,
const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
#endif
// placement new of context on top of fiber's stack
- return intrusive_ptr< context >(
- ::new ( sp) context(
+ return intrusive_ptr< context >{
+ ::new ( sp) context{
worker_context,
policy,
- boost::context::preallocated( sp, size, sctx),
+ boost::context::preallocated{ sp, size, sctx },
salloc,
std::forward< Fn >( fn),
- std::make_tuple( std::forward< Args >( args) ... ) ) );
+ std::make_tuple( std::forward< Args >( args) ... ) } };
}
namespace detail {