diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-09-13 11:24:46 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-09-13 11:25:39 +0900 |
commit | 4fadd968fa12130524c8380f33fcfe25d4de79e5 (patch) | |
tree | fd26a490cd15388d42fc6652b3c5c13012e7f93e /boost/context | |
parent | b5c87084afaef42b2d058f68091be31988a6a874 (diff) | |
download | boost-4fadd968fa12130524c8380f33fcfe25d4de79e5.tar.gz boost-4fadd968fa12130524c8380f33fcfe25d4de79e5.tar.bz2 boost-4fadd968fa12130524c8380f33fcfe25d4de79e5.zip |
Imported Upstream version 1.65.0upstream/1.65.0
Change-Id: Icf8400b375482cb11bcf77440a6934ba360d6ba4
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'boost/context')
23 files changed, 1541 insertions, 1460 deletions
diff --git a/boost/context/continuation.hpp b/boost/context/continuation.hpp index 6a50713158..8db62a9506 100644 --- a/boost/context/continuation.hpp +++ b/boost/context/continuation.hpp @@ -4,551 +4,10 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_CONTEXT_CONTINUATION_H -#define BOOST_CONTEXT_CONTINUATION_H - -#include <boost/context/detail/config.hpp> - -#include <algorithm> -#include <cstddef> -#include <cstdint> -#include <cstdlib> -#include <exception> -#include <functional> -#include <memory> -#include <ostream> -#include <tuple> -#include <utility> - -#include <boost/assert.hpp> -#include <boost/config.hpp> -#include <boost/intrusive_ptr.hpp> - -#if defined(BOOST_NO_CXX17_STD_APPLY) -#include <boost/context/detail/apply.hpp> -#endif -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) -#include <boost/context/detail/exchange.hpp> -#endif -#if defined(BOOST_NO_CXX17_STD_INVOKE) -#include <boost/context/detail/invoke.hpp> -#endif -#include <boost/context/detail/disable_overload.hpp> -#include <boost/context/detail/exception.hpp> -#include <boost/context/detail/fcontext.hpp> -#include <boost/context/detail/tuple.hpp> -#include <boost/context/fixedsize_stack.hpp> -#include <boost/context/flags.hpp> -#include <boost/context/preallocated.hpp> -#include <boost/context/segmented_stack.hpp> -#include <boost/context/stack_context.hpp> - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -#if defined(BOOST_MSVC) -# pragma warning(push) -# pragma warning(disable: 4702) -#endif - -namespace boost { -namespace context { -namespace detail { - -template< int N > -struct helper { - template< typename T > - static T convert( T && t) noexcept { - return std::forward< T >( t); - } -}; - -template<> -struct helper< 1 > { - template< typename T > - static std::tuple< T > convert( T && t) noexcept { - return std::make_tuple( std::forward< T >( t) ); - } -}; - -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 != t_.fctx); - 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 StackAlloc, - typename Fn -> -class record { -private: - StackAlloc salloc_; - stack_context sctx_; - typename std::decay< Fn >::type fn_; - - 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) noexcept : - salloc_( salloc), - sctx_( sctx), - fn_( std::forward< Fn >( fn) ) { - } - - record( record const&) = delete; - record & operator=( record const&) = delete; - - void deallocate() noexcept { - destroy( this); - } - - transfer_t run( transfer_t t) { - Ctx from{ t }; - // invoke context-function -#if defined(BOOST_NO_CXX17_STD_INVOKE) - Ctx cc = invoke( fn_, std::move( from) ); -#else - Ctx cc = std::invoke( fn_, std::move( from) ); -#endif -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return { exchange( cc.t_.fctx, nullptr), nullptr }; +#if defined(BOOST_USE_UCONTEXT) +#include <boost/context/continuation_ucontext.hpp> +#elif defined(BOOST_USE_WINFIB) +#include <boost/context/continuation_winfib.hpp> #else - return { std::exchange( cc.t_.fctx, nullptr), nullptr }; +#include <boost/context/continuation_fcontext.hpp> #endif - } -}; - -template< typename Record, typename StackAlloc, typename Fn > -fcontext_t context_create( StackAlloc salloc, Fn && fn) { - 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); - void * sp = static_cast< char * >( sctx.sp) - sizeof( Record); -#else - constexpr std::size_t func_alignment = 64; // alignof( Record); - constexpr std::size_t func_size = sizeof( Record); - // 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 >); - BOOST_ASSERT( nullptr != fctx); - // placment new for control structure on context-stack - auto rec = ::new ( sp) Record{ - sctx, salloc, std::forward< Fn >( fn) }; - // transfer control structure to context-stack - return jump_fcontext( fctx, rec).fctx; -} - -template< typename Record, typename StackAlloc, typename Fn > -fcontext_t context_create( preallocated palloc, StackAlloc salloc, Fn && fn) { - // 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); - void * sp = static_cast< char * >( palloc.sp) - sizeof( Record); -#else - constexpr std::size_t func_alignment = 64; // alignof( Record); - constexpr std::size_t func_size = sizeof( Record); - // 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 >); - BOOST_ASSERT( nullptr != fctx); - // placment new for control structure on context-stack - auto rec = ::new ( sp) Record{ - palloc.sctx, salloc, std::forward< Fn >( fn) }; - // transfer control structure to context-stack - return jump_fcontext( fctx, rec).fctx; -} - -template< typename ... Arg > -struct result_type { - typedef std::tuple< Arg ... > type; - - static - type get( detail::transfer_t & t) { - auto p = static_cast< std::tuple< Arg ... > * >( t.data); - return std::move( * p); - } -}; - -template< typename Arg > -struct result_type< Arg > { - typedef Arg type; - - static - type get( detail::transfer_t & t) { - auto p = static_cast< std::tuple< Arg > * >( t.data); - return std::forward< Arg >( std::get< 0 >( * p) ); - } -}; - -} - -template< typename Ctx, typename Fn, typename ... Arg > -detail::transfer_t context_ontop( detail::transfer_t t) { - auto p = static_cast< std::tuple< Fn, std::tuple< Arg ... > > * >( t.data); - BOOST_ASSERT( nullptr != p); - typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * p) ); - t.data = & std::get< 1 >( * p); - Ctx c{ t }; - // execute function, pass continuation via reference - std::get< 1 >( * p) = detail::helper< sizeof ... (Arg) >::convert( fn( std::move( c) ) ); -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return { detail::exchange( c.t_.fctx, nullptr), & std::get< 1 >( * p) }; -#else - return { std::exchange( c.t_.fctx, nullptr), & std::get< 1 >( * p) }; -#endif -} - -template< typename Ctx, typename Fn > -detail::transfer_t context_ontop_void( detail::transfer_t t) { - auto p = static_cast< std::tuple< Fn > * >( t.data); - BOOST_ASSERT( nullptr != p); - typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * p) ); - Ctx c{ t }; - // execute function, pass continuation via reference - fn( std::move( c) ); -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return { detail::exchange( c.t_.fctx, nullptr), nullptr }; -#else - return { std::exchange( c.t_.fctx, nullptr), nullptr }; -#endif -} - -class continuation { -private: - template< typename Ctx, typename StackAlloc, typename Fn > - friend class detail::record; - - template< typename Ctx, typename Fn, typename ... Arg > - friend detail::transfer_t - context_ontop( detail::transfer_t); - - template< typename Ctx, typename Fn > - friend detail::transfer_t - context_ontop_void( detail::transfer_t); - - template< typename StackAlloc, typename Fn, typename ... Arg > - friend continuation - callcc( std::allocator_arg_t, StackAlloc, Fn &&, Arg ...); - - template< typename StackAlloc, typename Fn, typename ... Arg > - friend continuation - callcc( std::allocator_arg_t, preallocated, StackAlloc, Fn &&, Arg ...); - - template< typename StackAlloc, typename Fn > - friend continuation - callcc( std::allocator_arg_t, StackAlloc, Fn &&); - - template< typename StackAlloc, typename Fn > - friend continuation - callcc( std::allocator_arg_t, preallocated, StackAlloc, Fn &&); - - detail::transfer_t t_{ nullptr, nullptr }; - - continuation( detail::fcontext_t fctx) noexcept : - t_{ fctx, nullptr } { - } - - continuation( detail::transfer_t t) noexcept : - t_{ t.fctx, t.data } { - } - -public: - continuation() noexcept = default; - - ~continuation() { - if ( nullptr != t_.fctx) { -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::ontop_fcontext( detail::exchange( t_.fctx, nullptr), nullptr, detail::context_unwind); -#else - detail::ontop_fcontext( std::exchange( t_.fctx, nullptr), nullptr, detail::context_unwind); -#endif - } - } - - continuation( continuation && other) noexcept : - t_{ other.t_.fctx, other.t_.data } { - other.t_ = { nullptr, nullptr }; - } - - continuation & operator=( continuation && other) noexcept { - if ( this != & other) { - continuation tmp = std::move( other); - swap( tmp); - } - return * this; - } - - continuation( continuation const& other) noexcept = delete; - continuation & operator=( continuation const& other) noexcept = delete; - - template< typename ... Arg > - continuation resume( Arg ... arg) { - BOOST_ASSERT( nullptr != t_.fctx); - auto tpl = std::make_tuple( std::forward< Arg >( arg) ... ); - return detail::jump_fcontext( -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( t_.fctx, nullptr), -#else - std::exchange( t_.fctx, nullptr), -#endif - & tpl); - } - - template< typename Fn, typename ... Arg > - continuation resume_with( Fn && fn, Arg ... arg) { - BOOST_ASSERT( nullptr != t_.fctx); - auto tpl = std::make_tuple( std::forward< Fn >( fn), std::forward< Arg >( arg) ... ); - return detail::ontop_fcontext( -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( t_.fctx, nullptr), -#else - std::exchange( t_.fctx, nullptr), -#endif - & tpl, - context_ontop< continuation, Fn, Arg ... >); - } - - continuation resume() { - BOOST_ASSERT( nullptr != t_.fctx); - return detail::jump_fcontext( -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( t_.fctx, nullptr), -#else - std::exchange( t_.fctx, nullptr), -#endif - nullptr); - } - - template< typename Fn > - continuation resume_with( Fn && fn) { - BOOST_ASSERT( nullptr != t_.fctx); - auto p = std::make_tuple( std::forward< Fn >( fn) ); - return detail::ontop_fcontext( -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( t_.fctx, nullptr), -#else - std::exchange( t_.fctx, nullptr), -#endif - & p, - context_ontop_void< continuation, Fn >); - } - - bool data_available() noexcept { - return * this && nullptr != t_.data; - } - - template< typename ... Arg > - typename detail::result_type< Arg ... >::type get_data() { - BOOST_ASSERT( nullptr != t_.data); - return detail::result_type< Arg ... >::get( t_); - } - - explicit operator bool() const noexcept { - return nullptr != t_.fctx; - } - - bool operator!() const noexcept { - return nullptr == t_.fctx; - } - - bool operator==( continuation const& other) const noexcept { - return t_.fctx == other.t_.fctx; - } - - bool operator!=( continuation const& other) const noexcept { - return t_.fctx != other.t_.fctx; - } - - bool operator<( continuation const& other) const noexcept { - return t_.fctx < other.t_.fctx; - } - - bool operator>( continuation const& other) const noexcept { - return other.t_.fctx < t_.fctx; - } - - bool operator<=( continuation const& other) const noexcept { - return ! ( * this > other); - } - - bool operator>=( continuation 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, continuation const& other) { - if ( nullptr != other.t_.fctx) { - return os << other.t_.fctx; - } else { - return os << "{not-a-context}"; - } - } - - void swap( continuation & other) noexcept { - std::swap( t_, other.t_); - } -}; - -// Arg -template< - typename Fn, - typename ... Arg, - typename = detail::disable_overload< continuation, Fn > -> -continuation -callcc( Fn && fn, Arg ... arg) { - return callcc( - std::allocator_arg, fixedsize_stack(), - std::forward< Fn >( fn), std::forward< Arg >( arg) ...); -} - -template< - typename StackAlloc, - typename Fn, - typename ... Arg -> -continuation -callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Arg ... arg) { - using Record = detail::record< continuation, StackAlloc, Fn >; - return continuation{ - detail::context_create< Record >( - salloc, std::forward< Fn >( fn) ) }.resume( - std::forward< Arg >( arg) ... ); -} - -template< - typename StackAlloc, - typename Fn, - typename ... Arg -> -continuation -callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Arg ... arg) { - using Record = detail::record< continuation, StackAlloc, Fn >; - return continuation{ - detail::context_create< Record >( - palloc, salloc, std::forward< Fn >( fn) ) }.resume( - std::forward< Arg >( arg) ... ); -} - -// void -template< - typename Fn, - typename = detail::disable_overload< continuation, Fn > -> -continuation -callcc( Fn && fn) { - return callcc( - std::allocator_arg, fixedsize_stack(), - std::forward< Fn >( fn) ); -} - -template< typename StackAlloc, typename Fn > -continuation -callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn) { - using Record = detail::record< continuation, StackAlloc, Fn >; - return continuation{ - detail::context_create< Record >( - salloc, std::forward< Fn >( fn) ) }.resume(); -} - -template< typename StackAlloc, typename Fn > -continuation -callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn) { - using Record = detail::record< continuation, StackAlloc, Fn >; - return continuation{ - detail::context_create< Record >( - palloc, salloc, std::forward< Fn >( fn) ) }.resume(); -} - -#if defined(BOOST_USE_SEGMENTED_STACKS) -template< - typename Fn, - typename ... Arg -> -continuation -callcc( std::allocator_arg_t, segmented_stack, Fn &&, Arg ...); - -template< - typename StackAlloc, - typename Fn, - typename ... Arg -> -continuation -callcc( std::allocator_arg_t, preallocated, segmented_stack, Fn &&, Arg ...); -#endif - -// swap -inline -void swap( continuation & l, continuation & r) noexcept { - l.swap( r); -} - -}} - -#if defined(BOOST_MSVC) -# pragma warning(pop) -#endif - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_CONTINUATION_H diff --git a/boost/context/continuation_fcontext.hpp b/boost/context/continuation_fcontext.hpp new file mode 100644 index 0000000000..5c309c3fed --- /dev/null +++ b/boost/context/continuation_fcontext.hpp @@ -0,0 +1,382 @@ + +// Copyright Oliver Kowalke 2017. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CONTEXT_CONTINUATION_H +#define BOOST_CONTEXT_CONTINUATION_H + +#include <boost/context/detail/config.hpp> + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <exception> +#include <functional> +#include <memory> +#include <ostream> +#include <tuple> +#include <utility> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/intrusive_ptr.hpp> + +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) +#include <boost/context/detail/exchange.hpp> +#endif +#if defined(BOOST_NO_CXX17_STD_INVOKE) +#include <boost/context/detail/invoke.hpp> +#endif +#include <boost/context/detail/disable_overload.hpp> +#include <boost/context/detail/exception.hpp> +#include <boost/context/detail/fcontext.hpp> +#include <boost/context/detail/tuple.hpp> +#include <boost/context/fixedsize_stack.hpp> +#include <boost/context/flags.hpp> +#include <boost/context/preallocated.hpp> +#include <boost/context/segmented_stack.hpp> +#include <boost/context/stack_context.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable: 4702) +#endif + +namespace boost { +namespace context { +namespace detail { + +inline +transfer_t 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 != t.fctx); + BOOST_ASSERT( nullptr != rec); + try { + // jump back to `create_context()` + t = jump_fcontext( t.fctx, nullptr); + // start executing + t.fctx = rec->run( t.fctx); + } catch ( forced_unwind const& e) { + t = { e.fctx, nullptr }; + } + BOOST_ASSERT( nullptr != t.fctx); + // destroy context-stack of `this`context on next context + ontop_fcontext( t.fctx, rec, context_exit< Rec >); + BOOST_ASSERT_MSG( false, "context already terminated"); +} + +template< typename Ctx, typename Fn > +transfer_t context_ontop( transfer_t t) { + auto p = static_cast< std::tuple< Fn > * >( t.data); + BOOST_ASSERT( nullptr != p); + typename std::decay< Fn >::type fn = std::get< 0 >( * p); + t.data = nullptr; + Ctx c{ t.fctx }; + // execute function, pass continuation via reference + fn( std::move( c) ); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return { exchange( c.fctx_, nullptr), nullptr }; +#else + return { std::exchange( c.fctx_, nullptr), nullptr }; +#endif +} + +template< typename Ctx, typename StackAlloc, typename Fn > +class record { +private: + stack_context sctx_; + StackAlloc salloc_; + typename std::decay< Fn >::type fn_; + + 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) noexcept : + sctx_( sctx), + salloc_( salloc), + fn_( std::forward< Fn >( fn) ) { + } + + record( record const&) = delete; + record & operator=( record const&) = delete; + + void deallocate() noexcept { + destroy( this); + } + + fcontext_t run( fcontext_t fctx) { + Ctx c{ fctx }; + // invoke context-function +#if defined(BOOST_NO_CXX17_STD_INVOKE) + c = invoke( fn_, std::move( c) ); +#else + c = std::invoke( fn_, std::move( c) ); +#endif +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( c.fctx_, nullptr); +#else + return std::exchange( c.fctx_, nullptr); +#endif + } +}; + +template< typename Record, typename StackAlloc, typename Fn > +fcontext_t create_context1( StackAlloc salloc, Fn && fn) { + auto sctx = salloc.allocate(); + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( Record) ) ) + & ~static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + Record * record = new ( storage) Record{ + sctx, salloc, std::forward< Fn >( fn) }; + // 64byte gab between control structure and stack top + // should be 16byte aligned + void * stack_top = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) ); + void * stack_bottom = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) ); + // create fast-context + const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom); + const fcontext_t fctx = make_fcontext( stack_top, size, & context_entry< Record >); + BOOST_ASSERT( nullptr != fctx); + // transfer control structure to context-stack + return jump_fcontext( fctx, record).fctx; +} + +template< typename Record, typename StackAlloc, typename Fn > +fcontext_t create_context2( preallocated palloc, StackAlloc salloc, Fn && fn) { + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( Record) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context-stack + Record * record = new ( storage) Record{ + palloc.sctx, salloc, std::forward< Fn >( fn) }; + // 64byte gab between control structure and stack top + void * stack_top = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) ); + void * stack_bottom = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) ); + // create fast-context + const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom); + const fcontext_t fctx = make_fcontext( stack_top, size, & context_entry< Record >); + BOOST_ASSERT( nullptr != fctx); + // transfer control structure to context-stack + return jump_fcontext( fctx, record).fctx; +} + +} + +class continuation { +private: + template< typename Ctx, typename StackAlloc, typename Fn > + friend class detail::record; + + template< typename Ctx, typename Fn > + friend detail::transfer_t + detail::context_ontop( detail::transfer_t); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, StackAlloc, Fn &&); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, preallocated, StackAlloc, Fn &&); + + detail::fcontext_t fctx_{ nullptr }; + + continuation( detail::fcontext_t fctx) noexcept : + fctx_{ fctx } { + } + +public: + continuation() noexcept = default; + + ~continuation() { + if ( BOOST_UNLIKELY( nullptr != fctx_) ) { + detail::ontop_fcontext( +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::exchange( fctx_, nullptr), +#else + std::exchange( fctx_, nullptr), +#endif + nullptr, + detail::context_unwind); + } + } + + continuation( continuation && other) noexcept { + std::swap( fctx_, other.fctx_); + } + + continuation & operator=( continuation && other) noexcept { + if ( BOOST_LIKELY( this != & other) ) { + continuation tmp = std::move( other); + swap( tmp); + } + return * this; + } + + continuation( continuation const& other) noexcept = delete; + continuation & operator=( continuation const& other) noexcept = delete; + + continuation resume() { + BOOST_ASSERT( nullptr != fctx_); + return detail::jump_fcontext( +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::exchange( fctx_, nullptr), +#else + std::exchange( fctx_, nullptr), +#endif + nullptr).fctx; + } + + template< typename Fn > + continuation resume_with( Fn && fn) { + BOOST_ASSERT( nullptr != fctx_); + auto p = std::make_tuple( std::forward< Fn >( fn) ); + return detail::ontop_fcontext( +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::exchange( fctx_, nullptr), +#else + std::exchange( fctx_, nullptr), +#endif + & p, + detail::context_ontop< continuation, Fn >).fctx; + } + + explicit operator bool() const noexcept { + return nullptr != fctx_; + } + + bool operator!() const noexcept { + return nullptr == fctx_; + } + + bool operator==( continuation const& other) const noexcept { + return fctx_ == other.fctx_; + } + + bool operator!=( continuation const& other) const noexcept { + return fctx_ != other.fctx_; + } + + bool operator<( continuation const& other) const noexcept { + return fctx_ < other.fctx_; + } + + bool operator>( continuation const& other) const noexcept { + return other.fctx_ < fctx_; + } + + bool operator<=( continuation const& other) const noexcept { + return ! ( * this > other); + } + + bool operator>=( continuation 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, continuation const& other) { + if ( nullptr != other.fctx_) { + return os << other.fctx_; + } else { + return os << "{not-a-context}"; + } + } + + void swap( continuation & other) noexcept { + std::swap( fctx_, other.fctx_); + } +}; + +template< + typename Fn, + typename = detail::disable_overload< continuation, Fn > +> +continuation +callcc( Fn && fn) { + return callcc( + std::allocator_arg, fixedsize_stack(), + std::forward< Fn >( fn) ); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn) { + using Record = detail::record< continuation, StackAlloc, Fn >; + return continuation{ + detail::create_context1< Record >( + salloc, std::forward< Fn >( fn) ) }.resume(); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn) { + using Record = detail::record< continuation, StackAlloc, Fn >; + return continuation{ + detail::create_context2< Record >( + palloc, salloc, std::forward< Fn >( fn) ) }.resume(); +} + +#if defined(BOOST_USE_SEGMENTED_STACKS) +template< typename Fn > +continuation +callcc( std::allocator_arg_t, segmented_stack, Fn &&); + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, preallocated, segmented_stack, Fn &&); +#endif + +// swap +inline +void swap( continuation & l, continuation & r) noexcept { + l.swap( r); +} + +}} + +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_CONTINUATION_H diff --git a/boost/context/continuation_ucontext.hpp b/boost/context/continuation_ucontext.hpp new file mode 100644 index 0000000000..6f964dc6f6 --- /dev/null +++ b/boost/context/continuation_ucontext.hpp @@ -0,0 +1,525 @@ + +// Copyright Oliver Kowalke 2017. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CONTEXT_CONTINUATION_H +#define BOOST_CONTEXT_CONTINUATION_H + +#include <boost/predef.h> +#if BOOST_OS_MACOS +#define _XOPEN_SOURCE 600 +#endif + +extern "C" { +#include <ucontext.h> +} + +#include <boost/context/detail/config.hpp> + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <functional> +#include <memory> +#include <ostream> +#include <system_error> +#include <tuple> +#include <utility> + +#include <boost/assert.hpp> +#include <boost/config.hpp> + +#include <boost/context/detail/disable_overload.hpp> +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) +#include <boost/context/detail/exchange.hpp> +#endif +#if defined(BOOST_NO_CXX17_STD_INVOKE) +#include <boost/context/detail/invoke.hpp> +#endif +#include <boost/context/fixedsize_stack.hpp> +#include <boost/context/flags.hpp> +#include <boost/context/preallocated.hpp> +#if defined(BOOST_USE_SEGMENTED_STACKS) +#include <boost/context/segmented_stack.hpp> +#endif +#include <boost/context/stack_context.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if defined(BOOST_USE_ASAN) +extern "C" { +void __sanitizer_start_switch_fiber( void **, const void *, size_t); +void __sanitizer_finish_switch_fiber( void *, const void **, size_t *); +} +#endif + +#if defined(BOOST_USE_SEGMENTED_STACKS) +extern "C" { +void __splitstack_getcontext( void * [BOOST_CONTEXT_SEGMENTS]); +void __splitstack_setcontext( void * [BOOST_CONTEXT_SEGMENTS]); +} +#endif + +namespace boost { +namespace context { +namespace detail { + +// tampoline function +// entered if the execution context +// is resumed for the first time +template< typename Record > +static void entry_func( void * data) noexcept { + Record * record = static_cast< Record * >( data); + BOOST_ASSERT( nullptr != record); + // start execution of toplevel context-function + record->run(); +} + +struct BOOST_CONTEXT_DECL activation_record { + thread_local static activation_record * current_rec; + + ucontext_t uctx{}; + stack_context sctx{}; + bool main_ctx{ true }; + activation_record * from{ nullptr }; + std::function< void(activation_record*&) > ontop{}; + bool terminated{ false }; + bool force_unwind{ false }; +#if defined(BOOST_USE_ASAN) + void * fake_stack{ nullptr }; + void * stack_bottom{ nullptr }; + std::size_t stack_size{ 0 }; + bool started{ false }; +#endif + + static activation_record *& current() noexcept; + + // used for toplevel-context + // (e.g. main context, thread-entry context) + activation_record() { + if ( BOOST_UNLIKELY( 0 != ::getcontext( & uctx) ) ) { + throw std::system_error( + std::error_code( errno, std::system_category() ), + "getcontext() failed"); + } +#if defined(BOOST_USE_ASAN) + stack_bottom = uctx.uc_stack.ss_sp; + stack_size = uctx.uc_stack.ss_size; +#endif + } + + activation_record( stack_context sctx_) noexcept : + sctx( sctx_ ), + main_ctx( false ) { + } + + virtual ~activation_record() { + } + + activation_record( activation_record const&) = delete; + activation_record & operator=( activation_record const&) = delete; + + bool is_main_context() const noexcept { + return main_ctx; + } + + activation_record * resume() { + from = current(); + // store `this` in static, thread local pointer + // `this` will become the active (running) context + current() = this; +#if defined(BOOST_USE_SEGMENTED_STACKS) + // adjust segmented stack properties + __splitstack_getcontext( from->sctx.segments_ctx); + __splitstack_setcontext( sctx.segments_ctx); +#endif +#if defined(BOOST_USE_ASAN) + if ( from->started) { + __sanitizer_finish_switch_fiber( from->fake_stack, (const void **) & from->stack_bottom, + & from->stack_size); + from->started = false; + } + __sanitizer_start_switch_fiber( & fake_stack, stack_bottom, stack_size); + started = true; +#endif + // context switch from parent context to `this`-context + ::swapcontext( & from->uctx, & uctx); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( current()->from, nullptr); +#else + return std::exchange( current()->from, nullptr); +#endif + } + + template< typename Ctx, typename Fn > + activation_record * resume_with( Fn && fn) { + from = current(); + // store `this` in static, thread local pointer + // `this` will become the active (running) context + // returned by continuation::current() + current() = this; +#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) + current()->ontop = std::bind( + [](typename std::decay< Fn >::type & fn, activation_record *& ptr){ + Ctx c{ ptr }; + fn( std::move( c) ); + if ( ! c) { + ptr = nullptr; + } + }, + std::forward< Fn >( fn), + std::placeholders::_1); +#else + current()->ontop = [fn=std::forward<Fn>(fn)](activation_record *& ptr){ + Ctx c{ ptr }; + fn( std::move( c) ); + if ( ! c) { + ptr = nullptr; + } + }; +#endif +#if defined(BOOST_USE_SEGMENTED_STACKS) + // adjust segmented stack properties + __splitstack_getcontext( from->sctx.segments_ctx); + __splitstack_setcontext( sctx.segments_ctx); +#endif +#if defined(BOOST_USE_ASAN) + if ( from->started) { + __sanitizer_finish_switch_fiber( from->fake_stack, (const void **) & from->stack_bottom, + & from->stack_size); + from->started = false; + } + __sanitizer_start_switch_fiber( & fake_stack, stack_bottom, stack_size); + started = true; +#endif + // context switch from parent context to `this`-context + ::swapcontext( & from->uctx, & uctx); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( current()->from, nullptr); +#else + return std::exchange( current()->from, nullptr); +#endif + } + + virtual void deallocate() noexcept { + } +}; + +struct BOOST_CONTEXT_DECL activation_record_initializer { + activation_record_initializer() noexcept; + ~activation_record_initializer(); +}; + +struct forced_unwind { + activation_record * from{ nullptr }; + + forced_unwind( activation_record * from_) noexcept : + from{ from_ } { + } +}; + +template< typename Ctx, typename StackAlloc, typename Fn > +class capture_record : public activation_record { +private: + StackAlloc salloc_; + typename std::decay< Fn >::type fn_; + + 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, Fn && fn) noexcept : + activation_record{ sctx }, + salloc_{ salloc }, + fn_( std::forward< Fn >( fn) ) { + } + + void deallocate() noexcept override final { + BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) ); + destroy( this); + } + + void run() { + Ctx c{ from }; + try { + // invoke context-function +#if defined(BOOST_NO_CXX17_STD_APPLY) + c = invoke( fn_, std::move( c) ); +#else + c = std::invoke( fn_, std::move( c) ); +#endif + } catch ( forced_unwind const& ex) { + c = Ctx{ ex.from }; + } + // this context has finished its task + from = nullptr; + ontop = nullptr; + terminated = true; + force_unwind = false; + c.resume(); + BOOST_ASSERT_MSG( false, "continuation already terminated"); + } +}; + +template< typename Ctx, typename StackAlloc, typename Fn > +static activation_record * create_context1( StackAlloc salloc, Fn && fn) { + typedef capture_record< Ctx, StackAlloc, Fn > capture_t; + + auto sctx = salloc.allocate(); + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + capture_t * record = new ( storage) capture_t{ + sctx, salloc, std::forward< Fn >( fn) }; + // stack bottom + void * stack_bottom = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) ); + // create user-context + if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) { + throw std::system_error( + std::error_code( errno, std::system_category() ), + "getcontext() failed"); + } + record->uctx.uc_stack.ss_sp = stack_bottom; + // 64byte gap between control structure and stack top + record->uctx.uc_stack.ss_size = reinterpret_cast< uintptr_t >( storage) - + reinterpret_cast< uintptr_t >( stack_bottom) - static_cast< uintptr_t >( 64); + record->uctx.uc_link = nullptr; + ::makecontext( & record->uctx, ( void (*)() ) & entry_func< capture_t >, 1, record); +#if defined(BOOST_USE_ASAN) + record->stack_bottom = record->uctx.uc_stack.ss_sp; + record->stack_size = record->uctx.uc_stack.ss_size; +#endif + return record; +} + +template< typename Ctx, typename StackAlloc, typename Fn > +static activation_record * create_context2( preallocated palloc, StackAlloc salloc, Fn && fn) { + typedef capture_record< Ctx, StackAlloc, Fn > capture_t; + + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + capture_t * record = new ( storage) capture_t{ + palloc.sctx, salloc, std::forward< Fn >( fn) }; + // stack bottom + void * stack_bottom = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) ); + // create user-context + if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) { + throw std::system_error( + std::error_code( errno, std::system_category() ), + "getcontext() failed"); + } + record->uctx.uc_stack.ss_sp = stack_bottom; + // 64byte gap between control structure and stack top + record->uctx.uc_stack.ss_size = reinterpret_cast< uintptr_t >( storage) - + reinterpret_cast< uintptr_t >( stack_bottom) - static_cast< uintptr_t >( 64); + record->uctx.uc_link = nullptr; + ::makecontext( & record->uctx, ( void (*)() ) & entry_func< capture_t >, 1, record); +#if defined(BOOST_USE_ASAN) + record->stack_bottom = record->uctx.uc_stack.ss_sp; + record->stack_size = record->uctx.uc_stack.ss_size; +#endif + return record; +} + +} + +class BOOST_CONTEXT_DECL continuation { +private: + friend struct detail::activation_record; + + template< typename Ctx, typename StackAlloc, typename Fn > + friend class detail::capture_record; + + template< typename Ctx, typename StackAlloc, typename Fn > + friend detail::activation_record * detail::create_context1( StackAlloc, Fn &&); + + template< typename Ctx, typename StackAlloc, typename Fn > + friend detail::activation_record * detail::create_context2( preallocated, StackAlloc, Fn &&); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, StackAlloc, Fn &&); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, preallocated, StackAlloc, Fn &&); + + detail::activation_record * ptr_{ nullptr }; + + continuation( detail::activation_record * ptr) noexcept : + ptr_{ ptr } { + } + +public: + continuation() = default; + + ~continuation() { + if ( BOOST_UNLIKELY( nullptr != ptr_) && ! ptr_->main_ctx) { + if ( BOOST_LIKELY( ! ptr_->terminated) ) { + ptr_->force_unwind = true; + ptr_->resume(); + BOOST_ASSERT( ptr_->terminated); + } + ptr_->deallocate(); + } + } + + continuation( continuation const&) = delete; + continuation & operator=( continuation const&) = delete; + + continuation( continuation && other) noexcept : + ptr_{ nullptr } { + swap( other); + } + + continuation & operator=( continuation && other) noexcept { + if ( BOOST_LIKELY( this != & other) ) { + ptr_ = other.ptr_; + other.ptr_ = nullptr; + } + return * this; + } + + continuation resume() { +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::activation_record * ptr = detail::exchange( ptr_, nullptr)->resume(); +#else + detail::activation_record * ptr = std::exchange( ptr_, nullptr)->resume(); +#endif + if ( BOOST_UNLIKELY( detail::activation_record::current()->force_unwind) ) { + throw detail::forced_unwind{ ptr}; + } else if ( BOOST_UNLIKELY( nullptr != detail::activation_record::current()->ontop) ) { + detail::activation_record::current()->ontop( ptr); + detail::activation_record::current()->ontop = nullptr; + } + return continuation{ ptr }; + } + + template< typename Fn > + continuation resume_with( Fn && fn) { +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::activation_record * ptr = + detail::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) ); +#else + detail::activation_record * ptr = + std::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) ); +#endif + if ( BOOST_UNLIKELY( detail::activation_record::current()->force_unwind) ) { + throw detail::forced_unwind{ ptr}; + } else if ( BOOST_UNLIKELY( nullptr != detail::activation_record::current()->ontop) ) { + detail::activation_record::current()->ontop( ptr); + detail::activation_record::current()->ontop = nullptr; + } + return continuation{ ptr }; + } + + explicit operator bool() const noexcept { + return nullptr != ptr_ && ! ptr_->terminated; + } + + bool operator!() const noexcept { + return nullptr == ptr_ || ptr_->terminated; + } + + bool operator==( continuation const& other) const noexcept { + return ptr_ == other.ptr_; + } + + bool operator!=( continuation const& other) const noexcept { + return ptr_ != other.ptr_; + } + + bool operator<( continuation const& other) const noexcept { + return ptr_ < other.ptr_; + } + + bool operator>( continuation const& other) const noexcept { + return other.ptr_ < ptr_; + } + + bool operator<=( continuation const& other) const noexcept { + return ! ( * this > other); + } + + bool operator>=( continuation 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, continuation const& other) { + if ( nullptr != other.ptr_) { + return os << other.ptr_; + } else { + return os << "{not-a-context}"; + } + } + + void swap( continuation & other) noexcept { + std::swap( ptr_, other.ptr_); + } +}; + +template< + typename Fn, + typename = detail::disable_overload< continuation, Fn > +> +continuation +callcc( Fn && fn) { + return callcc( + std::allocator_arg, +#if defined(BOOST_USE_SEGMENTED_STACKS) + segmented_stack(), +#else + fixedsize_stack(), +#endif + std::forward< Fn >( fn) ); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn) { + return continuation{ + detail::create_context1< continuation >( + salloc, std::forward< Fn >( fn) ) }.resume(); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn) { + return continuation{ + detail::create_context2< continuation >( + palloc, salloc, std::forward< Fn >( fn) ) }.resume(); +} + +inline +void swap( continuation & l, continuation & r) noexcept { + l.swap( r); +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_CONTINUATION_H diff --git a/boost/context/continuation_winfib.hpp b/boost/context/continuation_winfib.hpp new file mode 100644 index 0000000000..8a814b0bd8 --- /dev/null +++ b/boost/context/continuation_winfib.hpp @@ -0,0 +1,453 @@ + +// Copyright Oliver Kowalke 2017. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CONTEXT_CONTINUATION_H +#define BOOST_CONTEXT_CONTINUATION_H + +#include <windows.h> + +#include <boost/context/detail/config.hpp> + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <functional> +#include <memory> +#include <ostream> +#include <system_error> +#include <tuple> +#include <utility> + +#include <boost/assert.hpp> +#include <boost/config.hpp> + +#include <boost/context/detail/disable_overload.hpp> +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) +#include <boost/context/detail/exchange.hpp> +#endif +#if defined(BOOST_NO_CXX17_STD_INVOKE) +#include <boost/context/detail/invoke.hpp> +#endif +#include <boost/context/fixedsize_stack.hpp> +#include <boost/context/flags.hpp> +#include <boost/context/preallocated.hpp> +#include <boost/context/stack_context.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable: 4702) +#endif + +namespace boost { +namespace context { +namespace detail { + +// tampoline function +// entered if the execution context +// is resumed for the first time +template< typename Record > +static VOID WINAPI entry_func( LPVOID data) noexcept { + Record * record = static_cast< Record * >( data); + BOOST_ASSERT( nullptr != record); + // start execution of toplevel context-function + record->run(); +} + +struct BOOST_CONTEXT_DECL activation_record { + thread_local static activation_record * current_rec; + + LPVOID fiber{ nullptr }; + stack_context sctx{}; + bool main_ctx{ true }; + activation_record * from{ nullptr }; + std::function< void(activation_record*&) > ontop{}; + bool terminated{ false }; + bool force_unwind{ false }; + + static activation_record *& current() noexcept; + + // used for toplevel-context + // (e.g. main context, thread-entry context) + activation_record() noexcept { +#if ( _WIN32_WINNT > 0x0600) + if ( ::IsThreadAFiber() ) { + fiber = ::GetCurrentFiber(); + } else { + fiber = ::ConvertThreadToFiber( nullptr); + } +#else + fiber = ::ConvertThreadToFiber( nullptr); + if ( BOOST_UNLIKELY( nullptr == fiber) ) { + DWORD err = ::GetLastError(); + BOOST_ASSERT( ERROR_ALREADY_FIBER == err); + fiber = ::GetCurrentFiber(); + BOOST_ASSERT( nullptr != fiber); + BOOST_ASSERT( reinterpret_cast< LPVOID >( 0x1E00) != fiber); + } +#endif + } + + activation_record( stack_context sctx_) noexcept : + sctx{ sctx_ }, + main_ctx{ false } { + } + + virtual ~activation_record() { + if ( BOOST_UNLIKELY( main_ctx) ) { + ::ConvertFiberToThread(); + } else { + ::DeleteFiber( fiber); + } + } + + activation_record( activation_record const&) = delete; + activation_record & operator=( activation_record const&) = delete; + + bool is_main_context() const noexcept { + return main_ctx; + } + + activation_record * resume() { + from = current(); + // store `this` in static, thread local pointer + // `this` will become the active (running) context + current() = this; + // context switch from parent context to `this`-context + // context switch + ::SwitchToFiber( fiber); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return detail::exchange( current()->from, nullptr); +#else + return std::exchange( current()->from, nullptr); +#endif + } + + template< typename Ctx, typename Fn > + activation_record * resume_with( Fn && fn) { + from = current(); + // store `this` in static, thread local pointer + // `this` will become the active (running) context + // returned by continuation::current() + current() = this; +#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) + current()->ontop = std::bind( + [](typename std::decay< Fn >::type & fn, activation_record *& ptr){ + Ctx c{ ptr }; + fn( std::move( c) ); + if ( ! c) { + ptr = nullptr; + } + }, + std::forward< Fn >( fn), + std::placeholders::_1); +#else + current()->ontop = [fn=std::forward<Fn>(fn)](activation_record *& ptr){ + Ctx c{ ptr }; + fn( std::move( c) ); + if ( ! c) { + ptr = nullptr; + } + }; +#endif + // context switch + ::SwitchToFiber( fiber); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return detail::exchange( current()->from, nullptr); +#else + return std::exchange( current()->from, nullptr); +#endif + } + + virtual void deallocate() noexcept { + } +}; + +struct BOOST_CONTEXT_DECL activation_record_initializer { + activation_record_initializer() noexcept; + ~activation_record_initializer(); +}; + +struct forced_unwind { + activation_record * from{ nullptr }; + + explicit forced_unwind( activation_record * from_) : + from{ from_ } { + } +}; + +template< typename Ctx, typename StackAlloc, typename Fn > +class capture_record : public activation_record { +private: + StackAlloc salloc_; + typename std::decay< Fn >::type fn_; + + 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 salloc, Fn && fn) noexcept : + activation_record( sctx), + salloc_( salloc), + fn_( std::forward< Fn >( fn) ) { + } + + void deallocate() noexcept override final { + BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) ); + destroy( this); + } + + void run() { + Ctx c{ from }; + try { + // invoke context-function +#if defined(BOOST_NO_CXX17_STD_INVOKE) + c = invoke( fn_, std::move( c) ); +#else + c = std::invoke( fn_, std::move( c) ); +#endif + } catch ( forced_unwind const& ex) { + c = Ctx{ ex.from }; + } + // this context has finished its task + from = nullptr; + ontop = nullptr; + terminated = true; + force_unwind = false; + c.resume(); + BOOST_ASSERT_MSG( false, "continuation already terminated"); + } +}; + +template< typename Ctx, typename StackAlloc, typename Fn > +static activation_record * create_context1( StackAlloc salloc, Fn && fn) { + typedef capture_record< Ctx, StackAlloc, Fn > capture_t; + + auto sctx = salloc.allocate(); + BOOST_ASSERT( ( sizeof( capture_t) ) < sctx.size); + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + capture_t * record = new ( storage) capture_t{ + sctx, salloc, std::forward< Fn >( fn) }; + // create user-context + record->fiber = ::CreateFiber( sctx.size, & detail::entry_func< capture_t >, record); + return record; +} + +template< typename Ctx, typename StackAlloc, typename Fn > +static activation_record * create_context2( preallocated palloc, StackAlloc salloc, Fn && fn) { + typedef capture_record< Ctx, StackAlloc, Fn > capture_t; + + BOOST_ASSERT( ( sizeof( capture_t) ) < palloc.size); + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + capture_t * record = new ( storage) capture_t{ + palloc.sctx, salloc, std::forward< Fn >( fn) }; + // create user-context + record->fiber = ::CreateFiber( palloc.sctx.size, & detail::entry_func< capture_t >, record); + return record; +} + +} + +class BOOST_CONTEXT_DECL continuation { +private: + friend struct detail::activation_record; + + template< typename Ctx, typename StackAlloc, typename Fn > + friend class detail::capture_record; + + template< typename Ctx, typename StackAlloc, typename Fn > + friend detail::activation_record * detail::create_context1( StackAlloc, Fn &&); + + template< typename Ctx, typename StackAlloc, typename Fn > + friend detail::activation_record * detail::create_context2( preallocated, StackAlloc, Fn &&); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, StackAlloc, Fn &&); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, preallocated, StackAlloc, Fn &&); + + detail::activation_record * ptr_{ nullptr }; + + continuation( detail::activation_record * ptr) noexcept : + ptr_{ ptr } { + } + +public: + continuation() = default; + + ~continuation() { + if ( BOOST_UNLIKELY( nullptr != ptr_) && ! ptr_->main_ctx) { + if ( BOOST_LIKELY( ! ptr_->terminated) ) { + ptr_->force_unwind = true; + ptr_->resume(); + BOOST_ASSERT( ptr_->terminated); + } + ptr_->deallocate(); + } + } + + continuation( continuation const&) = delete; + continuation & operator=( continuation const&) = delete; + + continuation( continuation && other) noexcept : + ptr_{ nullptr } { + swap( other); + } + + continuation & operator=( continuation && other) noexcept { + if ( BOOST_LIKELY( this != & other) ) { + ptr_ = other.ptr_; + other.ptr_ = nullptr; + } + return * this; + } + + continuation resume() { +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::activation_record * ptr = detail::exchange( ptr_, nullptr)->resume(); +#else + detail::activation_record * ptr = std::exchange( ptr_, nullptr)->resume(); +#endif + if ( BOOST_UNLIKELY( detail::activation_record::current()->force_unwind) ) { + throw detail::forced_unwind{ ptr}; + } else if ( BOOST_UNLIKELY( nullptr != detail::activation_record::current()->ontop) ) { + detail::activation_record::current()->ontop( ptr); + detail::activation_record::current()->ontop = nullptr; + } + return continuation{ ptr }; + } + + template< typename Fn > + continuation resume_with( Fn && fn) { +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::activation_record * ptr = + detail::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) ); +#else + detail::activation_record * ptr = + std::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) ); +#endif + if ( BOOST_UNLIKELY( detail::activation_record::current()->force_unwind) ) { + throw detail::forced_unwind{ ptr}; + } else if ( BOOST_UNLIKELY( nullptr != detail::activation_record::current()->ontop) ) { + detail::activation_record::current()->ontop( ptr); + detail::activation_record::current()->ontop = nullptr; + } + return continuation{ ptr }; + } + + explicit operator bool() const noexcept { + return nullptr != ptr_ && ! ptr_->terminated; + } + + bool operator!() const noexcept { + return nullptr == ptr_ || ptr_->terminated; + } + + bool operator==( continuation const& other) const noexcept { + return ptr_ == other.ptr_; + } + + bool operator!=( continuation const& other) const noexcept { + return ptr_ != other.ptr_; + } + + bool operator<( continuation const& other) const noexcept { + return ptr_ < other.ptr_; + } + + bool operator>( continuation const& other) const noexcept { + return other.ptr_ < ptr_; + } + + bool operator<=( continuation const& other) const noexcept { + return ! ( * this > other); + } + + bool operator>=( continuation 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, continuation const& other) { + if ( nullptr != other.ptr_) { + return os << other.ptr_; + } else { + return os << "{not-a-context}"; + } + } + + void swap( continuation & other) noexcept { + std::swap( ptr_, other.ptr_); + } +}; + +template< + typename Fn, + typename = detail::disable_overload< continuation, Fn > +> +continuation +callcc( Fn && fn) { + return callcc( + std::allocator_arg, + fixedsize_stack(), + std::forward< Fn >( fn) ); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn) { + return continuation{ + detail::create_context1< continuation >( + salloc, std::forward< Fn >( fn) ) }.resume(); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn) { + return continuation{ + detail::create_context2< continuation >( + palloc, salloc, std::forward< Fn >( fn) ) }.resume(); +} + +inline +void swap( continuation & l, continuation & r) noexcept { + l.swap( r); +} + +}} + +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_CONTINUATION_H diff --git a/boost/context/detail/config.hpp b/boost/context/detail/config.hpp index 84dd238100..15d03574b1 100644 --- a/boost/context/detail/config.hpp +++ b/boost/context/detail/config.hpp @@ -104,4 +104,15 @@ # endif #endif +#if ! defined(BOOST_NO_CXX11_CONSTEXPR) +// modern architectures have cachelines with 64byte length +// ARM Cortex-A15 32/64byte, Cortex-A9 16/32/64bytes +// MIPS 74K: 32byte, 4KEc: 16byte +// ist should be safe to use 64byte for all +static constexpr std::size_t cache_alignment{ 64 }; +static constexpr std::size_t cacheline_length{ 64 }; +// lookahead size for prefetching +static constexpr std::size_t prefetch_stride{ 4 * cacheline_length }; +#endif + #endif // BOOST_CONTEXT_DETAIL_CONFIG_H diff --git a/boost/context/detail/exception.hpp b/boost/context/detail/exception.hpp index 8ffff6780a..14b4ab5217 100644 --- a/boost/context/detail/exception.hpp +++ b/boost/context/detail/exception.hpp @@ -20,7 +20,9 @@ namespace context { namespace detail { struct forced_unwind { - fcontext_t fctx; + fcontext_t fctx{ nullptr }; + + forced_unwind() = default; forced_unwind( fcontext_t fctx_) : fctx( fctx_) { diff --git a/boost/context/detail/fcontext_arm.hpp b/boost/context/detail/fcontext_arm.hpp deleted file mode 100644 index 8b88ccfdd4..0000000000 --- a/boost/context/detail/fcontext_arm.hpp +++ /dev/null @@ -1,68 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// 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_FCONTEXT_ARM_H -#define BOOST_CONTEXT_DETAIL_FCONTEXT_ARM_H - -#include <cstddef> - -#include <boost/config.hpp> -#include <boost/cstdint.hpp> - -#include <boost/context/detail/config.hpp> - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { - -extern "C" { - -#define BOOST_CONTEXT_CALLDECL - -struct stack_t -{ - void * sp; - std::size_t size; - - stack_t() : - sp( 0), size( 0) - {} -}; - -struct fp_t -{ - boost::uint32_t fc_freg[16]; - - fp_t() : - fc_freg() - {} -}; - -struct fcontext_t -{ - boost::uint32_t fc_greg[11]; - stack_t fc_stack; - fp_t fc_fp; - - fcontext_t() : - fc_greg(), - fc_stack(), - fc_fp() - {} -}; - -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_DETAIL_FCONTEXT_ARM_H diff --git a/boost/context/detail/fcontext_arm_mac.hpp b/boost/context/detail/fcontext_arm_mac.hpp deleted file mode 100644 index a8416efd0c..0000000000 --- a/boost/context/detail/fcontext_arm_mac.hpp +++ /dev/null @@ -1,70 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// 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_FCONTEXT_ARM_MAC_H -#define BOOST_CONTEXT_DETAIL_FCONTEXT_ARM_MAC_H - -#include <cstddef> - -#include <boost/config.hpp> -#include <boost/cstdint.hpp> - -#include <boost/context/detail/config.hpp> - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { - -extern "C" { - -#define BOOST_CONTEXT_CALLDECL - -struct stack_t -{ - void * sp; - std::size_t size; - - stack_t() : - sp( 0), size( 0) - {} -}; - -struct fp_t -{ - boost::uint32_t fc_freg[16]; - - fp_t() : - fc_freg() - {} -}; - -struct fcontext_t -{ - boost::uint32_t fc_greg[11]; - stack_t fc_stack; - fp_t fc_fp; - void * fc_unwind_sjlj; - - fcontext_t() : - fc_greg(), - fc_stack(), - fc_fp(), - fc_unwind_sjlj( 0) - {} -}; - -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_DETAIL_FCONTEXT_ARM_MAC_H diff --git a/boost/context/detail/fcontext_arm_win.hpp b/boost/context/detail/fcontext_arm_win.hpp deleted file mode 100644 index 5449ae763f..0000000000 --- a/boost/context/detail/fcontext_arm_win.hpp +++ /dev/null @@ -1,71 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// 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_FCONTEXT_ARM_WIN_H -#define BOOST_CONTEXT_DETAIL_FCONTEXT_ARM_WIN_H - -#include <cstddef> - -#include <boost/config.hpp> -#include <boost/cstdint.hpp> - -#include <boost/context/detail/config.hpp> - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { - -extern "C" { - -#define BOOST_CONTEXT_CALLDECL - -struct stack_t -{ - void * sp; - std::size_t size; - void * limit; - - stack_t() : - sp( 0), size( 0), limit( 0) - {} -}; - -struct fp_t -{ - boost::uint32_t fc_freg[16]; - - fp_t() : - fc_freg() - {} -}; - -struct fcontext_t -{ - boost::uint32_t fc_greg[11]; - stack_t fc_stack; - fp_t fc_fp; - boost::uint32_t fc_dealloc; - - fcontext_t() : - fc_greg(), - fc_stack(), - fc_fp(), - fc_dealloc( 0) - {} -}; - -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_DETAIL_FCONTEXT_ARM_WIN_H diff --git a/boost/context/detail/fcontext_i386.hpp b/boost/context/detail/fcontext_i386.hpp deleted file mode 100644 index 2e01323556..0000000000 --- a/boost/context/detail/fcontext_i386.hpp +++ /dev/null @@ -1,59 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// 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_FCONTEXT_I386H -#define BOOST_CONTEXT_DETAIL_FCONTEXT_I386H - -#include <cstddef> - -#include <boost/config.hpp> -#include <boost/cstdint.hpp> - -#include <boost/context/detail/config.hpp> - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { - -extern "C" { - -#define BOOST_CONTEXT_CALLDECL __attribute__((cdecl)) - -struct stack_t -{ - void * sp; - std::size_t size; - - stack_t() : - sp( 0), size( 0) - {} -}; - -struct fcontext_t -{ - boost::uint32_t fc_greg[6]; - stack_t fc_stack; - boost::uint32_t fc_freg[2]; - - fcontext_t() : - fc_greg(), - fc_stack(), - fc_freg() - {} -}; - -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_DETAIL_FCONTEXT_I386_H diff --git a/boost/context/detail/fcontext_i386_win.hpp b/boost/context/detail/fcontext_i386_win.hpp deleted file mode 100644 index 44c6b0ef56..0000000000 --- a/boost/context/detail/fcontext_i386_win.hpp +++ /dev/null @@ -1,88 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// 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_FCONTEXT_I386H -#define BOOST_CONTEXT_DETAIL_FCONTEXT_I386H - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include <cstddef> - -#include <boost/config.hpp> -#include <boost/cstdint.hpp> - -#include <boost/context/detail/config.hpp> - -#if defined(BOOST_MSVC) -#pragma warning(push) -#pragma warning(disable:4351) -#endif - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { - -extern "C" { - -#define BOOST_CONTEXT_CALLDECL __cdecl - -struct stack_t -{ - void * sp; - std::size_t size; - void * limit; - - stack_t() : - sp( 0), size( 0), limit( 0) - {} -}; - -struct fp_t -{ - boost::uint32_t fc_freg[2]; - - fp_t() : - fc_freg() - {} -}; - -struct fcontext_t -{ - boost::uint32_t fc_greg[6]; - stack_t fc_stack; - void * fc_excpt_lst; - void * fc_local_storage; - fp_t fc_fp; - boost::uint32_t fc_dealloc; - - fcontext_t() : - fc_greg(), - fc_stack(), - fc_excpt_lst( 0), - fc_local_storage( 0), - fc_fp(), - fc_dealloc( 0) - {} -}; - -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#if defined(BOOST_MSVC) -#pragma warning(pop) -#endif - -#endif // BOOST_CONTEXT_DETAIL_FCONTEXT_I386_H diff --git a/boost/context/detail/fcontext_mips.hpp b/boost/context/detail/fcontext_mips.hpp deleted file mode 100644 index d3cd60de48..0000000000 --- a/boost/context/detail/fcontext_mips.hpp +++ /dev/null @@ -1,70 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// 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_FCONTEXT_MIPS_H -#define BOOST_CONTEXT_DETAIL_FCONTEXT_MIPS_H - -#include <cstddef> - -#include <boost/config.hpp> -#include <boost/cstdint.hpp> - -#include <boost/context/detail/config.hpp> - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { - -extern "C" { - -#define BOOST_CONTEXT_CALLDECL - -// on MIPS we assume 64bit regsiters - even for 32bit ABIs - -struct stack_t -{ - void * sp; - std::size_t size; - - stack_t() : - sp( 0), size( 0) - {} -}; - -struct fp_t -{ - boost::uint64_t fc_freg[6]; - - fp_t() : - fc_freg() - {} -}; - -struct fcontext_t -{ - boost::uint32_t fc_greg[12]; - stack_t fc_stack; - fp_t fc_fp; - - fcontext_t() : - fc_greg(), - fc_stack(), - fc_fp() - {} -}; - -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_DETAIL_FCONTEXT_MIPS_H diff --git a/boost/context/detail/fcontext_ppc.hpp b/boost/context/detail/fcontext_ppc.hpp deleted file mode 100644 index 6cb019f54f..0000000000 --- a/boost/context/detail/fcontext_ppc.hpp +++ /dev/null @@ -1,72 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// 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_FCONTEXT_PPC_H -#define BOOST_CONTEXT_DETAIL_FCONTEXT_PPC_H - -#include <cstddef> - -#include <boost/config.hpp> -#include <boost/cstdint.hpp> - -#include <boost/context/detail/config.hpp> - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { - -extern "C" { - -#define BOOST_CONTEXT_CALLDECL - -struct stack_t -{ - void * sp; - std::size_t size; - - stack_t() : - sp( 0), size( 0) - {} -}; - -struct fp_t -{ - boost::uint64_t fc_freg[19]; - - fp_t() : - fc_freg() - {} -}; - -struct fcontext_t -{ -# if defined(__powerpc64__) - boost::uint64_t fc_greg[23]; -# else - boost::uint32_t fc_greg[23]; -# endif - stack_t fc_stack; - fp_t fc_fp; - - fcontext_t() : - fc_greg(), - fc_stack(), - fc_fp() - {} -}; - -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_DETAIL_FCONTEXT_PPC_H diff --git a/boost/context/detail/fcontext_sparc.hpp b/boost/context/detail/fcontext_sparc.hpp deleted file mode 100644 index 9264714aee..0000000000 --- a/boost/context/detail/fcontext_sparc.hpp +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright Martin Husemann 2012 -// 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_CTX_DETAIL_FCONTEXT_SPARC_H -#define BOOST_CTX_DETAIL_FCONTEXT_SPARC_H - -#include <cstddef> - -#include <boost/config.hpp> -#include <boost/cstdint.hpp> - -#include <boost/context/detail/config.hpp> - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { - -extern "C" { - -#define BOOST_CONTEXT_CALLDECL - -// if defined(_LP64) we are compiling for sparc64, otherwise it is 32 bit -// sparc. - - -struct stack_t -{ - void * sp; - std::size_t size; - - stack_t() : - sp( 0), size( 0) - {} -}; - -struct fp_t -{ -#ifdef _LP64 - boost::uint64_t fp_freg[32]; - boost::uint64_t fp_fprs, fp_fsr; -#else - boost::uint64_t fp_freg[16]; - boost::uint32_t fp_fsr; -#endif - - fp_t() : - fp_freg(), -#ifdef _LP64 - fp_fprs(), -#endif - fp_fsr() - {} -} -#ifdef _LP64 - __attribute__((__aligned__(64))) // allow VIS instructions to be used -#endif -; - -struct fcontext_t -{ - fp_t fc_fp; // fpu stuff first, for easier alignement -#ifdef _LP64 - boost::uint64_t -#else - boost::uint32_t -#endif - fc_greg[8]; - stack_t fc_stack; - - fcontext_t() : - fc_fp(), - fc_greg(), - fc_stack() - {} -}; - -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CTX_DETAIL_FCONTEXT_SPARC_H diff --git a/boost/context/detail/fcontext_x86_64.hpp b/boost/context/detail/fcontext_x86_64.hpp deleted file mode 100644 index 6e8d93c0cb..0000000000 --- a/boost/context/detail/fcontext_x86_64.hpp +++ /dev/null @@ -1,68 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// 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_FCONTEXT_X86_64_H -#define BOOST_CONTEXT_DETAIL_FCONTEXT_X86_64_H - -#include <cstddef> - -#include <boost/config.hpp> -#include <boost/cstdint.hpp> - -#include <boost/context/detail/config.hpp> - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { - -extern "C" { - -#define BOOST_CONTEXT_CALLDECL - -struct stack_t -{ - void * sp; - std::size_t size; - - stack_t() : - sp( 0), size( 0) - {} -}; - -struct fp_t -{ - boost::uint32_t fc_freg[2]; - - fp_t() : - fc_freg() - {} -}; - -struct fcontext_t -{ - boost::uint64_t fc_greg[8]; - stack_t fc_stack; - fp_t fc_fp; - - fcontext_t() : - fc_greg(), - fc_stack(), - fc_fp() - {} -}; - -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_DETAIL_FCONTEXT_X86_64_H diff --git a/boost/context/detail/fcontext_x86_64_win.hpp b/boost/context/detail/fcontext_x86_64_win.hpp deleted file mode 100644 index 7bcea55fb3..0000000000 --- a/boost/context/detail/fcontext_x86_64_win.hpp +++ /dev/null @@ -1,77 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// 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_FCONTEXT_X86_64_H -#define BOOST_CONTEXT_DETAIL_FCONTEXT_X86_64_H - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include <cstddef> - -#include <boost/config.hpp> -#include <boost/cstdint.hpp> - -#include <boost/context/detail/config.hpp> - -#if defined(BOOST_MSVC) -#pragma warning(push) -#pragma warning(disable:4351) -#endif - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { - -extern "C" { - -#define BOOST_CONTEXT_CALLDECL - -struct stack_t -{ - void * sp; - std::size_t size; - void * limit; - - stack_t() : - sp( 0), size( 0), limit( 0) - {} -}; - -struct fcontext_t -{ - boost::uint64_t fc_greg[10]; - stack_t fc_stack; - void * fc_local_storage; - boost::uint64_t fc_fp[24]; - boost::uint64_t fc_dealloc; - - fcontext_t() : - fc_greg(), - fc_stack(), - fc_local_storage( 0), - fc_fp(), - fc_dealloc() - {} -}; - -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#if defined(BOOST_MSVC) -#pragma warning(pop) -#endif - -#endif // BOOST_CONTEXT_DETAIL_FCONTEXT_X86_64_H diff --git a/boost/context/detail/prefetch.hpp b/boost/context/detail/prefetch.hpp new file mode 100644 index 0000000000..a479450c74 --- /dev/null +++ b/boost/context/detail/prefetch.hpp @@ -0,0 +1,78 @@ +// Copyright Oliver Kowalke 2017. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CONTEXT_DETAIL_PREFETCH_H +#define BOOST_CONTEXT_DETAIL_PREFETCH_H + +#include <cstddef> +#include <cstdint> + +#include <boost/config.hpp> +#include <boost/predef.h> + +#include <boost/context/detail/config.hpp> + +#if BOOST_COMP_INTEL || BOOST_COMP_INTEL_EMULATED +#include <immintrin.h> +#endif + +#if BOOST_COMP_MSVC +#include <mmintrin.h> +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +#if BOOST_COMP_GNUC || BOOST_COMP_CLANG +#define BOOST_HAS_PREFETCH 1 +BOOST_FORCEINLINE +void prefetch( void * addr) { + // L1 cache : hint == 1 + __builtin_prefetch( addr, 1, 1); +} +#elif BOOST_COMP_INTEL || BOOST_COMP_INTEL_EMULATED +#define BOOST_HAS_PREFETCH 1 +BOOST_FORCEINLINE +void prefetch( void * addr) { + // L1 cache : hint == _MM_HINT_T0 + _mm_prefetch( (const char *)addr, _MM_HINT_T0); +} +#elif BOOST_COMP_MSVC +#define BOOST_HAS_PREFETCH 1 +BOOST_FORCEINLINE +void prefetch( void * addr) { + // L1 cache : hint == _MM_HINT_T0 + _mm_prefetch( (const char *)addr, _MM_HINT_T0); +} +#endif + +inline +void prefetch_range( void * addr, std::size_t len) { +#if defined(BOOST_HAS_PREFETCH) + void * vp = addr; + void * end = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( addr) + static_cast< uintptr_t >( len) ); + while ( vp < end) { + prefetch( vp); + vp = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( vp) + static_cast< uintptr_t >( prefetch_stride) ); + } +#endif +} + +#undef BOOST_HAS_PREFETCH + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_PREFETCH_H diff --git a/boost/context/fixedsize_stack.hpp b/boost/context/fixedsize_stack.hpp index 46e7866891..756b260bda 100644 --- a/boost/context/fixedsize_stack.hpp +++ b/boost/context/fixedsize_stack.hpp @@ -4,10 +4,77 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_CONTEXT_FIXEDSIZE_H +#define BOOST_CONTEXT_FIXEDSIZE_H + +#include <cstddef> +#include <cstdlib> +#include <new> + +#include <boost/assert.hpp> #include <boost/config.hpp> -#if defined(BOOST_WINDOWS) -# include <boost/context/windows/fixedsize_stack.hpp> -#else -# include <boost/context/posix/fixedsize_stack.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_fixedsize_stack { +private: + std::size_t size_; + +public: + typedef traitsT traits_type; + + basic_fixedsize_stack( std::size_t size = traits_type::default_size() ) BOOST_NOEXCEPT_OR_NOTHROW : + size_( size) { + } + + stack_context allocate() { + void * vp = std::malloc( size_); + if ( ! vp) { + throw std::bad_alloc(); + } + stack_context sctx; + sctx.size = 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); + +#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); + } +}; + +typedef basic_fixedsize_stack< stack_traits > fixedsize_stack; +# if ! defined(BOOST_USE_SEGMENTED_STACKS) +typedef fixedsize_stack default_stack; +# endif + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_FIXEDSIZE_H diff --git a/boost/context/pooled_fixedsize_stack.hpp b/boost/context/pooled_fixedsize_stack.hpp index 3c0953cd07..9c417fd7ce 100644 --- a/boost/context/pooled_fixedsize_stack.hpp +++ b/boost/context/pooled_fixedsize_stack.hpp @@ -14,6 +14,7 @@ #include <boost/assert.hpp> #include <boost/config.hpp> +#include <boost/intrusive_ptr.hpp> #include <boost/pool/pool.hpp> #include <boost/context/detail/config.hpp> diff --git a/boost/context/posix/fixedsize_stack.hpp b/boost/context/posix/fixedsize_stack.hpp deleted file mode 100644 index 756b260bda..0000000000 --- a/boost/context/posix/fixedsize_stack.hpp +++ /dev/null @@ -1,80 +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_FIXEDSIZE_H -#define BOOST_CONTEXT_FIXEDSIZE_H - -#include <cstddef> -#include <cstdlib> -#include <new> - -#include <boost/assert.hpp> -#include <boost/config.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_fixedsize_stack { -private: - std::size_t size_; - -public: - typedef traitsT traits_type; - - basic_fixedsize_stack( std::size_t size = traits_type::default_size() ) BOOST_NOEXCEPT_OR_NOTHROW : - size_( size) { - } - - stack_context allocate() { - void * vp = std::malloc( size_); - if ( ! vp) { - throw std::bad_alloc(); - } - stack_context sctx; - sctx.size = 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); - -#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); - } -}; - -typedef basic_fixedsize_stack< stack_traits > fixedsize_stack; -# if ! defined(BOOST_USE_SEGMENTED_STACKS) -typedef fixedsize_stack default_stack; -# endif - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_FIXEDSIZE_H diff --git a/boost/context/posix/protected_fixedsize_stack.hpp b/boost/context/posix/protected_fixedsize_stack.hpp index f36d451b40..b0c7f7e675 100644 --- a/boost/context/posix/protected_fixedsize_stack.hpp +++ b/boost/context/posix/protected_fixedsize_stack.hpp @@ -49,15 +49,13 @@ public: } stack_context allocate() { - // page at bottom will be used as guard-page - const std::size_t pages( - static_cast< std::size_t >( - std::floor( + // calculate how many pages are required + const std::size_t pages( + static_cast< std::size_t >( + std::ceil( static_cast< float >( size_) / traits_type::page_size() ) ) ); - BOOST_ASSERT_MSG( 2 <= pages, "at least two pages must fit into stack (one page is guard-page)"); - const std::size_t size__( pages * traits_type::page_size() ); - BOOST_ASSERT( 0 != size_ && 0 != size__); - BOOST_ASSERT( size__ <= size_); + // add one page at bottom that will be used as guard-page + const std::size_t size__ = ( pages + 1) * traits_type::page_size(); // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) #if defined(MAP_ANON) diff --git a/boost/context/windows/fixedsize_stack.hpp b/boost/context/windows/fixedsize_stack.hpp deleted file mode 100644 index a67c315c47..0000000000 --- a/boost/context/windows/fixedsize_stack.hpp +++ /dev/null @@ -1,80 +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_FIXEDSIZE_H -#define BOOST_CONTEXT_FIXEDSIZE_H - -extern "C" { -#include <windows.h> -} - -#include <cmath> -#include <cstddef> -#include <new> - -#include <boost/config.hpp> - -#include <boost/context/detail/config.hpp> -#include <boost/context/stack_context.hpp> -#include <boost/context/stack_traits.hpp> - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { - -template< typename traitsT > -class basic_fixedsize_stack { -private: - std::size_t size_; - -public: - typedef traitsT traits_type; - - basic_fixedsize_stack( std::size_t size = traits_type::default_size() ) BOOST_NOEXCEPT_OR_NOTHROW : - size_( size) { - } - - stack_context allocate() { - // page at bottom will be used as guard-page - const std::size_t pages( - static_cast< std::size_t >( - std::floor( - static_cast< float >( size_) / traits_type::page_size() ) ) ); - BOOST_ASSERT_MSG( 1 <= pages, "at least one page must fit into stack"); - const std::size_t size__( pages * traits_type::page_size() ); - BOOST_ASSERT( 0 != size_ && 0 != size__); - BOOST_ASSERT( size__ <= size_); - - void * vp = ::VirtualAlloc( 0, size__, MEM_COMMIT, PAGE_READWRITE); - if ( ! vp) throw std::bad_alloc(); - - stack_context sctx; - sctx.size = size__; - sctx.sp = static_cast< char * >( vp) + sctx.size; - return sctx; - } - - void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { - BOOST_ASSERT( sctx.sp); - - void * vp = static_cast< char * >( sctx.sp) - sctx.size; - ::VirtualFree( vp, 0, MEM_RELEASE); - } -}; - -typedef basic_fixedsize_stack< stack_traits > fixedsize_stack; -typedef fixedsize_stack default_stack; - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_FIXEDSIZE_H diff --git a/boost/context/windows/protected_fixedsize_stack.hpp b/boost/context/windows/protected_fixedsize_stack.hpp index 437f091088..26d2086095 100644 --- a/boost/context/windows/protected_fixedsize_stack.hpp +++ b/boost/context/windows/protected_fixedsize_stack.hpp @@ -41,15 +41,13 @@ public: } stack_context allocate() { - // page at bottom will be used as guard-page - const std::size_t pages( - static_cast< std::size_t >( - std::floor( + // calculate how many pages are required + const std::size_t pages( + static_cast< std::size_t >( + std::ceil( static_cast< float >( size_) / traits_type::page_size() ) ) ); - BOOST_ASSERT_MSG( 2 <= pages, "at least two pages must fit into stack (one page is guard-page)"); - const std::size_t size__( pages * traits_type::page_size() ); - BOOST_ASSERT( 0 != size_ && 0 != size__); - BOOST_ASSERT( size__ <= size_); + // add one page at bottom that will be used as guard-page + const std::size_t size__ = ( pages + 1) * traits_type::page_size(); void * vp = ::VirtualAlloc( 0, size__, MEM_COMMIT, PAGE_READWRITE); if ( ! vp) throw std::bad_alloc(); |