summaryrefslogtreecommitdiff
path: root/boost/context
diff options
context:
space:
mode:
Diffstat (limited to 'boost/context')
-rw-r--r--boost/context/all.hpp2
-rw-r--r--boost/context/continuation_fcontext.hpp25
-rw-r--r--boost/context/continuation_ucontext.hpp34
-rw-r--r--boost/context/continuation_winfib.hpp19
-rw-r--r--boost/context/detail/apply.hpp4
-rw-r--r--boost/context/detail/externc.hpp23
-rw-r--r--boost/context/execution_context.hpp13
-rw-r--r--boost/context/execution_context_v1.hpp110
-rw-r--r--boost/context/execution_context_v2.hpp102
-rw-r--r--boost/context/execution_context_v2_void.ipp52
-rw-r--r--boost/context/fiber.hpp13
-rw-r--r--boost/context/fiber_fcontext.hpp365
-rw-r--r--boost/context/fiber_ucontext.hpp515
-rw-r--r--boost/context/fiber_winfib.hpp453
14 files changed, 1557 insertions, 173 deletions
diff --git a/boost/context/all.hpp b/boost/context/all.hpp
index 193eefb937..efee26026a 100644
--- a/boost/context/all.hpp
+++ b/boost/context/all.hpp
@@ -5,7 +5,9 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/context/continuation.hpp>
+#include <boost/context/fiber.hpp>
#include <boost/context/fixedsize_stack.hpp>
+#include <boost/context/execution_context.hpp>
#include <boost/context/pooled_fixedsize_stack.hpp>
#include <boost/context/protected_fixedsize_stack.hpp>
#include <boost/context/segmented_stack.hpp>
diff --git a/boost/context/continuation_fcontext.hpp b/boost/context/continuation_fcontext.hpp
index 461933fda5..03f8f6a644 100644
--- a/boost/context/continuation_fcontext.hpp
+++ b/boost/context/continuation_fcontext.hpp
@@ -138,7 +138,7 @@ public:
Ctx c{ fctx };
// invoke context-function
#if defined(BOOST_NO_CXX17_STD_INVOKE)
- c = invoke( fn_, std::move( c) );
+ c = boost::context::detail::invoke( fn_, std::move( c) );
#else
c = std::invoke( fn_, std::move( c) );
#endif
@@ -238,7 +238,7 @@ public:
}
continuation( continuation && other) noexcept {
- std::swap( fctx_, other.fctx_);
+ swap( other);
}
continuation & operator=( continuation && other) noexcept {
@@ -252,29 +252,38 @@ public:
continuation( continuation const& other) noexcept = delete;
continuation & operator=( continuation const& other) noexcept = delete;
- continuation resume() {
+ continuation resume() & {
+ return std::move( * this).resume();
+ }
+
+ continuation resume() && {
BOOST_ASSERT( nullptr != fctx_);
- return detail::jump_fcontext(
+ return { detail::jump_fcontext(
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
detail::exchange( fctx_, nullptr),
#else
std::exchange( fctx_, nullptr),
#endif
- nullptr).fctx;
+ nullptr).fctx };
+ }
+
+ template< typename Fn >
+ continuation resume_with( Fn && fn) & {
+ return std::move( * this).resume_with( std::forward< Fn >( fn) );
}
template< typename Fn >
- continuation resume_with( Fn && fn) {
+ continuation resume_with( Fn && fn) && {
BOOST_ASSERT( nullptr != fctx_);
auto p = std::make_tuple( std::forward< Fn >( fn) );
- return detail::ontop_fcontext(
+ return { detail::ontop_fcontext(
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
detail::exchange( fctx_, nullptr),
#else
std::exchange( fctx_, nullptr),
#endif
& p,
- detail::context_ontop< continuation, Fn >).fctx;
+ detail::context_ontop< continuation, Fn >).fctx };
}
explicit operator bool() const noexcept {
diff --git a/boost/context/continuation_ucontext.hpp b/boost/context/continuation_ucontext.hpp
index 030d3e9ed6..b2682cf47f 100644
--- a/boost/context/continuation_ucontext.hpp
+++ b/boost/context/continuation_ucontext.hpp
@@ -37,6 +37,7 @@ extern "C" {
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
#include <boost/context/detail/exchange.hpp>
#endif
+#include <boost/context/detail/externc.hpp>
#if defined(BOOST_NO_CXX17_STD_INVOKE)
#include <boost/context/detail/invoke.hpp>
#endif
@@ -52,20 +53,6 @@ extern "C" {
# include BOOST_ABI_PREFIX
#endif
-#if defined(BOOST_USE_ASAN)
-extern "C" {
-void __sanitizer_start_switch_fiber( void **, const void *, size_t);
-void __sanitizer_finish_switch_fiber( void *, const void **, size_t *);
-}
-#endif
-
-#if defined(BOOST_USE_SEGMENTED_STACKS)
-extern "C" {
-void __splitstack_getcontext( void * [BOOST_CONTEXT_SEGMENTS]);
-void __splitstack_setcontext( void * [BOOST_CONTEXT_SEGMENTS]);
-}
-#endif
-
namespace boost {
namespace context {
namespace detail {
@@ -266,7 +253,7 @@ public:
try {
// invoke context-function
#if defined(BOOST_NO_CXX17_STD_INVOKE)
- c = invoke( fn_, std::move( c) );
+ c = boost::context::detail::invoke( fn_, std::move( c) );
#else
c = std::invoke( fn_, std::move( c) );
#endif
@@ -408,7 +395,11 @@ public:
return * this;
}
- continuation resume() {
+ continuation resume() & {
+ return std::move( * this).resume();
+ }
+
+ continuation resume() && {
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
detail::activation_record * ptr = detail::exchange( ptr_, nullptr)->resume();
#else
@@ -420,11 +411,16 @@ public:
ptr = detail::activation_record::current()->ontop( ptr);
detail::activation_record::current()->ontop = nullptr;
}
- return continuation{ ptr };
+ return { ptr };
+ }
+
+ template< typename Fn >
+ continuation resume_with( Fn && fn) & {
+ return std::move( * this).resume_with( std::forward< Fn >( fn) );
}
template< typename Fn >
- continuation resume_with( Fn && fn) {
+ continuation resume_with( Fn && fn) && {
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
detail::activation_record * ptr =
detail::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) );
@@ -438,7 +434,7 @@ public:
ptr = detail::activation_record::current()->ontop( ptr);
detail::activation_record::current()->ontop = nullptr;
}
- return continuation{ ptr };
+ return { ptr };
}
explicit operator bool() const noexcept {
diff --git a/boost/context/continuation_winfib.hpp b/boost/context/continuation_winfib.hpp
index 5d24bbf95e..a92463f326 100644
--- a/boost/context/continuation_winfib.hpp
+++ b/boost/context/continuation_winfib.hpp
@@ -224,7 +224,7 @@ public:
try {
// invoke context-function
#if defined(BOOST_NO_CXX17_STD_INVOKE)
- c = invoke( fn_, std::move( c) );
+ c = boost::context::detail::invoke( fn_, std::move( c) );
#else
c = std::invoke( fn_, std::move( c) );
#endif
@@ -334,7 +334,11 @@ public:
return * this;
}
- continuation resume() {
+ continuation resume() & {
+ return std::move( * this).resume();
+ }
+
+ continuation resume() && {
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
detail::activation_record * ptr = detail::exchange( ptr_, nullptr)->resume();
#else
@@ -346,11 +350,16 @@ public:
ptr = detail::activation_record::current()->ontop( ptr);
detail::activation_record::current()->ontop = nullptr;
}
- return continuation{ ptr };
+ return { ptr };
+ }
+
+ template< typename Fn >
+ continuation resume_with( Fn && fn) & {
+ return std::move( * this).resume_with( std::forward< Fn >( fn) );
}
template< typename Fn >
- continuation resume_with( Fn && fn) {
+ continuation resume_with( Fn && fn) && {
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
detail::activation_record * ptr =
detail::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) );
@@ -364,7 +373,7 @@ public:
ptr = detail::activation_record::current()->ontop( ptr);
detail::activation_record::current()->ontop = nullptr;
}
- return continuation{ ptr };
+ return { ptr };
}
explicit operator bool() const noexcept {
diff --git a/boost/context/detail/apply.hpp b/boost/context/detail/apply.hpp
index e1dd40a4db..fbf0ca6176 100644
--- a/boost/context/detail/apply.hpp
+++ b/boost/context/detail/apply.hpp
@@ -37,13 +37,13 @@ template< typename Fn, typename Tpl, std::size_t ... I >
auto
apply_impl( Fn && fn, Tpl && tpl, index_sequence< I ... >)
#if defined(BOOST_NO_CXX17_STD_INVOKE)
- -> decltype( invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... ) )
+ -> decltype( boost::context::detail::invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... ) )
#else
-> decltype( std::invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... ) )
#endif
{
#if defined(BOOST_NO_CXX17_STD_INVOKE)
- return invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... );
+ return boost::context::detail::invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... );
#else
return std::invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... );
#endif
diff --git a/boost/context/detail/externc.hpp b/boost/context/detail/externc.hpp
new file mode 100644
index 0000000000..850bc1a3d7
--- /dev/null
+++ b/boost/context/detail/externc.hpp
@@ -0,0 +1,23 @@
+
+// Copyright Oliver Kowalke 2014.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/config.hpp>
+#include <boost/context/detail/config.hpp>
+
+#if defined(BOOST_USE_ASAN)
+extern "C" {
+void __sanitizer_start_switch_fiber( void **, const void *, size_t);
+void __sanitizer_finish_switch_fiber( void *, const void **, size_t *);
+}
+#endif
+
+#if defined(BOOST_USE_SEGMENTED_STACKS)
+extern "C" {
+void __splitstack_getcontext( void * [BOOST_CONTEXT_SEGMENTS]);
+void __splitstack_setcontext( void * [BOOST_CONTEXT_SEGMENTS]);
+}
+#endif
diff --git a/boost/context/execution_context.hpp b/boost/context/execution_context.hpp
index 2eb02e12ee..5808e027de 100644
--- a/boost/context/execution_context.hpp
+++ b/boost/context/execution_context.hpp
@@ -6,14 +6,7 @@
#include <boost/context/detail/config.hpp>
-#if ! defined(BOOST_CONTEXT_NO_CXX11)
-# if (defined(BOOST_EXECUTION_CONTEXT) && (BOOST_EXECUTION_CONTEXT == 1))
-# if !defined(BOOST_NO_CXX11_THREAD_LOCAL)
-# include <boost/context/execution_context_v1.hpp>
-# else
-# error "keyword thread_local not supported"
-# endif
-# else
-# include <boost/context/execution_context_v2.hpp>
-# endif
+#if !defined(BOOST_NO_CXX11_THREAD_LOCAL)
+# include <boost/context/execution_context_v1.hpp>
#endif
+#include <boost/context/execution_context_v2.hpp>
diff --git a/boost/context/execution_context_v1.hpp b/boost/context/execution_context_v1.hpp
index 5cf0a91d2a..73008e63ab 100644
--- a/boost/context/execution_context_v1.hpp
+++ b/boost/context/execution_context_v1.hpp
@@ -4,8 +4,8 @@
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
-#ifndef BOOST_CONTEXT_EXECUTION_CONTEXT_H
-#define BOOST_CONTEXT_EXECUTION_CONTEXT_H
+#ifndef BOOST_CONTEXT_EXECUTION_CONTEXT_V1_H
+#define BOOST_CONTEXT_EXECUTION_CONTEXT_V1_H
#include <boost/context/detail/config.hpp>
@@ -28,6 +28,7 @@
#include <boost/context/detail/apply.hpp>
#endif
#include <boost/context/detail/disable_overload.hpp>
+#include <boost/context/detail/externc.hpp>
#include <boost/context/detail/fcontext.hpp>
#include <boost/context/fixedsize_stack.hpp>
#include <boost/context/flags.hpp>
@@ -39,31 +40,24 @@
# include BOOST_ABI_PREFIX
#endif
-#if defined(BOOST_USE_SEGMENTED_STACKS)
-extern "C" {
-void __splitstack_getcontext( void * [BOOST_CONTEXT_SEGMENTS]);
-void __splitstack_setcontext( void * [BOOST_CONTEXT_SEGMENTS]);
-}
-#endif
-
namespace boost {
namespace context {
namespace detail {
template< typename Fn >
-transfer_t context_ontop( transfer_t);
+transfer_t ecv1_context_ontop( transfer_t);
-struct activation_record;
+struct ecv1_activation_record;
-struct data_t {
- activation_record * from;
- void * data;
+struct ecv1_data_t {
+ ecv1_activation_record * from;
+ void * data;
};
-struct BOOST_CONTEXT_DECL activation_record {
- typedef boost::intrusive_ptr< activation_record > ptr_t;
+struct BOOST_CONTEXT_DECL ecv1_activation_record {
+ typedef boost::intrusive_ptr< ecv1_activation_record > ptr_t;
- thread_local static ptr_t current_rec;
+ static ptr_t & current() noexcept;
std::atomic< std::size_t > use_count{ 0 };
fcontext_t fctx{ nullptr };
@@ -72,15 +66,15 @@ struct BOOST_CONTEXT_DECL activation_record {
// used for toplevel-context
// (e.g. main context, thread-entry context)
- activation_record() = default;
+ ecv1_activation_record() = default;
- activation_record( fcontext_t fctx_, stack_context sctx_) noexcept :
+ ecv1_activation_record( fcontext_t fctx_, stack_context sctx_) noexcept :
fctx{ fctx_ },
sctx( sctx_ ), // sctx{ sctx_ } - clang-3.6: no viable conversion from 'boost::context::stack_context' to 'std::size_t'
main_ctx{ false } {
}
- virtual ~activation_record() = default;
+ virtual ~ecv1_activation_record() = default;
bool is_main_context() const noexcept {
return main_ctx;
@@ -88,20 +82,20 @@ struct BOOST_CONTEXT_DECL activation_record {
void * resume( void * vp) {
// store current activation record in local variable
- auto from = current_rec.get();
+ auto from = current().get();
// store `this` in static, thread local pointer
// `this` will become the active (running) context
// returned by execution_context::current()
- current_rec = this;
+ current() = this;
#if defined(BOOST_USE_SEGMENTED_STACKS)
// adjust segmented stack properties
__splitstack_getcontext( from->sctx.segments_ctx);
__splitstack_setcontext( sctx.segments_ctx);
#endif
- data_t d = { from, vp };
+ ecv1_data_t d = { from, vp };
// context switch from parent context to `this`-context
transfer_t t = jump_fcontext( fctx, & d);
- data_t * dp = reinterpret_cast< data_t * >( t.data);
+ ecv1_data_t * dp = reinterpret_cast< ecv1_data_t * >( t.data);
dp->from->fctx = t.fctx;
// parent context resumed
return dp->data;
@@ -110,22 +104,22 @@ struct BOOST_CONTEXT_DECL activation_record {
template< typename Fn >
void * resume_ontop( void * data, Fn && fn) {
// store current activation record in local variable
- activation_record * from = current_rec.get();
+ ecv1_activation_record * from = current().get();
// store `this` in static, thread local pointer
// `this` will become the active (running) context
// returned by execution_context::current()
- current_rec = this;
+ current() = this;
#if defined(BOOST_USE_SEGMENTED_STACKS)
// adjust segmented stack properties
__splitstack_getcontext( from->sctx.segments_ctx);
__splitstack_setcontext( sctx.segments_ctx);
#endif
std::tuple< void *, Fn > p = std::forward_as_tuple( data, fn);
- data_t d = { from, & p };
+ ecv1_data_t d = { from, & p };
// context switch from parent context to `this`-context
// execute Fn( Tpl) on top of `this`
- transfer_t t = ontop_fcontext( fctx, & d, context_ontop< Fn >);
- data_t * dp = reinterpret_cast< data_t * >( t.data);
+ transfer_t t = ontop_fcontext( fctx, & d, ecv1_context_ontop< Fn >);
+ ecv1_data_t * dp = reinterpret_cast< ecv1_data_t * >( t.data);
dp->from->fctx = t.fctx;
// parent context resumed
return dp->data;
@@ -134,11 +128,11 @@ struct BOOST_CONTEXT_DECL activation_record {
virtual void deallocate() noexcept {
}
- friend void intrusive_ptr_add_ref( activation_record * ar) noexcept {
+ friend void intrusive_ptr_add_ref( ecv1_activation_record * ar) noexcept {
++ar->use_count;
}
- friend void intrusive_ptr_release( activation_record * ar) noexcept {
+ friend void intrusive_ptr_release( ecv1_activation_record * ar) noexcept {
BOOST_ASSERT( nullptr != ar);
if ( 0 == --ar->use_count) {
ar->deallocate();
@@ -146,21 +140,21 @@ struct BOOST_CONTEXT_DECL activation_record {
}
};
-struct BOOST_CONTEXT_DECL activation_record_initializer {
- activation_record_initializer() noexcept;
- ~activation_record_initializer();
+struct BOOST_CONTEXT_DECL ecv1_activation_record_initializer {
+ ecv1_activation_record_initializer() noexcept;
+ ~ecv1_activation_record_initializer();
};
template< typename Fn >
-transfer_t context_ontop( transfer_t t) {
- data_t * dp = reinterpret_cast< data_t * >( t.data);
+transfer_t ecv1_context_ontop( transfer_t t) {
+ ecv1_data_t * dp = reinterpret_cast< ecv1_data_t * >( t.data);
dp->from->fctx = t.fctx;
auto tpl = reinterpret_cast< std::tuple< void *, Fn > * >( dp->data);
BOOST_ASSERT( nullptr != tpl);
auto data = std::get< 0 >( * tpl);
typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 1 >( * tpl) );
#if defined(BOOST_NO_CXX17_STD_APPLY)
- dp->data = apply( fn, std::tie( data) );
+ dp->data = boost::context::detail::apply( fn, std::tie( data) );
#else
dp->data = std::apply( fn, std::tie( data) );
#endif
@@ -168,28 +162,28 @@ transfer_t context_ontop( transfer_t t) {
}
template< typename StackAlloc, typename Fn, typename ... Args >
-class capture_record : public activation_record {
+class ecv1_capture_record : public ecv1_activation_record {
private:
typename std::decay< StackAlloc >::type salloc_;
typename std::decay< Fn >::type fn_;
std::tuple< typename std::decay< Args >::type ... > args_;
- activation_record * caller_;
+ ecv1_activation_record * caller_;
- static void destroy( capture_record * p) noexcept {
+ static void destroy( ecv1_capture_record * p) noexcept {
typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
stack_context sctx = p->sctx;
// deallocate activation record
- p->~capture_record();
+ p->~ecv1_capture_record();
// destroy stack with stack allocator
salloc.deallocate( sctx);
}
public:
- capture_record( stack_context sctx, StackAlloc && salloc,
+ ecv1_capture_record( stack_context sctx, StackAlloc && salloc,
fcontext_t fctx,
- activation_record * caller,
+ ecv1_activation_record * caller,
Fn && fn, Args && ... args) noexcept :
- activation_record{ fctx, sctx },
+ ecv1_activation_record{ fctx, sctx },
salloc_{ std::forward< StackAlloc >( salloc) },
fn_( std::forward< Fn >( fn) ),
args_( std::forward< Args >( args) ... ),
@@ -203,7 +197,7 @@ public:
void run() {
auto data = caller_->resume( nullptr);
#if defined(BOOST_NO_CXX17_STD_APPLY)
- apply( fn_, std::tuple_cat( args_, std::tie( data) ) );
+ boost::context::detail::apply( fn_, std::tuple_cat( args_, std::tie( data) ) );
#else
std::apply( fn_, std::tuple_cat( args_, std::tie( data) ) );
#endif
@@ -213,6 +207,8 @@ public:
}
+namespace v1 {
+
class BOOST_CONTEXT_DECL execution_context {
private:
// tampoline function
@@ -220,7 +216,7 @@ private:
// is resumed for the first time
template< typename AR >
static void entry_func( detail::transfer_t t) noexcept {
- detail::data_t * dp = reinterpret_cast< detail::data_t * >( t.data);
+ detail::ecv1_data_t * dp = reinterpret_cast< detail::ecv1_data_t * >( t.data);
AR * ar = static_cast< AR * >( dp->data);
BOOST_ASSERT( nullptr != ar);
dp->from->fctx = t.fctx;
@@ -228,14 +224,14 @@ private:
ar->run();
}
- typedef boost::intrusive_ptr< detail::activation_record > ptr_t;
+ typedef boost::intrusive_ptr< detail::ecv1_activation_record > ptr_t;
ptr_t ptr_;
template< typename StackAlloc, typename Fn, typename ... Args >
- static detail::activation_record * create_context( StackAlloc && salloc,
+ static detail::ecv1_activation_record * create_context( StackAlloc && salloc,
Fn && fn, Args && ... args) {
- typedef detail::capture_record<
+ typedef detail::ecv1_capture_record<
StackAlloc, Fn, Args ...
> capture_t;
@@ -267,9 +263,9 @@ private:
}
template< typename StackAlloc, typename Fn, typename ... Args >
- static detail::activation_record * create_context( preallocated palloc, StackAlloc && salloc,
+ static detail::ecv1_activation_record * create_context( preallocated palloc, StackAlloc && salloc,
Fn && fn, Args && ... args) {
- typedef detail::capture_record<
+ typedef detail::ecv1_capture_record<
StackAlloc, Fn, Args ...
> capture_t;
@@ -300,8 +296,8 @@ private:
}
execution_context() noexcept :
- // default constructed with current activation_record
- ptr_{ detail::activation_record::current_rec } {
+ // default constructed with current ecv1_activation_record
+ ptr_{ detail::ecv1_activation_record::current() } {
}
public:
@@ -333,7 +329,7 @@ public:
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
- ptr_{ create_context( std::forward< StackAlloc >( salloc),
+ ptr_{ create_context( salloc,
std::forward< Fn >( fn),
std::forward< Args >( args) ...) } {
ptr_->resume( ptr_.get() );
@@ -348,7 +344,7 @@ public:
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
- ptr_{ create_context( palloc, std::forward< StackAlloc >( salloc),
+ ptr_{ create_context( palloc, salloc,
std::forward< Fn >( fn),
std::forward< Args >( args) ...) } {
ptr_->resume( ptr_.get() );
@@ -488,10 +484,10 @@ void swap( execution_context & l, execution_context & r) noexcept {
l.swap( r);
}
-}}
+}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
-#endif // BOOST_CONTEXT_EXECUTION_CONTEXT_H
+#endif // BOOST_CONTEXT_EXECUTION_CONTEXT_V1_H
diff --git a/boost/context/execution_context_v2.hpp b/boost/context/execution_context_v2.hpp
index 86c7ecf001..22a5502603 100644
--- a/boost/context/execution_context_v2.hpp
+++ b/boost/context/execution_context_v2.hpp
@@ -4,8 +4,8 @@
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
-#ifndef BOOST_CONTEXT_EXECUTION_CONTEXT_H
-#define BOOST_CONTEXT_EXECUTION_CONTEXT_H
+#ifndef BOOST_CONTEXT_EXECUTION_CONTEXT_V2_H
+#define BOOST_CONTEXT_EXECUTION_CONTEXT_V2_H
#include <boost/context/detail/config.hpp>
@@ -51,42 +51,42 @@ namespace boost {
namespace context {
namespace detail {
-transfer_t context_unwind( transfer_t);
+transfer_t ecv2_context_unwind( transfer_t);
template< typename Rec >
-transfer_t context_exit( transfer_t) noexcept;
+transfer_t ecv2_context_exit( transfer_t) noexcept;
template< typename Rec >
-void context_entry( transfer_t) noexcept;
+void ecv2_context_etry( transfer_t) noexcept;
template< typename Ctx, typename Fn, typename ... Args >
-transfer_t context_ontop( transfer_t);
+transfer_t ecv2_context_ontop( transfer_t);
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
-fcontext_t context_create( StackAlloc &&, Fn &&, Params && ...);
+fcontext_t ecv2_context_create( StackAlloc &&, Fn &&, Params && ...);
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
-fcontext_t context_create( preallocated, StackAlloc &&, Fn &&, Params && ...);
+fcontext_t ecv2_context_create( preallocated, StackAlloc &&, Fn &&, Params && ...);
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
-class record {
+class ecv2_record {
private:
typename std::decay< StackAlloc >::type salloc_;
stack_context sctx_;
typename std::decay< Fn >::type fn_;
std::tuple< typename std::decay< Params >::type ... > params_;
- static void destroy( record * p) noexcept {
+ static void destroy( ecv2_record * p) noexcept {
typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
stack_context sctx = p->sctx_;
- // deallocate record
- p->~record();
+ // deallocate ecv2_record
+ p->~ecv2_record();
// destroy stack with stack allocator
salloc.deallocate( sctx);
}
public:
- record( stack_context sctx, StackAlloc && salloc,
+ ecv2_record( stack_context sctx, StackAlloc && salloc,
Fn && fn, Params && ... params) noexcept :
salloc_( std::forward< StackAlloc >( salloc)),
sctx_( sctx),
@@ -94,8 +94,8 @@ public:
params_( std::forward< Params >( params) ... ) {
}
- record( record const&) = delete;
- record & operator=( record const&) = delete;
+ ecv2_record( ecv2_record const&) = delete;
+ ecv2_record & operator=( ecv2_record const&) = delete;
void deallocate() noexcept {
destroy( this);
@@ -110,7 +110,7 @@ public:
std::move( args) );
// invoke context-function
#if defined(BOOST_NO_CXX17_STD_APPLY)
- Ctx cc = apply( std::move( fn_), std::move( tpl) );
+ Ctx cc = boost::context::detail::apply( std::move( fn_), std::move( tpl) );
#else
Ctx cc = std::apply( std::move( fn_), std::move( tpl) );
#endif
@@ -120,6 +120,8 @@ public:
}
+inline namespace v2 {
+
template< typename ... Args >
class execution_context {
private:
@@ -129,10 +131,10 @@ private:
typedef std::tuple< execution_context, typename std::decay< Args >::type ... > ret_tpl_t;
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
- friend class detail::record;
+ friend class detail::ecv2_record;
template< typename Ctx, typename Fn, typename ... ArgsT >
- friend detail::transfer_t detail::context_ontop( detail::transfer_t);
+ friend detail::transfer_t detail::ecv2_context_ontop( detail::transfer_t);
detail::fcontext_t fctx_{ nullptr };
@@ -162,7 +164,7 @@ public:
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
- fctx_( detail::context_create< execution_context >(
+ fctx_( detail::ecv2_context_create< execution_context >(
fixedsize_stack(),
std::forward< Fn >( fn),
std::forward< Params >( params) ... ) ) {
@@ -178,7 +180,7 @@ public:
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
- fctx_( detail::context_create< execution_context >(
+ fctx_( detail::ecv2_context_create< execution_context >(
std::forward< StackAlloc >( salloc),
std::forward< Fn >( fn),
std::forward< Params >( params) ... ) ) {
@@ -194,7 +196,7 @@ public:
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
- fctx_( detail::context_create< execution_context >(
+ fctx_( detail::ecv2_context_create< execution_context >(
palloc, std::forward< StackAlloc >( salloc),
std::forward< Fn >( fn),
std::forward< Params >( params) ... ) ) {
@@ -203,7 +205,7 @@ public:
~execution_context() {
if ( nullptr != fctx_) {
- detail::ontop_fcontext( detail::exchange( fctx_, nullptr), nullptr, detail::context_unwind);
+ detail::ontop_fcontext( detail::exchange( fctx_, nullptr), nullptr, detail::ecv2_context_unwind);
}
}
@@ -322,7 +324,7 @@ execution_context< Args ... >::operator()( exec_ontop_arg_t, Fn && fn, Args ...
detail::transfer_t t = detail::ontop_fcontext(
detail::exchange( fctx_, nullptr),
& p,
- detail::context_ontop< execution_context, Fn, Args ... >);
+ detail::ecv2_context_ontop< execution_context, Fn, Args ... >);
if ( nullptr != t.data) {
auto p = static_cast< std::tuple< std::exception_ptr, args_tpl_t > * >( t.data);
std::exception_ptr eptr = std::get< 0 >( * p);
@@ -338,6 +340,8 @@ execution_context< Args ... >::operator()( exec_ontop_arg_t, Fn && fn, Args ...
return std::tuple_cat( std::forward_as_tuple( execution_context( t.fctx) ), std::move( data) );
}
+}
+
namespace detail {
template< int N >
@@ -357,13 +361,13 @@ struct helper< 1 > {
};
inline
-transfer_t context_unwind( transfer_t t) {
+transfer_t ecv2_context_unwind( transfer_t t) {
throw forced_unwind( t.fctx);
return { nullptr, nullptr };
}
template< typename Rec >
-transfer_t context_exit( transfer_t t) noexcept {
+transfer_t ecv2_context_exit( transfer_t t) noexcept {
Rec * rec = static_cast< Rec * >( t.data);
// destroy context stack
rec->deallocate();
@@ -371,13 +375,13 @@ transfer_t context_exit( transfer_t t) noexcept {
}
template< typename Rec >
-void context_entry( transfer_t t_) noexcept {
+void ecv2_context_etry( transfer_t t_) noexcept {
// transfer control structure to the context-stack
Rec * rec = static_cast< Rec * >( t_.data);
BOOST_ASSERT( nullptr != rec);
transfer_t t = { nullptr, nullptr };
try {
- // jump back to `context_create()`
+ // jump back to `ecv2_context_create()`
t = jump_fcontext( t_.fctx, nullptr);
// start executing
t = rec->run( t);
@@ -386,12 +390,12 @@ void context_entry( transfer_t t_) noexcept {
}
BOOST_ASSERT( nullptr != t.fctx);
// destroy context-stack of `this`context on next context
- ontop_fcontext( t.fctx, rec, context_exit< Rec >);
+ ontop_fcontext( t.fctx, rec, ecv2_context_exit< Rec >);
BOOST_ASSERT_MSG( false, "context already terminated");
}
template< typename Ctx, typename Fn, typename ... Args >
-transfer_t context_ontop( transfer_t t) {
+transfer_t ecv2_context_ontop( transfer_t t) {
auto p = static_cast< std::tuple< Fn, std::tuple< std::exception_ptr, std::tuple< Args ... > > > * >( t.data);
BOOST_ASSERT( nullptr != p);
typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * p) );
@@ -399,7 +403,7 @@ transfer_t context_ontop( transfer_t t) {
try {
// execute function
#if defined(BOOST_NO_CXX17_STD_APPLY)
- std::get< 1 >( std::get< 1 >( * p) ) = helper< sizeof ... (Args) >::convert( apply( fn, std::move( args) ) );
+ std::get< 1 >( std::get< 1 >( * p) ) = helper< sizeof ... (Args) >::convert( boost::context::detail::apply( fn, std::move( args) ) );
#else
std::get< 1 >( std::get< 1 >( * p) ) = helper< sizeof ... (Args) >::convert( std::apply( fn, std::move( args) ) );
#endif
@@ -411,17 +415,17 @@ transfer_t context_ontop( transfer_t t) {
}
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
-fcontext_t context_create( StackAlloc && salloc, Fn && fn, Params && ... params) {
- typedef record< Ctx, StackAlloc, Fn, Params ... > record_t;
+fcontext_t ecv2_context_create( StackAlloc && salloc, Fn && fn, Params && ... params) {
+ typedef ecv2_record< Ctx, StackAlloc, Fn, Params ... > ecv2_record_t;
auto sctx = salloc.allocate();
// reserve space for control structure
#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
- const std::size_t size = sctx.size - sizeof( record_t);
- void * sp = static_cast< char * >( sctx.sp) - sizeof( record_t);
+ const std::size_t size = sctx.size - sizeof( ecv2_record_t);
+ void * sp = static_cast< char * >( sctx.sp) - sizeof( ecv2_record_t);
#else
- constexpr std::size_t func_alignment = 64; // alignof( record_t);
- constexpr std::size_t func_size = sizeof( record_t);
+ constexpr std::size_t func_alignment = 64; // alignof( ecv2_record_t);
+ constexpr std::size_t func_size = sizeof( ecv2_record_t);
// reserve space on stack
void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
// align sp pointer
@@ -432,26 +436,26 @@ fcontext_t context_create( StackAlloc && salloc, Fn && fn, Params && ... params)
const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
#endif
// create fast-context
- const fcontext_t fctx = make_fcontext( sp, size, & context_entry< record_t >);
+ const fcontext_t fctx = make_fcontext( sp, size, & ecv2_context_etry< ecv2_record_t >);
BOOST_ASSERT( nullptr != fctx);
// placment new for control structure on context-stack
- auto rec = ::new ( sp) record_t{
+ auto rec = ::new ( sp) ecv2_record_t{
sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn), std::forward< Params >( params) ... };
// transfer control structure to context-stack
return jump_fcontext( fctx, rec).fctx;
}
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
-fcontext_t context_create( preallocated palloc, StackAlloc && salloc, Fn && fn, Params && ... params) {
- typedef record< Ctx, StackAlloc, Fn, Params ... > record_t;
+fcontext_t ecv2_context_create( preallocated palloc, StackAlloc && salloc, Fn && fn, Params && ... params) {
+ typedef ecv2_record< Ctx, StackAlloc, Fn, Params ... > ecv2_record_t;
// reserve space for control structure
#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
- const std::size_t size = palloc.size - sizeof( record_t);
- void * sp = static_cast< char * >( palloc.sp) - sizeof( record_t);
+ const std::size_t size = palloc.size - sizeof( ecv2_record_t);
+ void * sp = static_cast< char * >( palloc.sp) - sizeof( ecv2_record_t);
#else
- constexpr std::size_t func_alignment = 64; // alignof( record_t);
- constexpr std::size_t func_size = sizeof( record_t);
+ constexpr std::size_t func_alignment = 64; // alignof( ecv2_record_t);
+ constexpr std::size_t func_size = sizeof( ecv2_record_t);
// reserve space on stack
void * sp = static_cast< char * >( palloc.sp) - func_size - func_alignment;
// align sp pointer
@@ -462,10 +466,10 @@ fcontext_t context_create( preallocated palloc, StackAlloc && salloc, Fn && fn,
const std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) );
#endif
// create fast-context
- const fcontext_t fctx = make_fcontext( sp, size, & context_entry< record_t >);
+ const fcontext_t fctx = make_fcontext( sp, size, & ecv2_context_etry< ecv2_record_t >);
BOOST_ASSERT( nullptr != fctx);
// placment new for control structure on context-stack
- auto rec = ::new ( sp) record_t{
+ auto rec = ::new ( sp) ecv2_record_t{
palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn), std::forward< Params >( params) ... };
// transfer control structure to context-stack
return jump_fcontext( fctx, rec).fctx;
@@ -475,12 +479,14 @@ fcontext_t context_create( preallocated palloc, StackAlloc && salloc, Fn && fn,
#include <boost/context/execution_context_v2_void.ipp>
+inline namespace v2 {
+
template< typename ... Args >
void swap( execution_context< Args ... > & l, execution_context< Args ... > & r) noexcept {
l.swap( r);
}
-}}
+}}}
#if defined(BOOST_MSVC)
# pragma warning(pop)
@@ -490,4 +496,4 @@ void swap( execution_context< Args ... > & l, execution_context< Args ... > & r)
# include BOOST_ABI_SUFFIX
#endif
-#endif // BOOST_CONTEXT_EXECUTION_CONTEXT_H
+#endif // BOOST_CONTEXT_EXECUTION_CONTEXT_V2_H
diff --git a/boost/context/execution_context_v2_void.ipp b/boost/context/execution_context_v2_void.ipp
index bab713639a..f262a0c9c9 100644
--- a/boost/context/execution_context_v2_void.ipp
+++ b/boost/context/execution_context_v2_void.ipp
@@ -7,33 +7,33 @@
namespace detail {
template< typename Ctx, typename Fn >
-transfer_t context_ontop_void( transfer_t);
+transfer_t ecv2_context_ontop_void( transfer_t);
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
-fcontext_t context_create_void( StackAlloc &&, Fn &&, Params && ...);
+fcontext_t ecv2_context_create_void( StackAlloc &&, Fn &&, Params && ...);
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
-fcontext_t context_create_void( preallocated, StackAlloc &&, Fn &&, Params && ...);
+fcontext_t ecv2_context_create_void( preallocated, StackAlloc &&, Fn &&, Params && ...);
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
-class record_void {
+class ecv2_record_void {
private:
typename std::decay< StackAlloc >::type salloc_;
stack_context sctx_;
typename std::decay< Fn >::type fn_;
std::tuple< typename std::decay< Params >::type ... > params_;
- static void destroy( record_void * p) noexcept {
+ static void destroy( ecv2_record_void * p) noexcept {
typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
stack_context sctx = p->sctx_;
// deallocate record
- p->~record_void();
+ p->~ecv2_record_void();
// destroy stack with stack allocator
salloc.deallocate( sctx);
}
public:
- record_void( stack_context sctx, StackAlloc && salloc,
+ ecv2_record_void( stack_context sctx, StackAlloc && salloc,
Fn && fn, Params && ... params) noexcept :
salloc_( std::forward< StackAlloc >( salloc) ),
sctx_( sctx),
@@ -41,8 +41,8 @@ public:
params_( std::forward< Params >( params) ... ) {
}
- record_void( record_void const&) = delete;
- record_void & operator=( record_void const&) = delete;
+ ecv2_record_void( ecv2_record_void const&) = delete;
+ ecv2_record_void & operator=( ecv2_record_void const&) = delete;
void deallocate() noexcept {
destroy( this);
@@ -52,7 +52,7 @@ public:
Ctx from{ t.fctx };
// invoke context-function
#if defined(BOOST_NO_CXX17_STD_APPLY)
- Ctx cc = apply( fn_, std::tuple_cat( params_, std::forward_as_tuple( std::move( from) ) ) );
+ Ctx cc = boost::context::detail::apply( fn_, std::tuple_cat( params_, std::forward_as_tuple( std::move( from) ) ) );
#else
Ctx cc = std::apply( fn_, std::tuple_cat( params_, std::forward_as_tuple( std::move( from) ) ) );
#endif
@@ -62,16 +62,18 @@ public:
}
+inline namespace v2 {
+
template<>
class execution_context< void > {
private:
friend class ontop_error;
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
- friend class detail::record_void;
+ friend class detail::ecv2_record_void;
template< typename Ctx, typename Fn >
- friend detail::transfer_t detail::context_ontop_void( detail::transfer_t);
+ friend detail::transfer_t detail::ecv2_context_ontop_void( detail::transfer_t);
detail::fcontext_t fctx_{ nullptr };
@@ -101,7 +103,7 @@ public:
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
- fctx_( detail::context_create_void< execution_context >(
+ fctx_( detail::ecv2_context_create_void< execution_context >(
fixedsize_stack(),
std::forward< Fn >( fn),
std::forward< Params >( params) ... ) ) {
@@ -117,7 +119,7 @@ public:
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
- fctx_( detail::context_create_void< execution_context >(
+ fctx_( detail::ecv2_context_create_void< execution_context >(
std::forward< StackAlloc >( salloc),
std::forward< Fn >( fn),
std::forward< Params >( params) ... ) ) {
@@ -133,7 +135,7 @@ public:
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
- fctx_( detail::context_create_void< execution_context >(
+ fctx_( detail::ecv2_context_create_void< execution_context >(
palloc, std::forward< StackAlloc >( salloc),
std::forward< Fn >( fn),
std::forward< Params >( params) ... ) ) {
@@ -142,7 +144,7 @@ public:
~execution_context() {
if ( nullptr != fctx_) {
- detail::ontop_fcontext( detail::exchange( fctx_, nullptr), nullptr, detail::context_unwind);
+ detail::ontop_fcontext( detail::exchange( fctx_, nullptr), nullptr, detail::ecv2_context_unwind);
}
}
@@ -183,7 +185,7 @@ public:
detail::transfer_t t = detail::ontop_fcontext(
detail::exchange( fctx_, nullptr),
& p,
- detail::context_ontop_void< execution_context, Fn >);
+ detail::ecv2_context_ontop_void< execution_context, Fn >);
if ( nullptr != t.data) {
std::exception_ptr * eptr = static_cast< std::exception_ptr * >( t.data);
try {
@@ -242,10 +244,12 @@ public:
}
};
+}
+
namespace detail {
template< typename Ctx, typename Fn >
-transfer_t context_ontop_void( transfer_t t) {
+transfer_t ecv2_context_ontop_void( transfer_t t) {
auto p = static_cast< std::tuple< Fn, std::exception_ptr > * >( t.data);
BOOST_ASSERT( nullptr != p);
typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * p) );
@@ -260,8 +264,8 @@ transfer_t context_ontop_void( transfer_t t) {
}
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
-fcontext_t context_create_void( StackAlloc && salloc, Fn && fn, Params && ... params) {
- typedef record_void< Ctx, StackAlloc, Fn, Params ... > record_t;
+fcontext_t ecv2_context_create_void( StackAlloc && salloc, Fn && fn, Params && ... params) {
+ typedef ecv2_record_void< Ctx, StackAlloc, Fn, Params ... > record_t;
auto sctx = salloc.allocate();
// reserve space for control structure
@@ -281,7 +285,7 @@ fcontext_t context_create_void( StackAlloc && salloc, Fn && fn, Params && ... pa
const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
#endif
// create fast-context
- const fcontext_t fctx = make_fcontext( sp, size, & context_entry< record_t >);
+ const fcontext_t fctx = make_fcontext( sp, size, & ecv2_context_etry< record_t >);
BOOST_ASSERT( nullptr != fctx);
// placment new for control structure on context-stack
auto rec = ::new ( sp) record_t{
@@ -291,8 +295,8 @@ fcontext_t context_create_void( StackAlloc && salloc, Fn && fn, Params && ... pa
}
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
-fcontext_t context_create_void( preallocated palloc, StackAlloc && salloc, Fn && fn, Params && ... params) {
- typedef record_void< Ctx, StackAlloc, Fn, Params ... > record_t;
+fcontext_t ecv2_context_create_void( preallocated palloc, StackAlloc && salloc, Fn && fn, Params && ... params) {
+ typedef ecv2_record_void< Ctx, StackAlloc, Fn, Params ... > record_t;
// reserve space for control structure
#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
@@ -311,7 +315,7 @@ fcontext_t context_create_void( preallocated palloc, StackAlloc && salloc, Fn &&
const std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) );
#endif
// create fast-context
- const fcontext_t fctx = make_fcontext( sp, size, & context_entry< record_t >);
+ const fcontext_t fctx = make_fcontext( sp, size, & ecv2_context_etry< record_t >);
BOOST_ASSERT( nullptr != fctx);
// placment new for control structure on context-stack
auto rec = ::new ( sp) record_t{
diff --git a/boost/context/fiber.hpp b/boost/context/fiber.hpp
new file mode 100644
index 0000000000..ff1b79e2da
--- /dev/null
+++ b/boost/context/fiber.hpp
@@ -0,0 +1,13 @@
+
+// Copyright Oliver Kowalke 2017.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#if defined(BOOST_USE_UCONTEXT)
+#include <boost/context/fiber_ucontext.hpp>
+#elif defined(BOOST_USE_WINFIB)
+#include <boost/context/fiber_winfib.hpp>
+#else
+#include <boost/context/fiber_fcontext.hpp>
+#endif
diff --git a/boost/context/fiber_fcontext.hpp b/boost/context/fiber_fcontext.hpp
new file mode 100644
index 0000000000..9b792bc96b
--- /dev/null
+++ b/boost/context/fiber_fcontext.hpp
@@ -0,0 +1,365 @@
+
+// Copyright Oliver Kowalke 2017.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_CONTEXT_FIBER_H
+#define BOOST_CONTEXT_FIBER_H
+
+#include <boost/context/detail/config.hpp>
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <exception>
+#include <functional>
+#include <memory>
+#include <ostream>
+#include <tuple>
+#include <utility>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+#include <boost/context/detail/exchange.hpp>
+#endif
+#if defined(BOOST_NO_CXX17_STD_INVOKE)
+#include <boost/context/detail/invoke.hpp>
+#endif
+#include <boost/context/detail/disable_overload.hpp>
+#include <boost/context/detail/exception.hpp>
+#include <boost/context/detail/fcontext.hpp>
+#include <boost/context/detail/tuple.hpp>
+#include <boost/context/fixedsize_stack.hpp>
+#include <boost/context/flags.hpp>
+#include <boost/context/preallocated.hpp>
+#include <boost/context/segmented_stack.hpp>
+#include <boost/context/stack_context.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+#if defined(BOOST_MSVC)
+# pragma warning(push)
+# pragma warning(disable: 4702)
+#endif
+
+namespace boost {
+namespace context {
+namespace detail {
+
+inline
+transfer_t fiber_unwind( transfer_t t) {
+ throw forced_unwind( t.fctx);
+ return { nullptr, nullptr };
+}
+
+template< typename Rec >
+transfer_t fiber_exit( transfer_t t) noexcept {
+ Rec * rec = static_cast< Rec * >( t.data);
+ // destroy context stack
+ rec->deallocate();
+ return { nullptr, nullptr };
+}
+
+template< typename Rec >
+void fiber_entry( transfer_t t) noexcept {
+ // transfer control structure to the context-stack
+ Rec * rec = static_cast< Rec * >( t.data);
+ BOOST_ASSERT( nullptr != t.fctx);
+ BOOST_ASSERT( nullptr != rec);
+ try {
+ // jump back to `create_context()`
+ t = jump_fcontext( t.fctx, nullptr);
+ // start executing
+ t.fctx = rec->run( t.fctx);
+ } catch ( forced_unwind const& e) {
+ t = { e.fctx, nullptr };
+ }
+ BOOST_ASSERT( nullptr != t.fctx);
+ // destroy context-stack of `this`context on next context
+ ontop_fcontext( t.fctx, rec, fiber_exit< Rec >);
+ BOOST_ASSERT_MSG( false, "context already terminated");
+}
+
+template< typename Ctx, typename Fn >
+transfer_t fiber_ontop( transfer_t t) {
+ auto p = static_cast< std::tuple< Fn > * >( t.data);
+ BOOST_ASSERT( nullptr != p);
+ typename std::decay< Fn >::type fn = std::get< 0 >( * p);
+ t.data = nullptr;
+ // execute function, pass fiber via reference
+ Ctx c = fn( Ctx{ t.fctx } );
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ return { exchange( c.fctx_, nullptr), nullptr };
+#else
+ return { std::exchange( c.fctx_, nullptr), nullptr };
+#endif
+}
+
+template< typename Ctx, typename StackAlloc, typename Fn >
+class fiber_record {
+private:
+ stack_context sctx_;
+ typename std::decay< StackAlloc >::type salloc_;
+ typename std::decay< Fn >::type fn_;
+
+ static void destroy( fiber_record * p) noexcept {
+ typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
+ stack_context sctx = p->sctx_;
+ // deallocate fiber_record
+ p->~fiber_record();
+ // destroy stack with stack allocator
+ salloc.deallocate( sctx);
+ }
+
+public:
+ fiber_record( stack_context sctx, StackAlloc && salloc,
+ Fn && fn) noexcept :
+ sctx_( sctx),
+ salloc_( std::forward< StackAlloc >( salloc)),
+ fn_( std::forward< Fn >( fn) ) {
+ }
+
+ fiber_record( fiber_record const&) = delete;
+ fiber_record & operator=( fiber_record const&) = delete;
+
+ void deallocate() noexcept {
+ destroy( this);
+ }
+
+ fcontext_t run( fcontext_t fctx) {
+ // invoke context-function
+#if defined(BOOST_NO_CXX17_STD_INVOKE)
+ Ctx c = boost::context::detail::invoke( fn_, Ctx{ fctx } );
+#else
+ Ctx c = std::invoke( fn_, Ctx{ fctx } );
+#endif
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ return exchange( c.fctx_, nullptr);
+#else
+ return std::exchange( c.fctx_, nullptr);
+#endif
+ }
+};
+
+template< typename Record, typename StackAlloc, typename Fn >
+fcontext_t create_fiber1( StackAlloc && salloc, Fn && fn) {
+ auto sctx = salloc.allocate();
+ // reserve space for control structure
+ void * storage = reinterpret_cast< void * >(
+ ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( Record) ) )
+ & ~static_cast< uintptr_t >( 0xff) );
+ // placment new for control structure on context stack
+ Record * record = new ( storage) Record{
+ sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) };
+ // 64byte gab between control structure and stack top
+ // should be 16byte aligned
+ void * stack_top = reinterpret_cast< void * >(
+ reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) );
+ void * stack_bottom = reinterpret_cast< void * >(
+ reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) );
+ // create fast-context
+ const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom);
+ const fcontext_t fctx = make_fcontext( stack_top, size, & fiber_entry< Record >);
+ BOOST_ASSERT( nullptr != fctx);
+ // transfer control structure to context-stack
+ return jump_fcontext( fctx, record).fctx;
+}
+
+template< typename Record, typename StackAlloc, typename Fn >
+fcontext_t create_fiber2( preallocated palloc, StackAlloc && salloc, Fn && fn) {
+ // reserve space for control structure
+ void * storage = reinterpret_cast< void * >(
+ ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( Record) ) )
+ & ~ static_cast< uintptr_t >( 0xff) );
+ // placment new for control structure on context-stack
+ Record * record = new ( storage) Record{
+ palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) };
+ // 64byte gab between control structure and stack top
+ void * stack_top = reinterpret_cast< void * >(
+ reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) );
+ void * stack_bottom = reinterpret_cast< void * >(
+ reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) );
+ // create fast-context
+ const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom);
+ const fcontext_t fctx = make_fcontext( stack_top, size, & fiber_entry< Record >);
+ BOOST_ASSERT( nullptr != fctx);
+ // transfer control structure to context-stack
+ return jump_fcontext( fctx, record).fctx;
+}
+
+}
+
+class fiber {
+private:
+ template< typename Ctx, typename StackAlloc, typename Fn >
+ friend class detail::fiber_record;
+
+ template< typename Ctx, typename Fn >
+ friend detail::transfer_t
+ detail::fiber_ontop( detail::transfer_t);
+
+ template< typename StackAlloc, typename Fn >
+ friend fiber
+ callcc( std::allocator_arg_t, StackAlloc &&, Fn &&);
+
+ template< typename StackAlloc, typename Fn >
+ friend fiber
+ callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&);
+
+ detail::fcontext_t fctx_{ nullptr };
+
+ fiber( detail::fcontext_t fctx) noexcept :
+ fctx_{ fctx } {
+ }
+
+public:
+ fiber() noexcept = default;
+
+ template< typename Fn, typename = detail::disable_overload< fiber, Fn > >
+ fiber( Fn && fn) :
+ fiber{ std::allocator_arg, fixedsize_stack(), std::forward< Fn >( fn) } {
+ }
+
+ template< typename StackAlloc, typename Fn >
+ fiber( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) :
+ fctx_{ detail::create_fiber1< detail::fiber_record< fiber, StackAlloc, Fn > >(
+ std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } {
+ }
+
+ template< typename StackAlloc, typename Fn >
+ fiber( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) :
+ fctx_{ detail::create_fiber2< detail::fiber_record< fiber, StackAlloc, Fn > >(
+ palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } {
+ }
+
+#if defined(BOOST_USE_SEGMENTED_STACKS)
+ template< typename Fn >
+ fiber( std::allocator_arg_t, segmented_stack, Fn &&);
+
+ template< typename StackAlloc, typename Fn >
+ fiber( std::allocator_arg_t, preallocated, segmented_stack, Fn &&);
+#endif
+
+ ~fiber() {
+ if ( BOOST_UNLIKELY( nullptr != fctx_) ) {
+ detail::ontop_fcontext(
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ detail::exchange( fctx_, nullptr),
+#else
+ std::exchange( fctx_, nullptr),
+#endif
+ nullptr,
+ detail::fiber_unwind);
+ }
+ }
+
+ fiber( fiber && other) noexcept {
+ swap( other);
+ }
+
+ fiber & operator=( fiber && other) noexcept {
+ if ( BOOST_LIKELY( this != & other) ) {
+ fiber tmp = std::move( other);
+ swap( tmp);
+ }
+ return * this;
+ }
+
+ fiber( fiber const& other) noexcept = delete;
+ fiber & operator=( fiber const& other) noexcept = delete;
+
+ fiber resume() && {
+ BOOST_ASSERT( nullptr != fctx_);
+ return { detail::jump_fcontext(
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ detail::exchange( fctx_, nullptr),
+#else
+ std::exchange( fctx_, nullptr),
+#endif
+ nullptr).fctx };
+ }
+
+ template< typename Fn >
+ fiber resume_with( Fn && fn) && {
+ BOOST_ASSERT( nullptr != fctx_);
+ auto p = std::make_tuple( std::forward< Fn >( fn) );
+ return { detail::ontop_fcontext(
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ detail::exchange( fctx_, nullptr),
+#else
+ std::exchange( fctx_, nullptr),
+#endif
+ & p,
+ detail::fiber_ontop< fiber, Fn >).fctx };
+ }
+
+ explicit operator bool() const noexcept {
+ return nullptr != fctx_;
+ }
+
+ bool operator!() const noexcept {
+ return nullptr == fctx_;
+ }
+
+ bool operator==( fiber const& other) const noexcept {
+ return fctx_ == other.fctx_;
+ }
+
+ bool operator!=( fiber const& other) const noexcept {
+ return fctx_ != other.fctx_;
+ }
+
+ bool operator<( fiber const& other) const noexcept {
+ return fctx_ < other.fctx_;
+ }
+
+ bool operator>( fiber const& other) const noexcept {
+ return other.fctx_ < fctx_;
+ }
+
+ bool operator<=( fiber const& other) const noexcept {
+ return ! ( * this > other);
+ }
+
+ bool operator>=( fiber const& other) const noexcept {
+ return ! ( * this < other);
+ }
+
+ template< typename charT, class traitsT >
+ friend std::basic_ostream< charT, traitsT > &
+ operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) {
+ if ( nullptr != other.fctx_) {
+ return os << other.fctx_;
+ } else {
+ return os << "{not-a-context}";
+ }
+ }
+
+ void swap( fiber & other) noexcept {
+ std::swap( fctx_, other.fctx_);
+ }
+};
+
+inline
+void swap( fiber & l, fiber & r) noexcept {
+ l.swap( r);
+}
+
+}}
+
+#if defined(BOOST_MSVC)
+# pragma warning(pop)
+#endif
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_CONTEXT_FIBER_H
diff --git a/boost/context/fiber_ucontext.hpp b/boost/context/fiber_ucontext.hpp
new file mode 100644
index 0000000000..ae62389526
--- /dev/null
+++ b/boost/context/fiber_ucontext.hpp
@@ -0,0 +1,515 @@
+
+// Copyright Oliver Kowalke 2017.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_CONTEXT_FIBER_H
+#define BOOST_CONTEXT_FIBER_H
+
+#include <boost/predef.h>
+#if BOOST_OS_MACOS
+#define _XOPEN_SOURCE 600
+#endif
+
+extern "C" {
+#include <ucontext.h>
+}
+
+#include <boost/context/detail/config.hpp>
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <memory>
+#include <ostream>
+#include <system_error>
+#include <tuple>
+#include <utility>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+
+#include <boost/context/detail/disable_overload.hpp>
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+#include <boost/context/detail/exchange.hpp>
+#endif
+#include <boost/context/detail/externc.hpp>
+#if defined(BOOST_NO_CXX17_STD_INVOKE)
+#include <boost/context/detail/invoke.hpp>
+#endif
+#include <boost/context/fixedsize_stack.hpp>
+#include <boost/context/flags.hpp>
+#include <boost/context/preallocated.hpp>
+#if defined(BOOST_USE_SEGMENTED_STACKS)
+#include <boost/context/segmented_stack.hpp>
+#endif
+#include <boost/context/stack_context.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace context {
+namespace detail {
+
+// tampoline function
+// entered if the execution context
+// is resumed for the first time
+template< typename Record >
+static void fiber_entry_func( void * data) noexcept {
+ Record * record = static_cast< Record * >( data);
+ BOOST_ASSERT( nullptr != record);
+ // start execution of toplevel context-function
+ record->run();
+}
+
+struct BOOST_CONTEXT_DECL fiber_activation_record {
+ ucontext_t uctx{};
+ stack_context sctx{};
+ bool main_ctx{ true };
+ fiber_activation_record * from{ nullptr };
+ std::function< fiber_activation_record*(fiber_activation_record*&) > ontop{};
+ bool terminated{ false };
+ bool force_unwind{ false };
+#if defined(BOOST_USE_ASAN)
+ void * fake_stack{ nullptr };
+ void * stack_bottom{ nullptr };
+ std::size_t stack_size{ 0 };
+#endif
+
+ static fiber_activation_record *& current() noexcept;
+
+ // used for toplevel-context
+ // (e.g. main context, thread-entry context)
+ fiber_activation_record() {
+ if ( BOOST_UNLIKELY( 0 != ::getcontext( & uctx) ) ) {
+ throw std::system_error(
+ std::error_code( errno, std::system_category() ),
+ "getcontext() failed");
+ }
+ }
+
+ fiber_activation_record( stack_context sctx_) noexcept :
+ sctx( sctx_ ),
+ main_ctx( false ) {
+ }
+
+ virtual ~fiber_activation_record() {
+ }
+
+ fiber_activation_record( fiber_activation_record const&) = delete;
+ fiber_activation_record & operator=( fiber_activation_record const&) = delete;
+
+ bool is_main_context() const noexcept {
+ return main_ctx;
+ }
+
+ fiber_activation_record * resume() {
+ from = current();
+ // store `this` in static, thread local pointer
+ // `this` will become the active (running) context
+ current() = this;
+#if defined(BOOST_USE_SEGMENTED_STACKS)
+ // adjust segmented stack properties
+ __splitstack_getcontext( from->sctx.segments_ctx);
+ __splitstack_setcontext( sctx.segments_ctx);
+#endif
+#if defined(BOOST_USE_ASAN)
+ if ( terminated) {
+ __sanitizer_start_switch_fiber( nullptr, stack_bottom, stack_size);
+ } else {
+ __sanitizer_start_switch_fiber( & from->fake_stack, stack_bottom, stack_size);
+ }
+#endif
+ // context switch from parent context to `this`-context
+ ::swapcontext( & from->uctx, & uctx);
+#if defined(BOOST_USE_ASAN)
+ __sanitizer_finish_switch_fiber( current()->fake_stack,
+ (const void **) & current()->from->stack_bottom,
+ & current()->from->stack_size);
+#endif
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ return exchange( current()->from, nullptr);
+#else
+ return std::exchange( current()->from, nullptr);
+#endif
+ }
+
+ template< typename Ctx, typename Fn >
+ fiber_activation_record * resume_with( Fn && fn) {
+ from = current();
+ // store `this` in static, thread local pointer
+ // `this` will become the active (running) context
+ // returned by fiber::current()
+ current() = this;
+#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
+ current()->ontop = std::bind(
+ [](typename std::decay< Fn >::type & fn, fiber_activation_record *& ptr){
+ Ctx c{ ptr };
+ c = fn( std::move( c) );
+ if ( ! c) {
+ ptr = nullptr;
+ }
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ return exchange( c.ptr_, nullptr);
+#else
+ return std::exchange( c.ptr_, nullptr);
+#endif
+ },
+ std::forward< Fn >( fn),
+ std::placeholders::_1);
+#else
+ current()->ontop = [fn=std::forward<Fn>(fn)](fiber_activation_record *& ptr){
+ Ctx c{ ptr };
+ c = fn( std::move( c) );
+ if ( ! c) {
+ ptr = nullptr;
+ }
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ return exchange( c.ptr_, nullptr);
+#else
+ return std::exchange( c.ptr_, nullptr);
+#endif
+ };
+#endif
+#if defined(BOOST_USE_SEGMENTED_STACKS)
+ // adjust segmented stack properties
+ __splitstack_getcontext( from->sctx.segments_ctx);
+ __splitstack_setcontext( sctx.segments_ctx);
+#endif
+#if defined(BOOST_USE_ASAN)
+ __sanitizer_start_switch_fiber( & from->fake_stack, stack_bottom, stack_size);
+#endif
+ // context switch from parent context to `this`-context
+ ::swapcontext( & from->uctx, & uctx);
+#if defined(BOOST_USE_ASAN)
+ __sanitizer_finish_switch_fiber( current()->fake_stack,
+ (const void **) & current()->from->stack_bottom,
+ & current()->from->stack_size);
+#endif
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ return exchange( current()->from, nullptr);
+#else
+ return std::exchange( current()->from, nullptr);
+#endif
+ }
+
+ virtual void deallocate() noexcept {
+ }
+};
+
+struct BOOST_CONTEXT_DECL fiber_activation_record_initializer {
+ fiber_activation_record_initializer() noexcept;
+ ~fiber_activation_record_initializer();
+};
+
+struct forced_unwind {
+ fiber_activation_record * from{ nullptr };
+
+ forced_unwind( fiber_activation_record * from_) noexcept :
+ from{ from_ } {
+ }
+};
+
+template< typename Ctx, typename StackAlloc, typename Fn >
+class fiber_capture_record : public fiber_activation_record {
+private:
+ typename std::decay< StackAlloc >::type salloc_;
+ typename std::decay< Fn >::type fn_;
+
+ static void destroy( fiber_capture_record * p) noexcept {
+ typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
+ stack_context sctx = p->sctx;
+ // deallocate activation record
+ p->~fiber_capture_record();
+ // destroy stack with stack allocator
+ salloc.deallocate( sctx);
+ }
+
+public:
+ fiber_capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept :
+ fiber_activation_record{ sctx },
+ salloc_{ std::forward< StackAlloc >( salloc) },
+ fn_( std::forward< Fn >( fn) ) {
+ }
+
+ void deallocate() noexcept override final {
+ BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) );
+ destroy( this);
+ }
+
+ void run() {
+#if defined(BOOST_USE_ASAN)
+ __sanitizer_finish_switch_fiber( fake_stack,
+ (const void **) & from->stack_bottom,
+ & from->stack_size);
+#endif
+ Ctx c{ from };
+ try {
+ // invoke context-function
+#if defined(BOOST_NO_CXX17_STD_INVOKE)
+ c = boost::context::detail::invoke( fn_, std::move( c) );
+#else
+ c = std::invoke( fn_, std::move( c) );
+#endif
+ } catch ( forced_unwind const& ex) {
+ c = Ctx{ ex.from };
+ }
+ // this context has finished its task
+ from = nullptr;
+ ontop = nullptr;
+ terminated = true;
+ force_unwind = false;
+ std::move( c).resume();
+ BOOST_ASSERT_MSG( false, "fiber already terminated");
+ }
+};
+
+template< typename Ctx, typename StackAlloc, typename Fn >
+static fiber_activation_record * create_fiber1( StackAlloc && salloc, Fn && fn) {
+ typedef fiber_capture_record< Ctx, StackAlloc, Fn > capture_t;
+
+ auto sctx = salloc.allocate();
+ // reserve space for control structure
+ void * storage = reinterpret_cast< void * >(
+ ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) )
+ & ~ static_cast< uintptr_t >( 0xff) );
+ // placment new for control structure on context stack
+ capture_t * record = new ( storage) capture_t{
+ sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) };
+ // stack bottom
+ void * stack_bottom = reinterpret_cast< void * >(
+ reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) );
+ // create user-context
+ if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) {
+ throw std::system_error(
+ std::error_code( errno, std::system_category() ),
+ "getcontext() failed");
+ }
+ record->uctx.uc_stack.ss_sp = stack_bottom;
+ // 64byte gap between control structure and stack top
+ record->uctx.uc_stack.ss_size = reinterpret_cast< uintptr_t >( storage) -
+ reinterpret_cast< uintptr_t >( stack_bottom) - static_cast< uintptr_t >( 64);
+ record->uctx.uc_link = nullptr;
+ ::makecontext( & record->uctx, ( void (*)() ) & fiber_entry_func< capture_t >, 1, record);
+#if defined(BOOST_USE_ASAN)
+ record->stack_bottom = record->uctx.uc_stack.ss_sp;
+ record->stack_size = record->uctx.uc_stack.ss_size;
+#endif
+ return record;
+}
+
+template< typename Ctx, typename StackAlloc, typename Fn >
+static fiber_activation_record * create_fiber2( preallocated palloc, StackAlloc && salloc, Fn && fn) {
+ typedef fiber_capture_record< Ctx, StackAlloc, Fn > capture_t;
+
+ // reserve space for control structure
+ void * storage = reinterpret_cast< void * >(
+ ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) )
+ & ~ static_cast< uintptr_t >( 0xff) );
+ // placment new for control structure on context stack
+ capture_t * record = new ( storage) capture_t{
+ palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) };
+ // stack bottom
+ void * stack_bottom = reinterpret_cast< void * >(
+ reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) );
+ // create user-context
+ if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) {
+ throw std::system_error(
+ std::error_code( errno, std::system_category() ),
+ "getcontext() failed");
+ }
+ record->uctx.uc_stack.ss_sp = stack_bottom;
+ // 64byte gap between control structure and stack top
+ record->uctx.uc_stack.ss_size = reinterpret_cast< uintptr_t >( storage) -
+ reinterpret_cast< uintptr_t >( stack_bottom) - static_cast< uintptr_t >( 64);
+ record->uctx.uc_link = nullptr;
+ ::makecontext( & record->uctx, ( void (*)() ) & fiber_entry_func< capture_t >, 1, record);
+#if defined(BOOST_USE_ASAN)
+ record->stack_bottom = record->uctx.uc_stack.ss_sp;
+ record->stack_size = record->uctx.uc_stack.ss_size;
+#endif
+ return record;
+}
+
+}
+
+class BOOST_CONTEXT_DECL fiber {
+private:
+ friend struct detail::fiber_activation_record;
+
+ template< typename Ctx, typename StackAlloc, typename Fn >
+ friend class detail::fiber_capture_record;
+
+ template< typename Ctx, typename StackAlloc, typename Fn >
+ friend detail::fiber_activation_record * detail::create_fiber1( StackAlloc &&, Fn &&);
+
+ template< typename Ctx, typename StackAlloc, typename Fn >
+ friend detail::fiber_activation_record * detail::create_fiber2( preallocated, StackAlloc &&, Fn &&);
+
+ template< typename StackAlloc, typename Fn >
+ friend fiber
+ callcc( std::allocator_arg_t, StackAlloc &&, Fn &&);
+
+ template< typename StackAlloc, typename Fn >
+ friend fiber
+ callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&);
+
+ detail::fiber_activation_record * ptr_{ nullptr };
+
+ fiber( detail::fiber_activation_record * ptr) noexcept :
+ ptr_{ ptr } {
+ }
+
+public:
+ fiber() = default;
+
+ template< typename Fn, typename = detail::disable_overload< fiber, Fn > >
+ fiber( Fn && fn) :
+ fiber{
+ std::allocator_arg,
+#if defined(BOOST_USE_SEGMENTED_STACKS)
+ segmented_stack(),
+#else
+ fixedsize_stack(),
+#endif
+ std::forward< Fn >( fn) } {
+ }
+
+ template< typename StackAlloc, typename Fn >
+ fiber( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) :
+ ptr_{ detail::create_fiber1< fiber >(
+ std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } {
+ }
+
+ template< typename StackAlloc, typename Fn >
+ fiber( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) :
+ ptr_{ detail::create_fiber2< fiber >(
+ palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } {
+ }
+
+ ~fiber() {
+ if ( BOOST_UNLIKELY( nullptr != ptr_) && ! ptr_->main_ctx) {
+ if ( BOOST_LIKELY( ! ptr_->terminated) ) {
+ ptr_->force_unwind = true;
+ ptr_->resume();
+ BOOST_ASSERT( ptr_->terminated);
+ }
+ ptr_->deallocate();
+ }
+ }
+
+ fiber( fiber const&) = delete;
+ fiber & operator=( fiber const&) = delete;
+
+ fiber( fiber && other) noexcept {
+ swap( other);
+ }
+
+ fiber & operator=( fiber && other) noexcept {
+ if ( BOOST_LIKELY( this != & other) ) {
+ fiber tmp = std::move( other);
+ swap( tmp);
+ }
+ return * this;
+ }
+
+ fiber resume() && {
+ BOOST_ASSERT( nullptr != ptr_);
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ detail::fiber_activation_record * ptr = detail::exchange( ptr_, nullptr)->resume();
+#else
+ detail::fiber_activation_record * ptr = std::exchange( ptr_, nullptr)->resume();
+#endif
+ if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) {
+ throw detail::forced_unwind{ ptr};
+ } else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) {
+ ptr = detail::fiber_activation_record::current()->ontop( ptr);
+ detail::fiber_activation_record::current()->ontop = nullptr;
+ }
+ return { ptr };
+ }
+
+ template< typename Fn >
+ fiber resume_with( Fn && fn) && {
+ BOOST_ASSERT( nullptr != ptr_);
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ detail::fiber_activation_record * ptr =
+ detail::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) );
+#else
+ detail::fiber_activation_record * ptr =
+ std::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) );
+#endif
+ if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) {
+ throw detail::forced_unwind{ ptr};
+ } else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) {
+ ptr = detail::fiber_activation_record::current()->ontop( ptr);
+ detail::fiber_activation_record::current()->ontop = nullptr;
+ }
+ return { ptr };
+ }
+
+ explicit operator bool() const noexcept {
+ return nullptr != ptr_ && ! ptr_->terminated;
+ }
+
+ bool operator!() const noexcept {
+ return nullptr == ptr_ || ptr_->terminated;
+ }
+
+ bool operator==( fiber const& other) const noexcept {
+ return ptr_ == other.ptr_;
+ }
+
+ bool operator!=( fiber const& other) const noexcept {
+ return ptr_ != other.ptr_;
+ }
+
+ bool operator<( fiber const& other) const noexcept {
+ return ptr_ < other.ptr_;
+ }
+
+ bool operator>( fiber const& other) const noexcept {
+ return other.ptr_ < ptr_;
+ }
+
+ bool operator<=( fiber const& other) const noexcept {
+ return ! ( * this > other);
+ }
+
+ bool operator>=( fiber const& other) const noexcept {
+ return ! ( * this < other);
+ }
+
+ template< typename charT, class traitsT >
+ friend std::basic_ostream< charT, traitsT > &
+ operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) {
+ if ( nullptr != other.ptr_) {
+ return os << other.ptr_;
+ } else {
+ return os << "{not-a-context}";
+ }
+ }
+
+ void swap( fiber & other) noexcept {
+ std::swap( ptr_, other.ptr_);
+ }
+};
+
+inline
+void swap( fiber & l, fiber & r) noexcept {
+ l.swap( r);
+}
+
+}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_CONTEXT_FIBER_H
diff --git a/boost/context/fiber_winfib.hpp b/boost/context/fiber_winfib.hpp
new file mode 100644
index 0000000000..cfd570a2e7
--- /dev/null
+++ b/boost/context/fiber_winfib.hpp
@@ -0,0 +1,453 @@
+
+// Copyright Oliver Kowalke 2017.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_CONTEXT_FIBER_H
+#define BOOST_CONTEXT_FIBER_H
+
+#include <windows.h>
+
+#include <boost/context/detail/config.hpp>
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <memory>
+#include <ostream>
+#include <system_error>
+#include <tuple>
+#include <utility>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+
+#include <boost/context/detail/disable_overload.hpp>
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+#include <boost/context/detail/exchange.hpp>
+#endif
+#if defined(BOOST_NO_CXX17_STD_INVOKE)
+#include <boost/context/detail/invoke.hpp>
+#endif
+#include <boost/context/fixedsize_stack.hpp>
+#include <boost/context/flags.hpp>
+#include <boost/context/preallocated.hpp>
+#include <boost/context/stack_context.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+#if defined(BOOST_MSVC)
+# pragma warning(push)
+# pragma warning(disable: 4702)
+#endif
+
+namespace boost {
+namespace context {
+namespace detail {
+
+// tampoline function
+// entered if the execution context
+// is resumed for the first time
+template< typename Record >
+static VOID WINAPI fiber_entry_func( LPVOID data) noexcept {
+ Record * record = static_cast< Record * >( data);
+ BOOST_ASSERT( nullptr != record);
+ // start execution of toplevel context-function
+ record->run();
+}
+
+struct BOOST_CONTEXT_DECL fiber_activation_record {
+ LPVOID fiber{ nullptr };
+ stack_context sctx{};
+ bool main_ctx{ true };
+ fiber_activation_record * from{ nullptr };
+ std::function< fiber_activation_record*(fiber_activation_record*&) > ontop{};
+ bool terminated{ false };
+ bool force_unwind{ false };
+
+ static fiber_activation_record *& current() noexcept;
+
+ // used for toplevel-context
+ // (e.g. main context, thread-entry context)
+ fiber_activation_record() noexcept {
+#if ( _WIN32_WINNT > 0x0600)
+ if ( ::IsThreadAFiber() ) {
+ fiber = ::GetCurrentFiber();
+ } else {
+ fiber = ::ConvertThreadToFiber( nullptr);
+ }
+#else
+ fiber = ::ConvertThreadToFiber( nullptr);
+ if ( BOOST_UNLIKELY( nullptr == fiber) ) {
+ DWORD err = ::GetLastError();
+ BOOST_ASSERT( ERROR_ALREADY_FIBER == err);
+ fiber = ::GetCurrentFiber();
+ BOOST_ASSERT( nullptr != fiber);
+ BOOST_ASSERT( reinterpret_cast< LPVOID >( 0x1E00) != fiber);
+ }
+#endif
+ }
+
+ fiber_activation_record( stack_context sctx_) noexcept :
+ sctx{ sctx_ },
+ main_ctx{ false } {
+ }
+
+ virtual ~fiber_activation_record() {
+ if ( BOOST_UNLIKELY( main_ctx) ) {
+ ::ConvertFiberToThread();
+ } else {
+ ::DeleteFiber( fiber);
+ }
+ }
+
+ fiber_activation_record( fiber_activation_record const&) = delete;
+ fiber_activation_record & operator=( fiber_activation_record const&) = delete;
+
+ bool is_main_context() const noexcept {
+ return main_ctx;
+ }
+
+ fiber_activation_record * resume() {
+ from = current();
+ // store `this` in static, thread local pointer
+ // `this` will become the active (running) context
+ current() = this;
+ // context switch from parent context to `this`-context
+ // context switch
+ ::SwitchToFiber( fiber);
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ return detail::exchange( current()->from, nullptr);
+#else
+ return std::exchange( current()->from, nullptr);
+#endif
+ }
+
+ template< typename Ctx, typename Fn >
+ fiber_activation_record * resume_with( Fn && fn) {
+ from = current();
+ // store `this` in static, thread local pointer
+ // `this` will become the active (running) context
+ // returned by fiber::current()
+ current() = this;
+#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
+ current()->ontop = std::bind(
+ [](typename std::decay< Fn >::type & fn, fiber_activation_record *& ptr){
+ Ctx c{ ptr };
+ c = fn( std::move( c) );
+ if ( ! c) {
+ ptr = nullptr;
+ }
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ return exchange( c.ptr_, nullptr);
+#else
+ return std::exchange( c.ptr_, nullptr);
+#endif
+ },
+ std::forward< Fn >( fn),
+ std::placeholders::_1);
+#else
+ current()->ontop = [fn=std::forward<Fn>(fn)](fiber_activation_record *& ptr){
+ Ctx c{ ptr };
+ c = fn( std::move( c) );
+ if ( ! c) {
+ ptr = nullptr;
+ }
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ return exchange( c.ptr_, nullptr);
+#else
+ return std::exchange( c.ptr_, nullptr);
+#endif
+ };
+#endif
+ // context switch
+ ::SwitchToFiber( fiber);
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ return detail::exchange( current()->from, nullptr);
+#else
+ return std::exchange( current()->from, nullptr);
+#endif
+ }
+
+ virtual void deallocate() noexcept {
+ }
+};
+
+struct BOOST_CONTEXT_DECL fiber_activation_record_initializer {
+ fiber_activation_record_initializer() noexcept;
+ ~fiber_activation_record_initializer();
+};
+
+struct forced_unwind {
+ fiber_activation_record * from{ nullptr };
+
+ explicit forced_unwind( fiber_activation_record * from_) :
+ from{ from_ } {
+ }
+};
+
+template< typename Ctx, typename StackAlloc, typename Fn >
+class fiber_capture_record : public fiber_activation_record {
+private:
+ typename std::decay< StackAlloc >::type salloc_;
+ typename std::decay< Fn >::type fn_;
+
+ static void destroy( fiber_capture_record * p) noexcept {
+ typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
+ stack_context sctx = p->sctx;
+ // deallocate activation record
+ p->~fiber_capture_record();
+ // destroy stack with stack allocator
+ salloc.deallocate( sctx);
+ }
+
+public:
+ fiber_capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept :
+ fiber_activation_record( sctx),
+ salloc_( std::forward< StackAlloc >( salloc)),
+ fn_( std::forward< Fn >( fn) ) {
+ }
+
+ void deallocate() noexcept override final {
+ BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) );
+ destroy( this);
+ }
+
+ void run() {
+ Ctx c{ from };
+ try {
+ // invoke context-function
+#if defined(BOOST_NO_CXX17_STD_INVOKE)
+ c = boost::context::detail::invoke( fn_, std::move( c) );
+#else
+ c = std::invoke( fn_, std::move( c) );
+#endif
+ } catch ( forced_unwind const& ex) {
+ c = Ctx{ ex.from };
+ }
+ // this context has finished its task
+ from = nullptr;
+ ontop = nullptr;
+ terminated = true;
+ force_unwind = false;
+ std::move( c).resume();
+ BOOST_ASSERT_MSG( false, "fiber already terminated");
+ }
+};
+
+template< typename Ctx, typename StackAlloc, typename Fn >
+static fiber_activation_record * create_fiber1( StackAlloc && salloc, Fn && fn) {
+ typedef fiber_capture_record< Ctx, StackAlloc, Fn > capture_t;
+
+ auto sctx = salloc.allocate();
+ BOOST_ASSERT( ( sizeof( capture_t) ) < sctx.size);
+ // reserve space for control structure
+ void * storage = reinterpret_cast< void * >(
+ ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) )
+ & ~ static_cast< uintptr_t >( 0xff) );
+ // placment new for control structure on context stack
+ capture_t * record = new ( storage) capture_t{
+ sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) };
+ // create user-context
+ record->fiber = ::CreateFiber( sctx.size, & detail::fiber_entry_func< capture_t >, record);
+ return record;
+}
+
+template< typename Ctx, typename StackAlloc, typename Fn >
+static fiber_activation_record * create_fiber2( preallocated palloc, StackAlloc && salloc, Fn && fn) {
+ typedef fiber_capture_record< Ctx, StackAlloc, Fn > capture_t;
+
+ BOOST_ASSERT( ( sizeof( capture_t) ) < palloc.size);
+ // reserve space for control structure
+ void * storage = reinterpret_cast< void * >(
+ ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) )
+ & ~ static_cast< uintptr_t >( 0xff) );
+ // placment new for control structure on context stack
+ capture_t * record = new ( storage) capture_t{
+ palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) };
+ // create user-context
+ record->fiber = ::CreateFiber( palloc.sctx.size, & detail::fiber_entry_func< capture_t >, record);
+ return record;
+}
+
+}
+
+class BOOST_CONTEXT_DECL fiber {
+private:
+ friend struct detail::fiber_activation_record;
+
+ template< typename Ctx, typename StackAlloc, typename Fn >
+ friend class detail::fiber_capture_record;
+
+ template< typename Ctx, typename StackAlloc, typename Fn >
+ friend detail::fiber_activation_record * detail::create_fiber1( StackAlloc &&, Fn &&);
+
+ template< typename Ctx, typename StackAlloc, typename Fn >
+ friend detail::fiber_activation_record * detail::create_fiber2( preallocated, StackAlloc &&, Fn &&);
+
+ template< typename StackAlloc, typename Fn >
+ friend fiber
+ callcc( std::allocator_arg_t, StackAlloc &&, Fn &&);
+
+ template< typename StackAlloc, typename Fn >
+ friend fiber
+ callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&);
+
+ detail::fiber_activation_record * ptr_{ nullptr };
+
+ fiber( detail::fiber_activation_record * ptr) noexcept :
+ ptr_{ ptr } {
+ }
+
+public:
+ fiber() = default;
+
+ template< typename Fn, typename = detail::disable_overload< fiber, Fn > >
+ fiber( Fn && fn) :
+ fiber{ std::allocator_arg,
+ fixedsize_stack(),
+ std::forward< Fn >( fn) } {
+ }
+
+ template< typename StackAlloc, typename Fn >
+ fiber( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) :
+ ptr_{ detail::create_fiber1< fiber >(
+ std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } {;
+ }
+
+ template< typename StackAlloc, typename Fn >
+ fiber( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) :
+ ptr_{ detail::create_fiber2< fiber >(
+ palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } {
+ }
+
+ ~fiber() {
+ if ( BOOST_UNLIKELY( nullptr != ptr_) && ! ptr_->main_ctx) {
+ if ( BOOST_LIKELY( ! ptr_->terminated) ) {
+ ptr_->force_unwind = true;
+ ptr_->resume();
+ BOOST_ASSERT( ptr_->terminated);
+ }
+ ptr_->deallocate();
+ }
+ }
+
+ fiber( fiber const&) = delete;
+ fiber & operator=( fiber const&) = delete;
+
+ fiber( fiber && other) noexcept {
+ swap( other);
+ }
+
+ fiber & operator=( fiber && other) noexcept {
+ if ( BOOST_LIKELY( this != & other) ) {
+ fiber tmp = std::move( other);
+ swap( tmp);
+ }
+ return * this;
+ }
+
+ fiber resume() && {
+ BOOST_ASSERT( nullptr != ptr_);
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ detail::fiber_activation_record * ptr = detail::exchange( ptr_, nullptr)->resume();
+#else
+ detail::fiber_activation_record * ptr = std::exchange( ptr_, nullptr)->resume();
+#endif
+ if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) {
+ throw detail::forced_unwind{ ptr};
+ } else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) {
+ ptr = detail::fiber_activation_record::current()->ontop( ptr);
+ detail::fiber_activation_record::current()->ontop = nullptr;
+ }
+ return { ptr };
+ }
+
+ template< typename Fn >
+ fiber resume_with( Fn && fn) && {
+ BOOST_ASSERT( nullptr != ptr_);
+#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
+ detail::fiber_activation_record * ptr =
+ detail::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) );
+#else
+ detail::fiber_activation_record * ptr =
+ std::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) );
+#endif
+ if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) {
+ throw detail::forced_unwind{ ptr};
+ } else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) {
+ ptr = detail::fiber_activation_record::current()->ontop( ptr);
+ detail::fiber_activation_record::current()->ontop = nullptr;
+ }
+ return { ptr };
+ }
+
+ explicit operator bool() const noexcept {
+ return nullptr != ptr_ && ! ptr_->terminated;
+ }
+
+ bool operator!() const noexcept {
+ return nullptr == ptr_ || ptr_->terminated;
+ }
+
+ bool operator==( fiber const& other) const noexcept {
+ return ptr_ == other.ptr_;
+ }
+
+ bool operator!=( fiber const& other) const noexcept {
+ return ptr_ != other.ptr_;
+ }
+
+ bool operator<( fiber const& other) const noexcept {
+ return ptr_ < other.ptr_;
+ }
+
+ bool operator>( fiber const& other) const noexcept {
+ return other.ptr_ < ptr_;
+ }
+
+ bool operator<=( fiber const& other) const noexcept {
+ return ! ( * this > other);
+ }
+
+ bool operator>=( fiber const& other) const noexcept {
+ return ! ( * this < other);
+ }
+
+ template< typename charT, class traitsT >
+ friend std::basic_ostream< charT, traitsT > &
+ operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) {
+ if ( nullptr != other.ptr_) {
+ return os << other.ptr_;
+ } else {
+ return os << "{not-a-context}";
+ }
+ }
+
+ void swap( fiber & other) noexcept {
+ std::swap( ptr_, other.ptr_);
+ }
+};
+
+inline
+void swap( fiber & l, fiber & r) noexcept {
+ l.swap( r);
+}
+
+}}
+
+#if defined(BOOST_MSVC)
+# pragma warning(pop)
+#endif
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_CONTEXT_FIBER_H