From e721688e1a047fc1bc8407c9ae0324ab56e7ae03 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Sun, 5 Sep 2021 15:34:47 +0200 Subject: [PATCH] C++03 --- build/Jamfile.v2 | 6 +- include/boost/context/continuation.hpp | 13 - .../boost/context/continuation_fcontext.hpp | 370 ------------ .../boost/context/continuation_ucontext.hpp | 538 ------------------ include/boost/context/continuation_winfib.hpp | 473 --------------- include/boost/context/detail/config.hpp | 6 + .../boost/context/detail/disable_overload.hpp | 19 +- include/boost/context/detail/exception.hpp | 6 +- include/boost/context/detail/exchange.hpp | 7 +- include/boost/context/detail/fcontext.hpp | 10 + include/boost/context/fiber_fcontext.hpp | 217 ++++--- .../boost/context/pooled_fixedsize_stack.hpp | 30 +- include/boost/context/preallocated.hpp | 2 +- src/continuation.cpp | 58 -- test/Jamfile.v2 | 58 +- test/test_callcc.cpp | 516 ----------------- 16 files changed, 168 insertions(+), 2161 deletions(-) delete mode 100644 include/boost/context/continuation.hpp delete mode 100644 include/boost/context/continuation_fcontext.hpp delete mode 100644 include/boost/context/continuation_ucontext.hpp delete mode 100644 include/boost/context/continuation_winfib.hpp delete mode 100644 src/continuation.cpp delete mode 100644 test/test_callcc.cpp diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 98a1779..39e65bb 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -821,8 +821,7 @@ alias impl_sources # ucontext_t alias impl_sources - : continuation.cpp - fiber.cpp + : fiber.cpp : ucontext [ requires cxx11_auto_declarations cxx11_constexpr @@ -841,8 +840,7 @@ alias impl_sources # WinFiber alias impl_sources - : continuation.cpp - fiber.cpp + : fiber.cpp : winfib [ requires cxx11_auto_declarations cxx11_constexpr diff --git a/include/boost/context/continuation.hpp b/include/boost/context/continuation.hpp deleted file mode 100644 index 8db62a9..0000000 --- a/include/boost/context/continuation.hpp +++ /dev/null @@ -1,13 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#if defined(BOOST_USE_UCONTEXT) -#include -#elif defined(BOOST_USE_WINFIB) -#include -#else -#include -#endif diff --git a/include/boost/context/continuation_fcontext.hpp b/include/boost/context/continuation_fcontext.hpp deleted file mode 100644 index 881e6f2..0000000 --- a/include/boost/context/continuation_fcontext.hpp +++ /dev/null @@ -1,370 +0,0 @@ - -// 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 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) -#include -#endif -#if defined(BOOST_NO_CXX17_STD_INVOKE) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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& ex) { - t = { ex.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 - c = 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_; - typename std::decay< StackAlloc >::type salloc_; - typename std::decay< Fn >::type fn_; - - static void destroy( record * p) noexcept { - typename std::decay< StackAlloc >::type salloc = std::move( 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 && salloc, - Fn && fn) noexcept : - sctx_( sctx), - salloc_( std::forward< StackAlloc >( 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 = boost::context::detail::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, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; - // 64byte gab between control structure and stack top - // should be 16byte aligned - void * stack_top = reinterpret_cast< void * >( - reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) ); - void * stack_bottom = reinterpret_cast< void * >( - reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) ); - // create fast-context - const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom); - const fcontext_t fctx = make_fcontext( stack_top, size, & 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, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; - // 64byte gab between control structure and stack top - void * stack_top = reinterpret_cast< void * >( - reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) ); - void * stack_bottom = reinterpret_cast< void * >( - reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) ); - // create fast-context - const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom); - const fcontext_t fctx = make_fcontext( stack_top, size, & 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 { - swap( other); - } - - 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() & { - return std::move( * this).resume(); - } - - 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) & { - return std::move( * this).resume_with( std::forward< Fn >( fn) ); - } - - 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_; - } - - 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 >( - std::forward< StackAlloc >( 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, std::forward< StackAlloc >( 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 - -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/include/boost/context/continuation_ucontext.hpp b/include/boost/context/continuation_ucontext.hpp deleted file mode 100644 index 951e542..0000000 --- a/include/boost/context/continuation_ucontext.hpp +++ /dev/null @@ -1,538 +0,0 @@ - -// 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 -#if BOOST_OS_MACOS -#define _XOPEN_SOURCE 600 -#endif - -extern "C" { -#include -} - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) -#include -#endif -#include -#if defined(BOOST_NO_CXX17_STD_INVOKE) -#include -#endif -#include -#include -#include -#if defined(BOOST_USE_SEGMENTED_STACKS) -#include -#endif -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { -namespace detail { - -// tampoline function -// entered if the execution context -// is resumed for the first time -template< typename Record > -static void 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 { - ucontext_t uctx{}; - stack_context sctx{}; - bool main_ctx{ true }; - activation_record * from{ nullptr }; - std::function< activation_record*(activation_record*&) > ontop{}; - bool terminated{ false }; - bool force_unwind{ false }; -#if defined(BOOST_USE_ASAN) - void * fake_stack{ nullptr }; - void * stack_bottom{ nullptr }; - std::size_t stack_size{ 0 }; -#endif - - static 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"); - } - } - - 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 ( terminated) { - __sanitizer_start_switch_fiber( nullptr, stack_bottom, stack_size); - } else { - __sanitizer_start_switch_fiber( & from->fake_stack, stack_bottom, stack_size); - } -#endif - // context switch from parent context to `this`-context - ::swapcontext( & from->uctx, & uctx); -#if defined(BOOST_USE_ASAN) - __sanitizer_finish_switch_fiber( current()->fake_stack, - (const void **) & current()->from->stack_bottom, - & current()->from->stack_size); -#endif -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( current()->from, nullptr); -#else - return std::exchange( current()->from, nullptr); -#endif - } - - template< typename Ctx, typename Fn > - 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 }; - c = fn( std::move( c) ); - if ( ! c) { - ptr = nullptr; - } -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.ptr_, nullptr); -#else - return std::exchange( c.ptr_, nullptr); -#endif - }, - std::forward< Fn >( fn), - std::placeholders::_1); -#else - current()->ontop = [fn=std::forward(fn)](activation_record *& ptr){ - Ctx c{ ptr }; - c = fn( std::move( c) ); - if ( ! c) { - ptr = nullptr; - } -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.ptr_, nullptr); -#else - return std::exchange( c.ptr_, nullptr); -#endif - }; -#endif -#if defined(BOOST_USE_SEGMENTED_STACKS) - // adjust segmented stack properties - __splitstack_getcontext( from->sctx.segments_ctx); - __splitstack_setcontext( sctx.segments_ctx); -#endif -#if defined(BOOST_USE_ASAN) - __sanitizer_start_switch_fiber( & from->fake_stack, stack_bottom, stack_size); -#endif - // context switch from parent context to `this`-context - ::swapcontext( & from->uctx, & uctx); -#if defined(BOOST_USE_ASAN) - __sanitizer_finish_switch_fiber( current()->fake_stack, - (const void **) & current()->from->stack_bottom, - & current()->from->stack_size); -#endif -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( current()->from, nullptr); -#else - return std::exchange( current()->from, nullptr); -#endif - } - - virtual void deallocate() noexcept { - } -}; - -struct BOOST_CONTEXT_DECL 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: - typename std::decay< StackAlloc >::type salloc_; - typename std::decay< Fn >::type fn_; - - static void destroy( capture_record * p) noexcept { - typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_); - stack_context sctx = p->sctx; - // deallocate activation record - p->~capture_record(); - // destroy stack with stack allocator - salloc.deallocate( sctx); - } - -public: - capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept : - activation_record{ sctx }, - salloc_{ std::forward< StackAlloc >( salloc) }, - fn_( std::forward< Fn >( fn) ) { - } - - void deallocate() noexcept override final { - BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) ); - destroy( this); - } - - void run() { -#if defined(BOOST_USE_ASAN) - __sanitizer_finish_switch_fiber( fake_stack, - (const void **) & from->stack_bottom, - & from->stack_size); -#endif - Ctx c{ from }; - try { - // invoke context-function -#if defined(BOOST_NO_CXX17_STD_INVOKE) - c = boost::context::detail::invoke( fn_, std::move( c) ); -#else - c = std::invoke( fn_, std::move( c) ); -#endif - } catch ( forced_unwind const& ex) { - c = Ctx{ ex.from }; - } - // this context has finished its task - from = nullptr; - ontop = nullptr; - terminated = true; - force_unwind = false; - 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, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; - // stack bottom - void * stack_bottom = reinterpret_cast< void * >( - reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) ); - // create user-context - if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) { - record->~capture_t(); - salloc.deallocate( sctx); - 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, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; - // stack bottom - void * stack_bottom = reinterpret_cast< void * >( - reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) ); - // create user-context - if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) { - record->~capture_t(); - salloc.deallocate( palloc.sctx); - 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 { - swap( other); - } - - continuation & operator=( continuation && other) noexcept { - if ( BOOST_LIKELY( this != & other) ) { - continuation tmp = std::move( other); - swap( tmp); - } - return * this; - } - - continuation resume() & { - return std::move( * this).resume(); - } - - continuation resume() && { -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::activation_record * ptr = detail::exchange( ptr_, nullptr)->resume(); -#else - 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) ) { - ptr = detail::activation_record::current()->ontop( ptr); - detail::activation_record::current()->ontop = nullptr; - } - return { ptr }; - } - - template< typename Fn > - continuation resume_with( Fn && fn) & { - return std::move( * this).resume_with( std::forward< Fn >( fn) ); - } - - template< typename Fn > - continuation resume_with( Fn && fn) && { -#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) ) { - ptr = detail::activation_record::current()->ontop( ptr); - detail::activation_record::current()->ontop = nullptr; - } - return { ptr }; - } - - explicit operator bool() const noexcept { - return nullptr != ptr_ && ! ptr_->terminated; - } - - bool operator!() const noexcept { - return nullptr == ptr_ || ptr_->terminated; - } - - bool operator<( continuation const& other) const noexcept { - return ptr_ < other.ptr_; - } - - #if !defined(BOOST_EMBTC) - - 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}"; - } - } - - #else - - template< typename charT, class traitsT > - friend std::basic_ostream< charT, traitsT > & - operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other); - - #endif - - void swap( continuation & other) noexcept { - std::swap( ptr_, other.ptr_); - } -}; - -#if defined(BOOST_EMBTC) - - template< typename charT, class traitsT > - inline 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}"; - } - } - -#endif - -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 >( - std::forward< StackAlloc >( 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, std::forward< StackAlloc >( 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/include/boost/context/continuation_winfib.hpp b/include/boost/context/continuation_winfib.hpp deleted file mode 100644 index 856c868..0000000 --- a/include/boost/context/continuation_winfib.hpp +++ /dev/null @@ -1,473 +0,0 @@ - -// 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 - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) -#include -#endif -#if defined(BOOST_NO_CXX17_STD_INVOKE) -#include -#endif -#include -#include -#include -#include - -#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 { - LPVOID fiber{ nullptr }; - stack_context sctx{}; - bool main_ctx{ true }; - activation_record * from{ nullptr }; - std::function< activation_record*(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 }; - c = fn( std::move( c) ); - if ( ! c) { - ptr = nullptr; - } -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.ptr_, nullptr); -#else - return std::exchange( c.ptr_, nullptr); -#endif - }, - std::forward< Fn >( fn), - std::placeholders::_1); -#else - current()->ontop = [fn=std::forward(fn)](activation_record *& ptr){ - Ctx c{ ptr }; - c = fn( std::move( c) ); - if ( ! c) { - ptr = nullptr; - } -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.ptr_, nullptr); -#else - return std::exchange( c.ptr_, nullptr); -#endif - }; -#endif - // context switch - ::SwitchToFiber( fiber); -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return detail::exchange( current()->from, nullptr); -#else - return std::exchange( current()->from, nullptr); -#endif - } - - virtual void deallocate() noexcept { - } -}; - -struct BOOST_CONTEXT_DECL 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: - typename std::decay< StackAlloc >::type salloc_; - typename std::decay< Fn >::type fn_; - - static void destroy( capture_record * p) noexcept { - typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_); - stack_context sctx = p->sctx; - // deallocate activation record - p->~capture_record(); - // destroy stack with stack allocator - salloc.deallocate( sctx); - } - -public: - capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept : - activation_record( sctx), - salloc_( std::forward< StackAlloc >( salloc)), - fn_( std::forward< Fn >( fn) ) { - } - - void deallocate() noexcept override final { - BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) ); - destroy( this); - } - - void run() { - Ctx c{ from }; - try { - // invoke context-function -#if defined(BOOST_NO_CXX17_STD_INVOKE) - c = boost::context::detail::invoke( fn_, std::move( c) ); -#else - c = std::invoke( fn_, std::move( c) ); -#endif - } catch ( forced_unwind const& ex) { - c = Ctx{ ex.from }; - } - // this context has finished its task - from = nullptr; - ontop = nullptr; - terminated = true; - force_unwind = false; - 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, std::forward< StackAlloc >( 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, std::forward< StackAlloc >( 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 { - swap( other); - } - - continuation & operator=( continuation && other) noexcept { - if ( BOOST_LIKELY( this != & other) ) { - continuation tmp = std::move( other); - swap( tmp); - } - return * this; - } - - continuation resume() & { - return std::move( * this).resume(); - } - - continuation resume() && { -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::activation_record * ptr = detail::exchange( ptr_, nullptr)->resume(); -#else - 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) ) { - ptr = detail::activation_record::current()->ontop( ptr); - detail::activation_record::current()->ontop = nullptr; - } - return { ptr }; - } - - template< typename Fn > - continuation resume_with( Fn && fn) & { - return std::move( * this).resume_with( std::forward< Fn >( fn) ); - } - - template< typename Fn > - continuation resume_with( Fn && fn) && { -#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) ) { - ptr = detail::activation_record::current()->ontop( ptr); - detail::activation_record::current()->ontop = nullptr; - } - return { ptr }; - } - - explicit operator bool() const noexcept { - return nullptr != ptr_ && ! ptr_->terminated; - } - - bool operator!() const noexcept { - return nullptr == ptr_ || ptr_->terminated; - } - - bool operator<( continuation const& other) const noexcept { - return ptr_ < other.ptr_; - } - - #if !defined(BOOST_EMBTC) - - 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}"; - } - } - - #else - - template< typename charT, class traitsT > - friend std::basic_ostream< charT, traitsT > & - operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other); - - #endif - - void swap( continuation & other) noexcept { - std::swap( ptr_, other.ptr_); - } -}; - -#if defined(BOOST_EMBTC) - - template< typename charT, class traitsT > - inline 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}"; - } - } - -#endif - -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 >( - std::forward< StackAlloc >( 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, std::forward< StackAlloc >( 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/include/boost/context/detail/config.hpp b/include/boost/context/detail/config.hpp index 06737fd..c5de503 100644 --- a/include/boost/context/detail/config.hpp +++ b/include/boost/context/detail/config.hpp @@ -133,4 +133,10 @@ static constexpr std::size_t prefetch_stride{ 4 * cacheline_length }; # define BOOST_CONTEXT_USE_MAP_STACK #endif +#if defined(BOOST_NO_CXX11_NULLPTR) +# define BOOST_CONTEXT_NULLPTR 0 +#else +# define BOOST_CONTEXT_NULLPTR nullptr +#endif + #endif // BOOST_CONTEXT_DETAIL_CONFIG_H diff --git a/include/boost/context/detail/disable_overload.hpp b/include/boost/context/detail/disable_overload.hpp index c88f916..65b1990 100644 --- a/include/boost/context/detail/disable_overload.hpp +++ b/include/boost/context/detail/disable_overload.hpp @@ -7,9 +7,14 @@ #ifndef BOOST_CONTEXT_DETAIL_DISABLE_OVERLOAD_H #define BOOST_CONTEXT_DETAIL_DISABLE_OVERLOAD_H +#if ! defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) #include +#endif #include +#if defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) +#include +#endif #include @@ -21,15 +26,15 @@ namespace boost { namespace context { namespace detail { -// http://ericniebler.com/2013/08/07/universal-references-and-the-copy-constructo/ template< typename X, typename Y > -using disable_overload = - typename std::enable_if< - ! std::is_base_of< +struct disable_overload : public + boost::enable_if< + ! boost::is_base_of< X, - typename std::decay< Y >::type - >::value - >::type; + typename boost::decay< Y >::type + > + > +{}; }}} diff --git a/include/boost/context/detail/exception.hpp b/include/boost/context/detail/exception.hpp index 801201d..103572c 100644 --- a/include/boost/context/detail/exception.hpp +++ b/include/boost/context/detail/exception.hpp @@ -21,9 +21,11 @@ namespace context { namespace detail { struct forced_unwind { - fcontext_t fctx{ nullptr }; + fcontext_t fctx; - forced_unwind() = default; + forced_unwind() BOOST_NOEXCEPT_OR_NOTHROW : + fctx( BOOST_CONTEXT_NULLPTR) { + } forced_unwind( fcontext_t fctx_) : fctx( fctx_) { diff --git a/include/boost/context/detail/exchange.hpp b/include/boost/context/detail/exchange.hpp index c5ee912..9504da8 100644 --- a/include/boost/context/detail/exchange.hpp +++ b/include/boost/context/detail/exchange.hpp @@ -11,6 +11,7 @@ #include #include +#include #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -21,9 +22,9 @@ namespace context { namespace detail { template< typename T, typename U = T > -T exchange( T & t, U && nv) { - T ov = std::move( t); - t = std::forward< U >( nv); +T exchange( T & t, BOOST_RV_REF( U) nv) { + T ov = boost::move( t); + t = boost::forward< U >( nv); return ov; } diff --git a/include/boost/context/detail/fcontext.hpp b/include/boost/context/detail/fcontext.hpp index 00cb24d..87b6148 100644 --- a/include/boost/context/detail/fcontext.hpp +++ b/include/boost/context/detail/fcontext.hpp @@ -25,6 +25,16 @@ typedef void* fcontext_t; struct transfer_t { fcontext_t fctx; void * data; + + transfer_t() BOOST_NOEXCEPT : + fctx( BOOST_CONTEXT_NULLPTR), + data( BOOST_CONTEXT_NULLPTR) { + } + + transfer_t( fcontext_t fctx_, void * data_) BOOST_NOEXCEPT : + fctx( fctx_), + data( data_) { + } }; extern "C" BOOST_CONTEXT_DECL diff --git a/include/boost/context/fiber_fcontext.hpp b/include/boost/context/fiber_fcontext.hpp index 88d7793..839c475 100644 --- a/include/boost/context/fiber_fcontext.hpp +++ b/include/boost/context/fiber_fcontext.hpp @@ -17,12 +17,13 @@ #include #include #include -#include #include #include #include -#include +#include +#include +#include #if defined(BOOST_NO_CXX14_STD_EXCHANGE) #include @@ -33,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -56,32 +56,32 @@ namespace detail { inline transfer_t fiber_unwind( transfer_t t) { throw forced_unwind( t.fctx); - return { nullptr, nullptr }; + return transfer_t( BOOST_CONTEXT_NULLPTR, BOOST_CONTEXT_NULLPTR); } template< typename Rec > -transfer_t fiber_exit( transfer_t t) noexcept { +transfer_t fiber_exit( transfer_t t) BOOST_NOEXCEPT_OR_NOTHROW { Rec * rec = static_cast< Rec * >( t.data); // destroy context stack rec->deallocate(); - return { nullptr, nullptr }; + return transfer_t( BOOST_CONTEXT_NULLPTR, BOOST_CONTEXT_NULLPTR); } template< typename Rec > -void fiber_entry( transfer_t t) noexcept { +void fiber_entry( transfer_t t) BOOST_NOEXCEPT_OR_NOTHROW { // transfer control structure to the context-stack Rec * rec = static_cast< Rec * >( t.data); - BOOST_ASSERT( nullptr != t.fctx); - BOOST_ASSERT( nullptr != rec); + BOOST_ASSERT( BOOST_CONTEXT_NULLPTR != t.fctx); + BOOST_ASSERT( BOOST_CONTEXT_NULLPTR != rec); try { // jump back to `create_context()` - t = jump_fcontext( t.fctx, nullptr); + t = jump_fcontext( t.fctx, BOOST_CONTEXT_NULLPTR); // start executing t.fctx = rec->run( t.fctx); } catch ( forced_unwind const& ex) { - t = { ex.fctx, nullptr }; + t = transfer_t( ex.fctx, BOOST_CONTEXT_NULLPTR); } - BOOST_ASSERT( nullptr != t.fctx); + BOOST_ASSERT( BOOST_CONTEXT_NULLPTR != t.fctx); // destroy context-stack of `this`context on next context ontop_fcontext( t.fctx, rec, fiber_exit< Rec >); BOOST_ASSERT_MSG( false, "context already terminated"); @@ -89,15 +89,15 @@ void fiber_entry( transfer_t t) noexcept { template< typename Ctx, typename Fn > transfer_t fiber_ontop( transfer_t t) { - BOOST_ASSERT( nullptr != t.data); + BOOST_ASSERT( BOOST_CONTEXT_NULLPTR != t.data); auto p = *static_cast< Fn * >( t.data); - t.data = nullptr; + t.data = BOOST_CONTEXT_NULLPTR; // execute function, pass fiber via reference - Ctx c = p( Ctx{ t.fctx } ); + Ctx c = p( Ctx( t.fctx) ); #if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return { exchange( c.fctx_, nullptr), nullptr }; + return transfer_t( exchange( c.fctx_, BOOST_CONTEXT_NULLPTR), BOOST_CONTEXT_NULLPTR); #else - return { std::exchange( c.fctx_, nullptr), nullptr }; + return transfer_t( std::exchange( c.fctx_, BOOST_CONTEXT_NULLPTR), BOOST_CONTEXT_NULLPTR); #endif } @@ -105,11 +105,11 @@ template< typename Ctx, typename StackAlloc, typename Fn > class fiber_record { private: stack_context sctx_; - typename std::decay< StackAlloc >::type salloc_; - typename std::decay< Fn >::type fn_; + typename boost::decay< StackAlloc >::type salloc_; + typename boost::decay< Fn >::type fn_; - static void destroy( fiber_record * p) noexcept { - typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_); + static void destroy( fiber_record * p) BOOST_NOEXCEPT_OR_NOTHROW { + typename boost::decay< StackAlloc >::type salloc = boost::move( p->salloc_); stack_context sctx = p->sctx_; // deallocate fiber_record p->~fiber_record(); @@ -118,45 +118,45 @@ private: } public: - fiber_record( stack_context sctx, StackAlloc && salloc, - Fn && fn) noexcept : + fiber_record( stack_context sctx, BOOST_RV_REF( StackAlloc) salloc, + BOOST_RV_REF( Fn) fn) BOOST_NOEXCEPT_OR_NOTHROW : sctx_( sctx), - salloc_( std::forward< StackAlloc >( salloc)), - fn_( std::forward< Fn >( fn) ) { + salloc_( boost::forward< StackAlloc >( salloc) ), + fn_( boost::forward< Fn >( fn) ) { } - fiber_record( fiber_record const&) = delete; - fiber_record & operator=( fiber_record const&) = delete; + BOOST_DELETED_FUNCTION( fiber_record( fiber_record const&) ); + BOOST_DELETED_FUNCTION( fiber_record & operator=( fiber_record const&) ); - void deallocate() noexcept { + void deallocate() BOOST_NOEXCEPT_OR_NOTHROW { destroy( this); } fcontext_t run( fcontext_t fctx) { // invoke context-function #if defined(BOOST_NO_CXX17_STD_INVOKE) - Ctx c = boost::context::detail::invoke( fn_, Ctx{ fctx } ); + Ctx c = boost::context::detail::invoke( fn_, Ctx( fctx) ); #else Ctx c = std::invoke( fn_, Ctx{ fctx } ); #endif #if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.fctx_, nullptr); + return exchange( c.fctx_, BOOST_CONTEXT_NULLPTR); #else - return std::exchange( c.fctx_, nullptr); + return std::exchange( c.fctx_, BOOST_CONTEXT_NULLPTR); #endif } }; template< typename Record, typename StackAlloc, typename Fn > -fcontext_t create_fiber1( StackAlloc && salloc, Fn && fn) { +fcontext_t create_fiber1( BOOST_RV_REF( StackAlloc) salloc, BOOST_RV_REF( 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) ); + ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( Record) ) ) + & ~static_cast< uintptr_t >( 0xff) ); // placment new for control structure on context stack - Record * record = new ( storage) Record{ - sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; + Record * record = new ( storage) Record( + sctx, boost::forward< StackAlloc >( salloc), boost::forward< Fn >( fn) ); // 64byte gab between control structure and stack top // should be 16byte aligned void * stack_top = reinterpret_cast< void * >( @@ -164,31 +164,35 @@ fcontext_t create_fiber1( StackAlloc && salloc, Fn && fn) { 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 std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - + reinterpret_cast< uintptr_t >( stack_bottom); const fcontext_t fctx = make_fcontext( stack_top, size, & fiber_entry< Record >); - BOOST_ASSERT( nullptr != fctx); + BOOST_ASSERT( BOOST_CONTEXT_NULLPTR != fctx); // transfer control structure to context-stack return jump_fcontext( fctx, record).fctx; } template< typename Record, typename StackAlloc, typename Fn > -fcontext_t create_fiber2( preallocated palloc, StackAlloc && salloc, Fn && fn) { +fcontext_t create_fiber2( preallocated palloc, BOOST_RV_REF( StackAlloc) salloc, + BOOST_RV_REF( 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) ); + ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( Record) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); // placment new for control structure on context-stack - Record * record = new ( storage) Record{ - palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; + Record * record = new ( storage) Record( + palloc.sctx, boost::forward< StackAlloc >( salloc), boost::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) ); + 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 std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - + reinterpret_cast< uintptr_t >( stack_bottom); const fcontext_t fctx = make_fcontext( stack_top, size, & fiber_entry< Record >); - BOOST_ASSERT( nullptr != fctx); + BOOST_ASSERT( BOOST_CONTEXT_NULLPTR != fctx); // transfer control structure to context-stack return jump_fcontext( fctx, record).fctx; } @@ -204,110 +208,105 @@ private: friend detail::transfer_t detail::fiber_ontop( detail::transfer_t); - template< typename StackAlloc, typename Fn > - friend fiber - callcc( std::allocator_arg_t, StackAlloc &&, Fn &&); + detail::fcontext_t fctx_; - template< typename StackAlloc, typename Fn > - friend fiber - callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&); - - detail::fcontext_t fctx_{ nullptr }; - - fiber( detail::fcontext_t fctx) noexcept : - fctx_{ fctx } { + fiber( detail::fcontext_t fctx) BOOST_NOEXCEPT_OR_NOTHROW : + fctx_( fctx) { } public: - fiber() noexcept = default; + fiber() BOOST_NOEXCEPT_OR_NOTHROW : + fctx_( BOOST_CONTEXT_NULLPTR) { + } template< typename Fn, typename = detail::disable_overload< fiber, Fn > > - fiber( Fn && fn) : - fiber{ std::allocator_arg, fixedsize_stack(), std::forward< Fn >( fn) } { + fiber( BOOST_RV_REF( Fn) fn) : + fctx_( detail::create_fiber1< detail::fiber_record< fiber, fixedsize_stack, Fn > >( + fixedsize_stack(), boost::forward< Fn >( fn) ) ) { } template< typename StackAlloc, typename Fn > - fiber( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) : - fctx_{ detail::create_fiber1< detail::fiber_record< fiber, StackAlloc, Fn > >( - std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } { + fiber( std::allocator_arg_t, BOOST_RV_REF( StackAlloc) salloc, BOOST_RV_REF( Fn) fn) : + fctx_( detail::create_fiber1< detail::fiber_record< fiber, StackAlloc, Fn > >( + boost::forward< StackAlloc >( salloc), boost::forward< Fn >( fn) ) ) { } template< typename StackAlloc, typename Fn > - fiber( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) : - fctx_{ detail::create_fiber2< detail::fiber_record< fiber, StackAlloc, Fn > >( - palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } { + fiber( std::allocator_arg_t, preallocated palloc, BOOST_RV_REF( StackAlloc) salloc, + BOOST_RV_REF( Fn) fn) : + fctx_( detail::create_fiber2< detail::fiber_record< fiber, StackAlloc, Fn > >( + palloc, boost::forward< StackAlloc >( salloc), boost::forward< Fn >( fn) ) ) { } -#if defined(BOOST_USE_SEGMENTED_STACKS) - template< typename Fn > - fiber( std::allocator_arg_t, segmented_stack, Fn &&); - - template< typename StackAlloc, typename Fn > - fiber( std::allocator_arg_t, preallocated, segmented_stack, Fn &&); -#endif - ~fiber() { - if ( BOOST_UNLIKELY( nullptr != fctx_) ) { + if ( BOOST_UNLIKELY( BOOST_CONTEXT_NULLPTR != fctx_) ) { detail::ontop_fcontext( #if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( fctx_, nullptr), + detail::exchange( fctx_, BOOST_CONTEXT_NULLPTR), #else - std::exchange( fctx_, nullptr), + std::exchange( fctx_, BOOST_CONTEXT_NULLPTR), #endif - nullptr, + BOOST_CONTEXT_NULLPTR, detail::fiber_unwind); } } - fiber( fiber && other) noexcept { + fiber( BOOST_RV_REF( fiber) other) BOOST_NOEXCEPT_OR_NOTHROW : + fctx_( BOOST_CONTEXT_NULLPTR) { swap( other); } - fiber & operator=( fiber && other) noexcept { + fiber & operator=( BOOST_RV_REF( fiber) other) BOOST_NOEXCEPT_OR_NOTHROW { if ( BOOST_LIKELY( this != & other) ) { - fiber tmp = std::move( other); + fiber tmp = boost::move( other); swap( tmp); } return * this; } - fiber( fiber const& other) noexcept = delete; - fiber & operator=( fiber const& other) noexcept = delete; + BOOST_DELETED_FUNCTION( fiber( fiber const& other) BOOST_NOEXCEPT_OR_NOTHROW); + BOOST_DELETED_FUNCTION( fiber & operator=( fiber const& other) BOOST_NOEXCEPT_OR_NOTHROW); - fiber resume() && { - BOOST_ASSERT( nullptr != fctx_); - return { detail::jump_fcontext( -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( fctx_, nullptr), -#else - std::exchange( fctx_, nullptr), + fiber resume() +#if ! defined(BOOST_NO_CXX11_REF_QUALIFIERS) + && #endif - nullptr).fctx }; + { + BOOST_ASSERT( BOOST_CONTEXT_NULLPTR != fctx_); + return fiber( detail::jump_fcontext( +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::exchange( fctx_, BOOST_CONTEXT_NULLPTR), +#else + std::exchange( fctx_, BOOST_CONTEXT_NULLPTR), +#endif + BOOST_CONTEXT_NULLPTR).fctx); } template< typename Fn > - fiber resume_with( Fn && fn) && { - BOOST_ASSERT( nullptr != fctx_); - auto p = std::forward< Fn >( fn); - return { detail::ontop_fcontext( + fiber resume_with( BOOST_RV_REF( Fn) fn) +#if ! defined(BOOST_NO_CXX11_REF_QUALIFIERS) + && +#endif + { + BOOST_ASSERT( BOOST_CONTEXT_NULLPTR != fctx_); + auto p = boost::forward< Fn >( fn); + return fiber( detail::ontop_fcontext( #if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( fctx_, nullptr), + detail::exchange( fctx_, BOOST_CONTEXT_NULLPTR), #else - std::exchange( fctx_, nullptr), + std::exchange( fctx_, BOOST_CONTEXT_NULLPTR), #endif & p, - detail::fiber_ontop< fiber, decltype(p) >).fctx }; + detail::fiber_ontop< fiber, decltype(p) >).fctx); // FIXME: decltype } - explicit operator bool() const noexcept { - return nullptr != fctx_; + BOOST_EXPLICIT_OPERATOR_BOOL(); + + bool operator!() const BOOST_NOEXCEPT_OR_NOTHROW { + return BOOST_CONTEXT_NULLPTR == fctx_; } - bool operator!() const noexcept { - return nullptr == fctx_; - } - - bool operator<( fiber const& other) const noexcept { + bool operator<( fiber const& other) const BOOST_NOEXCEPT_OR_NOTHROW { return fctx_ < other.fctx_; } @@ -316,7 +315,7 @@ public: template< typename charT, class traitsT > friend std::basic_ostream< charT, traitsT > & operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) { - if ( nullptr != other.fctx_) { + if ( BOOST_CONTEXT_NULLPTR != other.fctx_) { return os << other.fctx_; } else { return os << "{not-a-context}"; @@ -331,7 +330,7 @@ public: #endif - void swap( fiber & other) noexcept { + void swap( fiber & other) BOOST_NOEXCEPT_OR_NOTHROW { std::swap( fctx_, other.fctx_); } }; @@ -341,7 +340,7 @@ public: template< typename charT, class traitsT > inline std::basic_ostream< charT, traitsT > & operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) { - if ( nullptr != other.fctx_) { + if ( BOOST_CONTEXT_NULLPTR != other.fctx_) { return os << other.fctx_; } else { return os << "{not-a-context}"; @@ -351,7 +350,7 @@ public: #endif inline -void swap( fiber & l, fiber & r) noexcept { +void swap( fiber & l, fiber & r) BOOST_NOEXCEPT_OR_NOTHROW { l.swap( r); } diff --git a/include/boost/context/pooled_fixedsize_stack.hpp b/include/boost/context/pooled_fixedsize_stack.hpp index c115c86..74fa229 100644 --- a/include/boost/context/pooled_fixedsize_stack.hpp +++ b/include/boost/context/pooled_fixedsize_stack.hpp @@ -4,15 +4,20 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_CONTEXT_POOLED_pooled_fixedsize_H -#define BOOST_CONTEXT_POOLED_pooled_fixedsize_H +#ifndef BOOST_CONTEXT_POOLED_POOLED_FIXEDSIZE_H +#define BOOST_CONTEXT_POOLED_POOLED_FIXEDSIZE_H +#if ! defined(BOOST_NO_CXX11_HDR_ATOMIC) #include +#endif #include #include #include #include +#if defined(BOOST_NO_CXX11_HDR_ATOMIC) +#include +#endif #include #include #include @@ -43,20 +48,21 @@ namespace context { namespace detail { template< typename traitsT > struct map_stack_allocator { - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; - static char * malloc( const size_type bytes) { - void * block; - if ( ::posix_memalign( &block, traitsT::page_size(), bytes) != 0) { + static char * malloc( size_type bytes) { + void * block = BOOST_CONTEXT_NULLPTR; + if ( 0 != ::posix_memalign( &block, traitsT::page_size(), bytes) ) { return 0; } - if ( mmap( block, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_STACK, -1, 0) == MAP_FAILED) { + if ( MAP_FAILED == ::mmap( block, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_STACK, -1, 0) ) { std::free( block); - return 0; + return BOOST_CONTEXT_NULLPTR; } return reinterpret_cast< char * >( block); } + static void free( char * const block) { std::free( block); } @@ -69,7 +75,11 @@ class basic_pooled_fixedsize_stack { private: class storage { private: +#if ! defined(BOOST_NO_CXX11_HDR_ATOMIC) std::atomic< std::size_t > use_count_; +#else + boost::atomic< std::size_t > use_count_; +#endif std::size_t stack_size_; #if defined(BOOST_CONTEXT_USE_MAP_STACK) boost::pool< detail::map_stack_allocator< traitsT > > storage_; @@ -149,4 +159,4 @@ typedef basic_pooled_fixedsize_stack< stack_traits > pooled_fixedsize_stack; # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_CONTEXT_POOLED_pooled_fixedsize_H +#endif // BOOST_CONTEXT_POOLED_POOLED_FIXEDSIZE_H diff --git a/include/boost/context/preallocated.hpp b/include/boost/context/preallocated.hpp index 862a6a5..a004899 100644 --- a/include/boost/context/preallocated.hpp +++ b/include/boost/context/preallocated.hpp @@ -25,7 +25,7 @@ struct preallocated { std::size_t size; stack_context sctx; - preallocated( void * sp_, std::size_t size_, stack_context sctx_) noexcept : + preallocated( void * sp_, std::size_t size_, stack_context sctx_) BOOST_NOEXCEPT_OR_NOTHROW : sp( sp_), size( size_), sctx( sctx_) { } }; diff --git a/src/continuation.cpp b/src/continuation.cpp deleted file mode 100644 index 2d77696..0000000 --- a/src/continuation.cpp +++ /dev/null @@ -1,58 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#if defined(BOOST_USE_UCONTEXT) -#include "boost/context/continuation_ucontext.hpp" -#elif defined(BOOST_USE_WINFIB) -#include "boost/context/continuation_winfib.hpp" -#endif - -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { -namespace detail { - -// zero-initialization -thread_local activation_record * current_rec; -thread_local static std::size_t counter; - -// schwarz counter -activation_record_initializer::activation_record_initializer() noexcept { - if ( 0 == counter++) { - current_rec = new activation_record(); - } -} - -activation_record_initializer::~activation_record_initializer() { - if ( 0 == --counter) { - BOOST_ASSERT( current_rec->is_main_context() ); - delete current_rec; - } -} - -} - -namespace detail { - -activation_record *& -activation_record::current() noexcept { - // initialized the first time control passes; per thread - thread_local static activation_record_initializer initializer; - return current_rec; -} - -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 78b9129..91e3f22 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -148,63 +148,7 @@ test-suite minimal : cxx11_template_aliases cxx11_thread_local cxx11_variadic_templates ] - : test_fiber_segmented ] - -[ run test_callcc.cpp : - : : - fcontext - [ requires cxx11_auto_declarations - cxx11_constexpr - cxx11_defaulted_functions - cxx11_final - cxx11_hdr_thread - cxx11_hdr_tuple - cxx11_lambdas - cxx11_noexcept - cxx11_nullptr - cxx11_rvalue_references - cxx11_template_aliases - cxx11_thread_local - cxx11_variadic_templates ] - : test_callcc_asm ] - -[ run test_callcc.cpp : - : : - @native-impl - [ requires cxx11_auto_declarations - cxx11_constexpr - cxx11_defaulted_functions - cxx11_final - cxx11_hdr_thread - cxx11_hdr_tuple - cxx11_lambdas - cxx11_noexcept - cxx11_nullptr - cxx11_rvalue_references - cxx11_template_aliases - cxx11_thread_local - cxx11_variadic_templates ] - : test_callcc_native ] - -[ run test_callcc.cpp : - : : - ucontext - @segmented-stack - [ requires cxx11_auto_declarations - cxx11_constexpr - cxx11_defaulted_functions - cxx11_final - cxx11_hdr_thread - cxx11_hdr_tuple - cxx11_lambdas - cxx11_noexcept - cxx11_nullptr - cxx11_rvalue_references - cxx11_template_aliases - cxx11_thread_local - cxx11_variadic_templates ] - : test_callcc_segmented ] ; - + : test_fiber_segmented ] ; test-suite full : minimal ; diff --git a/test/test_callcc.cpp b/test/test_callcc.cpp deleted file mode 100644 index 7ba783e..0000000 --- a/test/test_callcc.cpp +++ /dev/null @@ -1,516 +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) - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef BOOST_WINDOWS -#include -#endif - -#if defined(BOOST_MSVC) -# pragma warning(push) -# pragma warning(disable: 4702 4723 4996) -#endif - -typedef boost::variant variant_t; - -namespace ctx = boost::context; - -int value1 = 0; -std::string value2; -double value3 = 0.; - -struct X { - ctx::continuation foo( ctx::continuation && c, int i) { - value1 = i; - return std::move( c); - } -}; - -struct Y { - Y() { - value1 = 3; - } - - Y( Y const&) = delete; - Y & operator=( Y const&) = delete; - - ~Y() { - value1 = 7; - } -}; - -class moveable { -public: - bool state; - int value; - - moveable() : - state( false), - value( -1) { - } - - moveable( int v) : - state( true), - value( v) { - } - - moveable( moveable && other) : - state( other.state), - value( other.value) { - other.state = false; - other.value = -1; - } - - moveable & operator=( moveable && other) { - if ( this == & other) return * this; - state = other.state; - value = other.value; - other.state = false; - other.value = -1; - return * this; - } - - moveable( moveable const& other) = delete; - moveable & operator=( moveable const& other) = delete; - - void operator()() { - value1 = value; - } -}; - -struct my_exception : public std::runtime_error { - ctx::continuation c; - my_exception( ctx::continuation && c_, char const* what) : - std::runtime_error( what), - c{ std::move( c_) } { - } -}; - -#ifdef BOOST_MSVC -// Optimizations can remove the integer-divide-by-zero here. -#pragma optimize("", off) -void seh( bool & catched) { - __try { - int i = 1; - i /= 0; - } __except( EXCEPTION_EXECUTE_HANDLER) { - catched = true; - } -} -#pragma optimize("", on) -#endif - -void test_move() { - value1 = 0; - int i = 1; - BOOST_CHECK_EQUAL( 0, value1); - ctx::continuation c1 = ctx::callcc( - [&i](ctx::continuation && c) { - value1 = i; - c = c.resume(); - value1 = i; - return std::move( c); - }); - BOOST_CHECK_EQUAL( 1, value1); - BOOST_CHECK( c1); - ctx::continuation c2; - BOOST_CHECK( ! c2); - c2 = std::move( c1); - BOOST_CHECK( ! c1); - BOOST_CHECK( c2); - i = 3; - c2.resume(); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK( ! c1); - BOOST_CHECK( ! c2); -} - -void test_bind() { - value1 = 0; - X x; - ctx::continuation c = ctx::callcc( std::bind( & X::foo, x, std::placeholders::_1, 7) ); - BOOST_CHECK_EQUAL( 7, value1); -} - -void test_exception() { - { - const char * what = "hello world"; - ctx::continuation c = ctx::callcc( - [&what](ctx::continuation && c) { - try { - throw std::runtime_error( what); - } catch ( std::runtime_error const& e) { - value2 = e.what(); - } - return std::move( c); - }); - BOOST_CHECK_EQUAL( std::string( what), value2); - BOOST_CHECK( ! c); - } -#ifdef BOOST_MSVC - { - bool catched = false; - std::thread([&catched](){ - ctx::continuation c = ctx::callcc([&catched](ctx::continuation && c){ - c = c.resume(); - seh( catched); - return std::move( c); - }); - BOOST_CHECK( c ); - c.resume(); - }).join(); - BOOST_CHECK( catched); - } -#endif -} - -void test_fp() { - value3 = 0.; - double d = 7.13; - ctx::continuation c = ctx::callcc( - [&d]( ctx::continuation && c) { - d += 3.45; - value3 = d; - return std::move( c); - }); - BOOST_CHECK_EQUAL( 10.58, value3); - BOOST_CHECK( ! c); -} - -void test_stacked() { - value1 = 0; - value3 = 0.; - ctx::continuation c = ctx::callcc( - [](ctx::continuation && c) { - ctx::continuation c1 = ctx::callcc( - [](ctx::continuation && c) { - value1 = 3; - return std::move( c); - }); - value3 = 3.14; - return std::move( c); - }); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK_EQUAL( 3.14, value3); - BOOST_CHECK( ! c ); -} - -void test_prealloc() { - value1 = 0; - ctx::default_stack alloc; - ctx::stack_context sctx( alloc.allocate() ); - void * sp = static_cast< char * >( sctx.sp) - 10; - std::size_t size = sctx.size - 10; - int i = 7; - ctx::continuation c = ctx::callcc( - std::allocator_arg, ctx::preallocated( sp, size, sctx), alloc, - [&i]( ctx::continuation && c) { - value1 = i; - return std::move( c); - }); - BOOST_CHECK_EQUAL( 7, value1); - BOOST_CHECK( ! c); -} - -void test_ontop() { - { - int i = 3; - ctx::continuation c = ctx::callcc([&i](ctx::continuation && c) { - for (;;) { - i *= 10; - c = c.resume(); - } - return std::move( c); - }); - c = c.resume_with( - [&i](ctx::continuation && c){ - i -= 10; - return std::move( c); - }); - BOOST_CHECK( c); - BOOST_CHECK_EQUAL( i, 200); - } - { - ctx::continuation c1; - ctx::continuation c = ctx::callcc([&c1](ctx::continuation && c) { - c = c.resume(); - BOOST_CHECK( ! c); - return std::move( c1); - }); - c = c.resume_with( - [&c1](ctx::continuation && c){ - c1 = std::move( c); - return std::move( c); - }); - } -} - -void test_ontop_exception() { - value1 = 0; - value2 = ""; - ctx::continuation c = ctx::callcc([](ctx::continuation && c){ - for (;;) { - value1 = 3; - try { - c = c.resume(); - } catch ( my_exception & ex) { - value2 = ex.what(); - return std::move( ex.c); - } - } - return std::move( c); - }); - c = c.resume(); - BOOST_CHECK_EQUAL( 3, value1); - const char * what = "hello world"; - c.resume_with( - [what](ctx::continuation && c){ - throw my_exception( std::move( c), what); - return std::move( c); - }); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK_EQUAL( std::string( what), value2); -} - -void test_termination1() { - { - value1 = 0; - ctx::continuation c = ctx::callcc( - [](ctx::continuation && c){ - Y y; - return c.resume(); - }); - BOOST_CHECK_EQUAL( 3, value1); - } - BOOST_CHECK_EQUAL( 7, value1); - { - value1 = 0; - BOOST_CHECK_EQUAL( 0, value1); - ctx::continuation c = ctx::callcc( - [](ctx::continuation && c) { - value1 = 3; - return std::move( c); - }); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK( ! c ); - } - { - value1 = 0; - BOOST_CHECK_EQUAL( 0, value1); - int i = 3; - ctx::continuation c = ctx::callcc( - [&i](ctx::continuation && c){ - value1 = i; - c = c.resume(); - value1 = i; - return std::move( c); - }); - BOOST_CHECK( c); - BOOST_CHECK_EQUAL( i, value1); - BOOST_CHECK( c); - i = 7; - c = c.resume(); - BOOST_CHECK( ! c); - BOOST_CHECK_EQUAL( i, value1); - } -} - -void test_termination2() { - { - value1 = 0; - value3 = 0.0; - ctx::continuation c = ctx::callcc( - [](ctx::continuation && c){ - Y y; - value1 = 3; - value3 = 4.; - c = c.resume(); - value1 = 7; - value3 = 8.; - c = c.resume(); - return std::move( c); - }); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK_EQUAL( 4., value3); - c = c.resume(); - } - BOOST_CHECK_EQUAL( 7, value1); - BOOST_CHECK_EQUAL( 8., value3); -} - -void test_sscanf() { - ctx::continuation c = ctx::callcc( - []( ctx::continuation && c) { - { - double n1 = 0; - double n2 = 0; - sscanf("3.14 7.13", "%lf %lf", & n1, & n2); - BOOST_CHECK( n1 == 3.14); - BOOST_CHECK( n2 == 7.13); - } - { - int n1=0; - int n2=0; - sscanf("1 23", "%d %d", & n1, & n2); - BOOST_CHECK( n1 == 1); - BOOST_CHECK( n2 == 23); - } - { - int n1=0; - int n2=0; - sscanf("1 jjj 23", "%d %*[j] %d", & n1, & n2); - BOOST_CHECK( n1 == 1); - BOOST_CHECK( n2 == 23); - } - return std::move( c); - }); -} - -void test_snprintf() { - ctx::continuation c = ctx::callcc( - []( ctx::continuation && c) { - { - const char *fmt = "sqrt(2) = %f"; - char buf[19]; - snprintf( buf, sizeof( buf), fmt, std::sqrt( 2) ); - BOOST_CHECK( 0 < sizeof( buf) ); - BOOST_ASSERT( std::string("sqrt(2) = 1.41") == std::string( buf, 14) ); - } - { - std::uint64_t n = 0xbcdef1234567890; - const char *fmt = "0x%016llX"; - char buf[100]; - snprintf( buf, sizeof( buf), fmt, n); - BOOST_ASSERT( std::string("0x0BCDEF1234567890") == std::string( buf, 18) ); - } - return std::move( c); - }); -} - -#ifdef BOOST_WINDOWS -void test_bug12215() { - ctx::continuation c = ctx::callcc( - [](ctx::continuation && c) { - char buffer[MAX_PATH]; - GetModuleFileName( nullptr, buffer, MAX_PATH); - return std::move( c); - }); -} -#endif - -void test_goodcatch() { - value1 = 0; - value3 = 0.0; - { - ctx::continuation c = ctx::callcc( - [](ctx::continuation && c) { - Y y; - value3 = 2.; - c = c.resume(); - try { - value3 = 3.; - c = c.resume(); - } catch ( boost::context::detail::forced_unwind const&) { - value3 = 4.; - throw; - } catch (...) { - value3 = 5.; - } - value3 = 6.; - return std::move( c); - }); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK_EQUAL( 2., value3); - c = c.resume(); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK_EQUAL( 3., value3); - } - BOOST_CHECK_EQUAL( 7, value1); - BOOST_CHECK_EQUAL( 4., value3); -} - -void test_badcatch() { -#if 0 - value1 = 0; - value3 = 0.; - { - ctx::continuation c = ctx::callcc( - [](ctx::continuation && c) { - Y y; - try { - value3 = 3.; - c = c.resume(); - } catch (...) { - value3 = 5.; - } - return std::move( c); - }); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK_EQUAL( 3., value3); - // the destruction of ctx here will cause a forced_unwind to be thrown that is not caught - // in fn19. That will trigger the "not caught" assertion in ~forced_unwind. Getting that - // assertion to propogate bak here cleanly is non-trivial, and there seems to not be a good - // way to hook directly into the assertion when it happens on an alternate stack. - std::move( c); - } - BOOST_CHECK_EQUAL( 7, value1); - BOOST_CHECK_EQUAL( 4., value3); -#endif -} - -boost::unit_test::test_suite * init_unit_test_suite( int, char* []) -{ - boost::unit_test::test_suite * test = - BOOST_TEST_SUITE("Boost.Context: callcc test suite"); - - test->add( BOOST_TEST_CASE( & test_move) ); - test->add( BOOST_TEST_CASE( & test_bind) ); - test->add( BOOST_TEST_CASE( & test_exception) ); - test->add( BOOST_TEST_CASE( & test_fp) ); - test->add( BOOST_TEST_CASE( & test_stacked) ); - test->add( BOOST_TEST_CASE( & test_prealloc) ); - test->add( BOOST_TEST_CASE( & test_ontop) ); - test->add( BOOST_TEST_CASE( & test_ontop_exception) ); - test->add( BOOST_TEST_CASE( & test_termination1) ); - test->add( BOOST_TEST_CASE( & test_termination2) ); - test->add( BOOST_TEST_CASE( & test_sscanf) ); - test->add( BOOST_TEST_CASE( & test_snprintf) ); -#ifdef BOOST_WINDOWS - test->add( BOOST_TEST_CASE( & test_bug12215) ); -#endif - test->add( BOOST_TEST_CASE( & test_goodcatch) ); - test->add( BOOST_TEST_CASE( & test_badcatch) ); - - return test; -} - -#if defined(BOOST_MSVC) -# pragma warning(pop) -#endif