diff options
Diffstat (limited to 'boost/context')
25 files changed, 1839 insertions, 954 deletions
diff --git a/boost/context/all.hpp b/boost/context/all.hpp index 152f299089..44b734cdb8 100644 --- a/boost/context/all.hpp +++ b/boost/context/all.hpp @@ -4,10 +4,10 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include <boost/context/fcontext.hpp> +#include <boost/context/execution_context.hpp> #include <boost/context/fixedsize_stack.hpp> +#include <boost/context/pooled_fixedsize_stack.hpp> #include <boost/context/protected_fixedsize_stack.hpp> #include <boost/context/segmented_stack.hpp> #include <boost/context/stack_context.hpp> #include <boost/context/stack_traits.hpp> -#include <boost/context/execution_context.hpp> diff --git a/boost/context/detail/apply.hpp b/boost/context/detail/apply.hpp new file mode 100644 index 0000000000..54db844b9e --- /dev/null +++ b/boost/context/detail/apply.hpp @@ -0,0 +1,55 @@ + +// 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_DETAIL_APPLY_H +#define BOOST_CONTEXT_DETAIL_APPLY_H + +#include <functional> +#include <tuple> +#include <type_traits> +#include <utility> + +#include <boost/config.hpp> + +#include <boost/context/detail/config.hpp> +#include <boost/context/detail/invoke.hpp> +#include <boost/context/detail/index_sequence.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +template< typename Fn, typename Tpl, std::size_t ... I > +auto +apply_impl( Fn && fn, Tpl && tpl, index_sequence< I ... >) + -> decltype( invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... ) ) +{ + return invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... ); +} + +template< typename Fn, typename Tpl > +auto +apply( Fn && fn, Tpl && tpl) + -> decltype( apply_impl( std::forward< Fn >( fn), + std::forward< Tpl >( tpl), + make_index_sequence< std::tuple_size< typename std::decay< Tpl >::type >::value >{}) ) +{ + return apply_impl( std::forward< Fn >( fn), + std::forward< Tpl >( tpl), + make_index_sequence< std::tuple_size< typename std::decay< Tpl >::type >::value >{}); +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_APPLY_H diff --git a/boost/context/detail/config.hpp b/boost/context/detail/config.hpp index 0d5fa757fa..84dd238100 100644 --- a/boost/context/detail/config.hpp +++ b/boost/context/detail/config.hpp @@ -57,32 +57,51 @@ # define BOOST_CONTEXT_SEGMENTS 10 #endif -#undef BOOST_CONTEXT_NO_EXECUTION_CONTEXT -#if defined(BOOST_NO_CXX11_CONSTEXPR) || \ - defined(BOOST_NO_CXX11_DECLTYPE) || \ - defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || \ - defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) || \ + +#define BOOST_CONTEXT_NO_CXX14_INTEGER_SEQUENCE +// use rd6 macros for std::integer_sequence +#if defined(__cpp_lib_integer_sequence) && __cpp_lib_integer_sequence >= 201304 +# undef BOOST_CONTEXT_NO_CXX14_INTEGER_SEQUENCE +#endif +// workaroud: MSVC 14 does not provide macros to test for compile-time integer sequence +#if _MSC_VER > 1800 // _MSC_VER == 1800 -> MS Visual Studio 2013 +# undef BOOST_CONTEXT_NO_INDEX_SEQUENCE +#endif +// workaround: Xcode clang feature detection +#if ! defined(__cpp_lib_integer_sequence) && __cpp_lib_integer_sequence >= 201304 +# if _LIBCPP_STD_VER > 11 +# undef BOOST_CONTEXT_NO_CXX14_INTEGER_SEQUENCE +# endif +#endif + +// workaroud: MSVC 14 does support constexpr +#if _MSC_VER > 1800 // _MSC_VER == 1800 -> MS Visual Studio 2013 +# undef BOOST_NO_CXX11_CONSTEXPR +#endif + +#undef BOOST_CONTEXT_NO_CXX11 +#if defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) || \ + defined(BOOST_NO_CXX11_CONSTEXPR) || \ + defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || \ + defined(BOOST_NO_CXX11_FINAL) || \ defined(BOOST_NO_CXX11_HDR_TUPLE) || \ - defined(BOOST_NO_CXX11_LAMBDAS) || \ defined(BOOST_NO_CXX11_NOEXCEPT) || \ defined(BOOST_NO_CXX11_NULLPTR) || \ - defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) || \ defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \ - defined(BOOST_NO_CXX11_VARIADIC_MACROS) || \ + defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) || \ + defined(BOOST_NO_CXX11_UNIFIED_INITIALISATION_SYNTAX) || \ defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || \ - defined(BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES) || \ - ! defined(__cpp_lib_integer_sequence) && __cpp_lib_integer_sequence < 201304 -# define BOOST_CONTEXT_NO_EXECUTION_CONTEXT -#endif -// workaroud: MSVC 14 does not provide macros to test for compile-time integer sequence -#if _MSC_VER > 1800 // _MSC_VER == 1800 -> MS Visual Studio 2013 -# undef BOOST_CONTEXT_NO_EXECUTION_CONTEXT + defined(BOOST_NO_HDR_ATOMIC) || \ + defined(BOOST_NO_HDR_TUPLE) +# define BOOST_CONTEXT_NO_CXX11 #endif -// workaround: Xcode clang feature detection -#if ! defined(__cpp_lib_integer_sequence) && __cpp_lib_integer_sequence < 201304 -# if _LIBCPP_STD_VER > 11 -# undef BOOST_CONTEXT_NO_EXECUTION_CONTEXT -# endif + +#if ! defined(BOOST_EXECUTION_CONTEXT) +# if defined(BOOST_USE_SEGMENTED_STACKS) +# define BOOST_EXECUTION_CONTEXT 1 +# else +# define BOOST_EXECUTION_CONTEXT 2 +# endif #endif #endif // BOOST_CONTEXT_DETAIL_CONFIG_H diff --git a/boost/context/detail/disable_overload.hpp b/boost/context/detail/disable_overload.hpp new file mode 100644 index 0000000000..c88f916e39 --- /dev/null +++ b/boost/context/detail/disable_overload.hpp @@ -0,0 +1,40 @@ + +// 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_DETAIL_DISABLE_OVERLOAD_H +#define BOOST_CONTEXT_DETAIL_DISABLE_OVERLOAD_H + +#include <type_traits> + +#include <boost/config.hpp> + +#include <boost/context/detail/config.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +// http://ericniebler.com/2013/08/07/universal-references-and-the-copy-constructo/ +template< typename X, typename Y > +using disable_overload = + typename std::enable_if< + ! std::is_base_of< + X, + typename std::decay< Y >::type + >::value + >::type; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_DISABLE_OVERLOAD_H diff --git a/boost/context/detail/exception.hpp b/boost/context/detail/exception.hpp new file mode 100644 index 0000000000..8ffff6780a --- /dev/null +++ b/boost/context/detail/exception.hpp @@ -0,0 +1,36 @@ + +// 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_DETAIL_EXCEPTION_H +#define BOOST_CONTEXT_DETAIL_EXCEPTION_H + +#include <boost/config.hpp> + +#include <boost/context/detail/fcontext.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +struct forced_unwind { + fcontext_t fctx; + + forced_unwind( fcontext_t fctx_) : + fctx( fctx_) { + } +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_EXCEPTION_H diff --git a/boost/context/detail/exchange.hpp b/boost/context/detail/exchange.hpp new file mode 100644 index 0000000000..c5ee91284e --- /dev/null +++ b/boost/context/detail/exchange.hpp @@ -0,0 +1,36 @@ + +// 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_DETAIL_EXCHANGE_H +#define BOOST_CONTEXT_DETAIL_EXCHANGE_H + +#include <algorithm> +#include <utility> + +#include <boost/config.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +template< typename T, typename U = T > +T exchange( T & t, U && nv) { + T ov = std::move( t); + t = std::forward< U >( nv); + return ov; +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_EXCHANGE_H diff --git a/boost/context/fcontext.hpp b/boost/context/detail/fcontext.hpp index 2ebcd46e38..00cb24d941 100644 --- a/boost/context/fcontext.hpp +++ b/boost/context/detail/fcontext.hpp @@ -4,16 +4,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_CONTEXT_FCONTEXT_H -#define BOOST_CONTEXT_FCONTEXT_H - -#if defined(__PGI) -#include <stdint.h> -#endif - -#if defined(_WIN32_WCE) -typedef int intptr_t; -#endif +#ifndef BOOST_CONTEXT_DETAIL_FCONTEXT_H +#define BOOST_CONTEXT_DETAIL_FCONTEXT_H #include <boost/config.hpp> #include <boost/cstdint.hpp> @@ -26,20 +18,29 @@ typedef int intptr_t; namespace boost { namespace context { +namespace detail { typedef void* fcontext_t; +struct transfer_t { + fcontext_t fctx; + void * data; +}; + +extern "C" BOOST_CONTEXT_DECL +transfer_t BOOST_CONTEXT_CALLDECL jump_fcontext( fcontext_t const to, void * vp); extern "C" BOOST_CONTEXT_DECL -intptr_t BOOST_CONTEXT_CALLDECL jump_fcontext( fcontext_t * ofc, fcontext_t nfc, - intptr_t vp, bool preserve_fpu = false); +fcontext_t BOOST_CONTEXT_CALLDECL make_fcontext( void * sp, std::size_t size, void (* fn)( transfer_t) ); + +// based on an idea of Giovanni Derreta extern "C" BOOST_CONTEXT_DECL -fcontext_t BOOST_CONTEXT_CALLDECL make_fcontext( void * sp, std::size_t size, void (* fn)( intptr_t) ); +transfer_t BOOST_CONTEXT_CALLDECL ontop_fcontext( fcontext_t const to, void * vp, transfer_t (* fn)( transfer_t) ); -}} +}}} #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_CONTEXT_FCONTEXT_H +#endif // BOOST_CONTEXT_DETAIL_FCONTEXT_H diff --git a/boost/context/detail/index_sequence.hpp b/boost/context/detail/index_sequence.hpp new file mode 100644 index 0000000000..2d484ba062 --- /dev/null +++ b/boost/context/detail/index_sequence.hpp @@ -0,0 +1,72 @@ + +// 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_DETAIL_INDEX_SEQUENCE_H +#define BOOST_CONTEXT_DETAIL_INDEX_SEQUENCE_H + +#include <cstddef> + +#include <boost/config.hpp> + +#include <boost/context/detail/config.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +#if ! defined(BOOST_CONTEXT_NO_CXX14_INTEGER_SEQUENCE) +template< std::size_t ... I > +using index_sequence = std::index_sequence< I ... >; +template< std::size_t I > +using make_index_sequence = std::make_index_sequence< I >; +template< typename ... T > +using index_sequence_for = std::index_sequence_for< T ... >; +#else +//http://stackoverflow.com/questions/17424477/implementation-c14-make-integer-sequence + +template< std::size_t ... I > +struct index_sequence { + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() { + return sizeof ... (I); + } +}; + +template< typename Seq1, typename Seq2 > +struct concat_sequence; + +template< std::size_t ... I1, std::size_t ... I2 > +struct concat_sequence< index_sequence< I1 ... >, index_sequence< I2 ... > > : public index_sequence< I1 ..., (sizeof ... (I1)+I2) ... > { +}; + +template< std::size_t I > +struct make_index_sequence : public concat_sequence< typename make_index_sequence< I/2 >::type, + typename make_index_sequence< I-I/2 >::type > { +}; + +template<> +struct make_index_sequence< 0 > : public index_sequence<> { +}; +template<> +struct make_index_sequence< 1 > : public index_sequence< 0 > { +}; + +template< typename ... T > +using index_sequence_for = make_index_sequence< sizeof ... (T) >; +#endif + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_INDEX_SEQUENCE_H diff --git a/boost/context/detail/invoke.hpp b/boost/context/detail/invoke.hpp index f63d22c3ff..5ec54800e3 100644 --- a/boost/context/detail/invoke.hpp +++ b/boost/context/detail/invoke.hpp @@ -13,6 +13,8 @@ #include <boost/config.hpp> +#include <boost/context/detail/config.hpp> + #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX #endif @@ -21,61 +23,27 @@ namespace boost { namespace context { namespace detail { -# if _MSC_VER > 1800 +#if _MSC_VER > 1800 using std::invoke; -# else -template< typename Fn, typename ... Args > -typename std::enable_if< - ( ! std::is_member_pointer< Fn >::value && - ! std::is_function< Fn >::value && - ! std::is_function< typename std::remove_pointer< Fn >::type >::value - ), - typename std::result_of< Fn( Args ... ) >::type ->::type -invoke( Fn & fn, Args && ... args) { - return fn( std::forward< Args >( args) ... ); -} - +#else template< typename Fn, typename ... Args > typename std::enable_if< - ( std::is_member_pointer< Fn >::value && - ! std::is_function< Fn >::value && - ! std::is_function< typename std::remove_pointer< Fn >::type >::value - ), - typename std::result_of< Fn( Args ... ) >::type + std::is_member_pointer< typename std::decay< Fn >::type >::value, + typename std::result_of< Fn &&( Args && ... ) >::type >::type -invoke( Fn & fn, Args && ... args) { - return std::mem_fn( fn)( std::forward< Args >( args) ... ); +invoke( Fn && fn, Args && ... args) { + return std::mem_fn( fn)( std::forward< Args >( args) ... ); } template< typename Fn, typename ... Args > typename std::enable_if< - ( std::is_pointer< Fn >::value && - std::is_function< typename std::remove_pointer< Fn >::type >::value - ), - typename std::result_of< Fn( Args ... ) >::type + ! std::is_member_pointer< typename std::decay< Fn >::type >::value, + typename std::result_of< Fn &&( Args && ... ) >::type >::type -invoke( Fn fn, Args && ... args) { - return fn( std::forward< Args >( args) ... ); -} -# endif - -template< typename Fn, typename Tpl, std::size_t... I > -decltype( auto) do_invoke( Fn && fn, Tpl && tpl, std::index_sequence< I ... >) { - return invoke( fn, - // std::tuple_element<> does not perfect forwarding - std::forward< decltype( std::get< I >( std::declval< typename std::decay< Tpl >::type >() ) ) >( - std::get< I >( std::forward< typename std::decay< Tpl >::type >( tpl) ) ) ... ); -} - - -template< typename Fn, typename Tpl > -decltype( auto) do_invoke( Fn && fn, Tpl && tpl) { - constexpr auto Size = std::tuple_size< typename std::decay< Tpl >::type >::value; - return do_invoke( std::forward< Fn >( fn), - std::forward< Tpl >( tpl), - std::make_index_sequence< Size >{}); +invoke( Fn && fn, Args && ... args) { + return std::forward< Fn >( fn)( std::forward< Args >( args) ... ); } +#endif }}} diff --git a/boost/context/detail/tuple.hpp b/boost/context/detail/tuple.hpp new file mode 100644 index 0000000000..e1b2f867a7 --- /dev/null +++ b/boost/context/detail/tuple.hpp @@ -0,0 +1,129 @@ + +// 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_DETAIL_TUPLE_H +#define BOOST_CONTEXT_DETAIL_TUPLE_H + +#include <tuple> +#include <utility> + +#include <boost/config.hpp> + +#include <boost/context/detail/config.hpp> +#include <boost/context/detail/index_sequence.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +template< typename ... S, typename ... T, std::size_t ... I > +void +head_impl( std::tuple< S ... > & s, + std::tuple< T ... > & t, index_sequence< I ... >) { + t = std::tuple< T ... >{ std::get< I >( s) ... }; +} + +template< typename ... S, typename ... T, std::size_t ... I > +void +head_impl( std::tuple< S ... > && s, + std::tuple< T ... > & t, index_sequence< I ... >) { + t = std::tuple< T ... >{ std::get< I >( std::move( s) ) ... }; +} + +template< typename ... S, std::size_t ... I1, typename ... T, std::size_t ... I2 > +void +tail_impl( std::tuple< S ... > & s, index_sequence< I1 ... >, + std::tuple< T ... > & t, index_sequence< I2 ... >) { + constexpr std::size_t Idx = (sizeof...(I1)) - (sizeof...(I2)); + t = std::tuple< T ... >{ std::get< (Idx + I2) >( s) ... }; +} + +template< typename ... S, std::size_t ... I1, typename ... T, std::size_t ... I2 > +void +tail_impl( std::tuple< S ... > && s, index_sequence< I1 ... >, + std::tuple< T ... > & t, index_sequence< I2 ... >) { + constexpr std::size_t Idx = (sizeof...(I1)) - (sizeof...(I2)); + t = std::tuple< T ... >{ std::get< (Idx + I2) >( std::move( s) ) ... }; +} + +template< typename ... T > +class tuple_head; + +template< typename ... T > +class tuple_head< std::tuple< T ... > > { +private: + std::tuple< T ... > & t_; + +public: + tuple_head( std::tuple< T ... > & t) noexcept : + t_( t) { + } + + template< typename ... S > + void operator=( std::tuple< S ... > & s) { + static_assert((sizeof...(T)) <= (sizeof...(S)), "invalid tuple size"); + head_impl( s, + t_, index_sequence_for< T ... >{} ); + } + template< typename ... S > + void operator=( std::tuple< S ... > && s) { + static_assert((sizeof...(T)) <= (sizeof...(S)), "invalid tuple size"); + head_impl( std::move( s), + t_, index_sequence_for< T ... >{} ); + } +}; + +template< typename ... T > +class tuple_tail; + +template< typename ... T > +class tuple_tail< std::tuple< T ... > > { +private: + std::tuple< T ... > & t_; + +public: + tuple_tail( std::tuple< T ... > & t) noexcept : + t_( t) { + } + + template< typename ... S > + void operator=( std::tuple< S ... > & s) { + static_assert((sizeof...(T)) <= (sizeof...(S)), "invalid tuple size"); + tail_impl( s, index_sequence_for< S ... >{}, + t_, index_sequence_for< T ... >{} ); + } + + template< typename ... S > + void operator=( std::tuple< S ... > && s) { + static_assert((sizeof...(T)) <= (sizeof...(S)), "invalid tuple size"); + tail_impl( std::move( s), index_sequence_for< S ... >{}, + t_, index_sequence_for< T ... >{} ); + } +}; + +template< typename ... T > +detail::tuple_head< std::tuple< T ... > > +head( std::tuple< T ... > & tpl) { + return tuple_head< std::tuple< T ... > >{ tpl }; +} + +template< typename ... T > +detail::tuple_tail< std::tuple< T ... > > +tail( std::tuple< T ... > & tpl) { + return tuple_tail< std::tuple< T ... > >{ tpl }; +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_TUPLE_H diff --git a/boost/context/execution_context.hpp b/boost/context/execution_context.hpp index 97b1d4e70a..9d9294f91d 100644 --- a/boost/context/execution_context.hpp +++ b/boost/context/execution_context.hpp @@ -4,8 +4,12 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#if defined(BOOST_USE_WINFIBERS) -#include <boost/context/execution_context_winfib.ipp> -#else -#include <boost/context/execution_context.ipp> +#include <boost/context/detail/config.hpp> + +#if ! defined(BOOST_CONTEXT_NO_CXX11) +# if (defined(BOOST_EXECUTION_CONTEXT) && (BOOST_EXECUTION_CONTEXT == 1)) +# include <boost/context/execution_context_v1.hpp> +# else +# include <boost/context/execution_context_v2.hpp> +# endif #endif diff --git a/boost/context/execution_context.ipp b/boost/context/execution_context.ipp deleted file mode 100644 index ec5443297f..0000000000 --- a/boost/context/execution_context.ipp +++ /dev/null @@ -1,452 +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 <boost/context/detail/config.hpp> - -#if ! defined(BOOST_CONTEXT_NO_EXECUTION_CONTEXT) - -# include <algorithm> -# include <atomic> -# include <cstddef> -# include <cstdint> -# include <cstdlib> -# include <functional> -# include <memory> -# include <ostream> -# include <tuple> -# include <utility> - -# include <boost/assert.hpp> -# include <boost/config.hpp> -# include <boost/context/fcontext.hpp> -# include <boost/intrusive_ptr.hpp> - -# include <boost/context/detail/invoke.hpp> -# include <boost/context/fixedsize_stack.hpp> -# include <boost/context/stack_context.hpp> -# include <boost/context/segmented_stack.hpp> - -# 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; - - enum flag_t { - flag_main_ctx = 1 << 1, - flag_preserve_fpu = 1 << 2 - }; - - thread_local static ptr_t current_rec; - - std::atomic< std::size_t > use_count; - fcontext_t fctx; - stack_context sctx; - int flags; - - // used for toplevel-context - // (e.g. main context, thread-entry context) - activation_record() noexcept : - use_count( 0), - fctx( nullptr), - sctx(), - flags( flag_main_ctx) { - } - - activation_record( fcontext_t fctx_, stack_context sctx_) noexcept : - use_count( 0), - fctx( fctx_), - sctx( sctx_), - flags( 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; - // set FPU flag - if (fpu) { - from->flags |= flag_preserve_fpu; - this->flags |= flag_preserve_fpu; - } else { - from->flags &= ~flag_preserve_fpu; - this->flags &= ~flag_preserve_fpu; - } -# 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 - intptr_t ret = jump_fcontext( & from->fctx, fctx, reinterpret_cast< intptr_t >( vp), fpu); - // parent context resumed - return reinterpret_cast< void * >( ret); - } - - 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_, 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 entry_func( intptr_t p) noexcept { - BOOST_ASSERT( 0 != p); - - AR * ar( reinterpret_cast< AR * >( p) ); - 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(), true); - } - - 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(), true); - } - - 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(), true); - } -# 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(), 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) ...) ) ) { - 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) ...) ) ) { - ptr_->resume( ptr_.get(), true); - } -# 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, bool preserve_fpu = false) noexcept { - return ptr_->resume( vp, preserve_fpu); - } - - 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/boost/context/execution_context_v1.hpp b/boost/context/execution_context_v1.hpp new file mode 100644 index 0000000000..6881354c88 --- /dev/null +++ b/boost/context/execution_context_v1.hpp @@ -0,0 +1,487 @@ + +// 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 <boost/context/detail/config.hpp> + +#include <algorithm> +#include <atomic> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <functional> +#include <memory> +#include <ostream> +#include <tuple> +#include <utility> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/intrusive_ptr.hpp> + +#include <boost/context/detail/apply.hpp> +#include <boost/context/detail/disable_overload.hpp> +#include <boost/context/detail/fcontext.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_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); + +struct activation_record; + +struct data_t { + activation_record * from; + void * data; +}; + +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) + constexpr activation_record() = default; + + 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; + + bool is_main_context() const noexcept { + return main_ctx; + } + + void * resume( void * vp) { + // store current activation record in local variable + auto 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 + 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); + dp->from->fctx = t.fctx; + // parent context resumed + return dp->data; + } + + template< typename Fn > + void * resume_ontop( void * data, Fn && fn) { + // 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 + std::tuple< void *, Fn > p = std::forward_as_tuple( data, fn); + 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); + dp->from->fctx = t.fctx; + // parent context resumed + return dp->data; + } + + 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() noexcept; + ~activation_record_initializer(); +}; + +template< typename Fn > +transfer_t context_ontop( transfer_t t) { + data_t * dp = reinterpret_cast< 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) ); + dp->data = apply( fn, std::tie( data) ); + return { t.fctx, dp }; +} + +template< typename StackAlloc, typename Fn, typename ... Args > +class capture_record : public activation_record { +private: + StackAlloc salloc_; + typename std::decay< Fn >::type fn_; + std::tuple< typename std::decay< Args >::type ... > args_; + 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, + activation_record * caller, + Fn && fn, Args && ... args) noexcept : + activation_record{ fctx, sctx }, + salloc_{ salloc }, + fn_( std::forward< Fn >( fn) ), + args_( std::forward< Args >( args) ... ), + caller_{ caller } { + } + + void deallocate() noexcept override final { + destroy( this); + } + + void run() { + auto data = caller_->resume( nullptr); + apply( fn_, std::tuple_cat( args_, 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( detail::transfer_t t) noexcept { + detail::data_t * dp = reinterpret_cast< detail::data_t * >( t.data); + AR * ar = static_cast< AR * >( dp->data); + BOOST_ASSERT( nullptr != ar); + dp->from->fctx = t.fctx; + // 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 ... Args > + static detail::activation_record * create_context( StackAlloc salloc, + Fn && fn, Args && ... args) { + typedef detail::capture_record< + StackAlloc, Fn, Args ... + > capture_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( 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 + const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) ); +#endif + // create fast-context + const detail::fcontext_t fctx = detail::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, curr.get(), std::forward< Fn >( fn), std::forward< Args >( args) ... }; + } + + template< typename StackAlloc, typename Fn, typename ... Args > + static detail::activation_record * create_context( preallocated palloc, StackAlloc salloc, + Fn && fn, Args && ... args) { + typedef detail::capture_record< + StackAlloc, Fn, Args ... + > capture_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( 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 + const std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) ); +#endif + // create fast-context + const detail::fcontext_t fctx = detail::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, curr.get(), std::forward< Fn >( fn), std::forward< Args >( args) ... }; + } + + 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, + typename = detail::disable_overload< execution_context, Fn > + > + 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::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::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::forward< Args >( args) ...) } { + ptr_->resume( ptr_.get() ); + } +#else + template< typename Fn, + typename ... Args, + typename = detail::disable_overload< execution_context, Fn > + > + 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::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::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::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); + } + + template< typename Fn > + void * operator()( exec_ontop_arg_t, Fn && fn, void * vp = nullptr) { + return ptr_->resume_ontop( vp, + std::forward< Fn >( fn) ); + } + + 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_EXECUTION_CONTEXT_H diff --git a/boost/context/execution_context_v2.hpp b/boost/context/execution_context_v2.hpp new file mode 100644 index 0000000000..1bc5f868d0 --- /dev/null +++ b/boost/context/execution_context_v2.hpp @@ -0,0 +1,395 @@ + +// 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 <boost/context/detail/config.hpp> + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <functional> +#include <memory> +#include <ostream> +#include <tuple> +#include <utility> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/intrusive_ptr.hpp> + +#include <boost/context/detail/apply.hpp> +#include <boost/context/detail/disable_overload.hpp> +#include <boost/context/detail/exception.hpp> +#include <boost/context/detail/exchange.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 + +namespace boost { +namespace context { +namespace detail { + +inline +transfer_t context_unwind( transfer_t t) { + throw forced_unwind( t.fctx); + return { nullptr, nullptr }; +} + +template< typename Rec > +transfer_t context_exit( transfer_t t) noexcept { + Rec * rec = static_cast< Rec * >( t.data); + // destroy context stack + rec->deallocate(); + return { nullptr, nullptr }; +} + +template< typename Rec > +void context_entry( 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()` + t = jump_fcontext( t_.fctx, nullptr); + // start executing + t = rec->run( t); + } 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, context_exit< Rec >); + BOOST_ASSERT_MSG( false, "context already terminated"); +} + +template< typename Ctx, typename Fn, typename ... Args > +transfer_t context_ontop( transfer_t t) { + auto tpl = static_cast< std::tuple< Fn, std::tuple< Args ... > > * >( t.data); + BOOST_ASSERT( nullptr != tpl); + typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * tpl) ); + auto args = std::move( std::get< 1 >( * tpl) ); + Ctx ctx{ t.fctx }; + // execute function + auto result = apply( + fn, + std::tuple_cat( + std::forward_as_tuple( std::move( ctx) ), + std::move( args) ) ); + ctx = std::move( std::get< 0 >( result) ); + // apply returned data + detail::tail( args) = std::move( result); + std::get< 1 >( * tpl) = std::move( args); + return { exchange( ctx.fctx_, nullptr), & std::get< 1 >( * tpl) }; +} + +template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params > +class record { +private: + StackAlloc salloc_; + stack_context sctx_; + typename std::decay< Fn >::type fn_; + std::tuple< typename std::decay< Params >::type ... > params_; + + static void destroy( record * p) noexcept { + StackAlloc salloc = p->salloc_; + stack_context sctx = p->sctx_; + // deallocate record + p->~record(); + // destroy stack with stack allocator + salloc.deallocate( sctx); + } + +public: + record( stack_context sctx, StackAlloc const& salloc, + Fn && fn, Params && ... params) noexcept : + salloc_( salloc), + sctx_( sctx), + fn_( std::forward< Fn >( fn) ), + params_( std::forward< Params >( params) ... ) { + } + + record( record const&) = delete; + record & operator=( record const&) = delete; + + void deallocate() noexcept { + destroy( this); + } + + transfer_t run( transfer_t t) { + Ctx from{ t.fctx }; + typename Ctx::args_tpl_t args = std::move( * static_cast< typename Ctx::args_tpl_t * >( t.data) ); + auto tpl = std::tuple_cat( + params_, + std::forward_as_tuple( std::move( from) ), + std::move( args) ); + // invoke context-function + Ctx cc = apply( std::move( fn_), std::move( tpl) ); + return { exchange( cc.fctx_, nullptr), nullptr }; + } +}; + +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; + + 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); +#else + constexpr std::size_t func_alignment = 64; // alignof( record_t); + constexpr std::size_t func_size = sizeof( record_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 + 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 >); + BOOST_ASSERT( nullptr != fctx); + // placment new for control structure on context-stack + auto rec = ::new ( sp) record_t{ + sctx, 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; + + // 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); +#else + constexpr std::size_t func_alignment = 64; // alignof( record_t); + constexpr std::size_t func_size = sizeof( record_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 + 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 >); + BOOST_ASSERT( nullptr != fctx); + // placment new for control structure on context-stack + auto rec = ::new ( sp) record_t{ + palloc.sctx, salloc, std::forward< Fn >( fn), std::forward< Params >( params) ... }; + // transfer control structure to context-stack + return jump_fcontext( fctx, rec).fctx; +} + +} + +template< typename ... Args > +class execution_context { +private: + typedef std::tuple< Args ... > args_tpl_t; + 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; + + template< typename Ctx, typename Fn, typename ... ArgsT > + friend detail::transfer_t detail::context_ontop( detail::transfer_t); + + detail::fcontext_t fctx_{ nullptr }; + + execution_context( detail::fcontext_t fctx) noexcept : + fctx_( fctx) { + } + +public: + constexpr execution_context() noexcept = default; + +#if defined(BOOST_USE_SEGMENTED_STACKS) + // segmented-stack requires to preserve the segments of the `current` context + // which is not possible (no global pointer to current context) + template< typename Fn, typename ... Params > + execution_context( std::allocator_arg_t, segmented_stack, Fn &&, Params && ...) = delete; + + template< typename Fn, typename ... Params > + execution_context( std::allocator_arg_t, preallocated, segmented_stack, Fn &&, Params && ...) = delete; +#else + template< typename Fn, + typename ... Params, + typename = detail::disable_overload< execution_context, Fn > + > + execution_context( Fn && fn, Params && ... params) : + // 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<> + fctx_( detail::context_create< execution_context >( + fixedsize_stack(), + std::forward< Fn >( fn), + std::forward< Params >( params) ... ) ) { + } + + template< typename StackAlloc, + typename Fn, + typename ... Params + > + execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Params && ... params) : + // 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<> + fctx_( detail::context_create< execution_context >( + salloc, + std::forward< Fn >( fn), + std::forward< Params >( params) ... ) ) { + } + + template< typename StackAlloc, + typename Fn, + typename ... Params + > + execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Params && ... params) : + // 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<> + fctx_( detail::context_create< execution_context >( + palloc, salloc, + std::forward< Fn >( fn), + std::forward< Params >( params) ... ) ) { + } +#endif + + ~execution_context() { + if ( nullptr != fctx_) { + detail::ontop_fcontext( detail::exchange( fctx_, nullptr), nullptr, detail::context_unwind); + } + } + + execution_context( execution_context && other) noexcept : + fctx_( other.fctx_) { + other.fctx_ = nullptr; + } + + execution_context & operator=( execution_context && other) noexcept { + if ( this != & other) { + execution_context tmp = std::move( other); + swap( tmp); + } + return * this; + } + + execution_context( execution_context const& other) noexcept = delete; + execution_context & operator=( execution_context const& other) noexcept = delete; + + ret_tpl_t operator()( Args ... args) { + BOOST_ASSERT( nullptr != fctx_); + args_tpl_t data( std::forward< Args >( args) ... ); + detail::transfer_t t = detail::jump_fcontext( detail::exchange( fctx_, nullptr), & data); + if ( nullptr != t.data) { + data = std::move( * static_cast< args_tpl_t * >( t.data) ); + } + return std::tuple_cat( std::forward_as_tuple( execution_context( t.fctx) ), std::move( data) ); + } + + template< typename Fn > + ret_tpl_t operator()( exec_ontop_arg_t, Fn && fn, Args ... args) { + BOOST_ASSERT( nullptr != fctx_); + args_tpl_t data{ std::forward< Args >( args) ... }; + auto p = std::make_tuple( fn, std::move( data) ); + detail::transfer_t t = detail::ontop_fcontext( + detail::exchange( fctx_, nullptr), + & p, + detail::context_ontop< execution_context, Fn, Args ... >); + if ( nullptr != t.data) { + data = std::move( * static_cast< args_tpl_t * >( t.data) ); + } + return std::tuple_cat( std::forward_as_tuple( execution_context( t.fctx) ), std::move( data) ); + } + + explicit operator bool() const noexcept { + return nullptr != fctx_; + } + + bool operator!() const noexcept { + return nullptr == fctx_; + } + + bool operator==( execution_context const& other) const noexcept { + return fctx_ == other.fctx_; + } + + bool operator!=( execution_context const& other) const noexcept { + return fctx_ != other.fctx_; + } + + bool operator<( execution_context const& other) const noexcept { + return fctx_ < other.fctx_; + } + + bool operator>( execution_context const& other) const noexcept { + return other.fctx_ < fctx_; + } + + 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.fctx_) { + return os << other.fctx_; + } else { + return os << "{not-a-context}"; + } + } + + void swap( execution_context & other) noexcept { + std::swap( fctx_, other.fctx_); + } +}; + +#include <boost/context/execution_context_v2_void.ipp> + +template< typename ... Args > +void swap( execution_context< Args ... > & l, execution_context< Args ... > & r) noexcept { + l.swap( r); +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_EXECUTION_CONTEXT_H diff --git a/boost/context/execution_context_v2_void.ipp b/boost/context/execution_context_v2_void.ipp new file mode 100644 index 0000000000..d0659beafb --- /dev/null +++ b/boost/context/execution_context_v2_void.ipp @@ -0,0 +1,290 @@ + +// 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) + +namespace detail { + +template< typename Ctx, typename Fn > +transfer_t context_ontop_void( transfer_t t) { + auto tpl = static_cast< std::tuple< Fn > * >( t.data); + BOOST_ASSERT( nullptr != tpl); + typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * tpl) ); + Ctx ctx{ t.fctx }; + // execute function + ctx = apply( + fn, + std::forward_as_tuple( std::move( ctx) ) ); + return { exchange( ctx.fctx_, nullptr), nullptr }; +} + +template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params > +class record_void { +private: + StackAlloc 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 { + StackAlloc salloc = p->salloc_; + stack_context sctx = p->sctx_; + // deallocate record + p->~record_void(); + // destroy stack with stack allocator + salloc.deallocate( sctx); + } + +public: + record_void( stack_context sctx, StackAlloc const& salloc, + Fn && fn, Params && ... params) noexcept : + salloc_( salloc), + sctx_( sctx), + fn_( std::forward< Fn >( fn) ), + params_( std::forward< Params >( params) ... ) { + } + + record_void( record_void const&) = delete; + record_void & operator=( record_void const&) = delete; + + void deallocate() noexcept { + destroy( this); + } + + transfer_t run( transfer_t t) { + Ctx from{ t.fctx }; + // invoke context-function + Ctx cc = apply( + fn_, + std::tuple_cat( + params_, + std::forward_as_tuple( std::move( from) ) ) ); + return { exchange( cc.fctx_, nullptr), nullptr }; + } +}; + +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; + + 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); +#else + constexpr std::size_t func_alignment = 64; // alignof( record_t); + constexpr std::size_t func_size = sizeof( record_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 + 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 >); + BOOST_ASSERT( nullptr != fctx); + // placment new for control structure on context-stack + auto rec = ::new ( sp) record_t{ + sctx, 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_void( preallocated palloc, StackAlloc salloc, Fn && fn, Params && ... params) { + typedef 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) + const std::size_t size = palloc.size - sizeof( record_t); + void * sp = static_cast< char * >( palloc.sp) - sizeof( record_t); +#else + constexpr std::size_t func_alignment = 64; // alignof( record_t); + constexpr std::size_t func_size = sizeof( record_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 + 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 >); + BOOST_ASSERT( nullptr != fctx); + // placment new for control structure on context-stack + auto rec = ::new ( sp) record_t{ + palloc.sctx, salloc, std::forward< Fn >( fn), std::forward< Params >( params) ... }; + // transfer control structure to context-stack + return jump_fcontext( fctx, rec).fctx; +} + +} + +template<> +class execution_context< void > { +private: + template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params > + friend class detail::record_void; + + template< typename Ctx, typename Fn > + friend detail::transfer_t detail::context_ontop_void( detail::transfer_t); + + detail::fcontext_t fctx_{ nullptr }; + + execution_context( detail::fcontext_t fctx) noexcept : + fctx_( fctx) { + } + +public: + constexpr execution_context() noexcept = default; + +#if defined(BOOST_USE_SEGMENTED_STACKS) + // segmented-stack requires to preserve the segments of the `current` context + // which is not possible (no global pointer to current context) + template< typename Fn, typename ... Params > + execution_context( std::allocator_arg_t, segmented_stack, Fn &&, Params && ...) = delete; + + template< typename Fn, typename ... Params > + execution_context( std::allocator_arg_t, preallocated, segmented_stack, Fn &&, Params && ...) = delete; +#else + template< typename Fn, + typename ... Params, + typename = detail::disable_overload< execution_context, Fn > + > + execution_context( Fn && fn, Params && ... params) : + // 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<> + fctx_( detail::context_create_void< execution_context >( + fixedsize_stack(), + std::forward< Fn >( fn), + std::forward< Params >( params) ... ) ) { + } + + template< typename StackAlloc, + typename Fn, + typename ... Params + > + execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Params && ... params) : + // 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<> + fctx_( detail::context_create_void< execution_context >( + salloc, + std::forward< Fn >( fn), + std::forward< Params >( params) ... ) ) { + } + + template< typename StackAlloc, + typename Fn, + typename ... Params + > + execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Params && ... params) : + // 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<> + fctx_( detail::context_create_void< execution_context >( + palloc, salloc, + std::forward< Fn >( fn), + std::forward< Params >( params) ... ) ) { + } +#endif + + ~execution_context() { + if ( nullptr != fctx_) { + detail::ontop_fcontext( detail::exchange( fctx_, nullptr), nullptr, detail::context_unwind); + } + } + + execution_context( execution_context && other) noexcept : + fctx_( other.fctx_) { + other.fctx_ = nullptr; + } + + execution_context & operator=( execution_context && other) noexcept { + if ( this != & other) { + execution_context tmp = std::move( other); + swap( tmp); + } + return * this; + } + + execution_context( execution_context const& other) noexcept = delete; + execution_context & operator=( execution_context const& other) noexcept = delete; + + execution_context operator()() { + BOOST_ASSERT( nullptr != fctx_); + detail::transfer_t t = detail::jump_fcontext( detail::exchange( fctx_, nullptr), nullptr); + return execution_context( t.fctx); + } + + template< typename Fn > + execution_context operator()( exec_ontop_arg_t, Fn && fn) { + BOOST_ASSERT( nullptr != fctx_); + std::tuple< Fn > p = std::forward_as_tuple( fn); + detail::transfer_t t = detail::ontop_fcontext( + detail::exchange( fctx_, nullptr), + & p, + detail::context_ontop_void< execution_context, Fn >); + return execution_context( t.fctx); + } + + explicit operator bool() const noexcept { + return nullptr != fctx_; + } + + bool operator!() const noexcept { + return nullptr == fctx_; + } + + bool operator==( execution_context const& other) const noexcept { + return fctx_ == other.fctx_; + } + + bool operator!=( execution_context const& other) const noexcept { + return fctx_ != other.fctx_; + } + + bool operator<( execution_context const& other) const noexcept { + return fctx_ < other.fctx_; + } + + bool operator>( execution_context const& other) const noexcept { + return other.fctx_ < fctx_; + } + + 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.fctx_) { + return os << other.fctx_; + } else { + return os << "{not-a-context}"; + } + } + + void swap( execution_context & other) noexcept { + std::swap( fctx_, other.fctx_); + } +}; diff --git a/boost/context/execution_context_winfib.ipp b/boost/context/execution_context_winfib.ipp deleted file mode 100644 index 1b106fa245..0000000000 --- a/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 <boost/context/detail/config.hpp> - -#if ! defined(BOOST_CONTEXT_NO_EXECUTION_CONTEXT) - -#include <windows.h> - -#include <algorithm> -#include <atomic> -#include <cstddef> -#include <cstdint> -#include <cstdlib> -#include <memory> -#include <tuple> -#include <utility> - -#include <boost/assert.hpp> -#include <boost/config.hpp> -#include <boost/intrusive_ptr.hpp> - -#include <boost/context/detail/invoke.hpp> -#include <boost/context/fixedsize_stack.hpp> -#include <boost/context/stack_context.hpp> - -#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/boost/context/fixedsize_stack.hpp b/boost/context/fixedsize_stack.hpp index b27d785d08..681de40576 100644 --- a/boost/context/fixedsize_stack.hpp +++ b/boost/context/fixedsize_stack.hpp @@ -32,16 +32,12 @@ namespace context { template< typename traitsT > class basic_fixedsize_stack { private: -#if defined(BOOST_USE_WINFIBERS) - friend class execution_context; -#endif - std::size_t size_; public: typedef traitsT traits_type; - basic_fixedsize_stack( std::size_t size = traits_type::default_size() ) : + basic_fixedsize_stack( std::size_t size = traits_type::default_size() ) BOOST_NOEXCEPT_OR_NOTHROW : size_( size) { BOOST_ASSERT( traits_type::minimum_size() <= size_); BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size_) ); @@ -60,17 +56,14 @@ public: return sctx; } - void deallocate( stack_context & sctx) { + void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT( sctx.sp); -#if ! defined(BOOST_USE_WINFIBERS) BOOST_ASSERT( traits_type::minimum_size() <= sctx.size); BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= sctx.size) ); -#endif #if defined(BOOST_USE_VALGRIND) VALGRIND_STACK_DEREGISTER( sctx.valgrind_stack_id); #endif - void * vp = static_cast< char * >( sctx.sp) - sctx.size; std::free( vp); } diff --git a/boost/context/flags.hpp b/boost/context/flags.hpp new file mode 100644 index 0000000000..c7ff1179da --- /dev/null +++ b/boost/context/flags.hpp @@ -0,0 +1,28 @@ + +// 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_FLAGS_H +#define BOOST_CONTEXT_FLAGS_H + +# include <boost/config.hpp> + +# ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +# endif + +namespace boost { +namespace context { + +struct exec_ontop_arg_t {}; +const exec_ontop_arg_t exec_ontop_arg{}; + +}} + +# ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +# endif + +#endif // BOOST_CONTEXT_FLAGS_H diff --git a/boost/context/pooled_fixedsize_stack.hpp b/boost/context/pooled_fixedsize_stack.hpp new file mode 100644 index 0000000000..3c0953cd07 --- /dev/null +++ b/boost/context/pooled_fixedsize_stack.hpp @@ -0,0 +1,115 @@ + +// 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_POOLED_pooled_fixedsize_H +#define BOOST_CONTEXT_POOLED_pooled_fixedsize_H + +#include <atomic> +#include <cstddef> +#include <cstdlib> +#include <new> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/pool/pool.hpp> + +#include <boost/context/detail/config.hpp> +#include <boost/context/stack_context.hpp> +#include <boost/context/stack_traits.hpp> + +#if defined(BOOST_USE_VALGRIND) +#include <valgrind/valgrind.h> +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { + +template< typename traitsT > +class basic_pooled_fixedsize_stack { +private: + class storage { + private: + std::atomic< std::size_t > use_count_; + std::size_t stack_size_; + boost::pool< boost::default_user_allocator_malloc_free > storage_; + + public: + storage( std::size_t stack_size, std::size_t next_size, std::size_t max_size) : + use_count_( 0), + stack_size_( stack_size), + storage_( stack_size, next_size, max_size) { + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= stack_size_) ); + } + + stack_context allocate() { + void * vp = storage_.malloc(); + if ( ! vp) { + throw std::bad_alloc(); + } + stack_context sctx; + sctx.size = stack_size_; + sctx.sp = static_cast< char * >( vp) + sctx.size; +#if defined(BOOST_USE_VALGRIND) + sctx.valgrind_stack_id = VALGRIND_STACK_REGISTER( sctx.sp, vp); +#endif + return sctx; + } + + void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT( sctx.sp); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= sctx.size) ); + +#if defined(BOOST_USE_VALGRIND) + VALGRIND_STACK_DEREGISTER( sctx.valgrind_stack_id); +#endif + void * vp = static_cast< char * >( sctx.sp) - sctx.size; + storage_.free( vp); + } + + friend void intrusive_ptr_add_ref( storage * s) noexcept { + ++s->use_count_; + } + + friend void intrusive_ptr_release( storage * s) noexcept { + if ( 0 == --s->use_count_) { + delete s; + } + } + }; + + intrusive_ptr< storage > storage_; + +public: + typedef traitsT traits_type; + + basic_pooled_fixedsize_stack( std::size_t stack_size = traits_type::default_size(), + std::size_t next_size = 32, + std::size_t max_size = 0) BOOST_NOEXCEPT_OR_NOTHROW : + storage_( new storage( stack_size, next_size, max_size) ) { + } + + stack_context allocate() { + return storage_->allocate(); + } + + void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { + storage_->deallocate( sctx); + } +}; + +typedef basic_pooled_fixedsize_stack< stack_traits > pooled_fixedsize_stack; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_POOLED_pooled_fixedsize_H diff --git a/boost/context/posix/protected_fixedsize_stack.hpp b/boost/context/posix/protected_fixedsize_stack.hpp index 25ce9a6828..7d1b789d01 100644 --- a/boost/context/posix/protected_fixedsize_stack.hpp +++ b/boost/context/posix/protected_fixedsize_stack.hpp @@ -44,7 +44,7 @@ private: public: typedef traitsT traits_type; - basic_protected_fixedsize_stack( std::size_t size = traits_type::default_size() ) : + basic_protected_fixedsize_stack( std::size_t size = traits_type::default_size() ) BOOST_NOEXCEPT_OR_NOTHROW : size_( size) { BOOST_ASSERT( traits_type::minimum_size() <= size_); BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size_) ); @@ -86,7 +86,7 @@ public: return sctx; } - void deallocate( stack_context & sctx) { + void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT( sctx.sp); BOOST_ASSERT( traits_type::minimum_size() <= sctx.size); BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= sctx.size) ); diff --git a/boost/context/posix/segmented_stack.hpp b/boost/context/posix/segmented_stack.hpp index 93f4210fd4..25842b6d32 100644 --- a/boost/context/posix/segmented_stack.hpp +++ b/boost/context/posix/segmented_stack.hpp @@ -45,7 +45,7 @@ private: public: typedef traitsT traits_type; - basic_segmented_stack( std::size_t size = traits_type::default_size() ) : + basic_segmented_stack( std::size_t size = traits_type::default_size() ) BOOST_NOEXCEPT_OR_NOTHROW : size_( size) { BOOST_ASSERT( traits_type::minimum_size() <= size_); BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size_) ); @@ -65,7 +65,7 @@ public: return sctx; } - void deallocate( stack_context & sctx) { + void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { __splitstack_releasecontext( sctx.segments_ctx); } }; diff --git a/boost/context/preallocated.hpp b/boost/context/preallocated.hpp new file mode 100644 index 0000000000..862a6a5060 --- /dev/null +++ b/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 <cstddef> + +#include <boost/config.hpp> + +#include <boost/context/detail/config.hpp> + +#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/boost/context/stack_context.hpp b/boost/context/stack_context.hpp index 24a54e5748..6e516a3adf 100644 --- a/boost/context/stack_context.hpp +++ b/boost/context/stack_context.hpp @@ -20,49 +20,46 @@ namespace boost { namespace context { -#if defined(BOOST_USE_SEGMENTED_STACKS) +#if ! defined(BOOST_CONTEXT_NO_CXX11) struct stack_context { +# if defined(BOOST_USE_SEGMENTED_STACKS) typedef void * segments_context[BOOST_CONTEXT_SEGMENTS]; +# endif - std::size_t size; - void * sp; - segments_context segments_ctx; -#if defined(BOOST_USE_VALGRIND) - unsigned valgrind_stack_id; -#endif - -#if defined(BOOST_NO_CXX11_CONSTEXPR) - stack_context() : -#else - constexpr stack_context() : -#endif - size( 0), - sp( 0), - segments_ctx() -#if defined(BOOST_USE_VALGRIND) - , valgrind_stack_id( 0) -#endif - {} + std::size_t size{ 0 }; + void * sp{ nullptr }; +# if defined(BOOST_USE_SEGMENTED_STACKS) + segments_context segments_ctx{}; +# endif +# if defined(BOOST_USE_VALGRIND) + unsigned valgrind_stack_id{ 0 }; +# endif }; #else struct stack_context { +# if defined(BOOST_USE_SEGMENTED_STACKS) + typedef void * segments_context[BOOST_CONTEXT_SEGMENTS]; +# endif + std::size_t size; void * sp; -#if defined(BOOST_USE_VALGRIND) +# if defined(BOOST_USE_SEGMENTED_STACKS) + segments_context segments_ctx; +# endif +# if defined(BOOST_USE_VALGRIND) unsigned valgrind_stack_id; -#endif +# endif -#if defined(BOOST_NO_CXX11_CONSTEXPR) stack_context() : -#else - constexpr stack_context() : -#endif size( 0), sp( 0) -#if defined(BOOST_USE_VALGRIND) +# if defined(BOOST_USE_SEGMENTED_STACKS) + , segments_ctx() +# endif +# if defined(BOOST_USE_VALGRIND) , valgrind_stack_id( 0) -#endif - {} +# endif + {} }; #endif diff --git a/boost/context/stack_traits.hpp b/boost/context/stack_traits.hpp index 9b8a70636d..d5320f509d 100644 --- a/boost/context/stack_traits.hpp +++ b/boost/context/stack_traits.hpp @@ -22,15 +22,15 @@ namespace context { struct BOOST_CONTEXT_DECL stack_traits { - static bool is_unbounded() BOOST_NOEXCEPT; + static bool is_unbounded() BOOST_NOEXCEPT_OR_NOTHROW; - static std::size_t page_size() BOOST_NOEXCEPT; + static std::size_t page_size() BOOST_NOEXCEPT_OR_NOTHROW; - static std::size_t default_size() BOOST_NOEXCEPT; + static std::size_t default_size() BOOST_NOEXCEPT_OR_NOTHROW; - static std::size_t minimum_size() BOOST_NOEXCEPT; + static std::size_t minimum_size() BOOST_NOEXCEPT_OR_NOTHROW; - static std::size_t maximum_size() BOOST_NOEXCEPT; + static std::size_t maximum_size() BOOST_NOEXCEPT_OR_NOTHROW; }; }} diff --git a/boost/context/windows/protected_fixedsize_stack.hpp b/boost/context/windows/protected_fixedsize_stack.hpp index 548bcda31f..cd59764c93 100644 --- a/boost/context/windows/protected_fixedsize_stack.hpp +++ b/boost/context/windows/protected_fixedsize_stack.hpp @@ -31,16 +31,12 @@ namespace context { template< typename traitsT > class basic_protected_fixedsize_stack { private: -#if defined(BOOST_USE_WINFIBERS) - friend class execution_context; -#endif - std::size_t size_; public: typedef traitsT traits_type; - basic_protected_fixedsize_stack( std::size_t size = traits_type::default_size() ) : + basic_protected_fixedsize_stack( std::size_t size = traits_type::default_size() ) BOOST_NOEXCEPT_OR_NOTHROW : size_( size) { BOOST_ASSERT( traits_type::minimum_size() <= size_); BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size_) ); @@ -76,12 +72,10 @@ public: return sctx; } - void deallocate( stack_context & sctx) { + void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT( sctx.sp); -#if ! defined(BOOST_USE_WINFIBERS) BOOST_ASSERT( traits_type::minimum_size() <= sctx.size); BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= sctx.size) ); -#endif void * vp = static_cast< char * >( sctx.sp) - sctx.size; ::VirtualFree( vp, 0, MEM_RELEASE); |