diff options
Diffstat (limited to 'boost/context')
-rw-r--r-- | boost/context/all.hpp | 13 | ||||
-rw-r--r-- | boost/context/detail/config.hpp | 34 | ||||
-rw-r--r-- | boost/context/execution_context.hpp | 307 | ||||
-rw-r--r-- | boost/context/fcontext.hpp | 2 | ||||
-rw-r--r-- | boost/context/fixedsize_stack.hpp | 81 | ||||
-rw-r--r-- | boost/context/posix/protected_fixedsize_stack.hpp | 112 | ||||
-rw-r--r-- | boost/context/posix/segmented_stack.hpp | 81 | ||||
-rw-r--r-- | boost/context/protected_fixedsize_stack.hpp | 13 | ||||
-rw-r--r-- | boost/context/segmented_stack.hpp | 13 | ||||
-rw-r--r-- | boost/context/stack_context.hpp | 67 | ||||
-rw-r--r-- | boost/context/stack_traits.hpp | 42 | ||||
-rw-r--r-- | boost/context/windows/protected_fixedsize_stack.hpp | 93 |
12 files changed, 846 insertions, 12 deletions
diff --git a/boost/context/all.hpp b/boost/context/all.hpp index 6bf7e8f190..152f299089 100644 --- a/boost/context/all.hpp +++ b/boost/context/all.hpp @@ -1,12 +1,13 @@ -// Copyright Oliver Kowalke 2009. +// 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_ALL_H -#define BOOST_CONTEXT_ALL_H - #include <boost/context/fcontext.hpp> - -#endif // BOOST_CONTEXT_ALL_H +#include <boost/context/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/config.hpp b/boost/context/detail/config.hpp index c30c8f8b84..28edf1f953 100644 --- a/boost/context/detail/config.hpp +++ b/boost/context/detail/config.hpp @@ -1,5 +1,5 @@ -// Copyright Oliver Kowalke 2009. +// 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) @@ -37,13 +37,37 @@ #undef BOOST_CONTEXT_CALLDECL #if (defined(i386) || defined(__i386__) || defined(__i386) \ - || defined(__i486__) || defined(__i586__) || defined(__i686__) \ - || defined(__X86__) || defined(_X86_) || defined(__THW_INTEL__) \ - || defined(__I86__) || defined(__INTEL__) || defined(__IA32__) \ - || defined(_M_IX86) || defined(_I86_)) && defined(BOOST_WINDOWS) + || defined(__i486__) || defined(__i586__) || defined(__i686__) \ + || defined(__X86__) || defined(_X86_) || defined(__THW_INTEL__) \ + || defined(__I86__) || defined(__INTEL__) || defined(__IA32__) \ + || defined(_M_IX86) || defined(_I86_)) && defined(BOOST_WINDOWS) # define BOOST_CONTEXT_CALLDECL __cdecl #else # define BOOST_CONTEXT_CALLDECL #endif +#if defined(BOOST_USE_SEGMENTED_STACKS) +# if ! ( (defined(__GNUC__) && __GNUC__ > 3 && __GNUC_MINOR__ > 6) || \ + (defined(__clang__) && __clang_major__ > 2 && __clang_minor__ > 3) ) +# error "compiler does not support segmented_stack stacks" +# endif +# define BOOST_CONTEXT_SEGMENTS 10 +#endif + +#undef BOOST_CONTEXT_NO_EXECUTION_CONTEXT +#if defined( BOOST_NO_CXX11_DECLTYPE) || \ + defined( BOOST_NO_CXX11_DELETED_FUNCTIONS) || \ + defined( BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) || \ + 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_VARIADIC_TEMPLATES) || \ + defined( BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES) +# define BOOST_CONTEXT_NO_EXECUTION_CONTEXT +#endif + #endif // BOOST_CONTEXT_DETAIL_CONFIG_H diff --git a/boost/context/execution_context.hpp b/boost/context/execution_context.hpp new file mode 100644 index 0000000000..4d809b0c21 --- /dev/null +++ b/boost/context/execution_context.hpp @@ -0,0 +1,307 @@ + +// 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 <cstddef> +# include <cstdint> +# include <cstdlib> +# include <exception> +# include <memory> +# 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/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 { + +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: + struct fcontext { + std::size_t use_count; + fcontext_t fctx; + stack_context sctx; + + // main-context + fcontext() noexcept : + use_count( 1), + fctx( nullptr), + sctx() { + } + + // worker-context + fcontext( fcontext_t fctx_, stack_context const& sctx_) noexcept : + use_count( 0), + fctx( fctx_), + sctx( sctx_) { + } + + virtual ~fcontext() noexcept { + } + + virtual void deallocate() { + } + + virtual void run() noexcept { + } + + friend void intrusive_ptr_add_ref( fcontext * ctx) { + ++ctx->use_count; + } + + friend void intrusive_ptr_release( fcontext * ctx) { + BOOST_ASSERT( nullptr != ctx); + + if ( 0 == --ctx->use_count) { + ctx->~fcontext(); + } + } + }; + + template< typename Fn, typename StackAlloc > + class worker_fcontext : public fcontext { + private: + StackAlloc salloc_; + Fn fn_; + + static void destroy( worker_fcontext * p) { + StackAlloc salloc( p->salloc_); + stack_context sctx( p->sctx); + p->~worker_fcontext(); + salloc.deallocate( sctx); + } + + public: + explicit worker_fcontext( stack_context sctx, StackAlloc const& salloc, fcontext_t fctx, Fn && fn) noexcept : + fcontext( fctx, sctx), + salloc_( salloc), + fn_( std::forward< Fn >( fn) ) { + } + + void deallocate() override final { + destroy( this); + } + + void run() noexcept override final { + fn_(); + } + }; + + static void entry_func( intptr_t p) noexcept { + BOOST_ASSERT( 0 != p); + + fcontext * bp( reinterpret_cast< fcontext * >( p) ); + BOOST_ASSERT( nullptr != bp); + + bp->run(); + } + + typedef boost::intrusive_ptr< fcontext > ptr_t; + + thread_local static fcontext main_ctx_; + thread_local static ptr_t current_ctx_; + + boost::intrusive_ptr< fcontext > ptr_; +# if defined(BOOST_USE_SEGMENTED_STACKS) + bool use_segmented_stack_ = false; +# endif + + template< typename StackAlloc, typename Fn > + static fcontext * create_context( StackAlloc salloc, Fn && fn) { + typedef worker_fcontext< Fn, StackAlloc > func_t; + + stack_context sctx( salloc.allocate() ); + // reserve space for control structure + std::size_t size = sctx.size - sizeof( func_t); + void * sp = static_cast< char * >( sctx.sp) - sizeof( func_t); +#if 0 + constexpr std::size_t func_alignment = 64; // alignof( func_t); + constexpr std::size_t func_size = sizeof( func_t); + // reserve space on stack + void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment; + // align sp pointer + sp = std::align( func_alignment, func_size, sp, func_size + func_alignment); + 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); + BOOST_ASSERT( nullptr != fctx); + // placment new for control structure on fast-context stack + return new ( sp) func_t( sctx, salloc, fctx, std::forward< Fn >( fn) ); + } + + template< typename StackAlloc, typename Fn > + static fcontext * create_context( preallocated palloc, StackAlloc salloc, Fn && fn) { + typedef worker_fcontext< Fn, StackAlloc > func_t; + + // reserve space for control structure + std::size_t size = palloc.size - sizeof( func_t); + void * sp = static_cast< char * >( palloc.sp) - sizeof( func_t); +#if 0 + constexpr std::size_t func_alignment = 64; // alignof( func_t); + constexpr std::size_t func_size = sizeof( func_t); + // reserve space on stack + void * sp = static_cast< char * >( palloc.sp) - func_size - func_alignment; + // align sp pointer + sp = std::align( func_alignment, func_size, sp, func_size + func_alignment); + 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); + BOOST_ASSERT( nullptr != fctx); + // placment new for control structure on fast-context stack + return new ( sp) func_t( palloc.sctx, salloc, fctx, std::forward< Fn >( fn) ); + } + + template< typename StackAlloc, typename Fn, typename Tpl, std::size_t ... I > + static fcontext * create_worker_fcontext( StackAlloc salloc, + Fn && fn_, Tpl && tpl_, + std::index_sequence< I ... >) { + return create_context( salloc, + [fn=std::forward< Fn >( fn_),tpl=std::forward< Tpl >( tpl_)] () mutable { + try { + fn( + // std::tuple_element<> does not perfect forwarding + std::forward< decltype( std::get< I >( std::declval< Tpl >() ) ) >( + std::get< I >( std::forward< Tpl >( tpl) ) ) ... ); + } catch (...) { + std::terminate(); + } + }); + } + + template< typename StackAlloc, typename Fn, typename Tpl, std::size_t ... I > + static fcontext * create_worker_fcontext( preallocated palloc, StackAlloc salloc, + Fn && fn_, Tpl && tpl_, + std::index_sequence< I ... >) { + return create_context( palloc, salloc, + [fn=std::forward< Fn >( fn_),tpl=std::forward< Tpl >( tpl_)] () mutable { + try { + fn( + // std::tuple_element<> does not perfect forwarding + std::forward< decltype( std::get< I >( std::declval< Tpl >() ) ) >( + std::get< I >( std::forward< Tpl >( tpl) ) ) ... ); + } catch (...) { + std::terminate(); + } + }); + } + + execution_context() : + ptr_( current_ctx_) { + } + +public: + static execution_context current() noexcept { + return execution_context(); + } + +# if defined(BOOST_USE_SEGMENTED_STACKS) + template< typename Fn, typename ... Args > + explicit execution_context( segmented_stack salloc, Fn && fn, Args && ... args) : + ptr_( create_worker_fcontext( salloc, + std::forward< Fn >( fn), + std::make_tuple( std::forward< Args >( args) ... ), + std::index_sequence_for< Args ... >() ) ), + use_segmented_stack_( true) { + } + + template< typename Fn, typename ... Args > + explicit execution_context( preallocated palloc, segmented_stack salloc, Fn && fn, Args && ... args) : + ptr_( create_worker_fcontext( palloc, salloc, + std::forward< Fn >( fn), + std::make_tuple( std::forward< Args >( args) ... ), + std::index_sequence_for< Args ... >() ) ), + use_segmented_stack_( true) { + } +# endif + + template< typename StackAlloc, typename Fn, typename ... Args > + explicit execution_context( StackAlloc salloc, Fn && fn, Args && ... args) : + ptr_( create_worker_fcontext( salloc, + std::forward< Fn >( fn), + std::make_tuple( std::forward< Args >( args) ... ), + std::index_sequence_for< Args ... >() ) ) { + } + + template< typename StackAlloc, typename Fn, typename ... Args > + explicit execution_context( preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args) : + ptr_( create_worker_fcontext( palloc, salloc, + std::forward< Fn >( fn), + std::make_tuple( std::forward< Args >( args) ... ), + std::index_sequence_for< Args ... >() ) ) { + } + + void resume( bool preserve_fpu = false) noexcept { + fcontext * old_ctx( current_ctx_.get() ); + fcontext * new_ctx( ptr_.get() ); + current_ctx_ = ptr_; +# if defined(BOOST_USE_SEGMENTED_STACKS) + if ( use_segmented_stack_) { + __splitstack_getcontext( old_ctx->sctx.segments_ctx); + __splitstack_setcontext( new_ctx->sctx.segments_ctx); + + jump_fcontext( & old_ctx->fctx, new_ctx->fctx, reinterpret_cast< intptr_t >( new_ctx), preserve_fpu); + + __splitstack_setcontext( old_ctx->sctx.segments_ctx); + } else { + jump_fcontext( & old_ctx->fctx, new_ctx->fctx, reinterpret_cast< intptr_t >( new_ctx), preserve_fpu); + } +# else + jump_fcontext( & old_ctx->fctx, new_ctx->fctx, reinterpret_cast< intptr_t >( new_ctx), preserve_fpu); +# endif + } +}; + +}} + +# ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +# endif + +#endif + +#endif // BOOST_CONTEXT_EXECUTION_CONTEXT_H diff --git a/boost/context/fcontext.hpp b/boost/context/fcontext.hpp index d054df290c..2ebcd46e38 100644 --- a/boost/context/fcontext.hpp +++ b/boost/context/fcontext.hpp @@ -31,7 +31,7 @@ typedef void* fcontext_t; extern "C" BOOST_CONTEXT_DECL intptr_t BOOST_CONTEXT_CALLDECL jump_fcontext( fcontext_t * ofc, fcontext_t nfc, - intptr_t vp, bool preserve_fpu = true); + intptr_t vp, bool preserve_fpu = false); extern "C" BOOST_CONTEXT_DECL fcontext_t BOOST_CONTEXT_CALLDECL make_fcontext( void * sp, std::size_t size, void (* fn)( intptr_t) ); diff --git a/boost/context/fixedsize_stack.hpp b/boost/context/fixedsize_stack.hpp new file mode 100644 index 0000000000..5acb5f47c0 --- /dev/null +++ b/boost/context/fixedsize_stack.hpp @@ -0,0 +1,81 @@ + +// 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() ) : + size_( size) { + BOOST_ASSERT( traits_type::minimum_size() <= size_); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_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_ASSERT( sctx.sp); + BOOST_ASSERT( traits_type::minimum_size() <= sctx.size); + 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; + std::free( vp); + } +}; + +typedef basic_fixedsize_stack< stack_traits > fixedsize_stack; + +}} + +#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 new file mode 100644 index 0000000000..c7e09439fc --- /dev/null +++ b/boost/context/posix/protected_fixedsize_stack.hpp @@ -0,0 +1,112 @@ + +// 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_PROTECTED_FIXEDSIZE_H +#define BOOST_CONTEXT_PROTECTED_FIXEDSIZE_H + +extern "C" { +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <unistd.h> +} + +#include <cmath> +#include <cstddef> +#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_protected_fixedsize_stack { +private: + std::size_t size_; + +public: + typedef traitsT traits_type; + + basic_protected_fixedsize_stack( std::size_t size = traits_type::default_size() ) : + size_( size) { + BOOST_ASSERT( traits_type::minimum_size() <= size_); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_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( 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_); + + // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) +#if defined(MAP_ANON) + void * vp = ::mmap( 0, size__, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); +#else + void * vp = ::mmap( 0, size__, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +#endif + if ( MAP_FAILED == vp) throw std::bad_alloc(); + + // conforming to POSIX.1-2001 +#if defined(BOOST_DISABLE_ASSERTS) + ::mprotect( vp, traits_type::page_size(), PROT_NONE); +#else + const int result( ::mprotect( vp, traits_type::page_size(), PROT_NONE) ); + BOOST_ASSERT( 0 == result); +#endif + + 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_ASSERT( sctx.sp); + BOOST_ASSERT( traits_type::minimum_size() <= sctx.size); + 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; + // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) + ::munmap( vp, sctx.size); + } +}; + +typedef basic_protected_fixedsize_stack< stack_traits > protected_fixedsize_stack; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_PROTECTED_FIXEDSIZE_H diff --git a/boost/context/posix/segmented_stack.hpp b/boost/context/posix/segmented_stack.hpp new file mode 100644 index 0000000000..f4a32d7394 --- /dev/null +++ b/boost/context/posix/segmented_stack.hpp @@ -0,0 +1,81 @@ + +// 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_SEGMENTED_H +#define BOOST_CONTEXT_SEGMENTED_H + +#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 + +// forward declaration for splitstack-functions defined in libgcc +extern "C" { +void *__splitstack_makecontext( std::size_t, + void * [BOOST_CONTEXT_SEGMENTS], + std::size_t *); + +void __splitstack_releasecontext( void * [BOOST_CONTEXT_SEGMENTS]); + +void __splitstack_resetcontext( void * [BOOST_CONTEXT_SEGMENTS]); + +void __splitstack_block_signals_context( void * [BOOST_CONTEXT_SEGMENTS], + int * new_value, int * old_value); +} + +namespace boost { +namespace context { + +template< typename traitsT > +class basic_segmented_stack { +private: + std::size_t size_; + +public: + typedef traitsT traits_type; + + basic_segmented_stack( std::size_t size = traits_type::default_size() ) : + size_( size) { + BOOST_ASSERT( traits_type::minimum_size() <= size_); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size_) ); + } + + stack_context allocate() { + stack_context sctx; + void * vp = __splitstack_makecontext( size_, sctx.segments_ctx, & sctx.size); + if ( ! vp) throw std::bad_alloc(); + + // sctx.size is already filled by __splitstack_makecontext + sctx.sp = static_cast< char * >( vp) + sctx.size; + + int off = 0; + __splitstack_block_signals_context( sctx.segments_ctx, & off, 0); + + return sctx; + } + + void deallocate( stack_context & sctx) { + __splitstack_releasecontext( sctx.segments_ctx); + } +}; + +typedef basic_segmented_stack< stack_traits > segmented_stack; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_SEGMENTED_H diff --git a/boost/context/protected_fixedsize_stack.hpp b/boost/context/protected_fixedsize_stack.hpp new file mode 100644 index 0000000000..a05aa73fe9 --- /dev/null +++ b/boost/context/protected_fixedsize_stack.hpp @@ -0,0 +1,13 @@ + +// Copyright Oliver Kowalke 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/config.hpp> + +#if defined(BOOST_WINDOWS) +# include <boost/context/windows/protected_fixedsize_stack.hpp> +#else +# include <boost/context/posix/protected_fixedsize_stack.hpp> +#endif diff --git a/boost/context/segmented_stack.hpp b/boost/context/segmented_stack.hpp new file mode 100644 index 0000000000..88e3e6a61f --- /dev/null +++ b/boost/context/segmented_stack.hpp @@ -0,0 +1,13 @@ + +// Copyright Oliver Kowalke 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/config.hpp> + +#if defined(BOOST_USE_SEGMENTED_STACKS) +# if ! defined(BOOST_WINDOWS) +# include <boost/context/posix/segmented_stack.hpp> +# endif +#endif diff --git a/boost/context/stack_context.hpp b/boost/context/stack_context.hpp new file mode 100644 index 0000000000..48863b3bc8 --- /dev/null +++ b/boost/context/stack_context.hpp @@ -0,0 +1,67 @@ + +// 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_STACK_CONTEXT_H +#define BOOST_CONTEXT_STACK_CONTEXT_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 { + +#if defined(BOOST_USE_SEGMENTED_STACKS) +struct stack_context { + typedef void * segments_context[BOOST_CONTEXT_SEGMENTS]; + + std::size_t size; + void * sp; + segments_context segments_ctx; +#if defined(BOOST_USE_VALGRIND) + unsigned valgrind_stack_id; +#endif + + stack_context() : + size( 0), + sp( 0), + segments_ctx() +#if defined(BOOST_USE_VALGRIND) + , valgrind_stack_id( 0) +#endif + {} +}; +#else +struct stack_context { + std::size_t size; + void * sp; +#if defined(BOOST_USE_VALGRIND) + unsigned valgrind_stack_id; +#endif + + stack_context() : + size( 0), + sp( 0) +#if defined(BOOST_USE_VALGRIND) + , valgrind_stack_id( 0) +#endif + {} +}; +#endif + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_STACK_CONTEXT_H diff --git a/boost/context/stack_traits.hpp b/boost/context/stack_traits.hpp new file mode 100644 index 0000000000..9b8a70636d --- /dev/null +++ b/boost/context/stack_traits.hpp @@ -0,0 +1,42 @@ + +// 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_STACK_TRAITS_H +#define BOOST_CONTEXT_STACK_TRAITS_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 BOOST_CONTEXT_DECL stack_traits +{ + static bool is_unbounded() BOOST_NOEXCEPT; + + static std::size_t page_size() BOOST_NOEXCEPT; + + static std::size_t default_size() BOOST_NOEXCEPT; + + static std::size_t minimum_size() BOOST_NOEXCEPT; + + static std::size_t maximum_size() BOOST_NOEXCEPT; +}; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_STACK_TRAITS_H diff --git a/boost/context/windows/protected_fixedsize_stack.hpp b/boost/context/windows/protected_fixedsize_stack.hpp new file mode 100644 index 0000000000..478c8c4ae1 --- /dev/null +++ b/boost/context/windows/protected_fixedsize_stack.hpp @@ -0,0 +1,93 @@ + +// 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_PROTECTED_FIXEDSIZE_H +#define BOOST_CONTEXT_PROTECTED_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_protected_fixedsize_stack { +private: + std::size_t size_; + +public: + typedef traitsT traits_type; + + basic_protected_fixedsize_stack( std::size_t size = traits_type::default_size() ) : + size_( size) { + BOOST_ASSERT( traits_type::minimum_size() <= size_); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_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( 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_); + + void * vp = ::VirtualAlloc( 0, size__, MEM_COMMIT, PAGE_READWRITE); + if ( ! vp) throw std::bad_alloc(); + + DWORD old_options; +#if defined(BOOST_DISABLE_ASSERTS) + ::VirtualProtect( + vp, traits_type::page_size(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); +#else + const BOOL result = ::VirtualProtect( + vp, traits_type::page_size(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); + BOOST_ASSERT( FALSE != result); +#endif + + stack_context sctx; + sctx.size = size__; + sctx.sp = static_cast< char * >( vp) + sctx.size; + return sctx; + } + + void deallocate( stack_context & sctx) { + BOOST_ASSERT( sctx.sp); + BOOST_ASSERT( traits_type::minimum_size() <= sctx.size); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= sctx.size) ); + + void * vp = static_cast< char * >( sctx.sp) - sctx.size; + ::VirtualFree( vp, 0, MEM_RELEASE); + } +}; + +typedef basic_protected_fixedsize_stack< stack_traits > protected_fixedsize_stack; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_PROTECTED_FIXEDSIZE_H |