1
0
mirror of https://git.suyu.dev/suyu/suyu synced 2025-09-09 15:56:32 -05:00

Initial commit

This commit is contained in:
Crimson-Hawk
2024-03-05 16:42:40 +08:00
commit f1e4595ebf
39576 changed files with 7006612 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
CRTLinkage: dynamic
LibraryLinkage: dynamic

View File

@@ -0,0 +1,8 @@
Package: boost-context
Version: 1.79.0
Depends: boost-assert, boost-build, boost-config, boost-core, boost-modular-build-helper, boost-mp11, boost-pool, boost-predef, boost-smart-ptr, boost-vcpkg-helpers, vcpkg-cmake
Architecture: x64-windows
Multi-Arch: same
Abi: e94ca7654d66a89fc41232ed8f559b3f0da8bbdf35e7851b96a39f97664a797a
Description: Boost context module
Type: Port

View File

@@ -0,0 +1,13 @@
// 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>
#else
#include <boost/context/continuation_fcontext.hpp>
#endif

View File

@@ -0,0 +1,370 @@
// 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& 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

View File

@@ -0,0 +1,538 @@
// Copyright Oliver Kowalke 2017.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_CONTINUATION_H
#define BOOST_CONTEXT_CONTINUATION_H
#include <boost/predef.h>
#if BOOST_OS_MACOS
#define _XOPEN_SOURCE 600
#endif
extern "C" {
#include <ucontext.h>
}
#include <boost/context/detail/config.hpp>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <memory>
#include <ostream>
#include <system_error>
#include <tuple>
#include <utility>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/context/detail/disable_overload.hpp>
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
#include <boost/context/detail/exchange.hpp>
#endif
#include <boost/context/detail/externc.hpp>
#if defined(BOOST_NO_CXX17_STD_INVOKE)
#include <boost/context/detail/invoke.hpp>
#endif
#include <boost/context/fixedsize_stack.hpp>
#include <boost/context/flags.hpp>
#include <boost/context/preallocated.hpp>
#if defined(BOOST_USE_SEGMENTED_STACKS)
#include <boost/context/segmented_stack.hpp>
#endif
#include <boost/context/stack_context.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
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>(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

View File

@@ -0,0 +1,473 @@
// Copyright Oliver Kowalke 2017.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_CONTINUATION_H
#define BOOST_CONTEXT_CONTINUATION_H
#include <windows.h>
#include <boost/context/detail/config.hpp>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <memory>
#include <ostream>
#include <system_error>
#include <tuple>
#include <utility>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/context/detail/disable_overload.hpp>
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
#include <boost/context/detail/exchange.hpp>
#endif
#if defined(BOOST_NO_CXX17_STD_INVOKE)
#include <boost/context/detail/invoke.hpp>
#endif
#include <boost/context/fixedsize_stack.hpp>
#include <boost/context/flags.hpp>
#include <boost/context/preallocated.hpp>
#include <boost/context/stack_context.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable: 4702)
#endif
namespace boost {
namespace context {
namespace detail {
// tampoline function
// entered if the execution context
// is resumed for the first time
template< typename Record >
static VOID WINAPI entry_func( LPVOID data) noexcept {
Record * record = static_cast< Record * >( data);
BOOST_ASSERT( nullptr != record);
// start execution of toplevel context-function
record->run();
}
struct BOOST_CONTEXT_DECL activation_record {
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>(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

View File

@@ -0,0 +1,74 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_DETAIL_APPLY_H
#define BOOST_CONTEXT_DETAIL_APPLY_H
#include <functional>
#include <tuple>
#include <type_traits>
#include <utility>
#include <boost/config.hpp>
#include <boost/context/detail/config.hpp>
#if defined(BOOST_NO_CXX17_STD_INVOKE)
#include <boost/context/detail/invoke.hpp>
#endif
#include <boost/context/detail/index_sequence.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable: 4100)
#endif
namespace boost {
namespace context {
namespace detail {
template< typename Fn, typename Tpl, std::size_t ... I >
auto
apply_impl( Fn && fn, Tpl && tpl, index_sequence< I ... >)
#if defined(BOOST_NO_CXX17_STD_INVOKE)
-> decltype( boost::context::detail::invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... ) )
#else
-> decltype( std::invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... ) )
#endif
{
#if defined(BOOST_NO_CXX17_STD_INVOKE)
return boost::context::detail::invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... );
#else
return std::invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... );
#endif
}
template< typename Fn, typename Tpl >
auto
apply( Fn && fn, Tpl && tpl)
-> decltype( apply_impl( std::forward< Fn >( fn),
std::forward< Tpl >( tpl),
make_index_sequence< std::tuple_size< typename std::decay< Tpl >::type >::value >{}) )
{
return apply_impl( std::forward< Fn >( fn),
std::forward< Tpl >( tpl),
make_index_sequence< std::tuple_size< typename std::decay< Tpl >::type >::value >{});
}
}}}
#if defined(BOOST_MSVC)
# pragma warning(pop)
#endif
#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_DETAIL_APPLY_H

View File

@@ -0,0 +1,136 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_DETAIL_CONFIG_H
#define BOOST_CONTEXT_DETAIL_CONFIG_H
// required for SD-6 compile-time integer sequences
#include <utility>
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#ifdef BOOST_CONTEXT_DECL
# undef BOOST_CONTEXT_DECL
#endif
#if (defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTEXT_DYN_LINK) ) && ! defined(BOOST_CONTEXT_STATIC_LINK)
# if defined(BOOST_CONTEXT_SOURCE)
# define BOOST_CONTEXT_DECL BOOST_SYMBOL_EXPORT
# define BOOST_CONTEXT_BUILD_DLL
# else
# define BOOST_CONTEXT_DECL BOOST_SYMBOL_IMPORT
# endif
#endif
#if ! defined(BOOST_CONTEXT_DECL)
# define BOOST_CONTEXT_DECL
#endif
#if ! defined(BOOST_USE_UCONTEXT) && defined(__CYGWIN__)
# define BOOST_USE_UCONTEXT
#endif
#if ! defined(BOOST_CONTEXT_SOURCE) && ! defined(BOOST_ALL_NO_LIB) && ! defined(BOOST_CONTEXT_NO_LIB)
# define BOOST_LIB_NAME boost_context
# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTEXT_DYN_LINK)
# define BOOST_DYN_LINK
# endif
# include <boost/config/auto_link.hpp>
#endif
#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)
# define BOOST_CONTEXT_CALLDECL __cdecl
#else
# define BOOST_CONTEXT_CALLDECL
#endif
#if defined(BOOST_USE_SEGMENTED_STACKS)
# if ! ( (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) ) ) || \
(defined(__clang__) && (__clang_major__ > 2 || ( __clang_major__ == 2 && __clang_minor__ > 3) ) ) )
# error "compiler does not support segmented_stack stacks"
# endif
# define BOOST_CONTEXT_SEGMENTS 10
#endif
#define BOOST_CONTEXT_NO_CXX14_INTEGER_SEQUENCE
// use rd6 macros for std::integer_sequence
#if defined(__cpp_lib_integer_sequence) && __cpp_lib_integer_sequence >= 201304
# undef BOOST_CONTEXT_NO_CXX14_INTEGER_SEQUENCE
#endif
// workaroud: MSVC 14 does not provide macros to test for compile-time integer sequence
#if _MSC_VER > 1800 // _MSC_VER == 1800 -> MS Visual Studio 2013
# undef BOOST_CONTEXT_NO_INDEX_SEQUENCE
#endif
// workaround: Xcode clang feature detection
#if ! defined(__cpp_lib_integer_sequence) && __cpp_lib_integer_sequence >= 201304
# if _LIBCPP_STD_VER > 11
# undef BOOST_CONTEXT_NO_CXX14_INTEGER_SEQUENCE
# endif
#endif
// workaroud: MSVC 14 does support constexpr
#if _MSC_VER > 1800 // _MSC_VER == 1800 -> MS Visual Studio 2013
# undef BOOST_NO_CXX11_CONSTEXPR
#endif
#undef BOOST_CONTEXT_NO_CXX11
#if defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) || \
defined(BOOST_NO_CXX11_CONSTEXPR) || \
defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || \
defined(BOOST_NO_CXX11_FINAL) || \
defined(BOOST_NO_CXX11_HDR_TUPLE) || \
defined(BOOST_NO_CXX11_NOEXCEPT) || \
defined(BOOST_NO_CXX11_NULLPTR) || \
defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \
defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) || \
defined(BOOST_NO_CXX11_UNIFIED_INITIALISATION_SYNTAX) || \
defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || \
defined(BOOST_NO_HDR_ATOMIC) || \
defined(BOOST_NO_HDR_TUPLE)
# define BOOST_CONTEXT_NO_CXX11
#endif
#if ! defined(BOOST_EXECUTION_CONTEXT)
# if defined(BOOST_USE_SEGMENTED_STACKS)
# define BOOST_EXECUTION_CONTEXT 1
# else
# define BOOST_EXECUTION_CONTEXT 2
# endif
#endif
#if ! defined(BOOST_NO_CXX11_CONSTEXPR)
// modern architectures have cachelines with 64byte length
// ARM Cortex-A15 32/64byte, Cortex-A9 16/32/64bytes
// MIPS 74K: 32byte, 4KEc: 16byte
// ist should be safe to use 64byte for all
static constexpr std::size_t cache_alignment{ 64 };
static constexpr std::size_t cacheline_length{ 64 };
// lookahead size for prefetching
static constexpr std::size_t prefetch_stride{ 4 * cacheline_length };
#endif
#if defined(__GLIBCPP__) || defined(__GLIBCXX__)
// GNU libstdc++ 3
# define BOOST_CONTEXT_HAS_CXXABI_H
#endif
#if defined( BOOST_CONTEXT_HAS_CXXABI_H )
# include <cxxabi.h>
#endif
#if defined(__OpenBSD__)
// stacks need mmap(2) with MAP_STACK
# define BOOST_CONTEXT_USE_MAP_STACK
#endif
#endif // BOOST_CONTEXT_DETAIL_CONFIG_H

View File

@@ -0,0 +1,40 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_DETAIL_DISABLE_OVERLOAD_H
#define BOOST_CONTEXT_DETAIL_DISABLE_OVERLOAD_H
#include <type_traits>
#include <boost/config.hpp>
#include <boost/context/detail/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace context {
namespace detail {
// http://ericniebler.com/2013/08/07/universal-references-and-the-copy-constructo/
template< typename X, typename Y >
using disable_overload =
typename std::enable_if<
! std::is_base_of<
X,
typename std::decay< Y >::type
>::value
>::type;
}}}
#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_DETAIL_DISABLE_OVERLOAD_H

View File

@@ -0,0 +1,39 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_DETAIL_EXCEPTION_H
#define BOOST_CONTEXT_DETAIL_EXCEPTION_H
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/context/detail/fcontext.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace context {
namespace detail {
struct forced_unwind {
fcontext_t fctx{ nullptr };
forced_unwind() = default;
forced_unwind( fcontext_t fctx_) :
fctx( fctx_) {
}
};
}}}
#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_DETAIL_EXCEPTION_H

View File

@@ -0,0 +1,36 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_DETAIL_EXCHANGE_H
#define BOOST_CONTEXT_DETAIL_EXCHANGE_H
#include <algorithm>
#include <utility>
#include <boost/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace context {
namespace detail {
template< typename T, typename U = T >
T exchange( T & t, U && nv) {
T ov = std::move( t);
t = std::forward< U >( nv);
return ov;
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_DETAIL_EXCHANGE_H

View File

@@ -0,0 +1,23 @@
// 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>
#include <boost/context/detail/config.hpp>
#if defined(BOOST_USE_ASAN)
extern "C" {
void __sanitizer_start_switch_fiber( void **, const void *, size_t);
void __sanitizer_finish_switch_fiber( void *, const void **, size_t *);
}
#endif
#if defined(BOOST_USE_SEGMENTED_STACKS)
extern "C" {
void __splitstack_getcontext( void * [BOOST_CONTEXT_SEGMENTS]);
void __splitstack_setcontext( void * [BOOST_CONTEXT_SEGMENTS]);
}
#endif

View File

@@ -0,0 +1,46 @@
// Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_DETAIL_FCONTEXT_H
#define BOOST_CONTEXT_DETAIL_FCONTEXT_H
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/context/detail/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace context {
namespace detail {
typedef void* fcontext_t;
struct transfer_t {
fcontext_t fctx;
void * data;
};
extern "C" BOOST_CONTEXT_DECL
transfer_t BOOST_CONTEXT_CALLDECL jump_fcontext( fcontext_t const to, void * vp);
extern "C" BOOST_CONTEXT_DECL
fcontext_t BOOST_CONTEXT_CALLDECL make_fcontext( void * sp, std::size_t size, void (* fn)( transfer_t) );
// based on an idea of Giovanni Derreta
extern "C" BOOST_CONTEXT_DECL
transfer_t BOOST_CONTEXT_CALLDECL ontop_fcontext( fcontext_t const to, void * vp, transfer_t (* fn)( transfer_t) );
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_DETAIL_FCONTEXT_H

View File

@@ -0,0 +1,50 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_DETAIL_INDEX_SEQUENCE_H
#define BOOST_CONTEXT_DETAIL_INDEX_SEQUENCE_H
#include <cstddef>
#include <boost/config.hpp>
#include <boost/context/detail/config.hpp>
#if defined(BOOST_CONTEXT_NO_CXX14_INTEGER_SEQUENCE)
#include <boost/mp11/integer_sequence.hpp>
#endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace context {
namespace detail {
#if ! defined(BOOST_CONTEXT_NO_CXX14_INTEGER_SEQUENCE)
template< std::size_t ... I >
using index_sequence = std::index_sequence< I ... >;
template< std::size_t I >
using make_index_sequence = std::make_index_sequence< I >;
template< typename ... T >
using index_sequence_for = std::index_sequence_for< T ... >;
#else
template< std::size_t ... I >
using index_sequence = mp11::index_sequence< I ... >;
template< std::size_t I >
using make_index_sequence = mp11::make_index_sequence< I >;
template< typename ... T >
using index_sequence_for = mp11::index_sequence_for< T ... >;
#endif
}}}
#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_DETAIL_INDEX_SEQUENCE_H

View File

@@ -0,0 +1,50 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_DETAIL_INVOKE_H
#define BOOST_CONTEXT_DETAIL_INVOKE_H
#include <functional>
#include <type_traits>
#include <utility>
#include <boost/config.hpp>
#include <boost/context/detail/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace context {
namespace detail {
template< typename Fn, typename ... Args >
typename std::enable_if<
std::is_member_pointer< typename std::decay< Fn >::type >::value,
typename std::result_of< Fn &&( Args && ... ) >::type
>::type
invoke( Fn && fn, Args && ... args) {
return std::mem_fn( fn)( std::forward< Args >( args) ... );
}
template< typename Fn, typename ... Args >
typename std::enable_if<
! std::is_member_pointer< typename std::decay< Fn >::type >::value,
typename std::result_of< Fn &&( Args && ... ) >::type
>::type
invoke( Fn && fn, Args && ... args) {
return std::forward< Fn >( fn)( std::forward< Args >( args) ... );
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_DETAIL_INVOKE_H

View File

@@ -0,0 +1,78 @@
// Copyright Oliver Kowalke 2017.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_DETAIL_PREFETCH_H
#define BOOST_CONTEXT_DETAIL_PREFETCH_H
#include <cstddef>
#include <cstdint>
#include <boost/config.hpp>
#include <boost/predef.h>
#include <boost/context/detail/config.hpp>
#if BOOST_COMP_INTEL || BOOST_COMP_INTEL_EMULATED
#include <immintrin.h>
#endif
#if BOOST_COMP_MSVC && !defined(_M_ARM) && !defined(_M_ARM64)
#include <mmintrin.h>
#endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace context {
namespace detail {
#if BOOST_COMP_GNUC || BOOST_COMP_CLANG
#define BOOST_HAS_PREFETCH 1
BOOST_FORCEINLINE
void prefetch( void * addr) {
// L1 cache : hint == 1
__builtin_prefetch( addr, 1, 1);
}
#elif BOOST_COMP_INTEL || BOOST_COMP_INTEL_EMULATED
#define BOOST_HAS_PREFETCH 1
BOOST_FORCEINLINE
void prefetch( void * addr) {
// L1 cache : hint == _MM_HINT_T0
_mm_prefetch( (const char *)addr, _MM_HINT_T0);
}
#elif BOOST_COMP_MSVC && !defined(_M_ARM) && !defined(_M_ARM64)
#define BOOST_HAS_PREFETCH 1
BOOST_FORCEINLINE
void prefetch( void * addr) {
// L1 cache : hint == _MM_HINT_T0
_mm_prefetch( (const char *)addr, _MM_HINT_T0);
}
#endif
inline
void prefetch_range( void * addr, std::size_t len) {
#if defined(BOOST_HAS_PREFETCH)
void * vp = addr;
void * end = reinterpret_cast< void * >(
reinterpret_cast< uintptr_t >( addr) + static_cast< uintptr_t >( len) );
while ( vp < end) {
prefetch( vp);
vp = reinterpret_cast< void * >(
reinterpret_cast< uintptr_t >( vp) + static_cast< uintptr_t >( prefetch_stride) );
}
#endif
}
#undef BOOST_HAS_PREFETCH
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_DETAIL_PREFETCH_H

View File

@@ -0,0 +1,129 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_DETAIL_TUPLE_H
#define BOOST_CONTEXT_DETAIL_TUPLE_H
#include <tuple>
#include <utility>
#include <boost/config.hpp>
#include <boost/context/detail/config.hpp>
#include <boost/context/detail/index_sequence.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace context {
namespace detail {
template< typename ... S, typename ... T, std::size_t ... I >
void
head_impl( std::tuple< S ... > & s,
std::tuple< T ... > & t, index_sequence< I ... >) {
t = std::tuple< T ... >{ std::get< I >( s) ... };
}
template< typename ... S, typename ... T, std::size_t ... I >
void
head_impl( std::tuple< S ... > && s,
std::tuple< T ... > & t, index_sequence< I ... >) {
t = std::tuple< T ... >{ std::get< I >( std::move( s) ) ... };
}
template< typename ... S, std::size_t ... I1, typename ... T, std::size_t ... I2 >
void
tail_impl( std::tuple< S ... > & s, index_sequence< I1 ... >,
std::tuple< T ... > & t, index_sequence< I2 ... >) {
constexpr std::size_t Idx = (sizeof...(I1)) - (sizeof...(I2));
t = std::tuple< T ... >{ std::get< (Idx + I2) >( s) ... };
}
template< typename ... S, std::size_t ... I1, typename ... T, std::size_t ... I2 >
void
tail_impl( std::tuple< S ... > && s, index_sequence< I1 ... >,
std::tuple< T ... > & t, index_sequence< I2 ... >) {
constexpr std::size_t Idx = (sizeof...(I1)) - (sizeof...(I2));
t = std::tuple< T ... >{ std::get< (Idx + I2) >( std::move( s) ) ... };
}
template< typename ... T >
class tuple_head;
template< typename ... T >
class tuple_head< std::tuple< T ... > > {
private:
std::tuple< T ... > & t_;
public:
tuple_head( std::tuple< T ... > & t) noexcept :
t_( t) {
}
template< typename ... S >
void operator=( std::tuple< S ... > & s) {
static_assert((sizeof...(T)) <= (sizeof...(S)), "invalid tuple size");
head_impl( s,
t_, index_sequence_for< T ... >{} );
}
template< typename ... S >
void operator=( std::tuple< S ... > && s) {
static_assert((sizeof...(T)) <= (sizeof...(S)), "invalid tuple size");
head_impl( std::move( s),
t_, index_sequence_for< T ... >{} );
}
};
template< typename ... T >
class tuple_tail;
template< typename ... T >
class tuple_tail< std::tuple< T ... > > {
private:
std::tuple< T ... > & t_;
public:
tuple_tail( std::tuple< T ... > & t) noexcept :
t_( t) {
}
template< typename ... S >
void operator=( std::tuple< S ... > & s) {
static_assert((sizeof...(T)) <= (sizeof...(S)), "invalid tuple size");
tail_impl( s, index_sequence_for< S ... >{},
t_, index_sequence_for< T ... >{} );
}
template< typename ... S >
void operator=( std::tuple< S ... > && s) {
static_assert((sizeof...(T)) <= (sizeof...(S)), "invalid tuple size");
tail_impl( std::move( s), index_sequence_for< S ... >{},
t_, index_sequence_for< T ... >{} );
}
};
template< typename ... T >
detail::tuple_head< std::tuple< T ... > >
head( std::tuple< T ... > & tpl) {
return tuple_head< std::tuple< T ... > >{ tpl };
}
template< typename ... T >
detail::tuple_tail< std::tuple< T ... > >
tail( std::tuple< T ... > & tpl) {
return tuple_tail< std::tuple< T ... > >{ tpl };
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_DETAIL_TUPLE_H

View File

@@ -0,0 +1,13 @@
// 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/fiber_ucontext.hpp>
#elif defined(BOOST_USE_WINFIB)
#include <boost/context/fiber_winfib.hpp>
#else
#include <boost/context/fiber_fcontext.hpp>
#endif

View File

@@ -0,0 +1,370 @@
// 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_FIBER_H
#define BOOST_CONTEXT_FIBER_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 fiber_unwind( transfer_t t) {
throw forced_unwind( t.fctx);
return { nullptr, nullptr };
}
template< typename Rec >
transfer_t fiber_exit( transfer_t t) noexcept {
Rec * rec = static_cast< Rec * >( t.data);
// destroy context stack
rec->deallocate();
return { nullptr, nullptr };
}
template< typename Rec >
void fiber_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, fiber_exit< Rec >);
BOOST_ASSERT_MSG( false, "context already terminated");
}
template< typename Ctx, typename Fn >
transfer_t fiber_ontop( transfer_t t) {
BOOST_ASSERT( nullptr != t.data);
auto p = *static_cast< Fn * >( t.data);
t.data = nullptr;
// execute function, pass fiber via reference
Ctx c = p( Ctx{ t.fctx } );
#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 fiber_record {
private:
stack_context sctx_;
typename std::decay< StackAlloc >::type salloc_;
typename std::decay< Fn >::type fn_;
static void destroy( fiber_record * p) noexcept {
typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
stack_context sctx = p->sctx_;
// deallocate fiber_record
p->~fiber_record();
// destroy stack with stack allocator
salloc.deallocate( sctx);
}
public:
fiber_record( stack_context sctx, StackAlloc && salloc,
Fn && fn) noexcept :
sctx_( sctx),
salloc_( std::forward< StackAlloc >( salloc)),
fn_( std::forward< Fn >( fn) ) {
}
fiber_record( fiber_record const&) = delete;
fiber_record & operator=( fiber_record const&) = delete;
void deallocate() noexcept {
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 } );
#else
Ctx c = std::invoke( fn_, Ctx{ fctx } );
#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_fiber1( 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, & fiber_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_fiber2( 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, & fiber_entry< Record >);
BOOST_ASSERT( nullptr != fctx);
// transfer control structure to context-stack
return jump_fcontext( fctx, record).fctx;
}
}
class fiber {
private:
template< typename Ctx, typename StackAlloc, typename Fn >
friend class detail::fiber_record;
template< typename Ctx, typename Fn >
friend detail::transfer_t
detail::fiber_ontop( detail::transfer_t);
template< typename StackAlloc, typename Fn >
friend fiber
callcc( std::allocator_arg_t, StackAlloc &&, Fn &&);
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 } {
}
public:
fiber() noexcept = default;
template< typename Fn, typename = detail::disable_overload< fiber, Fn > >
fiber( Fn && fn) :
fiber{ std::allocator_arg, fixedsize_stack(), std::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) ) } {
}
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) ) } {
}
#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_) ) {
detail::ontop_fcontext(
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
detail::exchange( fctx_, nullptr),
#else
std::exchange( fctx_, nullptr),
#endif
nullptr,
detail::fiber_unwind);
}
}
fiber( fiber && other) noexcept {
swap( other);
}
fiber & operator=( fiber && other) noexcept {
if ( BOOST_LIKELY( this != & other) ) {
fiber tmp = std::move( other);
swap( tmp);
}
return * this;
}
fiber( fiber const& other) noexcept = delete;
fiber & operator=( fiber const& other) noexcept = delete;
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),
#endif
nullptr).fctx };
}
template< typename Fn >
fiber resume_with( Fn && fn) && {
BOOST_ASSERT( nullptr != fctx_);
auto p = 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::fiber_ontop< fiber, decltype(p) >).fctx };
}
explicit operator bool() const noexcept {
return nullptr != fctx_;
}
bool operator!() const noexcept {
return nullptr == fctx_;
}
bool operator<( fiber const& other) const noexcept {
return fctx_ < other.fctx_;
}
#if !defined(BOOST_EMBTC)
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_) {
return os << other.fctx_;
} 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, fiber const& other);
#endif
void swap( fiber & other) noexcept {
std::swap( fctx_, other.fctx_);
}
};
#if defined(BOOST_EMBTC)
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_) {
return os << other.fctx_;
} else {
return os << "{not-a-context}";
}
}
#endif
inline
void swap( fiber & l, fiber & r) noexcept {
l.swap( r);
}
typedef fiber fiber_context;
}}
#if defined(BOOST_MSVC)
# pragma warning(pop)
#endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_FIBER_H

View File

@@ -0,0 +1,566 @@
// 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_FIBER_H
#define BOOST_CONTEXT_FIBER_H
#include <boost/predef.h>
#if BOOST_OS_MACOS
#define _XOPEN_SOURCE 600
#endif
extern "C" {
#include <ucontext.h>
}
#include <boost/context/detail/config.hpp>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <memory>
#include <ostream>
#include <system_error>
#include <tuple>
#include <utility>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/predef.h>
#include <boost/context/detail/disable_overload.hpp>
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
#include <boost/context/detail/exchange.hpp>
#endif
#include <boost/context/detail/externc.hpp>
#if defined(BOOST_NO_CXX17_STD_INVOKE)
#include <boost/context/detail/invoke.hpp>
#endif
#include <boost/context/fixedsize_stack.hpp>
#include <boost/context/flags.hpp>
#include <boost/context/preallocated.hpp>
#if defined(BOOST_USE_SEGMENTED_STACKS)
#include <boost/context/segmented_stack.hpp>
#endif
#include <boost/context/stack_context.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
#ifdef BOOST_USE_TSAN
#include <sanitizer/tsan_interface.h>
#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 fiber_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 fiber_activation_record {
ucontext_t uctx{};
stack_context sctx{};
bool main_ctx{ true };
fiber_activation_record * from{ nullptr };
std::function< fiber_activation_record*(fiber_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
#if defined(BOOST_USE_TSAN)
void * tsan_fiber{ nullptr };
bool destroy_tsan_fiber{ true };
#endif
static fiber_activation_record *& current() noexcept;
// used for toplevel-context
// (e.g. main context, thread-entry context)
fiber_activation_record() {
if ( BOOST_UNLIKELY( 0 != ::getcontext( & uctx) ) ) {
throw std::system_error(
std::error_code( errno, std::system_category() ),
"getcontext() failed");
}
#if defined(BOOST_USE_TSAN)
tsan_fiber = __tsan_get_current_fiber();
destroy_tsan_fiber = false;
#endif
}
fiber_activation_record( stack_context sctx_) noexcept :
sctx( sctx_ ),
main_ctx( false ) {
}
virtual ~fiber_activation_record() {
#if defined(BOOST_USE_TSAN)
if (destroy_tsan_fiber)
__tsan_destroy_fiber(tsan_fiber);
#endif
}
fiber_activation_record( fiber_activation_record const&) = delete;
fiber_activation_record & operator=( fiber_activation_record const&) = delete;
bool is_main_context() const noexcept {
return main_ctx;
}
fiber_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
#if defined (BOOST_USE_TSAN)
__tsan_switch_to_fiber(tsan_fiber, 0);
#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 >
fiber_activation_record * resume_with( Fn && fn) {
from = current();
// store `this` in static, thread local pointer
// `this` will become the active (running) context
// returned by fiber::current()
current() = this;
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
current()->ontop = std::bind(
[](typename std::decay< Fn >::type & fn, fiber_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>(fn)](fiber_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
#if defined (BOOST_USE_TSAN)
__tsan_switch_to_fiber(tsan_fiber, 0);
#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 fiber_activation_record_initializer {
fiber_activation_record_initializer() noexcept;
~fiber_activation_record_initializer();
};
struct forced_unwind {
fiber_activation_record * from{ nullptr };
forced_unwind( fiber_activation_record * from_) noexcept :
from{ from_ } {
}
};
template< typename Ctx, typename StackAlloc, typename Fn >
class fiber_capture_record : public fiber_activation_record {
private:
typename std::decay< StackAlloc >::type salloc_;
typename std::decay< Fn >::type fn_;
static void destroy( fiber_capture_record * p) noexcept {
typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
stack_context sctx = p->sctx;
// deallocate activation record
p->~fiber_capture_record();
// destroy stack with stack allocator
salloc.deallocate( sctx);
}
public:
fiber_capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept :
fiber_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;
std::move( c).resume();
BOOST_ASSERT_MSG( false, "fiber already terminated");
}
};
template< typename Ctx, typename StackAlloc, typename Fn >
static fiber_activation_record * create_fiber1( StackAlloc && salloc, Fn && fn) {
typedef fiber_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");
}
#if BOOST_OS_BSD_FREE
// because FreeBSD defines stack_t::ss_sp as char *
record->uctx.uc_stack.ss_sp = static_cast< char * >( stack_bottom);
#else
record->uctx.uc_stack.ss_sp = stack_bottom;
#endif
// 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 (*)() ) & fiber_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
#if defined (BOOST_USE_TSAN)
record->tsan_fiber = __tsan_create_fiber(0);
#endif
return record;
}
template< typename Ctx, typename StackAlloc, typename Fn >
static fiber_activation_record * create_fiber2( preallocated palloc, StackAlloc && salloc, Fn && fn) {
typedef fiber_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");
}
#if BOOST_OS_BSD_FREE
// because FreeBSD defines stack_t::ss_sp as char *
record->uctx.uc_stack.ss_sp = static_cast< char * >( stack_bottom);
#else
record->uctx.uc_stack.ss_sp = stack_bottom;
#endif
// 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 (*)() ) & fiber_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
#if defined (BOOST_USE_TSAN)
record->tsan_fiber = __tsan_create_fiber(0);
#endif
return record;
}
}
class BOOST_CONTEXT_DECL fiber {
private:
friend struct detail::fiber_activation_record;
template< typename Ctx, typename StackAlloc, typename Fn >
friend class detail::fiber_capture_record;
template< typename Ctx, typename StackAlloc, typename Fn >
friend detail::fiber_activation_record * detail::create_fiber1( StackAlloc &&, Fn &&);
template< typename Ctx, typename StackAlloc, typename Fn >
friend detail::fiber_activation_record * detail::create_fiber2( preallocated, StackAlloc &&, Fn &&);
template< typename StackAlloc, typename Fn >
friend fiber
callcc( std::allocator_arg_t, StackAlloc &&, Fn &&);
template< typename StackAlloc, typename Fn >
friend fiber
callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&);
detail::fiber_activation_record * ptr_{ nullptr };
fiber( detail::fiber_activation_record * ptr) noexcept :
ptr_{ ptr } {
}
public:
fiber() = default;
template< typename Fn, typename = detail::disable_overload< fiber, Fn > >
fiber( Fn && fn) :
fiber{
std::allocator_arg,
#if defined(BOOST_USE_SEGMENTED_STACKS)
segmented_stack(),
#else
fixedsize_stack(),
#endif
std::forward< Fn >( fn) } {
}
template< typename StackAlloc, typename Fn >
fiber( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) :
ptr_{ detail::create_fiber1< fiber >(
std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } {
}
template< typename StackAlloc, typename Fn >
fiber( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) :
ptr_{ detail::create_fiber2< fiber >(
palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } {
}
~fiber() {
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();
}
}
fiber( fiber const&) = delete;
fiber & operator=( fiber const&) = delete;
fiber( fiber && other) noexcept {
swap( other);
}
fiber & operator=( fiber && other) noexcept {
if ( BOOST_LIKELY( this != & other) ) {
fiber tmp = std::move( other);
swap( tmp);
}
return * this;
}
fiber resume() && {
BOOST_ASSERT( nullptr != ptr_);
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
detail::fiber_activation_record * ptr = detail::exchange( ptr_, nullptr)->resume();
#else
detail::fiber_activation_record * ptr = std::exchange( ptr_, nullptr)->resume();
#endif
if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) {
throw detail::forced_unwind{ ptr};
} else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) {
ptr = detail::fiber_activation_record::current()->ontop( ptr);
detail::fiber_activation_record::current()->ontop = nullptr;
}
return { ptr };
}
template< typename Fn >
fiber resume_with( Fn && fn) && {
BOOST_ASSERT( nullptr != ptr_);
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
detail::fiber_activation_record * ptr =
detail::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) );
#else
detail::fiber_activation_record * ptr =
std::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) );
#endif
if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) {
throw detail::forced_unwind{ ptr};
} else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) {
ptr = detail::fiber_activation_record::current()->ontop( ptr);
detail::fiber_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<( fiber 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, fiber 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, fiber const& other);
#endif
void swap( fiber & 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, fiber const& other) {
if ( nullptr != other.ptr_) {
return os << other.ptr_;
} else {
return os << "{not-a-context}";
}
}
#endif
inline
void swap( fiber & l, fiber & r) noexcept {
l.swap( r);
}
typedef fiber fiber_context;
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_FIBER_H

View File

@@ -0,0 +1,458 @@
// 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_FIBER_H
#define BOOST_CONTEXT_FIBER_H
#include <windows.h>
#include <boost/context/detail/config.hpp>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <memory>
#include <ostream>
#include <system_error>
#include <tuple>
#include <utility>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/context/detail/disable_overload.hpp>
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
#include <boost/context/detail/exchange.hpp>
#endif
#if defined(BOOST_NO_CXX17_STD_INVOKE)
#include <boost/context/detail/invoke.hpp>
#endif
#include <boost/context/fixedsize_stack.hpp>
#include <boost/context/flags.hpp>
#include <boost/context/preallocated.hpp>
#include <boost/context/stack_context.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable: 4702)
#endif
namespace boost {
namespace context {
namespace detail {
// tampoline function
// entered if the execution context
// is resumed for the first time
template< typename Record >
static VOID WINAPI fiber_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 fiber_activation_record {
LPVOID fiber{ nullptr };
stack_context sctx{};
bool main_ctx{ true };
fiber_activation_record * from{ nullptr };
std::function< fiber_activation_record*(fiber_activation_record*&) > ontop{};
bool terminated{ false };
bool force_unwind{ false };
static fiber_activation_record *& current() noexcept;
// used for toplevel-context
// (e.g. main context, thread-entry context)
fiber_activation_record() noexcept {
#if ( _WIN32_WINNT > 0x0600)
if ( ::IsThreadAFiber() ) {
fiber = ::GetCurrentFiber();
} else {
fiber = ::ConvertThreadToFiber( nullptr);
}
#else
fiber = ::ConvertThreadToFiber( nullptr);
if ( BOOST_UNLIKELY( nullptr == fiber) ) {
BOOST_ASSERT( ERROR_ALREADY_FIBER == ::GetLastError());
fiber = ::GetCurrentFiber();
BOOST_ASSERT( nullptr != fiber);
BOOST_ASSERT( reinterpret_cast< LPVOID >( 0x1E00) != fiber);
}
#endif
}
fiber_activation_record( stack_context sctx_) noexcept :
sctx{ sctx_ },
main_ctx{ false } {
}
virtual ~fiber_activation_record() {
if ( BOOST_UNLIKELY( main_ctx) ) {
::ConvertFiberToThread();
} else {
::DeleteFiber( fiber);
}
}
fiber_activation_record( fiber_activation_record const&) = delete;
fiber_activation_record & operator=( fiber_activation_record const&) = delete;
bool is_main_context() const noexcept {
return main_ctx;
}
fiber_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 >
fiber_activation_record * resume_with( Fn && fn) {
from = current();
// store `this` in static, thread local pointer
// `this` will become the active (running) context
// returned by fiber::current()
current() = this;
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
current()->ontop = std::bind(
[](typename std::decay< Fn >::type & fn, fiber_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>(fn)](fiber_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 fiber_activation_record_initializer {
fiber_activation_record_initializer() noexcept;
~fiber_activation_record_initializer();
};
struct forced_unwind {
fiber_activation_record * from{ nullptr };
explicit forced_unwind( fiber_activation_record * from_) :
from{ from_ } {
}
};
template< typename Ctx, typename StackAlloc, typename Fn >
class fiber_capture_record : public fiber_activation_record {
private:
typename std::decay< StackAlloc >::type salloc_;
typename std::decay< Fn >::type fn_;
static void destroy( fiber_capture_record * p) noexcept {
typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
stack_context sctx = p->sctx;
// deallocate activation record
p->~fiber_capture_record();
// destroy stack with stack allocator
salloc.deallocate( sctx);
}
public:
fiber_capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept :
fiber_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;
std::move( c).resume();
BOOST_ASSERT_MSG( false, "fiber already terminated");
}
};
template< typename Ctx, typename StackAlloc, typename Fn >
static fiber_activation_record * create_fiber1( StackAlloc && salloc, Fn && fn) {
typedef fiber_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::fiber_entry_func< capture_t >, record);
return record;
}
template< typename Ctx, typename StackAlloc, typename Fn >
static fiber_activation_record * create_fiber2( preallocated palloc, StackAlloc && salloc, Fn && fn) {
typedef fiber_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::fiber_entry_func< capture_t >, record);
return record;
}
}
class BOOST_CONTEXT_DECL fiber {
private:
friend struct detail::fiber_activation_record;
template< typename Ctx, typename StackAlloc, typename Fn >
friend class detail::fiber_capture_record;
template< typename Ctx, typename StackAlloc, typename Fn >
friend detail::fiber_activation_record * detail::create_fiber1( StackAlloc &&, Fn &&);
template< typename Ctx, typename StackAlloc, typename Fn >
friend detail::fiber_activation_record * detail::create_fiber2( preallocated, StackAlloc &&, Fn &&);
template< typename StackAlloc, typename Fn >
friend fiber
callcc( std::allocator_arg_t, StackAlloc &&, Fn &&);
template< typename StackAlloc, typename Fn >
friend fiber
callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&);
detail::fiber_activation_record * ptr_{ nullptr };
fiber( detail::fiber_activation_record * ptr) noexcept :
ptr_{ ptr } {
}
public:
fiber() = default;
template< typename Fn, typename = detail::disable_overload< fiber, Fn > >
fiber( Fn && fn) :
fiber{ std::allocator_arg,
fixedsize_stack(),
std::forward< Fn >( fn) } {
}
template< typename StackAlloc, typename Fn >
fiber( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) :
ptr_{ detail::create_fiber1< fiber >(
std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } {;
}
template< typename StackAlloc, typename Fn >
fiber( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) :
ptr_{ detail::create_fiber2< fiber >(
palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } {
}
~fiber() {
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();
}
}
fiber( fiber const&) = delete;
fiber & operator=( fiber const&) = delete;
fiber( fiber && other) noexcept {
swap( other);
}
fiber & operator=( fiber && other) noexcept {
if ( BOOST_LIKELY( this != & other) ) {
fiber tmp = std::move( other);
swap( tmp);
}
return * this;
}
fiber resume() && {
BOOST_ASSERT( nullptr != ptr_);
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
detail::fiber_activation_record * ptr = detail::exchange( ptr_, nullptr)->resume();
#else
detail::fiber_activation_record * ptr = std::exchange( ptr_, nullptr)->resume();
#endif
if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) {
throw detail::forced_unwind{ ptr};
} else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) {
ptr = detail::fiber_activation_record::current()->ontop( ptr);
detail::fiber_activation_record::current()->ontop = nullptr;
}
return { ptr };
}
template< typename Fn >
fiber resume_with( Fn && fn) && {
BOOST_ASSERT( nullptr != ptr_);
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
detail::fiber_activation_record * ptr =
detail::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) );
#else
detail::fiber_activation_record * ptr =
std::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) );
#endif
if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) {
throw detail::forced_unwind{ ptr};
} else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) {
ptr = detail::fiber_activation_record::current()->ontop( ptr);
detail::fiber_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<( fiber 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, fiber 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, fiber const& other);
#endif
void swap( fiber & 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, fiber const& other) {
if ( nullptr != other.ptr_) {
return os << other.ptr_;
} else {
return os << "{not-a-context}";
}
}
#endif
inline
void swap( fiber & l, fiber & r) noexcept {
l.swap( r);
}
typedef fiber fiber_context;
}}
#if defined(BOOST_MSVC)
# pragma warning(pop)
#endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_FIBER_H

View File

@@ -0,0 +1,97 @@
// 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_CONTEXT_USE_MAP_STACK)
extern "C" {
#include <sys/mman.h>
}
#endif
#if defined(BOOST_USE_VALGRIND)
#include <valgrind/valgrind.h>
#endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace context {
template< typename traitsT >
class basic_fixedsize_stack {
private:
std::size_t size_;
public:
typedef traitsT traits_type;
basic_fixedsize_stack( std::size_t size = traits_type::default_size() ) BOOST_NOEXCEPT_OR_NOTHROW :
size_( size) {
}
stack_context allocate() {
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
void * vp = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
if ( vp == MAP_FAILED) {
throw std::bad_alloc();
}
#else
void * vp = std::malloc( size_);
if ( ! vp) {
throw std::bad_alloc();
}
#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_NOEXCEPT_OR_NOTHROW {
BOOST_ASSERT( sctx.sp);
#if defined(BOOST_USE_VALGRIND)
VALGRIND_STACK_DEREGISTER( sctx.valgrind_stack_id);
#endif
void * vp = static_cast< char * >( sctx.sp) - sctx.size;
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
::munmap( vp, sctx.size);
#else
std::free( vp);
#endif
}
};
typedef basic_fixedsize_stack< stack_traits > fixedsize_stack;
# if ! defined(BOOST_USE_SEGMENTED_STACKS)
typedef fixedsize_stack default_stack;
# endif
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_FIXEDSIZE_H

View File

@@ -0,0 +1,28 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_FLAGS_H
#define BOOST_CONTEXT_FLAGS_H
# include <boost/config.hpp>
# ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
# endif
namespace boost {
namespace context {
struct exec_ontop_arg_t {};
const exec_ontop_arg_t exec_ontop_arg{};
}}
# ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
# endif
#endif // BOOST_CONTEXT_FLAGS_H

View File

@@ -0,0 +1,152 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_POOLED_pooled_fixedsize_H
#define BOOST_CONTEXT_POOLED_pooled_fixedsize_H
#include <atomic>
#include <cstddef>
#include <cstdlib>
#include <new>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/pool/pool.hpp>
#include <boost/context/detail/config.hpp>
#include <boost/context/stack_context.hpp>
#include <boost/context/stack_traits.hpp>
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
extern "C" {
#include <sys/mman.h>
#include <stdlib.h>
}
#endif
#if defined(BOOST_USE_VALGRIND)
#include <valgrind/valgrind.h>
#endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace context {
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
namespace detail {
template< typename traitsT >
struct map_stack_allocator {
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) {
return 0;
}
if ( mmap( block, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_STACK, -1, 0) == MAP_FAILED) {
std::free( block);
return 0;
}
return reinterpret_cast< char * >( block);
}
static void free( char * const block) {
std::free( block);
}
};
}
#endif
template< typename traitsT >
class basic_pooled_fixedsize_stack {
private:
class storage {
private:
std::atomic< std::size_t > use_count_;
std::size_t stack_size_;
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
boost::pool< detail::map_stack_allocator< traitsT > > storage_;
#else
boost::pool< boost::default_user_allocator_malloc_free > storage_;
#endif
public:
storage( std::size_t stack_size, std::size_t next_size, std::size_t max_size) :
use_count_( 0),
stack_size_( stack_size),
storage_( stack_size, next_size, max_size) {
BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= stack_size_) );
}
stack_context allocate() {
void * vp = storage_.malloc();
if ( ! vp) {
throw std::bad_alloc();
}
stack_context sctx;
sctx.size = stack_size_;
sctx.sp = static_cast< char * >( vp) + sctx.size;
#if defined(BOOST_USE_VALGRIND)
sctx.valgrind_stack_id = VALGRIND_STACK_REGISTER( sctx.sp, vp);
#endif
return sctx;
}
void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW {
BOOST_ASSERT( sctx.sp);
BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= sctx.size) );
#if defined(BOOST_USE_VALGRIND)
VALGRIND_STACK_DEREGISTER( sctx.valgrind_stack_id);
#endif
void * vp = static_cast< char * >( sctx.sp) - sctx.size;
storage_.free( vp);
}
friend void intrusive_ptr_add_ref( storage * s) noexcept {
++s->use_count_;
}
friend void intrusive_ptr_release( storage * s) noexcept {
if ( 0 == --s->use_count_) {
delete s;
}
}
};
intrusive_ptr< storage > storage_;
public:
typedef traitsT traits_type;
basic_pooled_fixedsize_stack( std::size_t stack_size = traits_type::default_size(),
std::size_t next_size = 32,
std::size_t max_size = 0) BOOST_NOEXCEPT_OR_NOTHROW :
storage_( new storage( stack_size, next_size, max_size) ) {
}
stack_context allocate() {
return storage_->allocate();
}
void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW {
storage_->deallocate( sctx);
}
};
typedef basic_pooled_fixedsize_stack< stack_traits > pooled_fixedsize_stack;
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_POOLED_pooled_fixedsize_H

View File

@@ -0,0 +1,102 @@
// 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/core/ignore_unused.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() ) BOOST_NOEXCEPT_OR_NOTHROW :
size_( size) {
}
stack_context allocate() {
// calculate how many pages are required
const std::size_t pages = (size_ + traits_type::page_size() - 1) / traits_type::page_size();
// add one page at bottom that will be used as guard-page
const std::size_t size__ = ( pages + 1) * traits_type::page_size();
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
void * vp = ::mmap( 0, size__, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
#elif 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
const int result( ::mprotect( vp, traits_type::page_size(), PROT_NONE) );
boost::ignore_unused(result);
BOOST_ASSERT( 0 == result);
stack_context sctx;
sctx.size = size__;
sctx.sp = static_cast< char * >( vp) + sctx.size;
#if defined(BOOST_USE_VALGRIND)
sctx.valgrind_stack_id = VALGRIND_STACK_REGISTER( sctx.sp, vp);
#endif
return sctx;
}
void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW {
BOOST_ASSERT( sctx.sp);
#if defined(BOOST_USE_VALGRIND)
VALGRIND_STACK_DEREGISTER( sctx.valgrind_stack_id);
#endif
void * vp = static_cast< char * >( sctx.sp) - sctx.size;
// 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

View File

@@ -0,0 +1,82 @@
// 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() ) BOOST_NOEXCEPT_OR_NOTHROW :
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) BOOST_NOEXCEPT_OR_NOTHROW {
__splitstack_releasecontext( sctx.segments_ctx);
}
};
typedef basic_segmented_stack< stack_traits > segmented_stack;
# if defined(BOOST_USE_SEGMENTED_STACKS)
typedef segmented_stack default_stack;
# endif
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_SEGMENTED_H

View File

@@ -0,0 +1,39 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_PREALLOCATED_H
#define BOOST_CONTEXT_PREALLOCATED_H
#include <cstddef>
#include <boost/config.hpp>
#include <boost/context/detail/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace context {
struct preallocated {
void * sp;
std::size_t size;
stack_context sctx;
preallocated( void * sp_, std::size_t size_, stack_context sctx_) noexcept :
sp( sp_), size( size_), sctx( sctx_) {
}
};
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_PREALLOCATED_H

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,72 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_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_CONTEXT_NO_CXX11)
struct BOOST_CONTEXT_DECL stack_context {
# if defined(BOOST_USE_SEGMENTED_STACKS)
typedef void * segments_context[BOOST_CONTEXT_SEGMENTS];
# endif
std::size_t size{ 0 };
void * sp{ nullptr };
# if defined(BOOST_USE_SEGMENTED_STACKS)
segments_context segments_ctx{};
# endif
# if defined(BOOST_USE_VALGRIND)
unsigned valgrind_stack_id{ 0 };
# endif
};
#else
struct BOOST_CONTEXT_DECL stack_context {
# if defined(BOOST_USE_SEGMENTED_STACKS)
typedef void * segments_context[BOOST_CONTEXT_SEGMENTS];
# endif
std::size_t size;
void * sp;
# if defined(BOOST_USE_SEGMENTED_STACKS)
segments_context segments_ctx;
# endif
# if defined(BOOST_USE_VALGRIND)
unsigned valgrind_stack_id;
# endif
stack_context() :
size( 0),
sp( 0)
# if defined(BOOST_USE_SEGMENTED_STACKS)
, segments_ctx()
# endif
# 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

View File

@@ -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_OR_NOTHROW;
static std::size_t page_size() BOOST_NOEXCEPT_OR_NOTHROW;
static std::size_t default_size() BOOST_NOEXCEPT_OR_NOTHROW;
static std::size_t minimum_size() BOOST_NOEXCEPT_OR_NOTHROW;
static std::size_t maximum_size() BOOST_NOEXCEPT_OR_NOTHROW;
};
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_STACK_TRAITS_H

View File

@@ -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_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/core/ignore_unused.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() ) BOOST_NOEXCEPT_OR_NOTHROW :
size_( size) {
}
stack_context allocate() {
// calculate how many pages are required
const std::size_t pages = (size_ + traits_type::page_size() - 1) / traits_type::page_size();
// add one page at bottom that will be used as guard-page
const std::size_t size__ = ( pages + 1) * traits_type::page_size();
void * vp = ::VirtualAlloc( 0, size__, MEM_COMMIT, PAGE_READWRITE);
if ( ! vp) throw std::bad_alloc();
DWORD old_options;
const BOOL result = ::VirtualProtect(
vp, traits_type::page_size(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options);
boost::ignore_unused(result);
BOOST_ASSERT( FALSE != result);
stack_context sctx;
sctx.size = size__;
sctx.sp = static_cast< char * >( vp) + sctx.size;
return sctx;
}
void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW {
BOOST_ASSERT( sctx.sp);
void * vp = static_cast< char * >( sctx.sp) - sctx.size;
::VirtualFree( vp, 0, MEM_RELEASE);
}
};
typedef basic_protected_fixedsize_stack< stack_traits > protected_fixedsize_stack;
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_PROTECTED_FIXEDSIZE_H

View File

@@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,4 @@
The package boost is compatible with built-in CMake targets:
find_package(Boost REQUIRED [COMPONENTS <libs>...])
target_link_libraries(main PRIVATE Boost::boost Boost::<lib1> Boost::<lib2> ...)

View File

@@ -0,0 +1,137 @@
{
"$schema": "https://raw.githubusercontent.com/spdx/spdx-spec/v2.2.1/schemas/spdx-schema.json",
"spdxVersion": "SPDX-2.2",
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"documentNamespace": "https://spdx.org/spdxdocs/boost-context-x64-windows-1.79.0-1695cce0-501f-40c8-8ded-fd04620cf457",
"name": "boost-context:x64-windows@1.79.0 e94ca7654d66a89fc41232ed8f559b3f0da8bbdf35e7851b96a39f97664a797a",
"creationInfo": {
"creators": [
"Tool: vcpkg-9268e366206712e38102b28dbd1617697a99ff2e"
],
"created": "2022-07-23T08:23:38Z"
},
"relationships": [
{
"spdxElementId": "SPDXRef-port",
"relationshipType": "GENERATES",
"relatedSpdxElement": "SPDXRef-binary"
},
{
"spdxElementId": "SPDXRef-port",
"relationshipType": "CONTAINS",
"relatedSpdxElement": "SPDXRef-file-0"
},
{
"spdxElementId": "SPDXRef-port",
"relationshipType": "CONTAINS",
"relatedSpdxElement": "SPDXRef-file-1"
},
{
"spdxElementId": "SPDXRef-port",
"relationshipType": "CONTAINS",
"relatedSpdxElement": "SPDXRef-file-2"
},
{
"spdxElementId": "SPDXRef-binary",
"relationshipType": "GENERATED_FROM",
"relatedSpdxElement": "SPDXRef-port"
},
{
"spdxElementId": "SPDXRef-file-0",
"relationshipType": "CONTAINED_BY",
"relatedSpdxElement": "SPDXRef-port"
},
{
"spdxElementId": "SPDXRef-file-1",
"relationshipType": "CONTAINED_BY",
"relatedSpdxElement": "SPDXRef-port"
},
{
"spdxElementId": "SPDXRef-file-2",
"relationshipType": "CONTAINED_BY",
"relatedSpdxElement": "SPDXRef-port"
},
{
"spdxElementId": "SPDXRef-file-2",
"relationshipType": "DEPENDENCY_MANIFEST_OF",
"relatedSpdxElement": "SPDXRef-port"
}
],
"packages": [
{
"name": "boost-context",
"SPDXID": "SPDXRef-port",
"versionInfo": "1.79.0",
"downloadLocation": "NOASSERTION",
"homepage": "https://github.com/boostorg/context",
"licenseConcluded": "BSL-1.0",
"licenseDeclared": "NOASSERTION",
"copyrightText": "NOASSERTION",
"description": "Boost context module",
"comment": "This is the port (recipe) consumed by vcpkg."
},
{
"name": "boost-context:x64-windows",
"SPDXID": "SPDXRef-binary",
"versionInfo": "e94ca7654d66a89fc41232ed8f559b3f0da8bbdf35e7851b96a39f97664a797a",
"downloadLocation": "NONE",
"licenseConcluded": "BSL-1.0",
"licenseDeclared": "NOASSERTION",
"copyrightText": "NOASSERTION",
"comment": "This is a binary package built by vcpkg."
},
{
"SPDXID": "SPDXRef-resource-1",
"name": "boostorg/context",
"downloadLocation": "git+https://github.com/boostorg/context@boost-1.79.0",
"licenseConcluded": "NOASSERTION",
"licenseDeclared": "NOASSERTION",
"copyrightText": "NOASSERTION",
"checksums": [
{
"algorithm": "SHA512",
"checksumValue": "25fc307a3ffa9b2b87199e0d7faf87ccd899c619d5043d3780e65476a0356a3edb0fcd55400bd2898f12de149952edf2fde58c79b62d993b534b81561bd174ea"
}
]
}
],
"files": [
{
"fileName": "./b2-options.cmake.in",
"SPDXID": "SPDXRef-file-0",
"checksums": [
{
"algorithm": "SHA256",
"checksumValue": "4f44072bea057c74d1dbc7e2543b65a21041811104e514e9718c43d3cd8753a1"
}
],
"licenseConcluded": "NOASSERTION",
"copyrightText": "NOASSERTION"
},
{
"fileName": "./portfile.cmake",
"SPDXID": "SPDXRef-file-1",
"checksums": [
{
"algorithm": "SHA256",
"checksumValue": "294d0cb82bc2dec99c167f3917da40493ae993b6dd42062b2eb364fd268a2f60"
}
],
"licenseConcluded": "NOASSERTION",
"copyrightText": "NOASSERTION"
},
{
"fileName": "./vcpkg.json",
"SPDXID": "SPDXRef-file-2",
"checksums": [
{
"algorithm": "SHA256",
"checksumValue": "c97ee12bfc22be95f9cb9d59743ce12bdb3597e3449172f41e8da07549ac99d9"
}
],
"licenseConcluded": "NOASSERTION",
"copyrightText": "NOASSERTION"
}
]
}

View File

@@ -0,0 +1,24 @@
b2-options.cmake.in 4f44072bea057c74d1dbc7e2543b65a21041811104e514e9718c43d3cd8753a1
boost-assert a50eed453b8be6c8932fb3d5f8feaf194a2ebeaed7982db4e36e3ba17f3ec107
boost-build ae2e04240d11929b681e289a0f6dd881454523061c007bfce13fdb89700330de
boost-config 797535e8975ed7cf5bbe11d9f7fe26caa5da8fe819888564758d82a21109fade
boost-core 498aea0b6b68bcfe1ec683e76c2f0d32477dfe9ba958f518980ff806b6faba90
boost-modular-build-helper 2a88f7e0b19495c5c387221437d68f0488f9ef0237f86b578a8560ce6e7192c2
boost-mp11 e71044de916a0c8906043124be4939850655f76df511f085fa53adeb68e2cb2c
boost-pool f53abd1be62e7e71cadf9ce7d38ccf5edc7b8505d9970a8c74849587e388bfd4
boost-predef 81dee9e0bcf888e119f86c0e53f2b816cb91df516cbab38757aa4502b0f9a74b
boost-smart-ptr 38f44cf21554a20b78483abc4409c3edd633b78cc519fcf48803a1fe6b53316f
boost-vcpkg-helpers c81c7b003df356a1a120a7c0c2f5a2ac95f3c33b006a2a5b4c02dcf0c9f3deaa
cmake 3.23.2
features core
portfile.cmake 294d0cb82bc2dec99c167f3917da40493ae993b6dd42062b2eb364fd268a2f60
ports.cmake 366c60b768113102408b32ac1d7c7b48ef7d30a477af2a220ecc222d9ffa3166
post_build_checks 2
powershell 7.2.5
triplet x64-windows
triplet_abi 4556164a2cd3dd6f4742101eabb46def7e71b6e5856faa88e5d005aac12a803c-c0600b35e024ce0485ed253ef5419f3686f7257cfb58cb6a24febcb600fc4b4c-27ebd443f77a6c449168adfa6ce8def60cf46e88
vcpkg-cmake 8a68341d77ea3fc25cc1a56db9e8d3a5f3cc851fed64c21e39dd6d26f8d28428
vcpkg.json c97ee12bfc22be95f9cb9d59743ce12bdb3597e3449172f41e8da07549ac99d9
vcpkg_from_git 0aab20e34e84d52ba4763f009e539bfa8f418c41c918c8cf700156f1a8551a10
vcpkg_from_github b743742296a114ea1b18ae99672e02f142c4eb2bef7f57d36c038bedbfb0502f
vcpkg_replace_string d43c8699ce27e25d47367c970d1c546f6bc36b6df8fb0be0c3986eb5830bd4f1