From 3bf228523c0a5f08dbbb113df4f29d14d7aadd68 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Tue, 12 Feb 2013 19:01:29 +0000 Subject: [PATCH] coroutine: support for segmented stacks added [SVN r82840] --- build/Jamfile.v2 | 44 +++ detail/coroutine_context.cpp | 83 +++++ detail/segmented_stack_allocator.cpp | 93 ++++++ detail/standard_stack_allocator_posix.cpp | 163 ++++++++++ detail/standard_stack_allocator_windows.cpp | 155 ++++++++++ doc/Jamfile.v2 | 14 +- doc/coro.qbk | 2 + doc/stack.qbk | 72 ++++- example/Jamfile.v2 | 16 +- example/fibonacci.cpp | 45 ++- example/segmented_stack.cpp | 64 ++++ include/boost/coroutine/coroutine.hpp | 6 +- include/boost/coroutine/detail/config.hpp | 7 + .../boost/coroutine/detail/coroutine_base.hpp | 34 ++- .../detail/coroutine_base_resume.hpp | 88 +++--- .../coroutine/detail/coroutine_caller.hpp | 2 +- .../coroutine/detail/coroutine_context.hpp | 63 ++++ .../coroutine/detail/coroutine_object.hpp | 23 ++ .../detail/coroutine_object_result_0.ipp | 192 ++++++------ .../detail/coroutine_object_result_1.ipp | 275 ++++++++--------- .../detail/coroutine_object_result_arity.ipp | 275 ++++++++--------- .../detail/coroutine_object_void_0.ipp | 190 ++++++------ .../detail/coroutine_object_void_1.ipp | 287 ++++++++---------- .../detail/coroutine_object_void_arity.ipp | 287 ++++++++---------- include/boost/coroutine/detail/holder.hpp | 16 +- .../detail/segmented_stack_allocator.hpp | 51 ++++ .../detail/stack_allocator_posix.hpp | 173 ----------- .../detail/stack_allocator_windows.hpp | 163 ---------- .../detail/standard_stack_allocator.hpp | 49 +++ include/boost/coroutine/stack_allocator.hpp | 30 +- include/boost/coroutine/stack_context.hpp | 54 ++++ performance/Jamfile.v2 | 4 +- performance/performance.cpp | 13 +- performance/simple_stack_allocator.hpp | 18 +- src/detail/coroutine_context.cpp | 83 +++++ src/detail/segmented_stack_allocator.cpp | 93 ++++++ src/detail/standard_stack_allocator_posix.cpp | 163 ++++++++++ .../standard_stack_allocator_windows.cpp | 155 ++++++++++ test/Jamfile.v2 | 2 + 39 files changed, 2296 insertions(+), 1251 deletions(-) create mode 100644 build/Jamfile.v2 create mode 100644 detail/coroutine_context.cpp create mode 100644 detail/segmented_stack_allocator.cpp create mode 100644 detail/standard_stack_allocator_posix.cpp create mode 100644 detail/standard_stack_allocator_windows.cpp create mode 100644 example/segmented_stack.cpp create mode 100644 include/boost/coroutine/detail/coroutine_context.hpp create mode 100644 include/boost/coroutine/detail/segmented_stack_allocator.hpp delete mode 100644 include/boost/coroutine/detail/stack_allocator_posix.hpp delete mode 100644 include/boost/coroutine/detail/stack_allocator_windows.hpp create mode 100644 include/boost/coroutine/detail/standard_stack_allocator.hpp create mode 100644 include/boost/coroutine/stack_context.hpp create mode 100644 src/detail/coroutine_context.cpp create mode 100644 src/detail/segmented_stack_allocator.cpp create mode 100644 src/detail/standard_stack_allocator_posix.cpp create mode 100644 src/detail/standard_stack_allocator_windows.cpp diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 new file mode 100644 index 0000000..aa01383 --- /dev/null +++ b/build/Jamfile.v2 @@ -0,0 +1,44 @@ + +# 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) + +import feature ; +import modules ; +import toolset ; + +project boost/coroutine + : requirements + /boost/context//boost_context +# gcc-4.7:-fsplit-stack +# gcc-4.7:"-static-libgcc" + static + multi + : source-location ../src + : usage-requirements + shared:BOOST_COROUTINES_DYN_LINK=1 + ; + +alias allocator_sources + : detail/standard_stack_allocator_windows.cpp + detail/segmented_stack_allocator.cpp + : windows + ; + +alias allocator_sources + : detail/standard_stack_allocator_posix.cpp + detail/segmented_stack_allocator.cpp + ; + +explicit yield_sources ; + +lib boost_coroutine + : allocator_sources + detail/coroutine_context.cpp + : shared:BOOST_COROUTINES_DYN_LINK=1 + : + : shared:../../context/build//boost_context + ; + +boost-install boost_coroutine ; diff --git a/detail/coroutine_context.cpp b/detail/coroutine_context.cpp new file mode 100644 index 0000000..bf24719 --- /dev/null +++ b/detail/coroutine_context.cpp @@ -0,0 +1,83 @@ + +// 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) + +#define BOOST_COROUTINES_SOURCE + +#include "boost/coroutine/detail/coroutine_context.hpp" + +#if defined(BOOST_USE_SEGMENTED_STACKS) +extern "C" { + +void __splitstack_getcontext( void * [BOOST_COROUTINES_SEGMENTS]); + +void __splitstack_setcontext( void * [BOOST_COROUTINES_SEGMENTS]); + +void __splitstack_releasecontext (void * [BOOST_COROUTINES_SEGMENTS]); + +void __splitstack_block_signals_context( void * [BOOST_COROUTINES_SEGMENTS], int *, int *); + +} +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +coroutine_context::coroutine_context() : + fcontext_t(), stack_ctx_( this), ctx_( this) +{ +#if defined(BOOST_USE_SEGMENTED_STACKS) + __splitstack_getcontext( stack_ctx_->segments_ctx); +#endif +} + +coroutine_context::coroutine_context( ctx_fn fn, stack_context * stack_ctx) : + fcontext_t(), stack_ctx_( stack_ctx), + ctx_( context::make_fcontext( stack_ctx_->sp, stack_ctx_->size, fn) ) +{} + +coroutine_context::coroutine_context( coroutine_context const& other) : + fcontext_t(), + stack_ctx_( other.stack_ctx_), + ctx_( other.ctx_) +{} + +coroutine_context & +coroutine_context::operator=( coroutine_context const& other) +{ + if ( this == & other) return * this; + + stack_ctx_ = other.stack_ctx_; + ctx_ = other.ctx_; + + return * this; +} + +intptr_t +coroutine_context::jump( coroutine_context & other, intptr_t param, bool preserve_fpu) +{ +#if defined(BOOST_USE_SEGMENTED_STACKS) + if ( stack_ctx_) + __splitstack_getcontext( stack_ctx_->segments_ctx); + if ( other.stack_ctx_) + __splitstack_setcontext( other.stack_ctx_->segments_ctx); +#endif + return context::jump_fcontext( ctx_, other.ctx_, param, preserve_fpu); +#if defined(BOOST_USE_SEGMENTED_STACKS) + if ( stack_ctx_) + __splitstack_setcontext( stack_ctx_->segments_ctx); +#endif +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/detail/segmented_stack_allocator.cpp b/detail/segmented_stack_allocator.cpp new file mode 100644 index 0000000..ab71769 --- /dev/null +++ b/detail/segmented_stack_allocator.cpp @@ -0,0 +1,93 @@ + +// 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) + +#define BOOST_COROUTINES_SOURCE + +#if defined(BOOST_USE_SEGMENTED_STACKS) + +#include + +#include +#include + +#include + +extern "C" { + +void *__splitstack_makecontext( std::size_t, + void * [BOOST_COROUTINES_SEGMENTS], + std::size_t *); + +void __splitstack_releasecontext( void * [BOOST_COROUTINES_SEGMENTS]); + +void __splitstack_resetcontext( void * [BOOST_COROUTINES_SEGMENTS]); + +void __splitstack_block_signals_context( void * [BOOST_COROUTINES_SEGMENTS], + int * new_value, int * old_value); +} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if !defined (SIGSTKSZ) +# define SIGSTKSZ (8 * 1024) +# define UDEF_SIGSTKSZ +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +bool +segmented_stack_allocator::is_stack_unbound() +{ return true; } + +std::size_t +segmented_stack_allocator::minimum_stacksize() +{ return SIGSTKSZ + sizeof( context::fcontext_t) + 15; } + +std::size_t +segmented_stack_allocator::default_stacksize() +{ return minimum_stacksize(); } + +std::size_t +segmented_stack_allocator::maximum_stacksize() +{ + BOOST_ASSERT_MSG( false, "segmented stack is unbound"); + return 0; +} + +void +segmented_stack_allocator::allocate( stack_context & ctx, std::size_t size) +{ + BOOST_ASSERT( default_stacksize() <= size); + + void * limit = __splitstack_makecontext( size, ctx.segments_ctx, & ctx.size); + BOOST_ASSERT( limit); + ctx.sp = static_cast< char * >( limit) + ctx.size; + + int off = 0; + __splitstack_block_signals_context( ctx.segments_ctx, & off, 0); +} + +void +segmented_stack_allocator::deallocate( stack_context & ctx) +{ + __splitstack_releasecontext( ctx.segments_ctx); +} + +}}} + +#ifdef UDEF_SIGSTKSZ +# undef SIGSTKSZ +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif diff --git a/detail/standard_stack_allocator_posix.cpp b/detail/standard_stack_allocator_posix.cpp new file mode 100644 index 0000000..ed9c6fe --- /dev/null +++ b/detail/standard_stack_allocator_posix.cpp @@ -0,0 +1,163 @@ + +// 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) + +#define BOOST_COROUTINES_SOURCE + +#include "boost/coroutine/detail/standard_stack_allocator.hpp" + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +} + +//#if _POSIX_C_SOURCE >= 200112L + +#include +#include +#include +#include + +#include +#include + +#include + +#if !defined (SIGSTKSZ) +# define SIGSTKSZ (8 * 1024) +# define UDEF_SIGSTKSZ +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +std::size_t pagesize() +{ + // conform to POSIX.1-2001 + static std::size_t size = ::sysconf( _SC_PAGESIZE); + return size; +} + +rlimit stacksize_limit_() +{ + rlimit limit; + // conforming to POSIX.1-2001 +#if defined(BOOST_DISABLE_ASSERTS) + ::getrlimit( RLIMIT_STACK, & limit); +#else + const int result = ::getrlimit( RLIMIT_STACK, & limit); + BOOST_ASSERT( 0 == result); +#endif + return limit; +} + +rlimit stacksize_limit() +{ + static rlimit limit = stacksize_limit_(); + return limit; +} + +std::size_t page_count( std::size_t stacksize) +{ + return static_cast< std::size_t >( + std::ceil( + static_cast< float >( stacksize) / pagesize() ) ); +} + +bool +standard_stack_allocator::is_stack_unbound() +{ return RLIM_INFINITY == detail::stacksize_limit().rlim_max; } + +std::size_t +standard_stack_allocator::default_stacksize() +{ + std::size_t size = 8 * minimum_stacksize(); + if ( is_stack_unbound() ) return size; + + BOOST_ASSERT( maximum_stacksize() >= minimum_stacksize() ); + return maximum_stacksize() == size + ? size + : (std::min)( size, maximum_stacksize() ); +} + +std::size_t +standard_stack_allocator::minimum_stacksize() +{ return SIGSTKSZ + sizeof( context::fcontext_t) + 15; } + +std::size_t +standard_stack_allocator::maximum_stacksize() +{ + BOOST_ASSERT( ! is_stack_unbound() ); + return static_cast< std::size_t >( detail::stacksize_limit().rlim_max); +} + +void +standard_stack_allocator::allocate( stack_context & ctx, std::size_t size) +{ + BOOST_ASSERT( minimum_stacksize() <= size); + BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= size) ); + + const std::size_t pages( detail::page_count( size) + 1); // add one guard page + const std::size_t size_( pages * detail::pagesize() ); + BOOST_ASSERT( 0 < size && 0 < size_); + + const int fd( ::open("/dev/zero", O_RDONLY) ); + BOOST_ASSERT( -1 != fd); + // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) + void * limit = +# if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) + ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); +# else + ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); +# endif + ::close( fd); + if ( ! limit) throw std::bad_alloc(); + + std::memset( limit, '\0', size_); + + // conforming to POSIX.1-2001 +#if defined(BOOST_DISABLE_ASSERTS) + ::mprotect( limit, detail::pagesize(), PROT_NONE); +#else + const int result( ::mprotect( limit, detail::pagesize(), PROT_NONE) ); + BOOST_ASSERT( 0 == result); +#endif + + ctx.size = size_; + ctx.sp = static_cast< char * >( limit) + ctx.size; +} + +void +standard_stack_allocator::deallocate( stack_context & ctx) +{ + BOOST_ASSERT( ctx.sp); + BOOST_ASSERT( minimum_stacksize() <= ctx.size); + BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= ctx.size) ); + + void * limit = static_cast< char * >( ctx.sp) - ctx.size; + // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) + ::munmap( limit, ctx.size); +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#ifdef UDEF_SIGSTKSZ +# undef SIGSTKSZ +#endif diff --git a/detail/standard_stack_allocator_windows.cpp b/detail/standard_stack_allocator_windows.cpp new file mode 100644 index 0000000..a6997eb --- /dev/null +++ b/detail/standard_stack_allocator_windows.cpp @@ -0,0 +1,155 @@ + +// 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) + +#define BOOST_COROUTINES_SOURCE + +#include "boost/coroutine/detail/standard_stack_allocator.hpp" + +extern "C" { +#include +} + +//#if defined (BOOST_WINDOWS) || _POSIX_C_SOURCE >= 200112L + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +# if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable:4244 4267) +# endif + +// x86_64 +// test x86_64 before i386 because icc might +// define __i686__ for x86_64 too +#if defined(__x86_64__) || defined(__x86_64) \ + || defined(__amd64__) || defined(__amd64) \ + || defined(_M_X64) || defined(_M_AMD64) + +// Windows seams not to provide a constant or function +// telling the minimal stacksize +# define MIN_STACKSIZE 8 * 1024 +#else +# define MIN_STACKSIZE 4 * 1024 +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +SYSTEM_INFO system_info_() +{ + SYSTEM_INFO si; + ::GetSystemInfo( & si); + return si; +} + +SYSTEM_INFO system_info() +{ + static SYSTEM_INFO si = system_info_(); + return si; +} + +std::size_t pagesize() +{ return static_cast< std::size_t >( system_info().dwPageSize); } + +std::size_t page_count( std::size_t stacksize) +{ + return static_cast< std::size_t >( + std::ceil( + static_cast< float >( stacksize) / pagesize() ) ); +} + +// Windows seams not to provide a limit for the stacksize +bool +standard_stack_allocator::is_stack_unbound() +{ return true; } + +std::size_t +standard_stack_allocator::default_stacksize() +{ + std::size_t size = 64 * 1024; // 64 kB + if ( is_stack_unbound() ) + return (std::max)( size, minimum_stacksize() ); + + BOOST_ASSERT( maximum_stacksize() >= minimum_stacksize() ); + return maximum_stacksize() == minimum_stacksize() + ? minimum_stacksize() + : ( std::min)( size, maximum_stacksize() ); +} + +// because Windows seams not to provide a limit for minimum stacksize +std::size_t +standard_stack_allocator::minimum_stacksize() +{ return MIN_STACKSIZE; } + +// because Windows seams not to provide a limit for maximum stacksize +// maximum_stacksize() can never be called (pre-condition ! is_stack_unbound() ) +std::size_t +standard_stack_allocator::maximum_stacksize() +{ + BOOST_ASSERT( ! is_stack_unbound() ); + return 1 * 1024 * 1024 * 1024; // 1GB +} + +void +standard_stack_allocator::allocate( stack_context & ctx, std::size_t size) +{ + BOOST_ASSERT( minimum_stacksize() <= size); + BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= size) ); + + const std::size_t pages( detail::page_count( size) + 1); // add one guard page + const std::size_t size_ = pages * detail::pagesize(); + BOOST_ASSERT( 0 < size && 0 < size_); + + void * limit = ::VirtualAlloc( 0, size_, MEM_COMMIT, PAGE_READWRITE); + if ( ! limit) throw std::bad_alloc(); + + std::memset( limit, '\0', size_); + + DWORD old_options; +#if defined(BOOST_DISABLE_ASSERTS) + ::VirtualProtect( + limit, detail::pagesize(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); +#else + const BOOL result = ::VirtualProtect( + limit, detail::pagesize(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); + BOOST_ASSERT( FALSE != result); +#endif + + ctx.size = size_; + ctx.sp = static_cast< char * >( limit) + ctx.size; +} + +void +standard_stack_allocator::deallocate( stack_context & ctx) +{ + BOOST_ASSERT( ctx.sp); + BOOST_ASSERT( minimum_stacksize() <= ctx.size); + BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= ctx.size) ); + + void * limit = static_cast< char * >( ctx.sp) - ctx.size; + ::VirtualFree( limit, 0, MEM_RELEASE); +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index d18dc6f..f02d4d4 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -3,12 +3,18 @@ # 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) -xml coro : coro.qbk ; +project coroutine/doc ; -boostbook standalone +import boostbook ; +import quickbook ; +import modules ; + +boostbook coro : - coro + coro.qbk : + # Path for links to Boost: + boost.root=../../../.. # HTML options first: # How far down we chunk nested sections, basically all of them: chunk.section.depth=3 @@ -20,6 +26,4 @@ boostbook standalone toc.max.depth=3 # How far down we go with TOC's generate.section.toc.level=10 - # Path for links to Boost: - boost.root=../../../.. ; diff --git a/doc/coro.qbk b/doc/coro.qbk index 9615952..01f1bad 100644 --- a/doc/coro.qbk +++ b/doc/coro.qbk @@ -43,6 +43,7 @@ [def __coros__ ['coroutines]] [def __not_a_coro__ ['not-a-coroutine]] [def __signature__ ['Signature]] +[def __segmented_stack__ ['segemented-stack]] [def __stack_allocator__ ['stack-allocator]] [def __stack_allocator_concept__ ['stack-allocator concept]] [def __stack__ ['stack]] @@ -67,6 +68,7 @@ [def __io_service__ ['boost::asio::io_sevice]] [def __server__ ['server]] [def __session__ ['session]] +[def __stack_context__ ['boost::coroutines::stack_context]] [def __start__ ['session::start()]] [def __thread__ ['boost::thread]] [def __tie__ ['boost::tie]] diff --git a/doc/stack.qbk b/doc/stack.qbk index f063ec0..90f2e32 100644 --- a/doc/stack.qbk +++ b/doc/stack.qbk @@ -15,20 +15,19 @@ which is required to model a __stack_allocator_concept__. [heading __stack_allocator_concept__] A __stack_allocator__ must satisfy the __stack_allocator_concept__ requirements shown in the following table, in which `a` is an object of a -__stack_allocator__ type, `p` is a `void *`, and `s` is a `std::size_t`: +__stack_allocator__ type, `sctx` is a `stack_context`, and `size` is a `std::size_t`: [table [[expression][return type][notes]] [ - [`a.allocate( s)`] - [`void *`] - [returns a pointer to `s` bytes allocated from the stack] + [`a.allocate( sctx, size)`] + [`void`] + [creates a stack of at least `size` bytes and stores both values in `sctx`] ] [ - [`a.deallocate( p, s)`] + [`a.deallocate( sctx)`] [`void`] - [deallocates `s` bytes of memory beginning at `p`, - a pointer previously returned by `a.allocate()`] + [deallocates the stack created by `a.allocate()`] ] ] @@ -68,9 +67,9 @@ virtual addresses are used.] static std::size_t minimum_stacksize(); - void * allocate( std::size_t size); + void allocate( stack_context &, std::size_t size); - void deallocate( void * sp, std::size_t size); + void deallocate( stack_context &); } [heading `static bool is_stack_unbound()`] @@ -97,24 +96,69 @@ If the stack is unbound then the present implementation returns the maximum of environment (Win32 4kB/Win64 8kB, defined by rlimit on POSIX).]] ] -[heading `void * allocate( std::size_t size)`] +[heading `void allocate( stack_context & sctx, std::size_t size)`] [variablelist [[Preconditions:] [`minimum_stacksize() > size` and `! is_stack_unbound() && ( maximum_stacksize() < size)`.]] -[[Effects:] [Allocates memory of `size` Bytes and appends one guard page at the -end of the allocated memory.]] +[[Effects:] [Allocates memory of at least `size` Bytes and stores a pointer +to the stack and its actual size in `sctx`.]] [[Returns:] [Returns pointer to the start address of the new stack. Depending on the architecture the stack grows downwards/upwards the returned address is the highest/lowest address of the stack.]] ] -[heading `void deallocate( void * sp, std::size_t size)`] +[heading `void deallocate( stack_context & sctx)`] [variablelist -[[Preconditions:] [`sp` is valid, `minimum_stacksize() > size` and +[[Preconditions:] [`sctx.sp` is valid, `minimum_stacksize() > sctx.size` and `! is_stack_unbound() && ( maximum_stacksize() < size)`.]] [[Effects:] [Deallocates the stack space.]] ] [endsect] + +[section:stack_context Class ['stack_context]] + +__boost_coroutine__ provides the class __stack_context__ which will contain +the stack pointer and the size of the stack. +In case of a __segmented_stack__ __stack_context__ contains some extra controll +structures. + + struct stack_context + { + void * sp; + std::size_t size; + + // might contain addition controll structures + // for instance for segmented stacks + } + +[heading `void * sp`] +[variablelist +[[Value:] [Pointer to the beginning of the stack.]] +] + +[heading `std::size_t size`] +[variablelist +[[Value:] [Actual size of the stack.]] +] + +[endsect] + + +[section:segmented_stack Segmented stacks] + +__boost_coroutine__ supports usage of a __segmented_stack__, e. g. the size of the +stack of a coroutine grows on demand. The coroutine is created with a stack with +an minimal stack and if the coroutine is execute the stack size is increased as +required. + +Segmented stack are currently only supported by [*gcc] from version [*4.7] onwards. +n order to use __segmented_stack__ compile __boost_coroutine__ with +[*cxxflags="-fsplit-stack -DBOOST_USE_SEGMENTED_STACKS" linkflags="-static-libgcc"] +at b2/bjam command-line and compile the application using __boost_coroutine__ with +[*cxxflags="-fsplit-stack -DBOOST_USE_SEGMENTED_STACKS"]. + +[endsect] + [endsect] diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 60e975c..c38e6d9 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -31,23 +31,19 @@ else if [ os.name ] = HPUX project boost/coroutine/example : requirements - /boost/context//boost_context + ../build//boost_coroutine /boost/program_options//boost_program_options /boost/system//boost_system /boost/thread//boost_thread - BOOST_ALL_NO_LIB=1 +# gcc-4.7:-fsplit-stack multi - SOLARIS:socket - SOLARIS:nsl - NT:_WIN32_WINNT=0x0501 - NT,gcc:ws2_32 - NT,gcc:mswsock - NT,gcc-cygwin:__USE_W32_SOCKETS - HPUX,gcc:_XOPEN_SOURCE_EXTENDED - HPUX:ipv6 static ; +exe segmented_stack + : segmented_stack.cpp + ; + exe fibonacci : fibonacci.cpp ; diff --git a/example/fibonacci.cpp b/example/fibonacci.cpp index dae7863..41dff61 100644 --- a/example/fibonacci.cpp +++ b/example/fibonacci.cpp @@ -7,14 +7,10 @@ #include #include -#include #include #include -typedef boost::coroutines::coroutine< int() > coro_t; -typedef boost::range_iterator< coro_t >::type iterator_t; - -void fibonacci( coro_t::caller_type & c) +void fibonacci( boost::coroutines::coroutine< void( int) > & c) { int first = 1, second = 1; while ( true) @@ -28,9 +24,10 @@ void fibonacci( coro_t::caller_type & c) int main() { - coro_t c( fibonacci); - iterator_t it( boost::begin( c) ); - BOOST_ASSERT( boost::end( c) != it); + boost::coroutines::coroutine< int() > c( fibonacci); + boost::range_iterator< + boost::coroutines::coroutine< int() > + >::type it( boost::begin( c) ); for ( int i = 0; i < 10; ++i) { std::cout << * it << " "; @@ -41,3 +38,35 @@ int main() return EXIT_SUCCESS; } + +// C++11 +#if 0 +int main() +{ + boost::coroutines::coroutine< int() > c( + [&]( boost::coroutines::coroutine< void( int) > & c) { + int first = 1, second = 1; + while ( true) + { + int third = first + second; + first = second; + second = third; + c( third); + } + }); + + boost::range_iterator< + boost::coroutines::coroutine< int() > + >::type it( boost::begin( c) ); + + for ( int i = 0; i < 10; ++i) + { + std::cout << * it << " "; + ++it; + } + + std::cout << "\nDone" << std::endl; + + return EXIT_SUCCESS; +} +#endif diff --git a/example/segmented_stack.cpp b/example/segmented_stack.cpp new file mode 100644 index 0000000..4a3859a --- /dev/null +++ b/example/segmented_stack.cpp @@ -0,0 +1,64 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include +#include + +typedef boost::coroutines::coroutine< void() > coro_t; + +int count = 20; + +void access( char *buf) __attribute__ ((noinline)); +void access( char *buf) +{ + buf[0] = '\0'; +} +void bar( int i) +{ + char buf[4 * 1024]; + + if ( i > 0) + { + access( buf); + std::cout << i << ". iteration" << std::endl; + bar( i - 1); + } +} + +void foo( coro_t & c) +{ + bar( count); + c(); +} + +void thread_fn() +{ + { + coro_t c( foo); + c(); + int i = 7; + } +} + +int main( int argc, char * argv[]) +{ +#if defined(BOOST_USE_SEGMENTED_STACKS) + std::cout << "using segmented stacks: allocates " << count << " * 4kB on stack, "; + std::cout << "initial stack size = " << boost::coroutines::stack_allocator::default_stacksize() / 1024 << "kB" << std::endl; + std::cout << "application should not fail" << std::endl; +#else + std::cout << "using standard stacks: allocates " << count << " * 4kB on stack, "; + std::cout << "initial stack size = " << boost::coroutines::stack_allocator::default_stacksize() / 1024 << "kB" << std::endl; + std::cout << "application might fail" << std::endl; +#endif + + boost::thread( thread_fn).join(); + + return 0; +} diff --git a/include/boost/coroutine/coroutine.hpp b/include/boost/coroutine/coroutine.hpp index 04a1f65..2a325dd 100644 --- a/include/boost/coroutine/coroutine.hpp +++ b/include/boost/coroutine/coroutine.hpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -25,6 +24,7 @@ #include #include +#include #include #include #include @@ -118,7 +118,7 @@ private: BOOST_MOVABLE_BUT_NOT_COPYABLE( coroutine) template< typename Allocator > - coroutine( context::fcontext_t * callee, + coroutine( detail::coroutine_context const& callee, bool unwind, bool preserve_fpu, Allocator const& alloc) : detail::coroutine_op< @@ -665,7 +665,7 @@ private: BOOST_MOVABLE_BUT_NOT_COPYABLE( coroutine) template< typename Allocator > - coroutine( context::fcontext_t * callee, + coroutine( detail::coroutine_context const& callee, bool unwind, bool preserve_fpu, Allocator const& alloc) : detail::coroutine_op< diff --git a/include/boost/coroutine/detail/config.hpp b/include/boost/coroutine/detail/config.hpp index c08a9a3..1caa3ac 100644 --- a/include/boost/coroutine/detail/config.hpp +++ b/include/boost/coroutine/detail/config.hpp @@ -39,4 +39,11 @@ # include #endif +#if defined(BOOST_USE_SEGMENTED_STACKS) +# if ! (defined(__GNUC__) && __GNUC__ > 3 && __GNUC_MINOR__ > 6) +# error "compiler does not support segmented stacks" +# endif +# define BOOST_COROUTINES_SEGMENTS 10 +#endif + #endif // BOOST_COROUTINES_DETAIL_CONFIG_H diff --git a/include/boost/coroutine/detail/coroutine_base.hpp b/include/boost/coroutine/detail/coroutine_base.hpp index 8f649c5..47d67fd 100644 --- a/include/boost/coroutine/detail/coroutine_base.hpp +++ b/include/boost/coroutine/detail/coroutine_base.hpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -25,6 +26,9 @@ namespace boost { namespace coroutines { + +struct stack_context; + namespace detail { template< typename Signature > @@ -45,17 +49,35 @@ private: template< typename X, typename Y, typename Z, typename A, typename B, typename C, int > friend class coroutine_object; - unsigned int use_count_; - context::fcontext_t caller_; - context::fcontext_t * callee_; - int flags_; - exception_ptr except_; + unsigned int use_count_; + coroutine_context caller_; + coroutine_context callee_; + int flags_; + exception_ptr except_; protected: virtual void deallocate_object() = 0; public: - coroutine_base( context::fcontext_t * callee, bool unwind, bool preserve_fpu) : + coroutine_base( coroutine_context::ctx_fn fn, stack_context * stack_ctx, + bool unwind, bool preserve_fpu) : + coroutine_base_resume< + Signature, + coroutine_base< Signature >, + typename function_traits< Signature >::result_type, + function_traits< Signature >::arity + >(), + use_count_( 0), + caller_(), + callee_( fn, stack_ctx), + flags_( 0), + except_() + { + if ( unwind) flags_ |= flag_force_unwind; + if ( preserve_fpu) flags_ |= flag_preserve_fpu; + } + + coroutine_base( coroutine_context const& callee, bool unwind, bool preserve_fpu) : coroutine_base_resume< Signature, coroutine_base< Signature >, diff --git a/include/boost/coroutine/detail/coroutine_base_resume.hpp b/include/boost/coroutine/detail/coroutine_base_resume.hpp index 83a3988..c344255 100644 --- a/include/boost/coroutine/detail/coroutine_base_resume.hpp +++ b/include/boost/coroutine/detail/coroutine_base_resume.hpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -42,16 +43,15 @@ class coroutine_base_resume< Signature, D, void, 0 > public: void resume() { - BOOST_ASSERT( static_cast< D * >( this)->callee_); - holder< void > hldr_to( & static_cast< D * >( this)->caller_); holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - hldr_to.ctx, - static_cast< D * >( this)->callee_, - reinterpret_cast< intptr_t >( & hldr_to), - static_cast< D * >( this)->preserve_fpu() ) ) ); - static_cast< D * >( this)->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + hldr_to.ctx->jump( + static_cast< D * >( this)->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + static_cast< D * >( this)->preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + static_cast< D * >( this)->callee_ = * hldr_from->ctx; if ( hldr_from->force_unwind) throw forced_unwind(); if ( static_cast< D * >( this)->except_) rethrow_exception( static_cast< D * >( this)->except_); @@ -66,16 +66,16 @@ public: { BOOST_ASSERT( static_cast< D * >( this)); BOOST_ASSERT( ! static_cast< D * >( this)->is_complete() ); - BOOST_ASSERT( static_cast< D * >( this)->callee_); holder< void > hldr_to( & static_cast< D * >( this)->caller_); holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - hldr_to.ctx, - static_cast< D * >( this)->callee_, - reinterpret_cast< intptr_t >( & hldr_to), - static_cast< D * >( this)->preserve_fpu() ) ) ); - static_cast< D * >( this)->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + hldr_to.ctx->jump( + static_cast< D * >( this)->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + static_cast< D * >( this)->preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + static_cast< D * >( this)->callee_ = * hldr_from->ctx; result_ = hldr_from->data; if ( hldr_from->force_unwind) throw forced_unwind(); if ( static_cast< D * >( this)->except_) @@ -99,16 +99,16 @@ public: { BOOST_ASSERT( static_cast< D * >( this)); BOOST_ASSERT( ! static_cast< D * >( this)->is_complete() ); - BOOST_ASSERT( static_cast< D * >( this)->callee_); holder< arg_type > hldr_to( & static_cast< D * >( this)->caller_, a1); holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - hldr_to.ctx, - static_cast< D * >( this)->callee_, - reinterpret_cast< intptr_t >( & hldr_to), - static_cast< D * >( this)->preserve_fpu() ) ) ); - static_cast< D * >( this)->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + hldr_to.ctx->jump( + static_cast< D * >( this)->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + static_cast< D * >( this)->preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + static_cast< D * >( this)->callee_ = * hldr_from->ctx; if ( hldr_from->force_unwind) throw forced_unwind(); if ( static_cast< D * >( this)->except_) rethrow_exception( static_cast< D * >( this)->except_); @@ -125,17 +125,17 @@ public: { BOOST_ASSERT( static_cast< D * >( this)); BOOST_ASSERT( ! static_cast< D * >( this)->is_complete() ); - BOOST_ASSERT( static_cast< D * >( this)->callee_); - context::fcontext_t caller; + coroutine_context caller; holder< arg_type > hldr_to( & static_cast< D * >( this)->caller_, a1); holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - hldr_to.ctx, - static_cast< D * >( this)->callee_, - reinterpret_cast< intptr_t >( & hldr_to), - static_cast< D * >( this)->preserve_fpu() ) ) ); - static_cast< D * >( this)->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + hldr_to.ctx->jump( + static_cast< D * >( this)->callee_, + reinterpret_cast< intptr_t >( & hldr_to), + static_cast< D * >( this)->preserve_fpu() ) ) ); + BOOST_ASSERT( hldr_from->ctx); + static_cast< D * >( this)->callee_ = * hldr_from->ctx; result_ = hldr_from->data; if ( hldr_from->force_unwind) throw forced_unwind(); if ( static_cast< D * >( this)->except_) @@ -167,18 +167,18 @@ public: \ { \ BOOST_ASSERT( static_cast< D * >( this)); \ BOOST_ASSERT( ! static_cast< D * >( this)->is_complete() ); \ - BOOST_ASSERT( static_cast< D * >( this)->callee_); \ \ holder< arg_type > hldr_to( \ & static_cast< D * >( this)->caller_, \ arg_type(BOOST_COROUTINE_BASE_RESUME_VALS(n) ) ); \ holder< void > * hldr_from( \ - reinterpret_cast< holder< void > * >( context::jump_fcontext( \ - hldr_to.ctx, \ - static_cast< D * >( this)->callee_, \ - reinterpret_cast< intptr_t >( & hldr_to), \ - static_cast< D * >( this)->preserve_fpu() ) ) ); \ - static_cast< D * >( this)->callee_ = hldr_from->ctx; \ + reinterpret_cast< holder< void > * >( \ + hldr_to.ctx->jump( \ + static_cast< D * >( this)->callee_, \ + reinterpret_cast< intptr_t >( & hldr_to), \ + static_cast< D * >( this)->preserve_fpu() ) ) ); \ + BOOST_ASSERT( hldr_from->ctx); \ + static_cast< D * >( this)->callee_ = * hldr_from->ctx; \ if ( hldr_from->force_unwind) throw forced_unwind(); \ if ( static_cast< D * >( this)->except_) \ rethrow_exception( static_cast< D * >( this)->except_); \ @@ -195,18 +195,18 @@ public: \ { \ BOOST_ASSERT( static_cast< D * >( this)); \ BOOST_ASSERT( ! static_cast< D * >( this)->is_complete() ); \ - BOOST_ASSERT( static_cast< D * >( this)->callee_); \ \ holder< arg_type > hldr_to( \ & static_cast< D * >( this)->caller_, \ arg_type(BOOST_COROUTINE_BASE_RESUME_VALS(n) ) ); \ holder< Result > * hldr_from( \ - reinterpret_cast< holder< Result > * >( context::jump_fcontext( \ - hldr_to.ctx, \ - static_cast< D * >( this)->callee_, \ - reinterpret_cast< intptr_t >( & hldr_to), \ - static_cast< D * >( this)->preserve_fpu() ) ) ); \ - static_cast< D * >( this)->callee_ = hldr_from->ctx; \ + reinterpret_cast< holder< Result > * >( \ + hldr_to.ctx->jump( \ + static_cast< D * >( this)->callee_, \ + reinterpret_cast< intptr_t >( & hldr_to), \ + static_cast< D * >( this)->preserve_fpu() ) ) ); \ + BOOST_ASSERT( hldr_from->ctx); \ + static_cast< D * >( this)->callee_ = * hldr_from->ctx; \ result_ = hldr_from->data; \ if ( hldr_from->force_unwind) throw forced_unwind(); \ if ( static_cast< D * >( this)->except_) \ diff --git a/include/boost/coroutine/detail/coroutine_caller.hpp b/include/boost/coroutine/detail/coroutine_caller.hpp index 067aff8..752d9c9 100644 --- a/include/boost/coroutine/detail/coroutine_caller.hpp +++ b/include/boost/coroutine/detail/coroutine_caller.hpp @@ -29,7 +29,7 @@ public: coroutine_caller< Signature, Allocator > >::other allocator_t; - coroutine_caller( context::fcontext_t * callee, bool unwind, bool preserve_fpu, + coroutine_caller( coroutine_context const& callee, bool unwind, bool preserve_fpu, allocator_t const& alloc) BOOST_NOEXCEPT : coroutine_base< Signature >( callee, unwind, preserve_fpu), alloc_( alloc) diff --git a/include/boost/coroutine/detail/coroutine_context.hpp b/include/boost/coroutine/detail/coroutine_context.hpp new file mode 100644 index 0000000..4fcf647 --- /dev/null +++ b/include/boost/coroutine/detail/coroutine_context.hpp @@ -0,0 +1,63 @@ + +// 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_COROUTINES_DETAIL_COROUTINE_CONTEXT_H +#define BOOST_COROUTINES_DETAIL_COROUTINE_CONTEXT_H + +#include + +#include +#include +#include +#include + +#include +#include "boost/coroutine/stack_context.hpp" + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if defined(BOOST_USE_SEGMENTED_STACKS) +extern "C" void *__splitstack_makecontext( + std::size_t, void * [BOOST_COROUTINES_SEGMENTS], std::size_t *); +#endif + +namespace boost { +namespace coroutines { +namespace detail { + + +class BOOST_COROUTINES_DECL coroutine_context : private noncopyable, + private context::fcontext_t, + private stack_context + +{ +private: + stack_context * stack_ctx_; + context::fcontext_t * ctx_; + +public: + typedef void( * ctx_fn)( intptr_t); + + coroutine_context(); + + explicit coroutine_context( ctx_fn, stack_context *); + + coroutine_context( coroutine_context const&); + + coroutine_context& operator=( coroutine_context const&); + + intptr_t jump( coroutine_context &, intptr_t = 0, bool = true); +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_COROUTINE_CONTEXT_H diff --git a/include/boost/coroutine/detail/coroutine_object.hpp b/include/boost/coroutine/detail/coroutine_object.hpp index 219be52..7f085a7 100644 --- a/include/boost/coroutine/detail/coroutine_object.hpp +++ b/include/boost/coroutine/detail/coroutine_object.hpp @@ -7,6 +7,8 @@ #ifndef BOOST_COROUTINES_DETAIL_COROUTINE_OBJECT_H #define BOOST_COROUTINES_DETAIL_COROUTINE_OBJECT_H +#include + #include #include #include @@ -15,6 +17,7 @@ #include #include #include +#include #include #include @@ -25,6 +28,7 @@ #include #include #include +#include #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -55,6 +59,25 @@ void trampoline2( intptr_t vp) coro->run( arg); } +template< typename StackAllocator > +struct stack_tuple +{ + coroutines::stack_context stack_ctx; + StackAllocator stack_alloc; + + stack_tuple( StackAllocator const& stack_alloc_, std::size_t size) : + stack_ctx(), + stack_alloc( stack_alloc_) + { + stack_alloc.allocate( stack_ctx, size); + } + + ~stack_tuple() + { + stack_alloc.deallocate( stack_ctx); + } +}; + template< typename Signature, typename Fn, typename StackAllocator, typename Allocator, diff --git a/include/boost/coroutine/detail/coroutine_object_result_0.ipp b/include/boost/coroutine/detail/coroutine_object_result_0.ipp index 1186b0d..ff15cde 100644 --- a/include/boost/coroutine/detail/coroutine_object_result_0.ipp +++ b/include/boost/coroutine/detail/coroutine_object_result_0.ipp @@ -11,6 +11,7 @@ template< typename Result > class coroutine_object< Signature, Fn, StackAllocator, Allocator, Caller, Result, 0 > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -21,12 +22,11 @@ public: >::other allocator_t; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -40,28 +40,28 @@ private: void enter_() { holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); - holder< Result > hldr_to( & caller); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - hldr_to.ctx, callee, + holder< Result > hldr_to( & caller); + caller.jump( + callee, reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); @@ -73,10 +73,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< Result > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -86,10 +86,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< void > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< void > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -101,58 +101,52 @@ public: coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( forward< Fn >( fn) ), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } #else coroutine_object( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } #endif ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } @@ -167,6 +161,7 @@ template< typename Result > class coroutine_object< Signature, reference_wrapper< Fn >, StackAllocator, Allocator, Caller, Result, 0 > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -177,12 +172,11 @@ public: >::other allocator_t; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -196,28 +190,28 @@ private: void enter_() { holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); - holder< Result > hldr_to( & caller); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - hldr_to.ctx, callee, + holder< Result > hldr_to( & caller); + caller.jump( + callee, reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); @@ -229,10 +223,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< Result > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -242,10 +236,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< void > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< void > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -256,27 +250,25 @@ public: coroutine_object( reference_wrapper< Fn > fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } @@ -291,6 +283,7 @@ template< typename Result > class coroutine_object< Signature, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller, Result, 0 > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -301,12 +294,11 @@ public: >::other allocator_t; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -320,10 +312,11 @@ private: void enter_() { holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); this->callee_ = hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); @@ -331,17 +324,16 @@ private: void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); - holder< Result > hldr_to( & caller); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - hldr_to.ctx, callee, + holder< Result > hldr_to( & caller); + caller.jump( + callee, reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); @@ -353,10 +345,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< Result > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -366,10 +358,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< void > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< void > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -380,22 +372,20 @@ public: coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() diff --git a/include/boost/coroutine/detail/coroutine_object_result_1.ipp b/include/boost/coroutine/detail/coroutine_object_result_1.ipp index 5042ccb..3246e99 100644 --- a/include/boost/coroutine/detail/coroutine_object_result_1.ipp +++ b/include/boost/coroutine/detail/coroutine_object_result_1.ipp @@ -11,6 +11,7 @@ template< typename Result > class coroutine_object< Signature, Fn, StackAllocator, Allocator, Caller, Result, 1 > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -22,12 +23,11 @@ public: typedef typename arg< Signature >::type arg_type; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -41,11 +41,12 @@ private: void enter_() { holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); } @@ -53,31 +54,31 @@ private: void enter_( typename detail::param< arg_type >::type arg) { tuple< coroutine_object *, - typename detail::param< arg_type >::type + typename detail::param< arg_type >::type > tpl( this, arg); holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( & tpl), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & tpl), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); holder< Result > hldr_to( & caller); - context::jump_fcontext( - hldr_to.ctx, callee, + caller.jump( + callee, reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); @@ -89,10 +90,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< Result > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -102,10 +103,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< arg_type > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< arg_type > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -117,109 +118,97 @@ public: coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( forward< Fn >( fn) ), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( forward< Fn >( fn) ), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } #else coroutine_object( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( Fn fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } #endif ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } void run( typename detail::param< arg_type >::type arg) { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); c.impl_->result_ = arg; run_( c); } @@ -235,6 +224,7 @@ template< typename Result > class coroutine_object< Signature, reference_wrapper< Fn >, StackAllocator, Allocator, Caller, Result, 1 > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -246,12 +236,11 @@ public: typedef typename arg< Signature >::type arg_type; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -265,11 +254,12 @@ private: void enter_() { holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); } @@ -277,31 +267,31 @@ private: void enter_( typename detail::param< arg_type >::type arg) { tuple< coroutine_object *, - typename detail::param< arg_type >::type + typename detail::param< arg_type >::type > tpl( this, arg); holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( & tpl), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & tpl), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); holder< Result > hldr_to( & caller); - context::jump_fcontext( - hldr_to.ctx, callee, + caller.jump( + callee, reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); @@ -313,10 +303,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< Result > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -326,10 +316,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< arg_type > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< arg_type > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -340,48 +330,44 @@ public: coroutine_object( reference_wrapper< Fn > fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( reference_wrapper< Fn > fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } void run( typename detail::param< arg_type >::type arg) { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); c.impl_->result_ = arg; run_( c); } @@ -397,6 +383,7 @@ template< typename Result > class coroutine_object< Signature, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller, Result, 1 > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -408,12 +395,11 @@ public: typedef typename arg< Signature >::type arg_type; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -427,11 +413,12 @@ private: void enter_() { holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); } @@ -439,31 +426,31 @@ private: void enter_( typename detail::param< arg_type >::type arg) { tuple< coroutine_object *, - typename detail::param< arg_type >::type + typename detail::param< arg_type >::type > tpl( this, arg); holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( & tpl), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & tpl), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); holder< Result > hldr_to( & caller); - context::jump_fcontext( - hldr_to.ctx, callee, + caller.jump( + callee, reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); @@ -475,10 +462,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< Result > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -488,10 +475,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< arg_type > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< arg_type > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -502,48 +489,44 @@ public: coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( const reference_wrapper< Fn > fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } void run( typename detail::param< arg_type >::type arg) { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); c.impl_->result_ = arg; run_( c); } diff --git a/include/boost/coroutine/detail/coroutine_object_result_arity.ipp b/include/boost/coroutine/detail/coroutine_object_result_arity.ipp index 975365e..27f2815 100644 --- a/include/boost/coroutine/detail/coroutine_object_result_arity.ipp +++ b/include/boost/coroutine/detail/coroutine_object_result_arity.ipp @@ -11,6 +11,7 @@ template< typename Result, int arity > class coroutine_object : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -22,12 +23,11 @@ public: typedef typename arg< Signature >::type arg_type; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -41,11 +41,12 @@ private: void enter_() { holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); } @@ -53,31 +54,31 @@ private: void enter_( typename detail::param< arg_type >::type arg) { tuple< coroutine_object *, - typename detail::param< arg_type >::type + typename detail::param< arg_type >::type > tpl( this, arg); holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( & tpl), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & tpl), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); holder< Result > hldr_to( & caller); - context::jump_fcontext( - hldr_to.ctx, callee, + caller.jump( + callee, reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); @@ -89,10 +90,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< Result > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -102,10 +103,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< arg_type > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< arg_type > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -117,109 +118,97 @@ public: coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( forward< Fn >( fn) ), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( forward< Fn >( fn) ), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } #else coroutine_object( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( Fn fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } #endif ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } void run( typename detail::param< arg_type >::type arg) { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); c.impl_->result_ = arg; run_( c); } @@ -235,6 +224,7 @@ template< typename Result, int arity > class coroutine_object< Signature, reference_wrapper< Fn >, StackAllocator, Allocator, Caller, Result, arity > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -246,12 +236,11 @@ public: typedef typename arg< Signature >::type arg_type; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -265,11 +254,12 @@ private: void enter_() { holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); } @@ -277,31 +267,31 @@ private: void enter_( typename detail::param< arg_type >::type arg) { tuple< coroutine_object *, - typename detail::param< arg_type >::type + typename detail::param< arg_type >::type > tpl( this, arg); holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( & tpl), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & tpl), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); holder< Result > hldr_to( & caller); - context::jump_fcontext( - hldr_to.ctx, callee, + caller.jump( + callee, reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); @@ -313,10 +303,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< Result > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -326,10 +316,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< arg_type > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< arg_type > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -340,48 +330,44 @@ public: coroutine_object( reference_wrapper< Fn > fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( reference_wrapper< Fn > fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } void run( typename detail::param< arg_type >::type arg) { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); c.impl_->result_ = arg; run_( c); } @@ -397,6 +383,7 @@ template< typename Result, int arity > class coroutine_object< Signature, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller, Result, arity > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -408,12 +395,11 @@ public: typedef typename arg< Signature >::type arg_type; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -427,11 +413,12 @@ private: void enter_() { holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); } @@ -439,31 +426,31 @@ private: void enter_( typename detail::param< arg_type >::type arg) { tuple< coroutine_object *, - typename detail::param< arg_type >::type + typename detail::param< arg_type >::type > tpl( this, arg); holder< Result > * hldr_from( - reinterpret_cast< holder< Result > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( & tpl), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< Result > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & tpl), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; this->result_ = hldr_from->data; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); holder< Result > hldr_to( & caller); - context::jump_fcontext( - hldr_to.ctx, callee, + caller.jump( + callee, reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); @@ -475,10 +462,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< Result > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -488,10 +475,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< arg_type > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< arg_type > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -502,48 +489,44 @@ public: coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( const reference_wrapper< Fn > fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } void run( typename detail::param< arg_type >::type arg) { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); c.impl_->result_ = arg; run_( c); } diff --git a/include/boost/coroutine/detail/coroutine_object_void_0.ipp b/include/boost/coroutine/detail/coroutine_object_void_0.ipp index 1fad47d..5ff5acc 100644 --- a/include/boost/coroutine/detail/coroutine_object_void_0.ipp +++ b/include/boost/coroutine/detail/coroutine_object_void_0.ipp @@ -10,6 +10,7 @@ template< typename Caller > class coroutine_object< Signature, Fn, StackAllocator, Allocator, Caller, void, 0 > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -20,12 +21,11 @@ public: >::other allocator_t; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -39,27 +39,27 @@ private: void enter_() { holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); holder< void > hldr_to( & caller); - context::jump_fcontext( - hldr_to.ctx, callee, + caller.jump( + callee, reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); @@ -71,10 +71,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -84,10 +84,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< void > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< void > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -99,58 +99,52 @@ public: coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( forward< Fn >( fn) ), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } #else coroutine_object( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->pbase_type::stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } #endif ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } @@ -164,6 +158,7 @@ template< typename Caller > class coroutine_object< Signature, reference_wrapper< Fn >, StackAllocator, Allocator, Caller, void, 0 > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -174,12 +169,11 @@ public: >::other allocator_t; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -193,27 +187,27 @@ private: void enter_() { holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); holder< void > hldr_to( & caller); - context::jump_fcontext( - hldr_to.ctx, callee, + caller.jump( + callee, reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); @@ -225,10 +219,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -238,10 +232,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< void > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< void > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -252,27 +246,25 @@ public: coroutine_object( reference_wrapper< Fn > fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } @@ -286,6 +278,7 @@ template< typename Caller > class coroutine_object< Signature, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller, void, 0 > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -296,12 +289,11 @@ public: >::other allocator_t; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -315,27 +307,27 @@ private: void enter_() { holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); holder< void > hldr_to( & caller); - context::jump_fcontext( - hldr_to.ctx, callee, + caller.jump( + callee, reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); @@ -347,10 +339,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -360,10 +352,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< void > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< void > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -374,27 +366,25 @@ public: coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } diff --git a/include/boost/coroutine/detail/coroutine_object_void_1.ipp b/include/boost/coroutine/detail/coroutine_object_void_1.ipp index 76cac24..b01918e 100644 --- a/include/boost/coroutine/detail/coroutine_object_void_1.ipp +++ b/include/boost/coroutine/detail/coroutine_object_void_1.ipp @@ -10,6 +10,7 @@ template< typename Caller > class coroutine_object< Signature, Fn, StackAllocator, Allocator, Caller, void, 1 > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -21,12 +22,11 @@ public: typedef typename arg< Signature >::type arg_type; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -40,42 +40,43 @@ private: void enter_() { holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void enter_( typename detail::param< arg_type >::type arg) { tuple< coroutine_object *, - typename detail::param< arg_type >::type + typename detail::param< arg_type >::type > tpl( this, arg); holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( & tpl), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & tpl), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - holder< void > hldr( & caller); - context::jump_fcontext( - hldr.ctx, callee, - ( intptr_t) & hldr, + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -86,10 +87,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -99,10 +100,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< arg_type > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< arg_type > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -114,109 +115,97 @@ public: coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( forward< Fn >( fn) ), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( forward< Fn >( fn) ), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } #else coroutine_object( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( Fn fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } #endif ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } void run( typename detail::param< arg_type >::type arg) { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); c.impl_->result_ = arg; run_( c); } @@ -231,6 +220,7 @@ template< typename Caller > class coroutine_object< Signature, reference_wrapper< Fn >, StackAllocator, Allocator, Caller, void, 1 > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -242,12 +232,11 @@ public: typedef typename arg< Signature >::type arg_type; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -261,42 +250,43 @@ private: void enter_() { holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void enter_( typename detail::param< arg_type >::type arg) { tuple< coroutine_object *, - typename detail::param< arg_type >::type + typename detail::param< arg_type >::type > tpl( this, arg); holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( & tpl), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & tpl), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - holder< void > hldr( & caller); - context::jump_fcontext( - hldr.ctx, callee, - ( intptr_t) & hldr, + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -307,10 +297,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -320,10 +310,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< arg_type > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< arg_type > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -334,15 +324,13 @@ public: coroutine_object( reference_wrapper< Fn > fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } @@ -350,33 +338,31 @@ public: typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } void run( typename detail::param< arg_type >::type arg) { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); c.impl_->result_ = arg; run_( c); } @@ -391,6 +377,7 @@ template< typename Caller > class coroutine_object< Signature, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller, void, 1 > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -402,12 +389,11 @@ public: typedef typename arg< Signature >::type arg_type; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -421,42 +407,43 @@ private: void enter_() { holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void enter_( typename detail::param< arg_type >::type arg) { tuple< coroutine_object *, - typename detail::param< arg_type >::type + typename detail::param< arg_type >::type > tpl( this, arg); holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( & tpl), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & tpl), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - holder< void > hldr( & caller); - context::jump_fcontext( - hldr.ctx, callee, - ( intptr_t) & hldr, + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -467,10 +454,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -480,10 +467,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< arg_type > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< arg_type > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -494,15 +481,13 @@ public: coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } @@ -510,33 +495,31 @@ public: typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } void run( typename detail::param< arg_type >::type arg) { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); c.impl_->result_ = arg; run_( c); } diff --git a/include/boost/coroutine/detail/coroutine_object_void_arity.ipp b/include/boost/coroutine/detail/coroutine_object_void_arity.ipp index 0f0eeeb..29a3f75 100644 --- a/include/boost/coroutine/detail/coroutine_object_void_arity.ipp +++ b/include/boost/coroutine/detail/coroutine_object_void_arity.ipp @@ -11,6 +11,7 @@ template< int arity > class coroutine_object< Signature, Fn, StackAllocator, Allocator, Caller, void, arity > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -22,12 +23,11 @@ public: typedef typename arg< Signature >::type arg_type; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -41,42 +41,43 @@ private: void enter_() { holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void enter_( typename detail::param< arg_type >::type arg) { tuple< coroutine_object *, - typename detail::param< arg_type >::type + typename detail::param< arg_type >::type > tpl( this, arg); holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( & tpl), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & tpl), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - holder< void > hldr( & caller); - context::jump_fcontext( - hldr.ctx, callee, - ( intptr_t) & hldr, + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -87,10 +88,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -100,10 +101,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< arg_type > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< arg_type > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -115,109 +116,97 @@ public: coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( forward< Fn >( fn) ), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( forward< Fn >( fn) ), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } #else coroutine_object( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( Fn fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } #endif ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } void run( typename detail::param< arg_type >::type arg) { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); c.impl_->result_ = arg; run_( c); } @@ -233,6 +222,7 @@ template< int arity > class coroutine_object< Signature, reference_wrapper< Fn >, StackAllocator, Allocator, Caller, void, arity > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -244,12 +234,11 @@ public: typedef typename arg< Signature >::type arg_type; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -263,42 +252,43 @@ private: void enter_() { holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void enter_( typename detail::param< arg_type >::type arg) { tuple< coroutine_object *, - typename detail::param< arg_type >::type + typename detail::param< arg_type >::type > tpl( this, arg); holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( & tpl), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & tpl), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - holder< void > hldr( & caller); - context::jump_fcontext( - hldr.ctx, callee, - ( intptr_t) & hldr, + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -309,10 +299,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -322,10 +312,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< arg_type > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< arg_type > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -336,48 +326,44 @@ public: coroutine_object( reference_wrapper< Fn > fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( reference_wrapper< Fn > fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } void run( typename detail::param< arg_type >::type arg) { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); c.impl_->result_ = arg; run_( c); } @@ -393,6 +379,7 @@ template< int arity > class coroutine_object< Signature, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller, void, arity > : + private stack_tuple< StackAllocator >, public coroutine_base< Signature > { public: @@ -404,12 +391,11 @@ public: typedef typename arg< Signature >::type arg_type; private: + typedef stack_tuple< StackAllocator > pbase_type; typedef coroutine_base< Signature > base_type; - Fn fn_; - context::stack_t stack_; - StackAllocator stack_alloc_; - allocator_t alloc_; + Fn fn_; + allocator_t alloc_; static void destroy_( allocator_t & alloc, coroutine_object * p) { @@ -423,42 +409,43 @@ private: void enter_() { holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( this), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( this), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void enter_( typename detail::param< arg_type >::type arg) { tuple< coroutine_object *, - typename detail::param< arg_type >::type + typename detail::param< arg_type >::type > tpl( this, arg); holder< void > * hldr_from( - reinterpret_cast< holder< void > * >( context::jump_fcontext( - & this->caller_, this->callee_, - reinterpret_cast< intptr_t >( & tpl), - this->preserve_fpu() ) ) ); - this->callee_ = hldr_from->ctx; + reinterpret_cast< holder< void > * >( + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & tpl), + this->preserve_fpu() ) ) ); + this->callee_ = * hldr_from->ctx; if ( this->except_) rethrow_exception( this->except_); } void run_( Caller & c) { - context::fcontext_t * callee( 0); - context::fcontext_t caller; + coroutine_context callee; + coroutine_context caller; try { fn_( c); this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - holder< void > hldr( & caller); - context::jump_fcontext( - hldr.ctx, callee, - ( intptr_t) & hldr, + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -469,10 +456,10 @@ private: this->flags_ |= flag_complete; callee = c.impl_->callee_; - BOOST_ASSERT( callee); - context::jump_fcontext( - & caller, callee, - reinterpret_cast< intptr_t >( & caller), + holder< void > hldr_to( & caller); + caller.jump( + callee, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); BOOST_ASSERT_MSG( false, "coroutine is complete"); } @@ -482,10 +469,10 @@ private: BOOST_ASSERT( ! this->is_complete() ); this->flags_ |= flag_unwind_stack; - holder< arg_type > hldr( & this->caller_, true); - context::jump_fcontext( - hldr.ctx, this->callee_, - reinterpret_cast< intptr_t >( & hldr), + holder< arg_type > hldr_to( & this->caller_, true); + this->caller_.jump( + this->callee_, + reinterpret_cast< intptr_t >( & hldr_to), this->preserve_fpu() ); this->flags_ &= ~flag_unwind_stack; @@ -496,48 +483,44 @@ public: coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline1< coroutine_object >), + trampoline1< coroutine_object >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_(); } coroutine_object( const reference_wrapper< Fn > fn, typename detail::param< arg_type >::type arg, attributes const& attr, StackAllocator const& stack_alloc, allocator_t const& alloc) : + pbase_type( stack_alloc, attr.size), base_type( - context::make_fcontext( - stack_alloc.allocate( attr.size), attr.size, - trampoline2< coroutine_object, typename detail::param< arg_type >::type >), + trampoline2< coroutine_object, typename detail::param< arg_type >::type >, + & this->stack_ctx, stack_unwind == attr.do_unwind, fpu_preserved == attr.preserve_fpu), fn_( fn), - stack_( base_type::callee_->fc_stack), - stack_alloc_( stack_alloc), alloc_( alloc) { enter_( arg); } ~coroutine_object() { - if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_(); - stack_alloc_.deallocate( stack_.sp, stack_.size); + if ( ! this->is_complete() && this->force_unwind() ) + unwind_stack_(); } void run() { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); run_( c); } void run( typename detail::param< arg_type >::type arg) { - Caller c( & this->caller_, false, this->preserve_fpu(), alloc_); + Caller c( this->caller_, false, this->preserve_fpu(), alloc_); c.impl_->result_ = arg; run_( c); } diff --git a/include/boost/coroutine/detail/holder.hpp b/include/boost/coroutine/detail/holder.hpp index f721158..0d2d4f0 100644 --- a/include/boost/coroutine/detail/holder.hpp +++ b/include/boost/coroutine/detail/holder.hpp @@ -11,6 +11,8 @@ #include #include +#include + #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX #endif @@ -22,19 +24,19 @@ namespace detail { template< typename Data > struct holder { - context::fcontext_t * ctx; + coroutine_context * ctx; optional< Data > data; bool force_unwind; - holder( context::fcontext_t * ctx_) : + explicit holder( coroutine_context * ctx_) : ctx( ctx_), data(), force_unwind( false) { BOOST_ASSERT( ctx); } - holder( context::fcontext_t * ctx_, Data data_) : + explicit holder( coroutine_context * ctx_, Data data_) : ctx( ctx_), data( data_), force_unwind( false) { BOOST_ASSERT( ctx); } - holder( context::fcontext_t * ctx_, bool force_unwind_) : + explicit holder( coroutine_context * ctx_, bool force_unwind_) : ctx( ctx_), data(), force_unwind( force_unwind_) { BOOST_ASSERT( ctx); @@ -59,10 +61,10 @@ struct holder template<> struct holder< void > { - context::fcontext_t * ctx; - bool force_unwind; + coroutine_context * ctx; + bool force_unwind; - holder( context::fcontext_t * ctx_, bool force_unwind_ = false) : + explicit holder( coroutine_context * ctx_, bool force_unwind_ = false) : ctx( ctx_), force_unwind( force_unwind_) { BOOST_ASSERT( ctx); } diff --git a/include/boost/coroutine/detail/segmented_stack_allocator.hpp b/include/boost/coroutine/detail/segmented_stack_allocator.hpp new file mode 100644 index 0000000..30b3e13 --- /dev/null +++ b/include/boost/coroutine/detail/segmented_stack_allocator.hpp @@ -0,0 +1,51 @@ + +// 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_COROUTINES_DETAIL_SEGMENTED_STACK_ALLOCATOR_H +#define BOOST_COROUTINES_DETAIL_SEGMENTED_STACK_ALLOCATOR_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +struct stack_context; + +namespace detail { + +#if defined(BOOST_USE_SEGMENTED_STACKS) +class segmented_stack_allocator +{ +public: + static bool is_stack_unbound(); + + static std::size_t default_stacksize(); + + static std::size_t minimum_stacksize(); + + static std::size_t maximum_stacksize(); + + void allocate( stack_context &, std::size_t size); + + void deallocate( stack_context &); +}; +#endif + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_SEGMENTED_STACK_ALLOCATOR_H diff --git a/include/boost/coroutine/detail/stack_allocator_posix.hpp b/include/boost/coroutine/detail/stack_allocator_posix.hpp deleted file mode 100644 index 62cfde2..0000000 --- a/include/boost/coroutine/detail/stack_allocator_posix.hpp +++ /dev/null @@ -1,173 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_COROUTINES_DETAIL_STACK_ALLOCATOR_H -#define BOOST_COROUTINES_DETAIL_STACK_ALLOCATOR_H - -#include - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -} - -//#if _POSIX_C_SOURCE >= 200112L - -#include -#include -#include -#include -#include - -#include -#include -#include - -#if !defined (SIGSTKSZ) -# define SIGSTKSZ (8 * 1024) -# define UDEF_SIGSTKSZ -#endif - - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace coroutines { -namespace detail { - -inline -std::size_t pagesize() -{ - // conform to POSIX.1-2001 - static std::size_t size = ::sysconf( _SC_PAGESIZE); - return size; -} - -inline -rlimit stacksize_limit_() -{ - rlimit limit; - // conforming to POSIX.1-2001 -#if defined(BOOST_DISABLE_ASSERTS) - ::getrlimit( RLIMIT_STACK, & limit); -#else - const int result = ::getrlimit( RLIMIT_STACK, & limit); - BOOST_ASSERT( 0 == result); -#endif - return limit; -} - -inline -rlimit stacksize_limit() -{ - static rlimit limit = stacksize_limit_(); - return limit; -} - -inline -std::size_t page_count( std::size_t stacksize) -{ - return static_cast< std::size_t >( - std::ceil( - static_cast< float >( stacksize) / pagesize() ) ); -} - -class stack_allocator -{ -public: - static bool is_stack_unbound() - { return RLIM_INFINITY == stacksize_limit().rlim_max; } - - static std::size_t default_stacksize() - { - std::size_t size = 8 * minimum_stacksize(); - if ( is_stack_unbound() ) return size; - - BOOST_ASSERT( maximum_stacksize() >= minimum_stacksize() ); - return maximum_stacksize() == size - ? size - : (std::min)( size, maximum_stacksize() ); - } - - static std::size_t minimum_stacksize() - { return SIGSTKSZ + sizeof( context::fcontext_t) + 15; } - - static std::size_t maximum_stacksize() - { - BOOST_ASSERT( ! is_stack_unbound() ); - return static_cast< std::size_t >( stacksize_limit().rlim_max); - } - - void * allocate( std::size_t size) const - { - BOOST_ASSERT( minimum_stacksize() <= size); - BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= size) ); - - const std::size_t pages( page_count( size) + 1); // add one guard page - const std::size_t size_( pages * pagesize() ); - BOOST_ASSERT( 0 < size && 0 < size_); - - const int fd( ::open("/dev/zero", O_RDONLY) ); - BOOST_ASSERT( -1 != fd); - // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) - void * limit = -# if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) - ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); -# else - ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); -# endif - ::close( fd); - if ( ! limit) throw std::bad_alloc(); - - std::memset( limit, size_, '\0'); - - // conforming to POSIX.1-2001 -#if defined(BOOST_DISABLE_ASSERTS) - ::mprotect( limit, pagesize(), PROT_NONE); -#else - const int result( ::mprotect( limit, pagesize(), PROT_NONE) ); - BOOST_ASSERT( 0 == result); -#endif - - return static_cast< char * >( limit) + size_; - } - - void deallocate( void * vp, std::size_t size) const - { - BOOST_ASSERT( vp); - BOOST_ASSERT( minimum_stacksize() <= size); - BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= size) ); - - const std::size_t pages = page_count( size) + 1; - const std::size_t size_ = pages * pagesize(); - BOOST_ASSERT( 0 < size && 0 < size_); - void * limit = static_cast< char * >( vp) - size_; - // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) - ::munmap( limit, size_); - } -}; - -}}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#ifdef UDEF_SIGSTKSZ -# undef SIGSTKSZ -#endif - -//#endif - -#endif // BOOST_COROUTINES_DETAIL_STACK_ALLOCATOR_H diff --git a/include/boost/coroutine/detail/stack_allocator_windows.hpp b/include/boost/coroutine/detail/stack_allocator_windows.hpp deleted file mode 100644 index 73155b3..0000000 --- a/include/boost/coroutine/detail/stack_allocator_windows.hpp +++ /dev/null @@ -1,163 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_COROUTINES_DETAIL_STACK_ALLOCATOR_H -#define BOOST_COROUTINES_DETAIL_STACK_ALLOCATOR_H - -#include - -extern "C" { -#include -} - -//#if defined (BOOST_WINDOWS) || _POSIX_C_SOURCE >= 200112L - -#include -#include -#include -#include -#include - -#include -#include -#include - -# if defined(BOOST_MSVC) -# pragma warning(push) -# pragma warning(disable:4244 4267) -# endif - -// x86_64 -// test x86_64 before i386 because icc might -// define __i686__ for x86_64 too -#if defined(__x86_64__) || defined(__x86_64) \ - || defined(__amd64__) || defined(__amd64) \ - || defined(_M_X64) || defined(_M_AMD64) - -// Windows seams not to provide a constant or function -// telling the minimal stacksize -# define MIN_STACKSIZE 8 * 1024 -#else -# define MIN_STACKSIZE 4 * 1024 -#endif - - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace coroutines { -namespace detail { - -inline -SYSTEM_INFO system_info_() -{ - SYSTEM_INFO si; - ::GetSystemInfo( & si); - return si; -} - -inline -SYSTEM_INFO system_info() -{ - static SYSTEM_INFO si = system_info_(); - return si; -} - -inline -std::size_t pagesize() -{ return static_cast< std::size_t >( system_info().dwPageSize); } - -inline -std::size_t page_count( std::size_t stacksize) -{ - return static_cast< std::size_t >( - std::ceil( - static_cast< float >( stacksize) / pagesize() ) ); -} - -class stack_allocator -{ -public: - // Windows seams not to provide a limit for the stacksize - static bool is_stack_unbound() - { return true; } - - static std::size_t default_stacksize() - { - std::size_t size = 64 * 1024; // 64 kB - if ( is_stack_unbound() ) - return (std::max)( size, minimum_stacksize() ); - - BOOST_ASSERT( maximum_stacksize() >= minimum_stacksize() ); - return maximum_stacksize() == minimum_stacksize() - ? minimum_stacksize() - : ( std::min)( size, maximum_stacksize() ); - } - - // because Windows seams not to provide a limit for minimum stacksize - static std::size_t minimum_stacksize() - { return MIN_STACKSIZE; } - - // because Windows seams not to provide a limit for maximum stacksize - // maximum_stacksize() can never be called (pre-condition ! is_stack_unbound() ) - static std::size_t maximum_stacksize() - { - BOOST_ASSERT( ! is_stack_unbound() ); - return 1 * 1024 * 1024 * 1024; // 1GB - } - - void * allocate( std::size_t size) const - { - BOOST_ASSERT( minimum_stacksize() <= size); - BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= size) ); - - const std::size_t pages( page_count( size) + 1); // add one guard page - const std::size_t size_ = pages * pagesize(); - BOOST_ASSERT( 0 < size && 0 < size_); - - void * limit = ::VirtualAlloc( 0, size_, MEM_COMMIT, PAGE_READWRITE); - if ( ! limit) throw std::bad_alloc(); - - std::memset( limit, size_, '\0'); - - DWORD old_options; -#if defined(BOOST_DISABLE_ASSERTS) - ::VirtualProtect( - limit, pagesize(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); -#else - const BOOL result = ::VirtualProtect( - limit, pagesize(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); - BOOST_ASSERT( FALSE != result); -#endif - - return static_cast< char * >( limit) + size_; - } - - void deallocate( void * vp, std::size_t size) const - { - BOOST_ASSERT( vp); - BOOST_ASSERT( minimum_stacksize() <= size); - BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= size) ); - - const std::size_t pages = page_count( size) + 1; - const std::size_t size_ = pages * pagesize(); - BOOST_ASSERT( 0 < size && 0 < size_); - void * limit = static_cast< char * >( vp) - size_; - ::VirtualFree( limit, 0, MEM_RELEASE); - } -}; - -}}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -//#endif - -#endif // BOOST_COROUTINES_DETAIL_STACK_ALLOCATOR_H diff --git a/include/boost/coroutine/detail/standard_stack_allocator.hpp b/include/boost/coroutine/detail/standard_stack_allocator.hpp new file mode 100644 index 0000000..c20499b --- /dev/null +++ b/include/boost/coroutine/detail/standard_stack_allocator.hpp @@ -0,0 +1,49 @@ + +// 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_COROUTINES_DETAIL_STANDARD_STACK_ALLOCATOR_H +#define BOOST_COROUTINES_DETAIL_STANDARD_STACK_ALLOCATOR_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +struct stack_context; + +namespace detail { + +class standard_stack_allocator +{ +public: + static bool is_stack_unbound(); + + static std::size_t default_stacksize(); + + static std::size_t minimum_stacksize(); + + static std::size_t maximum_stacksize(); + + void allocate( stack_context &, std::size_t); + + void deallocate( stack_context &); +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_STANDARD_STACK_ALLOCATOR_H diff --git a/include/boost/coroutine/stack_allocator.hpp b/include/boost/coroutine/stack_allocator.hpp index 6d80583..3b52679 100644 --- a/include/boost/coroutine/stack_allocator.hpp +++ b/include/boost/coroutine/stack_allocator.hpp @@ -4,20 +4,34 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_COROUTINES_STACK_ALLOCATOR_H -#define BOOST_COROUTINES_STACK_ALLOCATOR_H +#ifndef BOOST_COROUTINES_DETAIL_STACK_ALLOCATOR_H +#define BOOST_COROUTINES_DETAIL_STACK_ALLOCATOR_H + +#include #include -#if defined (BOOST_WINDOWS) -#include -#else -#include +#include +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX #endif namespace boost { namespace coroutines { -using detail::stack_allocator; + +#if defined(BOOST_USE_SEGMENTED_STACKS) +typedef detail::segmented_stack_allocator stack_allocator; +#else +typedef detail::standard_stack_allocator stack_allocator; +#endif + }} -#endif // BOOST_COROUTINES_STACK_ALLOCATOR_H +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_DETAIL_STACK_ALLOCATOR_H diff --git a/include/boost/coroutine/stack_context.hpp b/include/boost/coroutine/stack_context.hpp new file mode 100644 index 0000000..53344e3 --- /dev/null +++ b/include/boost/coroutine/stack_context.hpp @@ -0,0 +1,54 @@ + +// 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_COROUTINES_STACK_CONTEXT_H +#define BOOST_COROUTINES_STACK_CONTEXT_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +#if defined(BOOST_USE_SEGMENTED_STACKS) +struct stack_context +{ + typedef void * segments_context[BOOST_COROUTINES_SEGMENTS]; + + std::size_t size; + void * sp; + segments_context segments_ctx; + + stack_context() : + size( 0), sp( 0), segments_ctx() + {} +}; +#else +struct stack_context +{ + std::size_t size; + void * sp; + + stack_context() : + size( 0), sp( 0) + {} +}; +#endif + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_STACK_CONTEXT_H diff --git a/performance/Jamfile.v2 b/performance/Jamfile.v2 index 108c0e1..a173610 100644 --- a/performance/Jamfile.v2 +++ b/performance/Jamfile.v2 @@ -16,9 +16,11 @@ import toolset ; project boost/context/performance : requirements /boost/context//boost_context + /boost/coroutine//boost_coroutine + gcc-4.7.2:-fsplit-stack static "-lrt" - single + multi ; alias sources diff --git a/performance/performance.cpp b/performance/performance.cpp index 834df24..c9ac8ab 100644 --- a/performance/performance.cpp +++ b/performance/performance.cpp @@ -26,7 +26,6 @@ #endif namespace coro = boost::coroutines; -namespace ctx = boost::context; typedef coro::coroutine< void() > coro_t; @@ -41,8 +40,12 @@ void fn( coro_t::caller_type & c) #ifdef BOOST_CONTEXT_CYCLE cycle_t test_cycles( cycle_t ov, coro::flag_fpu_t preserve_fpu) { - ctx::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc; +#if defined(BOOST_USE_SEGMENTED_STACKS) + coro_t c( fn, coro::attributes( preserve_fpu) ); +#else + coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc; coro_t c( fn, coro::attributes( preserve_fpu), alloc); +#endif // cache warum-up BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~) @@ -63,8 +66,12 @@ BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~) #if _POSIX_C_SOURCE >= 199309L zeit_t test_zeit( zeit_t ov, coro::flag_fpu_t preserve_fpu) { - ctx::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc; +#if defined(BOOST_USE_SEGMENTED_STACKS) + coro_t c( fn, coro::attributes( preserve_fpu) ); +#else + coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc; coro_t c( fn, coro::attributes( preserve_fpu), alloc); +#endif // cache warum-up BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~) diff --git a/performance/simple_stack_allocator.hpp b/performance/simple_stack_allocator.hpp index afc5068..d6724d7 100644 --- a/performance/simple_stack_allocator.hpp +++ b/performance/simple_stack_allocator.hpp @@ -15,13 +15,14 @@ #include #include +#include #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX #endif namespace boost { -namespace context { +namespace coroutines { template< std::size_t Max, std::size_t Default, std::size_t Min > class simple_stack_allocator @@ -36,7 +37,7 @@ public: static std::size_t minimum_stacksize() { return Min; } - void * allocate( std::size_t size) const + void allocate( stack_context & ctx, std::size_t size) { BOOST_ASSERT( minimum_stacksize() <= size); BOOST_ASSERT( maximum_stacksize() >= size); @@ -44,16 +45,17 @@ public: void * limit = std::calloc( size, sizeof( char) ); if ( ! limit) throw std::bad_alloc(); - return static_cast< char * >( limit) + size; + ctx.size = size; + ctx.sp = static_cast< char * >( limit) + ctx.size; } - void deallocate( void * vp, std::size_t size) const + void deallocate( stack_context & ctx) { - BOOST_ASSERT( vp); - BOOST_ASSERT( minimum_stacksize() <= size); - BOOST_ASSERT( maximum_stacksize() >= size); + BOOST_ASSERT( ctx.sp); + BOOST_ASSERT( minimum_stacksize() <= ctx.size); + BOOST_ASSERT( maximum_stacksize() >= ctx.size); - void * limit = static_cast< char * >( vp) - size; + void * limit = static_cast< char * >( ctx.sp) - ctx.size; std::free( limit); } }; diff --git a/src/detail/coroutine_context.cpp b/src/detail/coroutine_context.cpp new file mode 100644 index 0000000..bf24719 --- /dev/null +++ b/src/detail/coroutine_context.cpp @@ -0,0 +1,83 @@ + +// 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) + +#define BOOST_COROUTINES_SOURCE + +#include "boost/coroutine/detail/coroutine_context.hpp" + +#if defined(BOOST_USE_SEGMENTED_STACKS) +extern "C" { + +void __splitstack_getcontext( void * [BOOST_COROUTINES_SEGMENTS]); + +void __splitstack_setcontext( void * [BOOST_COROUTINES_SEGMENTS]); + +void __splitstack_releasecontext (void * [BOOST_COROUTINES_SEGMENTS]); + +void __splitstack_block_signals_context( void * [BOOST_COROUTINES_SEGMENTS], int *, int *); + +} +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +coroutine_context::coroutine_context() : + fcontext_t(), stack_ctx_( this), ctx_( this) +{ +#if defined(BOOST_USE_SEGMENTED_STACKS) + __splitstack_getcontext( stack_ctx_->segments_ctx); +#endif +} + +coroutine_context::coroutine_context( ctx_fn fn, stack_context * stack_ctx) : + fcontext_t(), stack_ctx_( stack_ctx), + ctx_( context::make_fcontext( stack_ctx_->sp, stack_ctx_->size, fn) ) +{} + +coroutine_context::coroutine_context( coroutine_context const& other) : + fcontext_t(), + stack_ctx_( other.stack_ctx_), + ctx_( other.ctx_) +{} + +coroutine_context & +coroutine_context::operator=( coroutine_context const& other) +{ + if ( this == & other) return * this; + + stack_ctx_ = other.stack_ctx_; + ctx_ = other.ctx_; + + return * this; +} + +intptr_t +coroutine_context::jump( coroutine_context & other, intptr_t param, bool preserve_fpu) +{ +#if defined(BOOST_USE_SEGMENTED_STACKS) + if ( stack_ctx_) + __splitstack_getcontext( stack_ctx_->segments_ctx); + if ( other.stack_ctx_) + __splitstack_setcontext( other.stack_ctx_->segments_ctx); +#endif + return context::jump_fcontext( ctx_, other.ctx_, param, preserve_fpu); +#if defined(BOOST_USE_SEGMENTED_STACKS) + if ( stack_ctx_) + __splitstack_setcontext( stack_ctx_->segments_ctx); +#endif +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/src/detail/segmented_stack_allocator.cpp b/src/detail/segmented_stack_allocator.cpp new file mode 100644 index 0000000..ab71769 --- /dev/null +++ b/src/detail/segmented_stack_allocator.cpp @@ -0,0 +1,93 @@ + +// 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) + +#define BOOST_COROUTINES_SOURCE + +#if defined(BOOST_USE_SEGMENTED_STACKS) + +#include + +#include +#include + +#include + +extern "C" { + +void *__splitstack_makecontext( std::size_t, + void * [BOOST_COROUTINES_SEGMENTS], + std::size_t *); + +void __splitstack_releasecontext( void * [BOOST_COROUTINES_SEGMENTS]); + +void __splitstack_resetcontext( void * [BOOST_COROUTINES_SEGMENTS]); + +void __splitstack_block_signals_context( void * [BOOST_COROUTINES_SEGMENTS], + int * new_value, int * old_value); +} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if !defined (SIGSTKSZ) +# define SIGSTKSZ (8 * 1024) +# define UDEF_SIGSTKSZ +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +bool +segmented_stack_allocator::is_stack_unbound() +{ return true; } + +std::size_t +segmented_stack_allocator::minimum_stacksize() +{ return SIGSTKSZ + sizeof( context::fcontext_t) + 15; } + +std::size_t +segmented_stack_allocator::default_stacksize() +{ return minimum_stacksize(); } + +std::size_t +segmented_stack_allocator::maximum_stacksize() +{ + BOOST_ASSERT_MSG( false, "segmented stack is unbound"); + return 0; +} + +void +segmented_stack_allocator::allocate( stack_context & ctx, std::size_t size) +{ + BOOST_ASSERT( default_stacksize() <= size); + + void * limit = __splitstack_makecontext( size, ctx.segments_ctx, & ctx.size); + BOOST_ASSERT( limit); + ctx.sp = static_cast< char * >( limit) + ctx.size; + + int off = 0; + __splitstack_block_signals_context( ctx.segments_ctx, & off, 0); +} + +void +segmented_stack_allocator::deallocate( stack_context & ctx) +{ + __splitstack_releasecontext( ctx.segments_ctx); +} + +}}} + +#ifdef UDEF_SIGSTKSZ +# undef SIGSTKSZ +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif diff --git a/src/detail/standard_stack_allocator_posix.cpp b/src/detail/standard_stack_allocator_posix.cpp new file mode 100644 index 0000000..ed9c6fe --- /dev/null +++ b/src/detail/standard_stack_allocator_posix.cpp @@ -0,0 +1,163 @@ + +// 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) + +#define BOOST_COROUTINES_SOURCE + +#include "boost/coroutine/detail/standard_stack_allocator.hpp" + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +} + +//#if _POSIX_C_SOURCE >= 200112L + +#include +#include +#include +#include + +#include +#include + +#include + +#if !defined (SIGSTKSZ) +# define SIGSTKSZ (8 * 1024) +# define UDEF_SIGSTKSZ +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +std::size_t pagesize() +{ + // conform to POSIX.1-2001 + static std::size_t size = ::sysconf( _SC_PAGESIZE); + return size; +} + +rlimit stacksize_limit_() +{ + rlimit limit; + // conforming to POSIX.1-2001 +#if defined(BOOST_DISABLE_ASSERTS) + ::getrlimit( RLIMIT_STACK, & limit); +#else + const int result = ::getrlimit( RLIMIT_STACK, & limit); + BOOST_ASSERT( 0 == result); +#endif + return limit; +} + +rlimit stacksize_limit() +{ + static rlimit limit = stacksize_limit_(); + return limit; +} + +std::size_t page_count( std::size_t stacksize) +{ + return static_cast< std::size_t >( + std::ceil( + static_cast< float >( stacksize) / pagesize() ) ); +} + +bool +standard_stack_allocator::is_stack_unbound() +{ return RLIM_INFINITY == detail::stacksize_limit().rlim_max; } + +std::size_t +standard_stack_allocator::default_stacksize() +{ + std::size_t size = 8 * minimum_stacksize(); + if ( is_stack_unbound() ) return size; + + BOOST_ASSERT( maximum_stacksize() >= minimum_stacksize() ); + return maximum_stacksize() == size + ? size + : (std::min)( size, maximum_stacksize() ); +} + +std::size_t +standard_stack_allocator::minimum_stacksize() +{ return SIGSTKSZ + sizeof( context::fcontext_t) + 15; } + +std::size_t +standard_stack_allocator::maximum_stacksize() +{ + BOOST_ASSERT( ! is_stack_unbound() ); + return static_cast< std::size_t >( detail::stacksize_limit().rlim_max); +} + +void +standard_stack_allocator::allocate( stack_context & ctx, std::size_t size) +{ + BOOST_ASSERT( minimum_stacksize() <= size); + BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= size) ); + + const std::size_t pages( detail::page_count( size) + 1); // add one guard page + const std::size_t size_( pages * detail::pagesize() ); + BOOST_ASSERT( 0 < size && 0 < size_); + + const int fd( ::open("/dev/zero", O_RDONLY) ); + BOOST_ASSERT( -1 != fd); + // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) + void * limit = +# if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) + ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); +# else + ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); +# endif + ::close( fd); + if ( ! limit) throw std::bad_alloc(); + + std::memset( limit, '\0', size_); + + // conforming to POSIX.1-2001 +#if defined(BOOST_DISABLE_ASSERTS) + ::mprotect( limit, detail::pagesize(), PROT_NONE); +#else + const int result( ::mprotect( limit, detail::pagesize(), PROT_NONE) ); + BOOST_ASSERT( 0 == result); +#endif + + ctx.size = size_; + ctx.sp = static_cast< char * >( limit) + ctx.size; +} + +void +standard_stack_allocator::deallocate( stack_context & ctx) +{ + BOOST_ASSERT( ctx.sp); + BOOST_ASSERT( minimum_stacksize() <= ctx.size); + BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= ctx.size) ); + + void * limit = static_cast< char * >( ctx.sp) - ctx.size; + // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) + ::munmap( limit, ctx.size); +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#ifdef UDEF_SIGSTKSZ +# undef SIGSTKSZ +#endif diff --git a/src/detail/standard_stack_allocator_windows.cpp b/src/detail/standard_stack_allocator_windows.cpp new file mode 100644 index 0000000..a6997eb --- /dev/null +++ b/src/detail/standard_stack_allocator_windows.cpp @@ -0,0 +1,155 @@ + +// 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) + +#define BOOST_COROUTINES_SOURCE + +#include "boost/coroutine/detail/standard_stack_allocator.hpp" + +extern "C" { +#include +} + +//#if defined (BOOST_WINDOWS) || _POSIX_C_SOURCE >= 200112L + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +# if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable:4244 4267) +# endif + +// x86_64 +// test x86_64 before i386 because icc might +// define __i686__ for x86_64 too +#if defined(__x86_64__) || defined(__x86_64) \ + || defined(__amd64__) || defined(__amd64) \ + || defined(_M_X64) || defined(_M_AMD64) + +// Windows seams not to provide a constant or function +// telling the minimal stacksize +# define MIN_STACKSIZE 8 * 1024 +#else +# define MIN_STACKSIZE 4 * 1024 +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +SYSTEM_INFO system_info_() +{ + SYSTEM_INFO si; + ::GetSystemInfo( & si); + return si; +} + +SYSTEM_INFO system_info() +{ + static SYSTEM_INFO si = system_info_(); + return si; +} + +std::size_t pagesize() +{ return static_cast< std::size_t >( system_info().dwPageSize); } + +std::size_t page_count( std::size_t stacksize) +{ + return static_cast< std::size_t >( + std::ceil( + static_cast< float >( stacksize) / pagesize() ) ); +} + +// Windows seams not to provide a limit for the stacksize +bool +standard_stack_allocator::is_stack_unbound() +{ return true; } + +std::size_t +standard_stack_allocator::default_stacksize() +{ + std::size_t size = 64 * 1024; // 64 kB + if ( is_stack_unbound() ) + return (std::max)( size, minimum_stacksize() ); + + BOOST_ASSERT( maximum_stacksize() >= minimum_stacksize() ); + return maximum_stacksize() == minimum_stacksize() + ? minimum_stacksize() + : ( std::min)( size, maximum_stacksize() ); +} + +// because Windows seams not to provide a limit for minimum stacksize +std::size_t +standard_stack_allocator::minimum_stacksize() +{ return MIN_STACKSIZE; } + +// because Windows seams not to provide a limit for maximum stacksize +// maximum_stacksize() can never be called (pre-condition ! is_stack_unbound() ) +std::size_t +standard_stack_allocator::maximum_stacksize() +{ + BOOST_ASSERT( ! is_stack_unbound() ); + return 1 * 1024 * 1024 * 1024; // 1GB +} + +void +standard_stack_allocator::allocate( stack_context & ctx, std::size_t size) +{ + BOOST_ASSERT( minimum_stacksize() <= size); + BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= size) ); + + const std::size_t pages( detail::page_count( size) + 1); // add one guard page + const std::size_t size_ = pages * detail::pagesize(); + BOOST_ASSERT( 0 < size && 0 < size_); + + void * limit = ::VirtualAlloc( 0, size_, MEM_COMMIT, PAGE_READWRITE); + if ( ! limit) throw std::bad_alloc(); + + std::memset( limit, '\0', size_); + + DWORD old_options; +#if defined(BOOST_DISABLE_ASSERTS) + ::VirtualProtect( + limit, detail::pagesize(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); +#else + const BOOL result = ::VirtualProtect( + limit, detail::pagesize(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); + BOOST_ASSERT( FALSE != result); +#endif + + ctx.size = size_; + ctx.sp = static_cast< char * >( limit) + ctx.size; +} + +void +standard_stack_allocator::deallocate( stack_context & ctx) +{ + BOOST_ASSERT( ctx.sp); + BOOST_ASSERT( minimum_stacksize() <= ctx.size); + BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= ctx.size) ); + + void * limit = static_cast< char * >( ctx.sp) - ctx.size; + ::VirtualFree( limit, 0, MEM_RELEASE); +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index b11e69b..6b6f692 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -17,6 +17,8 @@ project boost/coroutine/test : requirements ../../test/build//boost_unit_test_framework /boost/context//boost_context + /boost/coroutine//boost_coroutine +# gcc-4.7:-fsplit-stack static ;