diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-09-13 11:24:46 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-09-13 11:25:39 +0900 |
commit | 4fadd968fa12130524c8380f33fcfe25d4de79e5 (patch) | |
tree | fd26a490cd15388d42fc6652b3c5c13012e7f93e /boost/context/continuation_fcontext.hpp | |
parent | b5c87084afaef42b2d058f68091be31988a6a874 (diff) | |
download | boost-4fadd968fa12130524c8380f33fcfe25d4de79e5.tar.gz boost-4fadd968fa12130524c8380f33fcfe25d4de79e5.tar.bz2 boost-4fadd968fa12130524c8380f33fcfe25d4de79e5.zip |
Imported Upstream version 1.65.0upstream/1.65.0
Change-Id: Icf8400b375482cb11bcf77440a6934ba360d6ba4
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'boost/context/continuation_fcontext.hpp')
-rw-r--r-- | boost/context/continuation_fcontext.hpp | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/boost/context/continuation_fcontext.hpp b/boost/context/continuation_fcontext.hpp new file mode 100644 index 0000000000..5c309c3fed --- /dev/null +++ b/boost/context/continuation_fcontext.hpp @@ -0,0 +1,382 @@ + +// Copyright Oliver Kowalke 2017. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CONTEXT_CONTINUATION_H +#define BOOST_CONTEXT_CONTINUATION_H + +#include <boost/context/detail/config.hpp> + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <exception> +#include <functional> +#include <memory> +#include <ostream> +#include <tuple> +#include <utility> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/intrusive_ptr.hpp> + +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) +#include <boost/context/detail/exchange.hpp> +#endif +#if defined(BOOST_NO_CXX17_STD_INVOKE) +#include <boost/context/detail/invoke.hpp> +#endif +#include <boost/context/detail/disable_overload.hpp> +#include <boost/context/detail/exception.hpp> +#include <boost/context/detail/fcontext.hpp> +#include <boost/context/detail/tuple.hpp> +#include <boost/context/fixedsize_stack.hpp> +#include <boost/context/flags.hpp> +#include <boost/context/preallocated.hpp> +#include <boost/context/segmented_stack.hpp> +#include <boost/context/stack_context.hpp> + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable: 4702) +#endif + +namespace boost { +namespace context { +namespace detail { + +inline +transfer_t context_unwind( transfer_t t) { + throw forced_unwind( t.fctx); + return { nullptr, nullptr }; +} + +template< typename Rec > +transfer_t context_exit( transfer_t t) noexcept { + Rec * rec = static_cast< Rec * >( t.data); + // destroy context stack + rec->deallocate(); + return { nullptr, nullptr }; +} + +template< typename Rec > +void context_entry( transfer_t t) noexcept { + // transfer control structure to the context-stack + Rec * rec = static_cast< Rec * >( t.data); + BOOST_ASSERT( nullptr != t.fctx); + BOOST_ASSERT( nullptr != rec); + try { + // jump back to `create_context()` + t = jump_fcontext( t.fctx, nullptr); + // start executing + t.fctx = rec->run( t.fctx); + } catch ( forced_unwind const& e) { + t = { e.fctx, nullptr }; + } + BOOST_ASSERT( nullptr != t.fctx); + // destroy context-stack of `this`context on next context + ontop_fcontext( t.fctx, rec, context_exit< Rec >); + BOOST_ASSERT_MSG( false, "context already terminated"); +} + +template< typename Ctx, typename Fn > +transfer_t context_ontop( transfer_t t) { + auto p = static_cast< std::tuple< Fn > * >( t.data); + BOOST_ASSERT( nullptr != p); + typename std::decay< Fn >::type fn = std::get< 0 >( * p); + t.data = nullptr; + Ctx c{ t.fctx }; + // execute function, pass continuation via reference + fn( std::move( c) ); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return { exchange( c.fctx_, nullptr), nullptr }; +#else + return { std::exchange( c.fctx_, nullptr), nullptr }; +#endif +} + +template< typename Ctx, typename StackAlloc, typename Fn > +class record { +private: + stack_context sctx_; + StackAlloc salloc_; + typename std::decay< Fn >::type fn_; + + static void destroy( record * p) noexcept { + StackAlloc salloc = p->salloc_; + stack_context sctx = p->sctx_; + // deallocate record + p->~record(); + // destroy stack with stack allocator + salloc.deallocate( sctx); + } + +public: + record( stack_context sctx, StackAlloc const& salloc, + Fn && fn) noexcept : + sctx_( sctx), + salloc_( salloc), + fn_( std::forward< Fn >( fn) ) { + } + + record( record const&) = delete; + record & operator=( record const&) = delete; + + void deallocate() noexcept { + destroy( this); + } + + fcontext_t run( fcontext_t fctx) { + Ctx c{ fctx }; + // invoke context-function +#if defined(BOOST_NO_CXX17_STD_INVOKE) + c = invoke( fn_, std::move( c) ); +#else + c = std::invoke( fn_, std::move( c) ); +#endif +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( c.fctx_, nullptr); +#else + return std::exchange( c.fctx_, nullptr); +#endif + } +}; + +template< typename Record, typename StackAlloc, typename Fn > +fcontext_t create_context1( StackAlloc salloc, Fn && fn) { + auto sctx = salloc.allocate(); + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( Record) ) ) + & ~static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + Record * record = new ( storage) Record{ + sctx, salloc, std::forward< Fn >( fn) }; + // 64byte gab between control structure and stack top + // should be 16byte aligned + void * stack_top = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) ); + void * stack_bottom = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) ); + // create fast-context + const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom); + const fcontext_t fctx = make_fcontext( stack_top, size, & context_entry< Record >); + BOOST_ASSERT( nullptr != fctx); + // transfer control structure to context-stack + return jump_fcontext( fctx, record).fctx; +} + +template< typename Record, typename StackAlloc, typename Fn > +fcontext_t create_context2( preallocated palloc, StackAlloc salloc, Fn && fn) { + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( Record) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context-stack + Record * record = new ( storage) Record{ + palloc.sctx, salloc, std::forward< Fn >( fn) }; + // 64byte gab between control structure and stack top + void * stack_top = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) ); + void * stack_bottom = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) ); + // create fast-context + const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom); + const fcontext_t fctx = make_fcontext( stack_top, size, & context_entry< Record >); + BOOST_ASSERT( nullptr != fctx); + // transfer control structure to context-stack + return jump_fcontext( fctx, record).fctx; +} + +} + +class continuation { +private: + template< typename Ctx, typename StackAlloc, typename Fn > + friend class detail::record; + + template< typename Ctx, typename Fn > + friend detail::transfer_t + detail::context_ontop( detail::transfer_t); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, StackAlloc, Fn &&); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, preallocated, StackAlloc, Fn &&); + + detail::fcontext_t fctx_{ nullptr }; + + continuation( detail::fcontext_t fctx) noexcept : + fctx_{ fctx } { + } + +public: + continuation() noexcept = default; + + ~continuation() { + if ( BOOST_UNLIKELY( nullptr != fctx_) ) { + detail::ontop_fcontext( +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::exchange( fctx_, nullptr), +#else + std::exchange( fctx_, nullptr), +#endif + nullptr, + detail::context_unwind); + } + } + + continuation( continuation && other) noexcept { + std::swap( fctx_, other.fctx_); + } + + continuation & operator=( continuation && other) noexcept { + if ( BOOST_LIKELY( this != & other) ) { + continuation tmp = std::move( other); + swap( tmp); + } + return * this; + } + + continuation( continuation const& other) noexcept = delete; + continuation & operator=( continuation const& other) noexcept = delete; + + continuation resume() { + BOOST_ASSERT( nullptr != fctx_); + return detail::jump_fcontext( +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::exchange( fctx_, nullptr), +#else + std::exchange( fctx_, nullptr), +#endif + nullptr).fctx; + } + + template< typename Fn > + continuation resume_with( Fn && fn) { + BOOST_ASSERT( nullptr != fctx_); + auto p = std::make_tuple( std::forward< Fn >( fn) ); + return detail::ontop_fcontext( +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::exchange( fctx_, nullptr), +#else + std::exchange( fctx_, nullptr), +#endif + & p, + detail::context_ontop< continuation, Fn >).fctx; + } + + explicit operator bool() const noexcept { + return nullptr != fctx_; + } + + bool operator!() const noexcept { + return nullptr == fctx_; + } + + bool operator==( continuation const& other) const noexcept { + return fctx_ == other.fctx_; + } + + bool operator!=( continuation const& other) const noexcept { + return fctx_ != other.fctx_; + } + + bool operator<( continuation const& other) const noexcept { + return fctx_ < other.fctx_; + } + + bool operator>( continuation const& other) const noexcept { + return other.fctx_ < fctx_; + } + + bool operator<=( continuation const& other) const noexcept { + return ! ( * this > other); + } + + bool operator>=( continuation const& other) const noexcept { + return ! ( * this < other); + } + + template< typename charT, class traitsT > + friend std::basic_ostream< charT, traitsT > & + operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other) { + if ( nullptr != other.fctx_) { + return os << other.fctx_; + } else { + return os << "{not-a-context}"; + } + } + + void swap( continuation & other) noexcept { + std::swap( fctx_, other.fctx_); + } +}; + +template< + typename Fn, + typename = detail::disable_overload< continuation, Fn > +> +continuation +callcc( Fn && fn) { + return callcc( + std::allocator_arg, fixedsize_stack(), + std::forward< Fn >( fn) ); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn) { + using Record = detail::record< continuation, StackAlloc, Fn >; + return continuation{ + detail::create_context1< Record >( + salloc, std::forward< Fn >( fn) ) }.resume(); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn) { + using Record = detail::record< continuation, StackAlloc, Fn >; + return continuation{ + detail::create_context2< Record >( + palloc, salloc, std::forward< Fn >( fn) ) }.resume(); +} + +#if defined(BOOST_USE_SEGMENTED_STACKS) +template< typename Fn > +continuation +callcc( std::allocator_arg_t, segmented_stack, Fn &&); + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, preallocated, segmented_stack, Fn &&); +#endif + +// swap +inline +void swap( continuation & l, continuation & r) noexcept { + l.swap( r); +} + +}} + +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_CONTINUATION_H |