diff --git a/doc/execution_context.qbk b/doc/execution_context.qbk
index 397a4f0..1d7721c 100644
--- a/doc/execution_context.qbk
+++ b/doc/execution_context.qbk
@@ -381,18 +381,5 @@ implementation-defined total order of `execution_context` values places `*this`
[[Effects:] [Creates an object of preallocated.]]
]
-[section:winfibers Using WinFiber-API]
-
-Because the TIB (thread information block) is not fully described in the MSDN,
-it might be possible that not all required TIB-parts are swapped.
-With compiler flag `BOOST_USE_WINFIBERS` `execution_context` uses internally the
-Windows Fiber API.
-[note The first call of `execution_context::operator()` converts the thread into a Windows fiber
-by invoking `ConvertThreadToFiber()`.
-If desired, `ConvertFiberToThread()` has to be called by the user explicitly in order to
-release resources allocated by `ConvertThreadToFiber()` (e.g. after using boost.context).]
-
-[endsect]
-
[endsect]
diff --git a/example/execution_context/fibonacci.cpp b/example/execution_context/fibonacci.cpp
index 22ddead..eba521b 100644
--- a/example/execution_context/fibonacci.cpp
+++ b/example/execution_context/fibonacci.cpp
@@ -31,7 +31,6 @@ int main() {
ctx();
std::cout<
( vp);
- std::string str = boost::lexical_cast(i);
- caller_( & str);
- } catch (...) {
- excptr_=std::current_exception();
- }
- })
+ callee_( [this]( void * vp){
+ try {
+ int i = * static_cast< int * >( vp);
+ std::string str = boost::lexical_cast(i);
+ caller_( & str);
+ } catch (...) {
+ excptr_=std::current_exception();
+ }
+ })
{}
std::string operator()(int i){
@@ -48,4 +47,5 @@ int main() {
X x;
std::cout< 0)
- {
+ if ( i > 0) {
access( buf);
std::cout << i << ". iteration" << std::endl;
bar( i - 1);
@@ -36,7 +32,6 @@ void bar( int i)
int main() {
int count = 384;
-
#if defined(BOOST_USE_SEGMENTED_STACKS)
std::cout << "using segmented_stack stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
std::cout << "initial stack size = " << boost::context::segmented_stack::traits_type::default_size() / 1024 << "kB" << std::endl;
@@ -46,19 +41,14 @@ int main() {
std::cout << "initial stack size = " << boost::context::fixedsize_stack::traits_type::default_size() / 1024 << "kB" << std::endl;
std::cout << "application might fail" << std::endl;
#endif
-
boost::context::execution_context main_ctx(
boost::context::execution_context::current() );
-
boost::context::execution_context bar_ctx(
[& main_ctx, count]( void *){
bar( count);
main_ctx();
});
-
bar_ctx();
-
std::cout << "main: done" << std::endl;
-
- return 0;
+ return EXIT_SUCCESS;
}
diff --git a/include/boost/context/execution_context.hpp b/include/boost/context/execution_context.hpp
index 97b1d4e..4dea100 100644
--- a/include/boost/context/execution_context.hpp
+++ b/include/boost/context/execution_context.hpp
@@ -4,8 +4,417 @@
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
-#if defined(BOOST_USE_WINFIBERS)
-#include
+#ifndef BOOST_CONTEXT_EXECUTION_CONTEXT_H
+#define BOOST_CONTEXT_EXECUTION_CONTEXT_H
+
+#include
+
+#if ! defined(BOOST_CONTEXT_NO_CPP14)
+
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+
+# include
+# include
+# include
+# include
+
+# include
+# include
+# include
+# include
+# include
+
+# ifdef BOOST_HAS_ABI_HEADERS
+# 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 {
+
+struct activation_record {
+ typedef boost::intrusive_ptr< activation_record > ptr_t;
+
+ thread_local static ptr_t current_rec;
+
+ std::atomic< std::size_t > use_count{ 0 };
+ fcontext_t fctx{ nullptr };
+ stack_context sctx{};
+ bool main_ctx{ true };
+
+ // used for toplevel-context
+ // (e.g. main context, thread-entry context)
+ activation_record() = default;
+
+ activation_record( fcontext_t fctx_, stack_context sctx_) noexcept :
+ use_count{ 0 },
+ 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() noexcept = default;
+
+ bool is_main_context() const noexcept {
+ return main_ctx;
+ }
+
+ void * resume( void * vp) {
+ // store current activation record in local variable
+ activation_record * from = current_rec.get();
+ // store `this` in static, thread local pointer
+ // `this` will become the active (running) context
+ // returned by execution_context::current()
+ current_rec = this;
+# if defined(BOOST_USE_SEGMENTED_STACKS)
+ // adjust segmented stack properties
+ __splitstack_getcontext( from->sctx.segments_ctx);
+ __splitstack_setcontext( sctx.segments_ctx);
+# endif
+ // context switch from parent context to `this`-context
+ return jump_fcontext( & from->fctx, fctx, vp);
+ }
+
+ virtual void deallocate() noexcept {
+ }
+
+ friend void intrusive_ptr_add_ref( activation_record * ar) noexcept {
+ ++ar->use_count;
+ }
+
+ friend void intrusive_ptr_release( activation_record * ar) noexcept {
+ BOOST_ASSERT( nullptr != ar);
+
+ if ( 0 == --ar->use_count) {
+ ar->deallocate();
+ }
+ }
+};
+
+struct activation_record_initializer {
+ activation_record_initializer();
+ ~activation_record_initializer() noexcept;
+};
+
+template< typename Fn, typename Tpl, typename StackAlloc >
+class capture_record : public activation_record {
+private:
+ StackAlloc salloc_;
+ Fn fn_;
+ Tpl tpl_;
+ activation_record * caller_;
+
+ static void destroy( capture_record * p) noexcept {
+ StackAlloc salloc = p->salloc_;
+ stack_context sctx = p->sctx;
+ // deallocate activation record
+ p->~capture_record();
+ // destroy stack with stack allocator
+ salloc.deallocate( sctx);
+ }
+
+public:
+ capture_record(
+ stack_context sctx, StackAlloc const& salloc,
+ fcontext_t fctx,
+ Fn && fn, Tpl && tpl,
+ activation_record * caller) noexcept :
+ activation_record{ fctx, sctx },
+ salloc_{ salloc },
+ fn_( std::forward< Fn >( fn) ), // fn_{ std::forward< Fn >( fn) } - msvc-14.0: void(__cdecl&)(double,void*) can not be converted to void(__cdecl&)(double,void*)
+ tpl_( std::forward< Tpl >( tpl) ),// tpl_{ std::forward< Tpl >( tpl) } - clang-3.6: excess elements in struct initializer
+ caller_{ caller } {
+ }
+
+ ~capture_record() noexcept = default;
+
+ void deallocate() noexcept override final {
+ destroy( this);
+ }
+
+ void run() {
+ auto data = caller_->resume( nullptr);
+ do_invoke( fn_, std::tuple_cat( tpl_, std::tie( data) ) );
+ BOOST_ASSERT_MSG( ! main_ctx, "main-context does not execute activation-record::run()");
+ }
+};
+
+}
+
+class BOOST_CONTEXT_DECL execution_context {
+private:
+ // tampoline function
+ // entered if the execution context
+ // is resumed for the first time
+ template< typename AR >
+ static void entry_func( void * vp) noexcept {
+ AR * ar = static_cast< AR * >( vp);
+ BOOST_ASSERT( nullptr != ar);
+ // start execution of toplevel context-function
+ ar->run();
+ }
+
+ typedef boost::intrusive_ptr< detail::activation_record > ptr_t;
+
+ ptr_t ptr_;
+
+ template< typename StackAlloc, typename Fn ,typename Tpl >
+ static detail::activation_record * create_context(
+ StackAlloc salloc,
+ Fn && fn, Tpl && tpl) {
+ typedef detail::capture_record< Fn, Tpl, StackAlloc > capture_t;
+
+ stack_context sctx = salloc.allocate();
+ // reserve space for control structure
+#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
+ std::size_t size = sctx.size - sizeof( capture_t);
+ void * sp = static_cast< char * >( sctx.sp) - sizeof( capture_t);
#else
-#include
+ constexpr std::size_t func_alignment = 64; // alignof( capture_t);
+ constexpr std::size_t func_size = sizeof( capture_t);
+ // reserve space on stack
+ void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
+ // align sp pointer
+ std::size_t space = func_size + func_alignment;
+ sp = std::align( func_alignment, func_size, sp, space);
+ BOOST_ASSERT( nullptr != sp);
+ // calculate remaining size
+ std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
#endif
+ // create fast-context
+ fcontext_t fctx = make_fcontext( sp, size, & execution_context::entry_func< capture_t >);
+ BOOST_ASSERT( nullptr != fctx);
+ // get current activation record
+ auto curr = execution_context::current().ptr_;
+ // placment new for control structure on fast-context stack
+ return new ( sp) capture_t{
+ sctx, salloc, fctx, std::forward< Fn >( fn), std::forward< Tpl >( tpl), curr.get() };
+ }
+
+ template< typename StackAlloc, typename Fn , typename Tpl >
+ static detail::activation_record * create_context(
+ preallocated palloc, StackAlloc salloc,
+ Fn && fn, Tpl && tpl) {
+ typedef detail::capture_record< Fn, Tpl, StackAlloc > capture_t;
+
+ // reserve space for control structure
+#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
+ std::size_t size = palloc.size - sizeof( capture_t);
+ void * sp = static_cast< char * >( palloc.sp) - sizeof( capture_t);
+#else
+ constexpr std::size_t func_alignment = 64; // alignof( capture_t);
+ constexpr std::size_t func_size = sizeof( capture_t);
+ // reserve space on stack
+ void * sp = static_cast< char * >( palloc.sp) - func_size - func_alignment;
+ // align sp pointer
+ std::size_t space = func_size + func_alignment;
+ sp = std::align( func_alignment, func_size, sp, space);
+ BOOST_ASSERT( nullptr != sp);
+ // calculate remaining size
+ std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) );
+#endif
+ // create fast-context
+ fcontext_t fctx = make_fcontext( sp, size, & execution_context::entry_func< capture_t >);
+ BOOST_ASSERT( nullptr != fctx);
+ // get current activation record
+ auto curr = execution_context::current().ptr_;
+ // placment new for control structure on fast-context stack
+ return new ( sp) capture_t{
+ palloc.sctx, salloc, fctx, std::forward< Fn >( fn), std::forward< Tpl >( tpl), curr.get() };
+ }
+
+ execution_context() noexcept :
+ // default constructed with current activation_record
+ ptr_{ detail::activation_record::current_rec } {
+ }
+
+public:
+ static execution_context current() noexcept;
+
+# if defined(BOOST_USE_SEGMENTED_STACKS)
+ template< typename Fn, typename ... Args >
+ execution_context( Fn && fn, Args && ... args) :
+ // deferred execution of fn and its arguments
+ // arguments are stored in std::tuple<>
+ // 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( segmented_stack(),
+ std::forward< Fn >( fn),
+ std::make_tuple( std::forward< Args >( args) ...) ) } {
+ ptr_->resume( ptr_.get() );
+ }
+
+ template< typename Fn, typename ... Args >
+ execution_context( std::allocator_arg_t, segmented_stack salloc, Fn && fn, Args && ... args) :
+ // deferred execution of fn and its arguments
+ // arguments are stored in std::tuple<>
+ // 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( salloc,
+ std::forward< Fn >( fn),
+ std::make_tuple( std::forward< Args >( args) ...) ) } {
+ ptr_->resume( ptr_.get() );
+ }
+
+ template< typename Fn, typename ... Args >
+ execution_context( std::allocator_arg_t, preallocated palloc, segmented_stack salloc, Fn && fn, Args && ... args) :
+ // deferred execution of fn and its arguments
+ // arguments are stored in std::tuple<>
+ // 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, salloc,
+ std::forward< Fn >( fn),
+ std::make_tuple( std::forward< Args >( args) ...) ) } {
+ ptr_->resume( ptr_.get() );
+ }
+# else
+ template< typename Fn, typename ... Args >
+ execution_context( Fn && fn, Args && ... args) :
+ // deferred execution of fn and its arguments
+ // arguments are stored in std::tuple<>
+ // 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( fixedsize_stack(),
+ std::forward< Fn >( fn),
+ std::make_tuple( std::forward< Args >( args) ...) ) } {
+ ptr_->resume( ptr_.get() );
+ }
+
+ template< typename StackAlloc, typename Fn, typename ... Args >
+ execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args) :
+ // deferred execution of fn and its arguments
+ // arguments are stored in std::tuple<>
+ // 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( salloc,
+ std::forward< Fn >( fn),
+ std::make_tuple( std::forward< Args >( args) ...) ) } {
+ ptr_->resume( ptr_.get() );
+ }
+
+ template< typename StackAlloc, typename Fn, typename ... Args >
+ execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args) :
+ // deferred execution of fn and its arguments
+ // arguments are stored in std::tuple<>
+ // 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, salloc,
+ std::forward< Fn >( fn),
+ std::make_tuple( std::forward< Args >( args) ...) ) } {
+ ptr_->resume( ptr_.get() );
+ }
+# endif
+
+ execution_context( execution_context const& other) noexcept :
+ ptr_{ other.ptr_ } {
+ }
+
+ execution_context( execution_context && other) noexcept :
+ ptr_{ other.ptr_ } {
+ other.ptr_.reset();
+ }
+
+ execution_context & operator=( execution_context const& other) noexcept {
+ // intrusive_ptr<> does not test for self-assignment
+ if ( this == & other) return * this;
+ ptr_ = other.ptr_;
+ return * this;
+ }
+
+ execution_context & operator=( execution_context && other) noexcept {
+ if ( this == & other) return * this;
+ execution_context tmp{ std::move( other) };
+ swap( tmp);
+ return * this;
+ }
+
+ void * operator()( void * vp = nullptr) {
+ return ptr_->resume( vp);
+ }
+
+ explicit operator bool() const noexcept {
+ return nullptr != ptr_.get();
+ }
+
+ bool operator!() const noexcept {
+ return nullptr == ptr_.get();
+ }
+
+ bool operator==( execution_context const& other) const noexcept {
+ return ptr_ == other.ptr_;
+ }
+
+ bool operator!=( execution_context const& other) const noexcept {
+ return ptr_ != other.ptr_;
+ }
+
+ bool operator<( execution_context const& other) const noexcept {
+ return ptr_ < other.ptr_;
+ }
+
+ bool operator>( execution_context const& other) const noexcept {
+ return other.ptr_ < ptr_;
+ }
+
+ bool operator<=( execution_context const& other) const noexcept {
+ return ! ( * this > other);
+ }
+
+ bool operator>=( execution_context 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, execution_context const& other) {
+ if ( nullptr != other.ptr_) {
+ return os << other.ptr_;
+ } else {
+ return os << "{not-a-context}";
+ }
+ }
+
+ void swap( execution_context & other) noexcept {
+ ptr_.swap( other.ptr_);
+ }
+};
+
+inline
+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_NO_CPP14
+
+#endif // BOOST_CONTEXT_EXECUTION_CONTEXT_H
diff --git a/include/boost/context/execution_context.ipp b/include/boost/context/execution_context.ipp
deleted file mode 100644
index 1f8f603..0000000
--- a/include/boost/context/execution_context.ipp
+++ /dev/null
@@ -1,435 +0,0 @@
-
-// 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)
-
-#ifndef BOOST_CONTEXT_EXECUTION_CONTEXT_H
-#define BOOST_CONTEXT_EXECUTION_CONTEXT_H
-
-#include
-
-#if ! defined(BOOST_CONTEXT_NO_EXECUTION_CONTEXT)
-
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-
-# include
-# include
-# include
-# include
-
-# include
-# include
-# include
-# include
-
-# ifdef BOOST_HAS_ABI_HEADERS
-# 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 {
-
-struct activation_record {
- typedef boost::intrusive_ptr< activation_record > ptr_t;
-
- thread_local static ptr_t current_rec;
-
- std::atomic< std::size_t > use_count;
- fcontext_t fctx;
- stack_context sctx;
- bool main_ctx;
-
- // used for toplevel-context
- // (e.g. main context, thread-entry context)
- activation_record() noexcept :
- use_count( 0),
- fctx( nullptr),
- sctx(),
- main_ctx( true) {
- }
-
- activation_record( fcontext_t fctx_, stack_context sctx_) noexcept :
- use_count( 0),
- fctx( fctx_),
- sctx( sctx_),
- main_ctx( false) {
- }
-
- virtual ~activation_record() noexcept = default;
-
- void * resume( void * vp) noexcept {
- // store current activation record in local variable
- activation_record * from = current_rec.get();
- // store `this` in static, thread local pointer
- // `this` will become the active (running) context
- // returned by execution_context::current()
- current_rec = this;
-# if defined(BOOST_USE_SEGMENTED_STACKS)
- // adjust segmented stack properties
- __splitstack_getcontext( from->sctx.segments_ctx);
- __splitstack_setcontext( sctx.segments_ctx);
-# endif
- // context switch from parent context to `this`-context
- return jump_fcontext( & from->fctx, fctx, vp);
- }
-
- virtual void deallocate() {
- delete this;
- }
-
- friend void intrusive_ptr_add_ref( activation_record * ar) {
- ++ar->use_count;
- }
-
- friend void intrusive_ptr_release( activation_record * ar) {
- BOOST_ASSERT( nullptr != ar);
-
- if ( 0 == --ar->use_count) {
- ar->deallocate();
- }
- }
-};
-
-struct activation_record_initializer {
- activation_record_initializer();
- ~activation_record_initializer();
-};
-
-template< typename Fn, typename Tpl, typename StackAlloc >
-class capture_record : public activation_record {
-private:
- StackAlloc salloc_;
- Fn fn_;
- Tpl tpl_;
- activation_record * caller_;
-
- static void destroy( capture_record * p) {
- StackAlloc salloc( p->salloc_);
- stack_context sctx( p->sctx);
- // deallocate activation record
- p->~capture_record();
- // destroy stack with stack allocator
- salloc.deallocate( sctx);
- }
-
-public:
- explicit capture_record(
- stack_context sctx, StackAlloc const& salloc,
- fcontext_t fctx,
- Fn && fn, Tpl && tpl,
- activation_record * caller) noexcept :
- activation_record( fctx, sctx),
- salloc_( salloc),
- fn_( std::forward< Fn >( fn) ),
- tpl_( std::forward< Tpl >( tpl) ),
- caller_( caller) {
- }
-
- void deallocate() override final {
- destroy( this);
- }
-
- void run() noexcept {
- try {
- void * vp = caller_->resume( caller_);
- do_invoke( fn_, std::tuple_cat( tpl_, std::tie( vp) ) );
- } catch (...) {
- std::terminate();
- }
- BOOST_ASSERT( ! main_ctx);
- }
-};
-
-}
-
-struct preallocated {
- void * sp;
- std::size_t size;
- stack_context sctx;
-
- preallocated( void * sp_, std::size_t size_, stack_context sctx_) noexcept :
- sp( sp_), size( size_), sctx( sctx_) {
- }
-};
-
-class BOOST_CONTEXT_DECL execution_context {
-private:
- // tampoline function
- // entered if the execution context
- // is resumed for the first time
- template< typename AR >
- static void entry_func( void * vp) noexcept {
- AR * ar( reinterpret_cast< AR * >( vp) );
- BOOST_ASSERT( nullptr != ar);
-
- // start execution of toplevel context-function
- ar->run();
- }
-
- typedef boost::intrusive_ptr< detail::activation_record > ptr_t;
-
- ptr_t ptr_;
-
- template< typename StackAlloc, typename Fn ,typename Tpl >
- static detail::activation_record * create_context(
- StackAlloc salloc,
- Fn && fn, Tpl && tpl) {
- typedef detail::capture_record< Fn, Tpl, StackAlloc > capture_t;
-
- stack_context sctx( salloc.allocate() );
- // reserve space for control structure
-#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
- std::size_t size = sctx.size - sizeof( capture_t);
- void * sp = static_cast< char * >( sctx.sp) - sizeof( capture_t);
-#else
- constexpr std::size_t func_alignment = 64; // alignof( capture_t);
- constexpr std::size_t func_size = sizeof( capture_t);
- // reserve space on stack
- void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
- // align sp pointer
- std::size_t space = func_size + func_alignment;
- sp = std::align( func_alignment, func_size, sp, space);
- BOOST_ASSERT( nullptr != sp);
- // calculate remaining size
- std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
-#endif
- // create fast-context
- fcontext_t fctx = make_fcontext( sp, size, & execution_context::entry_func< capture_t >);
- BOOST_ASSERT( nullptr != fctx);
- // get current activation record
- ptr_t curr = execution_context::current().ptr_;
- // placment new for control structure on fast-context stack
- return new ( sp) capture_t(
- sctx, salloc, fctx, std::forward< Fn >( fn), std::forward< Tpl >( tpl), curr.get() );
- }
-
- template< typename StackAlloc, typename Fn , typename Tpl >
- static detail::activation_record * create_context(
- preallocated palloc, StackAlloc salloc,
- Fn && fn, Tpl && tpl) {
- typedef detail::capture_record< Fn, Tpl, StackAlloc > capture_t;
-
- // reserve space for control structure
-#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
- std::size_t size = palloc.size - sizeof( capture_t);
- void * sp = static_cast< char * >( palloc.sp) - sizeof( capture_t);
-#else
- constexpr std::size_t func_alignment = 64; // alignof( capture_t);
- constexpr std::size_t func_size = sizeof( capture_t);
- // reserve space on stack
- void * sp = static_cast< char * >( palloc.sp) - func_size - func_alignment;
- // align sp pointer
- std::size_t space = func_size + func_alignment;
- sp = std::align( func_alignment, func_size, sp, space);
- BOOST_ASSERT( nullptr != sp);
- // calculate remaining size
- std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) );
-#endif
- // create fast-context
- fcontext_t fctx = make_fcontext( sp, size, & execution_context::entry_func< capture_t >);
- BOOST_ASSERT( nullptr != fctx);
- // get current activation record
- ptr_t curr = execution_context::current().ptr_;
- // placment new for control structure on fast-context stack
- return new ( sp) capture_t(
- palloc.sctx, salloc, fctx, std::forward< Fn >( fn), std::forward< Tpl >( tpl), curr.get() );
- }
-
- execution_context() :
- // default constructed with current activation_record
- ptr_( detail::activation_record::current_rec) {
- }
-
-public:
- static execution_context current() noexcept;
-
-# if defined(BOOST_USE_SEGMENTED_STACKS)
- template< typename Fn, typename ... Args >
- explicit execution_context( Fn && fn, Args && ... args) :
- // deferred execution of fn and its arguments
- // arguments are stored in std::tuple<>
- // 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( segmented_stack(),
- std::forward< Fn >( fn),
- std::make_tuple( std::forward< Args >( args) ...) ) ) {
- ptr_->resume( ptr_.get() );
- }
-
- template< typename Fn, typename ... Args >
- explicit execution_context( std::allocator_arg_t, segmented_stack salloc, Fn && fn, Args && ... args) :
- // deferred execution of fn and its arguments
- // arguments are stored in std::tuple<>
- // 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( salloc,
- std::forward< Fn >( fn),
- std::make_tuple( std::forward< Args >( args) ...) ) ) {
- ptr_->resume( ptr_.get() );
- }
-
- template< typename Fn, typename ... Args >
- explicit execution_context( std::allocator_arg_t, preallocated palloc, segmented_stack salloc, Fn && fn, Args && ... args) :
- // deferred execution of fn and its arguments
- // arguments are stored in std::tuple<>
- // 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, salloc,
- std::forward< Fn >( fn),
- std::make_tuple( std::forward< Args >( args) ...) ) ) {
- ptr_->resume( ptr_.get() );
- }
-# else
- template< typename Fn, typename ... Args >
- explicit execution_context( Fn && fn, Args && ... args) :
- // deferred execution of fn and its arguments
- // arguments are stored in std::tuple<>
- // 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( fixedsize_stack(),
- std::forward< Fn >( fn),
- std::make_tuple( std::forward< Args >( args) ...) ) ) {
- ptr_->resume( ptr_.get() );
- }
-
- template< typename StackAlloc, typename Fn, typename ... Args >
- explicit execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args) :
- // deferred execution of fn and its arguments
- // arguments are stored in std::tuple<>
- // 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( salloc,
- std::forward< Fn >( fn),
- std::make_tuple( std::forward< Args >( args) ...) ) ) {
- ptr_->resume( ptr_.get() );
- }
-
- template< typename StackAlloc, typename Fn, typename ... Args >
- explicit execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args) :
- // deferred execution of fn and its arguments
- // arguments are stored in std::tuple<>
- // 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, salloc,
- std::forward< Fn >( fn),
- std::make_tuple( std::forward< Args >( args) ...) ) ) {
- ptr_->resume( ptr_.get() );
- }
-# endif
-
- execution_context( execution_context const& other) noexcept :
- ptr_( other.ptr_) {
- }
-
- execution_context( execution_context && other) noexcept :
- ptr_( other.ptr_) {
- other.ptr_.reset();
- }
-
- execution_context & operator=( execution_context const& other) noexcept {
- if ( this != & other) {
- ptr_ = other.ptr_;
- }
- return * this;
- }
-
- execution_context & operator=( execution_context && other) noexcept {
- if ( this != & other) {
- ptr_ = other.ptr_;
- other.ptr_.reset();
- }
- return * this;
- }
-
- void * operator()( void * vp = nullptr) noexcept {
- return ptr_->resume( vp);
- }
-
- explicit operator bool() const noexcept {
- return nullptr != ptr_.get();
- }
-
- bool operator!() const noexcept {
- return nullptr == ptr_.get();
- }
-
- bool operator==( execution_context const& other) const noexcept {
- return ptr_ == other.ptr_;
- }
-
- bool operator!=( execution_context const& other) const noexcept {
- return ptr_ != other.ptr_;
- }
-
- bool operator<( execution_context const& other) const noexcept {
- return ptr_ < other.ptr_;
- }
-
- bool operator>( execution_context const& other) const noexcept {
- return other.ptr_ < ptr_;
- }
-
- bool operator<=( execution_context const& other) const noexcept {
- return ! ( * this > other);
- }
-
- bool operator>=( execution_context 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, execution_context const& other) {
- if ( nullptr != other.ptr_) {
- return os << other.ptr_;
- } else {
- return os << "{not-valid}";
- }
- }
-
- void swap( execution_context & other) noexcept {
- ptr_.swap( other.ptr_);
- }
-};
-
-inline
-void swap( execution_context & l, execution_context & r) noexcept {
- l.swap( r);
-}
-
-}}
-
-# ifdef BOOST_HAS_ABI_HEADERS
-# include BOOST_ABI_SUFFIX
-# endif
-
-#endif
-
-#endif // BOOST_CONTEXT_EXECUTION_CONTEXT_H
diff --git a/include/boost/context/execution_context_winfib.ipp b/include/boost/context/execution_context_winfib.ipp
deleted file mode 100644
index 1b106fa..0000000
--- a/include/boost/context/execution_context_winfib.ipp
+++ /dev/null
@@ -1,361 +0,0 @@
-
-// 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)
-
-#ifndef BOOST_CONTEXT_EXECUTION_CONTEXT_H
-#define BOOST_CONTEXT_EXECUTION_CONTEXT_H
-
-#include
-
-#if ! defined(BOOST_CONTEXT_NO_EXECUTION_CONTEXT)
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#ifdef BOOST_HAS_ABI_HEADERS
-# include BOOST_ABI_PREFIX
-#endif
-
-namespace boost {
-namespace context {
-namespace detail {
-
-struct activation_record {
- typedef boost::intrusive_ptr< activation_record > ptr_t;
-
- enum flag_t {
- flag_main_ctx = 1 << 1,
- flag_preserve_fpu = 1 << 2,
- flag_segmented_stack = 1 << 3
- };
-
- thread_local static ptr_t current_rec;
-
- std::atomic< std::size_t > use_count;
- LPVOID fiber;
- stack_context sctx;
- void * data;
- int flags;
-
- // used for toplevel-context
- // (e.g. main context, thread-entry context)
- activation_record() noexcept :
- use_count( 0),
- fiber( nullptr),
- sctx(),
- flags( flag_main_ctx
-# if defined(BOOST_USE_SEGMENTED_STACKS)
- | flag_segmented_stack
-# endif
- ) {
- }
-
- activation_record( stack_context sctx_, bool use_segmented_stack) noexcept :
- use_count( 0),
- fiber( nullptr),
- sctx( sctx_),
- data( nullptr),
- flags( use_segmented_stack ? flag_segmented_stack : 0) {
- }
-
- virtual ~activation_record() noexcept = default;
-
- void * resume( void * vp, bool fpu) noexcept {
- // store current activation record in local variable
- activation_record * from = current_rec.get();
- // store `this` in static, thread local pointer
- // `this` will become the active (running) context
- // returned by execution_context::current()
- current_rec = this;
- // context switch from parent context to `this`-context
-#if ( _WIN32_WINNT > 0x0600)
- if ( ::IsThreadAFiber() ) {
- from->fiber = ::GetCurrentFiber();
- } else {
- from->fiber = ::ConvertThreadToFiber( nullptr);
- }
-#else
- from->fiber = ::ConvertThreadToFiber( nullptr);
- if ( nullptr == from->fiber) {
- DWORD err = ::GetLastError();
- BOOST_ASSERT( ERROR_ALREADY_FIBER == err);
- from->fiber = ::GetCurrentFiber();
- BOOST_ASSERT( nullptr != from->fiber);
- BOOST_ASSERT( reinterpret_cast< LPVOID >( 0x1E00) != from->fiber);
- }
-#endif
- // store passed argument (void pointer)
- data = vp;
- // context switch
- ::SwitchToFiber( fiber);
- // access the activation-record of the current fiber
- activation_record * ar = static_cast< activation_record * >( GetFiberData() );
- return nullptr != ar ? ar->data : nullptr;
- }
-
- virtual void deallocate() {
- delete this;
- }
-
- friend void intrusive_ptr_add_ref( activation_record * ar) {
- ++ar->use_count;
- }
-
- friend void intrusive_ptr_release( activation_record * ar) {
- BOOST_ASSERT( nullptr != ar);
-
- if ( 0 == --ar->use_count) {
- ar->deallocate();
- }
- }
-};
-
-struct activation_record_initializer {
- activation_record_initializer();
- ~activation_record_initializer();
-};
-
-template< typename Fn, typename Tpl, typename StackAlloc >
-class capture_record : public activation_record {
-private:
- StackAlloc salloc_;
- Fn fn_;
- Tpl tpl_;
- activation_record * caller_;
-
- static void destroy( capture_record * p) {
- StackAlloc salloc( p->salloc_);
- stack_context sctx( p->sctx);
- // deallocate activation record
- p->~capture_record();
- // destroy stack with stack allocator
- salloc.deallocate( sctx);
- }
-
-public:
- explicit capture_record(
- stack_context sctx, StackAlloc const& salloc,
- Fn && fn, Tpl && tpl,
- activation_record * caller,
- bool use_segmented_stack) noexcept :
- activation_record( sctx, use_segmented_stack),
- salloc_( salloc),
- fn_( std::forward< Fn >( fn) ),
- tpl_( std::forward< Tpl >( tpl) ),
- caller_( caller) {
- }
-
- void deallocate() override final {
- destroy( this);
- }
-
- void run() noexcept {
- try {
- void * vp = caller_->resume( caller_, true);
- do_invoke( fn_, std::tuple_cat( tpl_, std::tie( vp) ) );
- } catch (...) {
- std::terminate();
- }
- BOOST_ASSERT( 0 == (flags & flag_main_ctx) );
- }
-};
-
-}
-
-struct preallocated {
- void * sp;
- std::size_t size;
- stack_context sctx;
-
- preallocated( void * sp_, std::size_t size_, stack_context sctx_) noexcept :
- sp( sp_), size( size_), sctx( sctx_) {
- }
-};
-
-class BOOST_CONTEXT_DECL execution_context {
-private:
- // tampoline function
- // entered if the execution context
- // is resumed for the first time
- template< typename AR >
- static VOID WINAPI entry_func( LPVOID p) {
- BOOST_ASSERT( 0 != p);
-
- AR * ar( reinterpret_cast< AR * >( p) );
- // start execution of toplevel context-function
- ar->run();
- //ctx->fn_(ctx->param_);
- ::DeleteFiber( ar->fiber);
- }
-
- typedef boost::intrusive_ptr< detail::activation_record > ptr_t;
-
- ptr_t ptr_;
-
- template< typename StackAlloc, typename Fn ,typename Tpl >
- static detail::activation_record * create_context(
- StackAlloc salloc,
- Fn && fn, Tpl && tpl,
- bool use_segmented_stack) {
- typedef detail::capture_record< Fn, Tpl, StackAlloc > capture_t;
-
- // hackish
- std::size_t fsize = salloc.size_;
- // protected_fixedsize_stack needs at least 2*page-size
- salloc.size_ = ( std::max)( sizeof( capture_t), 2 * stack_traits::page_size() );
-
- stack_context sctx( salloc.allocate() );
- // reserve space for control structure
- void * sp = static_cast< char * >( sctx.sp) - sizeof( capture_t);
- // get current activation record
- ptr_t curr = execution_context::current().ptr_;
- // placement new for control structure on fast-context stack
- capture_t * cr = new ( sp) capture_t(
- sctx, salloc, std::forward< Fn >( fn), std::forward< Tpl >( tpl), curr.get(), use_segmented_stack);
- // create fiber
- // use default stacksize
- cr->fiber = ::CreateFiber( fsize, execution_context::entry_func< capture_t >, cr);
- BOOST_ASSERT( nullptr != cr->fiber);
- return cr;
- }
-
- template< typename StackAlloc, typename Fn , typename Tpl >
- static detail::activation_record * create_context(
- preallocated palloc, StackAlloc salloc,
- Fn && fn, Tpl && tpl,
- bool use_segmented_stack) {
- typedef detail::capture_record< Fn, Tpl, StackAlloc > capture_t;
-
- // hackish
- std::size_t fsize = salloc.size_;
- // protected_fixedsize_stack needs at least 2*page-size
- salloc.size_ = ( std::max)( sizeof( capture_t), 2 * stack_traits::page_size() );
-
- // reserve space for control structure
- void * sp = static_cast< char * >( palloc.sp) - sizeof( capture_t);
- // get current activation record
- ptr_t curr = execution_context::current().ptr_;
- // placement new for control structure on fast-context stack
- capture_t * cr = new ( sp) capture_t(
- palloc.sctx, salloc, std::forward< Fn >( fn), std::forward< Tpl >( tpl), curr.get(), use_segmented_stack);
- // create fiber
- // use default stacksize
- cr->fiber = ::CreateFiber( fsize, execution_context::entry_func< capture_t >, cr);
- BOOST_ASSERT( nullptr != cr->fiber);
- return cr;
- }
-
- execution_context() :
- // default constructed with current activation_record
- ptr_( detail::activation_record::current_rec) {
- }
-
-public:
- static execution_context current() noexcept;
-
- template< typename Fn, typename ... Args >
- explicit execution_context( Fn && fn, Args && ... args) :
- // deferred execution of fn and its arguments
- // arguments are stored in std::tuple<>
- // 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( fixedsize_stack(),
- std::forward< Fn >( fn),
- std::make_tuple( std::forward< Args >( args) ...),
- false) ) {
- ptr_->resume( ptr_.get(), true);
- }
-
- template< typename StackAlloc, typename Fn, typename ... Args >
- explicit execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args) :
- // deferred execution of fn and its arguments
- // arguments are stored in std::tuple<>
- // 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( salloc,
- std::forward< Fn >( fn),
- std::make_tuple( std::forward< Args >( args) ...),
- false) ) {
- ptr_->resume( ptr_.get(), true);
- }
-
- template< typename StackAlloc, typename Fn, typename ... Args >
- explicit execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args) :
- // deferred execution of fn and its arguments
- // arguments are stored in std::tuple<>
- // 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, salloc,
- std::forward< Fn >( fn),
- std::make_tuple( std::forward< Args >( args) ...),
- false) ) {
- ptr_->resume( ptr_.get(), true);
- }
-
- execution_context( execution_context const& other) noexcept :
- ptr_( other.ptr_) {
- }
-
- execution_context( execution_context && other) noexcept :
- ptr_( other.ptr_) {
- other.ptr_.reset();
- }
-
- execution_context & operator=( execution_context const& other) noexcept {
- if ( this != & other) {
- ptr_ = other.ptr_;
- }
- return * this;
- }
-
- execution_context & operator=( execution_context && other) noexcept {
- if ( this != & other) {
- ptr_ = other.ptr_;
- other.ptr_.reset();
- }
- return * this;
- }
-
- explicit operator bool() const noexcept {
- return nullptr != ptr_.get();
- }
-
- bool operator!() const noexcept {
- return nullptr == ptr_.get();
- }
-
- void * operator()( void * vp = nullptr, bool preserve_fpu = false) noexcept {
- return ptr_->resume( vp, preserve_fpu);
- }
-};
-
-}}
-
-# ifdef BOOST_HAS_ABI_HEADERS
-# include BOOST_ABI_SUFFIX
-# endif
-
-#endif
-
-#endif // BOOST_CONTEXT_EXECUTION_CONTEXT_H
diff --git a/include/boost/context/preallocated.hpp b/include/boost/context/preallocated.hpp
new file mode 100644
index 0000000..862a6a5
--- /dev/null
+++ b/include/boost/context/preallocated.hpp
@@ -0,0 +1,39 @@
+
+// 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)
+
+#ifndef BOOST_CONTEXT_PREALLOCATED_H
+#define BOOST_CONTEXT_PREALLOCATED_H
+
+#include
+
+#include
+
+#include
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace context {
+
+struct preallocated {
+ void * sp;
+ std::size_t size;
+ stack_context sctx;
+
+ preallocated( void * sp_, std::size_t size_, stack_context sctx_) noexcept :
+ sp( sp_), size( size_), sctx( sctx_) {
+ }
+};
+
+}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_CONTEXT_PREALLOCATED_H
diff --git a/src/execution_context.cpp b/src/execution_context.cpp
index 80bff36..19605be 100644
--- a/src/execution_context.cpp
+++ b/src/execution_context.cpp
@@ -6,7 +6,7 @@
#include
-#if ! defined(BOOST_CONTEXT_NO_EXECUTION_CONTEXT)
+#if ! defined(BOOST_CONTEXT_NO_CPP14)
# include "boost/context/execution_context.hpp"
@@ -34,9 +34,11 @@ activation_record_initializer::activation_record_initializer() {
}
}
-activation_record_initializer::~activation_record_initializer() {
+activation_record_initializer::~activation_record_initializer() noexcept {
if ( 0 == --counter) {
- activation_record::current_rec.reset();
+ BOOST_ASSERT( activation_record::current_rec->is_main_context() );
+ delete activation_record::current_rec.detach();
+
}
}