diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 8684cb7..49650fa 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -29,33 +29,21 @@ project boost/coroutine : source-location ../src ; -alias protected_allocator_sources - : protected_stack_allocator_windows.cpp +alias stack_traits_sources + : windows/stack_traits.cpp : windows ; -alias protected_allocator_sources - : protected_stack_allocator_posix.cpp +alias stack_traits_sources + : posix/stack_traits.cpp ; -explicit protected_allocator_sources ; - -alias segmented_allocator_sources - : segmented_stack_allocator.cpp - : on - ; - -alias segmented_allocator_sources - ; - -explicit segmented_allocator_sources ; +explicit stack_traits_sources ; lib boost_coroutine : detail/coroutine_context.cpp exceptions.cpp - protected_allocator_sources - segmented_allocator_sources - standard_stack_allocator.cpp + stack_traits_sources : shared:../../context/build//boost_context shared:../../system/build//boost_system shared:../../thread/build//boost_thread diff --git a/doc/coro.qbk b/doc/coro.qbk index 062f3e9..5035fb7 100644 --- a/doc/coro.qbk +++ b/doc/coro.qbk @@ -48,6 +48,7 @@ [def __signature__ ['Signature]] [def __stack_allocator_concept__ ['stack-allocator concept]] [def __stack_allocator__ ['stack-allocator]] +[def __stack_traits__ ['stack-traits]] [def __stack__ ['stack]] [def __tls__ ['thread-local-storage]] diff --git a/doc/stack.qbk b/doc/stack.qbk index 5197773..10cd9dd 100644 --- a/doc/stack.qbk +++ b/doc/stack.qbk @@ -64,51 +64,24 @@ efficient to use as any other stack.] [note The appended `guard page` is [*not] mapped to physical memory, only virtual addresses are used.] - class protected_stack_allocator + #include + + template< typename traitsT > + struct basic_protected_stack_allocator { - static bool is_stack_unbounded(); - - static std::size_t maximum_stacksize(); - - static std::size_t default_stacksize(); - - static std::size_t minimum_stacksize(); + typedef traitT traits_type; void allocate( stack_context &, std::size_t size); void deallocate( stack_context &); } -[heading `static bool is_stack_unbounded()`] -[variablelist -[[Returns:] [Returns `true` if the environment defines no limit for the size of -a stack.]] -] - -[heading `static std::size_t maximum_stacksize()`] -[variablelist -[[Preconditions:] [`is_stack_unbounded()` returns `false`.]] -[[Returns:] [Returns the maximum size in bytes of stack defined by the -environment.]] -] - -[heading `static std::size_t default_stacksize()`] -[variablelist -[[Returns:] [Returns a default stack size, which may be platform specific. -If the stack is unbounded then the present implementation returns the maximum of -`64 kB` and `minimum_stacksize()`.]] -] - -[heading `static std::size_t minimum_stacksize()`] -[variablelist -[[Returns:] [Returns the minimum size in bytes of stack defined by the -environment (Win32 4kB/Win64 8kB, defined by rlimit on POSIX).]] -] + typedef basic_protected_stack_allocator< stack_traits > protected_stack_allocator [heading `void allocate( stack_context & sctx, std::size_t size)`] [variablelist -[[Preconditions:] [`minimum_stacksize() <= size` and -`! is_stack_unbounded() && ( maximum_stacksize() >= size)`.]] +[[Preconditions:] [`minimum_size() <= size` and +`! is_unbounded() && ( maximum_size() >= size)`.]] [[Effects:] [Allocates memory of at least `size` Bytes and stores a pointer to the stack and its actual size in `sctx`. Depending on the architecture (the stack grows downwards/upwards) the stored address is @@ -117,8 +90,8 @@ the highest/lowest address of the stack.]] [heading `void deallocate( stack_context & sctx)`] [variablelist -[[Preconditions:] [`sctx.sp` is valid, `minimum_stacksize() <= sctx.size` and -`! is_stack_unbounded() && ( maximum_stacksize() >= sctx.size)`.]] +[[Preconditions:] [`sctx.sp` is valid, `minimum_size() <= sctx.size` and +`! is_unbounded() && ( maximum_size() >= sctx.size)`.]] [[Effects:] [Deallocates the stack space.]] ] @@ -135,51 +108,24 @@ end of each stack. The memory is simply managed by `std::malloc()` and [note The __standard_allocator__ is the default stack allocator.] - class standard_stack_allocator + #include + + template< typename traitsT > + struct standard_stack_allocator { - static bool is_stack_unbounded(); - - static std::size_t maximum_stacksize(); - - static std::size_t default_stacksize(); - - static std::size_t minimum_stacksize(); + typedef traitT traits_type; void allocate( stack_context &, std::size_t size); void deallocate( stack_context &); } -[heading `static bool is_stack_unbounded()`] -[variablelist -[[Returns:] [Returns `true` if the environment defines no limit for the size of -a stack.]] -] - -[heading `static std::size_t maximum_stacksize()`] -[variablelist -[[Preconditions:] [`is_stack_unbounded()` returns `false`.]] -[[Returns:] [Returns the maximum size in bytes of stack defined by the -environment.]] -] - -[heading `static std::size_t default_stacksize()`] -[variablelist -[[Returns:] [Returns a default stack size, which may be platform specific. -If the stack is unbounded then the present implementation returns the maximum of -`64 kB` and `minimum_stacksize()`.]] -] - -[heading `static std::size_t minimum_stacksize()`] -[variablelist -[[Returns:] [Returns the minimum size in bytes of stack defined by the -environment (Win32 4kB/Win64 8kB, defined by rlimit on POSIX).]] -] + typedef basic_standard_stack_allocator< stack_traits > standard_stack_allocator [heading `void allocate( stack_context & sctx, std::size_t size)`] [variablelist -[[Preconditions:] [`minimum_stacksize() <= size` and -`! is_stack_unbounded() && ( maximum_stacksize() >= size)`.]] +[[Preconditions:] [`minimum_size() <= size` and +`! is_unbounded() && ( maximum_size() >= size)`.]] [[Effects:] [Allocates memory of at least `size` Bytes and stores a pointer to the stack and its actual size in `sctx`. Depending on the architecture (the stack grows downwards/upwards) the stored address is the highest/lowest @@ -188,8 +134,8 @@ address of the stack.]] [heading `void deallocate( stack_context & sctx)`] [variablelist -[[Preconditions:] [`sctx.sp` is valid, `minimum_stacksize() <= sctx.size` and -`! is_stack_unbounded() && ( maximum_stacksize() >= sctx.size)`.]] +[[Preconditions:] [`sctx.sp` is valid, `minimum_size() <= sctx.size` and +`! is_unbounded() && ( maximum_size() >= sctx.size)`.]] [[Effects:] [Deallocates the stack space.]] ] @@ -210,51 +156,24 @@ onwards. In order to use a __segmented_stack__ __boost_coroutine__ must be built with [*toolset=gcc segmented-stacks=on] at b2/bjam command-line. Applications must be compiled with compiler-flags [*-fsplit-stack -DBOOST_USE_SEGMENTED_STACKS].] - class segmented_stack_allocator + #include + + template< typename traitsT > + struct basic_segmented_stack_allocator { - static bool is_stack_unbounded(); - - static std::size_t maximum_stacksize(); - - static std::size_t default_stacksize(); - - static std::size_t minimum_stacksize(); + typedef traitT traits_type; void allocate( stack_context &, std::size_t size); void deallocate( stack_context &); } -[heading `static bool is_stack_unbounded()`] -[variablelist -[[Returns:] [Returns `true` if the environment defines no limit for the size of -a stack.]] -] - -[heading `static std::size_t maximum_stacksize()`] -[variablelist -[[Preconditions:] [`is_stack_unbounded()` returns `false`.]] -[[Returns:] [Returns the maximum size in bytes of stack defined by the -environment.]] -] - -[heading `static std::size_t default_stacksize()`] -[variablelist -[[Returns:] [Returns a default stack size, which may be platform specific. -If the stack is unbounded then the present implementation returns the maximum of -`64 kB` and `minimum_stacksize()`.]] -] - -[heading `static std::size_t minimum_stacksize()`] -[variablelist -[[Returns:] [Returns the minimum size in bytes of stack defined by the -environment (Win32 4kB/Win64 8kB, defined by rlimit on POSIX).]] -] + typedef basic_segmented_stack_allocator< stack_traits > segmented_stack_allocator; [heading `void allocate( stack_context & sctx, std::size_t size)`] [variablelist -[[Preconditions:] [`minimum_stacksize() <= size` and -`! is_stack_unbounded() && ( maximum_stacksize() >= size)`.]] +[[Preconditions:] [`minimum_size() <= size` and +`! is_unbounded() && ( maximum_size() >= size)`.]] [[Effects:] [Allocates memory of at least `size` Bytes and stores a pointer to the stack and its actual size in `sctx`. Depending on the architecture (the stack grows downwards/upwards) the stored address is the highest/lowest @@ -263,14 +182,76 @@ address of the stack.]] [heading `void deallocate( stack_context & sctx)`] [variablelist -[[Preconditions:] [`sctx.sp` is valid, `minimum_stacksize() <= sctx.size` and -`! is_stack_unbounded() && ( maximum_stacksize() >= sctx.size)`.]] +[[Preconditions:] [`sctx.sp` is valid, `minimum_size() <= sctx.size` and +`! is_unbounded() && ( maximum_size() >= sctx.size)`.]] [[Effects:] [Deallocates the stack space.]] ] [endsect] +[section:stack_traits Class ['stack_traits]] + +['stack_traits] models a __stack_traits__ providing a way to access certain +properites defined by the enironment. Stack allocators use __stack_traits__ to +allocate stacks. + + #include + + struct stack_traits + { + static bool is_unbounded() noexcept; + + static std::size_t page_size() noexcept; + + static std::size_t default_size() noexcept; + + static std::size_t minimum_size() noexcept; + + static std::size_t maximum_size() noexcept; + } + + +[heading `static bool is_unbounded()`] +[variablelist +[[Returns:] [Returns `true` if the environment defines no limit for the size of +a stack.]] +[[Throws:] [Nothing.]] +] + +[heading `static std::size_t page_size()`] +[variablelist +[[Returns:] [Returns the page size in bytes.]] +[[Throws:] [Nothing.]] +] + +[heading `static std::size_t default_size()`] +[variablelist +[[Returns:] [Returns a default stack size, which may be platform specific. +If the stack is unbounded then the present implementation returns the maximum of +`64 kB` and `minimum_size()`.]] +[[Throws:] [Nothing.]] +] + +[heading `static std::size_t minimum_size()`] +[variablelist +[[Returns:] [Returns the minimum size in bytes of stack defined by the +environment (Win32 4kB/Win64 8kB, defined by rlimit on POSIX).]] +[[Throws:] [Nothing.]] +] + +[heading `static std::size_t maximum_size()`] +[variablelist +[[Preconditions:] [`is_unbounded()` returns `false`.]] +[[Returns:] [Returns the maximum size in bytes of stack defined by the +environment.]] +[[Throws:] [Nothing.]] +] + + +[endsect] + + [section:stack_context Class ['stack_context]] __boost_coroutine__ provides the class __stack_context__ which will contain diff --git a/example/cpp03/asymmetric/segmented_stack.cpp b/example/cpp03/asymmetric/segmented_stack.cpp index 262e405..fec875a 100644 --- a/example/cpp03/asymmetric/segmented_stack.cpp +++ b/example/cpp03/asymmetric/segmented_stack.cpp @@ -53,11 +53,11 @@ int main( int argc, char * argv[]) { #if defined(BOOST_USE_SEGMENTED_STACKS) std::cout << "using segmented stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, "; - std::cout << "initial stack size = " << boost::coroutines::stack_allocator::default_stacksize() / 1024 << "kB" << std::endl; + std::cout << "initial stack size = " << boost::coroutines::stack_allocator::traits_type::default_size() / 1024 << "kB" << std::endl; std::cout << "application should not fail" << std::endl; #else std::cout << "using standard stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, "; - std::cout << "initial stack size = " << boost::coroutines::stack_allocator::default_stacksize() / 1024 << "kB" << std::endl; + std::cout << "initial stack size = " << boost::coroutines::stack_allocator::traits_type::default_size() / 1024 << "kB" << std::endl; std::cout << "application might fail" << std::endl; #endif diff --git a/example/cpp11/asymmetric/Jamfile.v2 b/example/cpp11/asymmetric/Jamfile.v2 index 22a0173..335f780 100644 --- a/example/cpp11/asymmetric/Jamfile.v2 +++ b/example/cpp11/asymmetric/Jamfile.v2 @@ -45,10 +45,6 @@ exe iterator_range : iterator_range.cpp ; -exe test_case - : test_case.cpp - ; - #exe await_emu # : await_emu.cpp # ; diff --git a/include/boost/coroutine/all.hpp b/include/boost/coroutine/all.hpp index d1ccc61..42f63a0 100644 --- a/include/boost/coroutine/all.hpp +++ b/include/boost/coroutine/all.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #endif // BOOST_COROUTINES_ALL_H diff --git a/include/boost/coroutine/attributes.hpp b/include/boost/coroutine/attributes.hpp index 207f581..065a4c6 100644 --- a/include/boost/coroutine/attributes.hpp +++ b/include/boost/coroutine/attributes.hpp @@ -28,7 +28,7 @@ struct attributes flag_fpu_t preserve_fpu; attributes() BOOST_NOEXCEPT : - size( stack_allocator::default_stacksize() ), + size( stack_allocator::traits_type::default_size() ), do_unwind( stack_unwind), preserve_fpu( fpu_preserved) {} @@ -40,13 +40,13 @@ struct attributes {} explicit attributes( flag_unwind_t do_unwind_) BOOST_NOEXCEPT : - size( stack_allocator::default_stacksize() ), + size( stack_allocator::traits_type::default_size() ), do_unwind( do_unwind_), preserve_fpu( fpu_preserved) {} explicit attributes( flag_fpu_t preserve_fpu_) BOOST_NOEXCEPT : - size( stack_allocator::default_stacksize() ), + size( stack_allocator::traits_type::default_size() ), do_unwind( stack_unwind), preserve_fpu( preserve_fpu_) {} @@ -70,7 +70,7 @@ struct attributes explicit attributes( flag_unwind_t do_unwind_, flag_fpu_t preserve_fpu_) BOOST_NOEXCEPT : - size( stack_allocator::default_stacksize() ), + size( stack_allocator::traits_type::default_size() ), do_unwind( do_unwind_), preserve_fpu( preserve_fpu_) {} diff --git a/include/boost/coroutine/posix/protected_stack_allocator.hpp b/include/boost/coroutine/posix/protected_stack_allocator.hpp new file mode 100644 index 0000000..3a6c9d7 --- /dev/null +++ b/include/boost/coroutine/posix/protected_stack_allocator.hpp @@ -0,0 +1,98 @@ + +// 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_PROTECTED_STACK_ALLOCATOR_H +#define BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H + +extern "C" { +#include +#include +#include +#include +} + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +template< typename traitsT > +struct basic_protected_stack_allocator +{ + typedef traitsT traits_type; + + void allocate( stack_context & ctx, std::size_t size = traits_type::minimum_size() ) + { + BOOST_ASSERT( traits_type::minimum_size() <= size); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size) ); + + // page at bottom will be used as guard-page + const std::size_t pages( + static_cast< std::size_t >( + std::floor( + static_cast< float >( size) / traits_type::page_size() ) ) ); + BOOST_ASSERT_MSG( 2 <= pages, "at least two pages must fit into stack (one page is guard-page)"); + const std::size_t size_( pages * traits_type::page_size() ); + BOOST_ASSERT( 0 < size && 0 < size_); + BOOST_ASSERT( size_ <= size); + + const int fd( ::open("/dev/zero", O_RDONLY) ); + BOOST_ASSERT( -1 != fd); + // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) +# if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) + void * limit = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); +# else + void * limit = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); +# endif + ::close( fd); + if ( MAP_FAILED == limit) throw std::bad_alloc(); + + // conforming to POSIX.1-2001 +#if defined(BOOST_DISABLE_ASSERTS) + ::mprotect( limit, traits_type::page_size(), PROT_NONE); +#else + const int result( ::mprotect( limit, traits_type::page_size(), PROT_NONE) ); + BOOST_ASSERT( 0 == result); +#endif + + ctx.size = size_; + ctx.sp = static_cast< char * >( limit) + ctx.size; + } + + void deallocate( stack_context & ctx) + { + BOOST_ASSERT( ctx.sp); + BOOST_ASSERT( traits_type::minimum_size() <= ctx.size); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= 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); + } +}; + +typedef basic_protected_stack_allocator< stack_traits > protected_stack_allocator; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H diff --git a/include/boost/coroutine/posix/segmented_stack_allocator.hpp b/include/boost/coroutine/posix/segmented_stack_allocator.hpp new file mode 100644 index 0000000..871c8a3 --- /dev/null +++ b/include/boost/coroutine/posix/segmented_stack_allocator.hpp @@ -0,0 +1,69 @@ + +// 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_SEGMENTED_STACK_ALLOCATOR_H +#define BOOST_COROUTINES_SEGMENTED_STACK_ALLOCATOR_H + +#include +#include + +#include + +#include +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +// forward declaration for splitstack-functions defined in libgcc +extern "C" { +void *__splitstack_makecontext( std::size_t, + void * [BOOST_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); +} + +namespace boost { +namespace coroutines { + +template< typename traitsT > +struct basic_segmented_stack_allocator +{ + typedef traitsT traits_type; + + void allocate( stack_context & ctx, std::size_t size = traits_type::minimum_size() ) + { + void * limit = __splitstack_makecontext( size, ctx.segments_ctx, & ctx.size); + if ( ! limit) throw std::bad_alloc(); + + // ctx.size is already filled by __splitstack_makecontext + ctx.sp = static_cast< char * >( limit) + ctx.size; + + int off = 0; + __splitstack_block_signals_context( ctx.segments_ctx, & off, 0); + } + + void deallocate( stack_context & ctx) + { __splitstack_releasecontext( ctx.segments_ctx); } +}; + +typedef basic_segmented_stack_allocator< stack_traits > segmented_stack_allocator; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_SEGMENTED_STACK_ALLOCATOR_H diff --git a/include/boost/coroutine/protected_stack_allocator.hpp b/include/boost/coroutine/protected_stack_allocator.hpp index 15735ac..268786f 100644 --- a/include/boost/coroutine/protected_stack_allocator.hpp +++ b/include/boost/coroutine/protected_stack_allocator.hpp @@ -4,44 +4,10 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H -#define BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H - -#include - #include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX +#if defined(BOOST_WINDOWS) +# include +#else +# include #endif - -namespace boost { -namespace coroutines { - -struct stack_context; - -class BOOST_COROUTINES_DECL protected_stack_allocator -{ -public: - static bool is_stack_unbounded(); - - 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_PROTECTED_STACK_ALLOCATOR_H diff --git a/include/boost/coroutine/segmented_stack_allocator.hpp b/include/boost/coroutine/segmented_stack_allocator.hpp index d768603..f9525a1 100644 --- a/include/boost/coroutine/segmented_stack_allocator.hpp +++ b/include/boost/coroutine/segmented_stack_allocator.hpp @@ -4,46 +4,12 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_COROUTINES_SEGMENTED_STACK_ALLOCATOR_H -#define BOOST_COROUTINES_SEGMENTED_STACK_ALLOCATOR_H - -#include - #include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace coroutines { - -struct stack_context; - #if defined(BOOST_USE_SEGMENTED_STACKS) -class BOOST_COROUTINES_DECL segmented_stack_allocator -{ -public: - static bool is_stack_unbounded(); - - 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 = minimum_stacksize() ); - - void deallocate( stack_context &); -}; +# if defined(BOOST_WINDOWS) +# error "segmented stacks are not supported by Windows" +# else +# include +# endif #endif - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_COROUTINES_SEGMENTED_STACK_ALLOCATOR_H diff --git a/include/boost/coroutine/stack_traits.hpp b/include/boost/coroutine/stack_traits.hpp new file mode 100644 index 0000000..0e8f251 --- /dev/null +++ b/include/boost/coroutine/stack_traits.hpp @@ -0,0 +1,42 @@ + +// 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_TRAITS_H +#define BOOST_COROUTINES_STACK_TRAITS_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +struct BOOST_COROUTINES_DECL stack_traits +{ + static bool is_unbounded() BOOST_NOEXCEPT; + + static std::size_t page_size() BOOST_NOEXCEPT; + + static std::size_t default_size() BOOST_NOEXCEPT; + + static std::size_t minimum_size() BOOST_NOEXCEPT; + + static std::size_t maximum_size() BOOST_NOEXCEPT; +}; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_STACK_TRAITS_H diff --git a/include/boost/coroutine/standard_stack_allocator.hpp b/include/boost/coroutine/standard_stack_allocator.hpp index 9e0ec17..3341ce3 100644 --- a/include/boost/coroutine/standard_stack_allocator.hpp +++ b/include/boost/coroutine/standard_stack_allocator.hpp @@ -8,10 +8,15 @@ #define BOOST_COROUTINES_STANDARD_STACK_ALLOCATOR_H #include +#include +#include +#include #include #include +#include +#include #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -20,24 +25,36 @@ namespace boost { namespace coroutines { -struct stack_context; - -class BOOST_COROUTINES_DECL standard_stack_allocator +template< typename traitsT > +struct basic_standard_stack_allocator { -public: - static bool is_stack_unbounded(); + typedef traitsT traits_type; - static std::size_t maximum_stacksize(); + void allocate( stack_context & ctx, std::size_t size = traits_type::minimum_size() ) + { + BOOST_ASSERT( traits_type::minimum_size() <= size); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size) ); - static std::size_t default_stacksize(); + void * limit = std::malloc( size); + if ( ! limit) throw std::bad_alloc(); - static std::size_t minimum_stacksize(); + ctx.size = size; + ctx.sp = static_cast< char * >( limit) + ctx.size; + } - void allocate( stack_context & ctx, std::size_t size); + void deallocate( stack_context & ctx) + { + BOOST_ASSERT( ctx.sp); + BOOST_ASSERT( traits_type::minimum_size() <= ctx.size); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= ctx.size) ); - void deallocate( stack_context & ctx); + void * limit = static_cast< char * >( ctx.sp) - ctx.size; + std::free( limit); + } }; +typedef basic_standard_stack_allocator< stack_traits > standard_stack_allocator; + }} #ifdef BOOST_HAS_ABI_HEADERS diff --git a/include/boost/coroutine/windows/protected_stack_allocator.hpp b/include/boost/coroutine/windows/protected_stack_allocator.hpp new file mode 100644 index 0000000..46f2d88 --- /dev/null +++ b/include/boost/coroutine/windows/protected_stack_allocator.hpp @@ -0,0 +1,87 @@ + +// 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_PROTECTED_STACK_ALLOCATOR_H +#define BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H + +extern "C" { +#include +} + +#include +#include +#include + +#include + +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { + +struct stack_context; + +template< typename traitsT > +struct protected_stack_allocator +{ + typedef traitsT traits_type; + + void allocate( stack_context & ctx, std::size_t size) + { + BOOST_ASSERT( traits_type::minimum_size() <= size); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size) ); + + // page at bottom will be used as guard-page + const std::size_t pages( + static_cast< std::size_t >( + std::floor( + static_cast< float >( size) / traits_type::page_size() ) ) ); + BOOST_ASSERT_MSG( 2 <= pages, "at least two pages must fit into stack (one page is guard-page)"); + const std::size_t size_ = pages * traits_type::page_size(); + BOOST_ASSERT( 0 < size && 0 < size_); + + void * limit = ::VirtualAlloc( 0, size_, MEM_COMMIT, PAGE_READWRITE); + if ( ! limit) throw std::bad_alloc(); + + 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 + + ctx.size = size_; + ctx.sp = static_cast< char * >( limit) + ctx.size; + } + + void deallocate( stack_context & ctx) + { + BOOST_ASSERT( ctx.sp); + BOOST_ASSERT( traits_type::minimum_size() <= ctx.size); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= ctx.size) ); + + void * limit = static_cast< char * >( ctx.sp) - ctx.size; + ::VirtualFree( limit, 0, MEM_RELEASE); + } +}; + +typedef basic_protected_stack_allocator< stack_traits > protected_stack_allocator; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H diff --git a/performance/asymmetric/performance_create_prealloc.cpp b/performance/asymmetric/performance_create_prealloc.cpp index 157fb9a..db04222 100644 --- a/performance/asymmetric/performance_create_prealloc.cpp +++ b/performance/asymmetric/performance_create_prealloc.cpp @@ -35,7 +35,7 @@ duration_type measure_time( duration_type overhead) time_point_type start( clock_type::now() ); for ( std::size_t i = 0; i < jobs; ++i) { coro_type::pull_type c( fn, - boost::coroutines::attributes( stack_allocator::default_stacksize(), unwind_stack, preserve_fpu), + boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc); } duration_type total = clock_type::now() - start; @@ -53,7 +53,7 @@ cycle_type measure_cycles( cycle_type overhead) cycle_type start( cycles() ); for ( std::size_t i = 0; i < jobs; ++i) { coro_type::pull_type c( fn, - boost::coroutines::attributes( stack_allocator::default_stacksize(), unwind_stack, preserve_fpu), + boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc); } cycle_type total = cycles() - start; diff --git a/performance/preallocated_stack_allocator.hpp b/performance/preallocated_stack_allocator.hpp index a2db143..3651ae1 100644 --- a/performance/preallocated_stack_allocator.hpp +++ b/performance/preallocated_stack_allocator.hpp @@ -33,7 +33,9 @@ public: stack_ctx_() { boost::coroutines::standard_stack_allocator allocator; - allocator.allocate( stack_ctx_, default_stacksize() ); + allocator.allocate( + stack_ctx_, + boost::coroutines::standard_stack_allocator::traits_type::default_size() ); } void allocate( boost::coroutines::stack_context & ctx, std::size_t size) @@ -45,15 +47,6 @@ public: void deallocate( boost::coroutines::stack_context & ctx) { } - - static std::size_t maximum_stacksize() - { return boost::coroutines::standard_stack_allocator::maximum_stacksize(); } - - static std::size_t default_stacksize() - { return boost::coroutines::standard_stack_allocator::default_stacksize(); } - - static std::size_t minimum_stacksize() - { return boost::coroutines::standard_stack_allocator::minimum_stacksize(); } }; #ifdef BOOST_HAS_ABI_HEADERS diff --git a/performance/symmetric/performance_create_prealloc.cpp b/performance/symmetric/performance_create_prealloc.cpp index b9fcad9..ad06e84 100644 --- a/performance/symmetric/performance_create_prealloc.cpp +++ b/performance/symmetric/performance_create_prealloc.cpp @@ -34,7 +34,7 @@ duration_type measure_time( duration_type overhead) time_point_type start( clock_type::now() ); for ( std::size_t i = 0; i < jobs; ++i) { coro_type::call_type c( fn, - boost::coroutines::attributes( stack_allocator::default_stacksize(), unwind_stack, preserve_fpu), + boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc); } duration_type total = clock_type::now() - start; @@ -52,7 +52,7 @@ cycle_type measure_cycles( cycle_type overhead) cycle_type start( cycles() ); for ( std::size_t i = 0; i < jobs; ++i) { coro_type::call_type c( fn, - boost::coroutines::attributes( stack_allocator::default_stacksize(), unwind_stack, preserve_fpu), + boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc); } cycle_type total = cycles() - start; diff --git a/src/posix/stack_traits.cpp b/src/posix/stack_traits.cpp new file mode 100644 index 0000000..c2d4328 --- /dev/null +++ b/src/posix/stack_traits.cpp @@ -0,0 +1,108 @@ + +// 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 "boost/coroutine/stack_traits.hpp" + +extern "C" { +#include +#include +#include +#include +} + +//#if _POSIX_C_SOURCE >= 200112L + +#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 { + +void pagesize_( std::size_t * size) +{ + // conform to POSIX.1-2001 + * size = ::sysconf( _SC_PAGESIZE); +} + +void 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 +} + +std::size_t pagesize() +{ + static std::size_t size = 0; + static boost::once_flag flag; + boost::call_once( flag, pagesize_, & size); + return size; +} + +rlimit stacksize_limit() +{ + static rlimit limit; + static boost::once_flag flag; + boost::call_once( flag, stacksize_limit_, & limit); + return limit; +} + +bool +stack_traits::is_unbounded() BOOST_NOEXCEPT +{ return RLIM_INFINITY == stacksize_limit().rlim_max; } + +std::size_t +stack_traits::page_size() BOOST_NOEXCEPT +{ return pagesize(); } + +std::size_t +stack_traits::default_size() BOOST_NOEXCEPT +{ + std::size_t size = 8 * minimum_size(); + if ( is_unbounded() ) return size; + + BOOST_ASSERT( maximum_size() >= minimum_size() ); + return maximum_size() == size + ? size + : (std::min)( size, maximum_size() ); +} + +std::size_t +stack_traits::minimum_size() BOOST_NOEXCEPT +{ return SIGSTKSZ; } + +std::size_t +stack_traits::maximum_size() BOOST_NOEXCEPT +{ + BOOST_ASSERT( ! is_unbounded() ); + return static_cast< std::size_t >( stacksize_limit().rlim_max); +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#ifdef UDEF_SIGSTKSZ +# undef SIGSTKSZ +#endif diff --git a/src/protected_stack_allocator_posix.cpp b/src/protected_stack_allocator_posix.cpp deleted file mode 100644 index 8cc4777..0000000 --- a/src/protected_stack_allocator_posix.cpp +++ /dev/null @@ -1,169 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include "boost/coroutine/protected_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 - -#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 { - -void pagesize_( std::size_t * size) -{ - // conform to POSIX.1-2001 - * size = ::sysconf( _SC_PAGESIZE); -} - -void 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 -} - -// conform to POSIX.1-2001 -std::size_t pagesize() -{ - static std::size_t size = 0; - static boost::once_flag flag; - boost::call_once( flag, pagesize_, & size); - return size; -} - -rlimit stacksize_limit() -{ - static rlimit limit; - static boost::once_flag flag; - boost::call_once( flag, stacksize_limit_, & limit); - return limit; -} - -std::size_t page_count( std::size_t stacksize) -{ - return static_cast< std::size_t >( - std::floor( - static_cast< float >( stacksize) / pagesize() ) ); -} - -bool -protected_stack_allocator::is_stack_unbounded() -{ return RLIM_INFINITY == stacksize_limit().rlim_max; } - -std::size_t -protected_stack_allocator::default_stacksize() -{ - std::size_t size = 8 * minimum_stacksize(); - if ( is_stack_unbounded() ) return size; - - BOOST_ASSERT( maximum_stacksize() >= minimum_stacksize() ); - return maximum_stacksize() == size - ? size - : (std::min)( size, maximum_stacksize() ); -} - -std::size_t -protected_stack_allocator::minimum_stacksize() -{ return SIGSTKSZ + sizeof( context::fcontext_t) + 15; } - -std::size_t -protected_stack_allocator::maximum_stacksize() -{ - BOOST_ASSERT( ! is_stack_unbounded() ); - return static_cast< std::size_t >( stacksize_limit().rlim_max); -} - -void -protected_stack_allocator::allocate( stack_context & ctx, std::size_t size) -{ - BOOST_ASSERT( minimum_stacksize() <= size); - BOOST_ASSERT( is_stack_unbounded() || ( maximum_stacksize() >= size) ); - - const std::size_t pages( page_count( size) ); // page at bottom will be used as guard-page - BOOST_ASSERT_MSG( 2 <= pages, "at least two pages must fit into stack (one page is guard-page)"); - const std::size_t size_( pages * pagesize() ); - BOOST_ASSERT( 0 < size && 0 < size_); - BOOST_ASSERT( size_ <= 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 ( MAP_FAILED == limit) throw std::bad_alloc(); - - // 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 - - ctx.size = size_; - ctx.sp = static_cast< char * >( limit) + ctx.size; -} - -void -protected_stack_allocator::deallocate( stack_context & ctx) -{ - BOOST_ASSERT( ctx.sp); - BOOST_ASSERT( minimum_stacksize() <= ctx.size); - BOOST_ASSERT( is_stack_unbounded() || ( 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/protected_stack_allocator_windows.cpp b/src/protected_stack_allocator_windows.cpp deleted file mode 100644 index 45de239..0000000 --- a/src/protected_stack_allocator_windows.cpp +++ /dev/null @@ -1,144 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include "boost/coroutine/protected_stack_allocator.hpp" - -extern "C" { -#include -} - -//#if defined (BOOST_WINDOWS) || _POSIX_C_SOURCE >= 200112L - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -// 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 { - -void system_info_( SYSTEM_INFO * si) -{ ::GetSystemInfo( si); } - -SYSTEM_INFO system_info() -{ - static SYSTEM_INFO si; - static boost::once_flag flag; - boost::call_once( flag, static_cast< void(*)( SYSTEM_INFO *) >( system_info_), & si); - 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::floor( - static_cast< float >( stacksize) / pagesize() ) ); -} - -// Windows seams not to provide a limit for the stacksize -bool -protected_stack_allocator::is_stack_unbounded() -{ return true; } - -std::size_t -protected_stack_allocator::default_stacksize() -{ - std::size_t size = 64 * 1024; // 64 kB - if ( is_stack_unbounded() ) - 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 -protected_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_unbounded() ) -std::size_t -protected_stack_allocator::maximum_stacksize() -{ - BOOST_ASSERT( ! is_stack_unbounded() ); - return 1 * 1024 * 1024 * 1024; // 1GB -} - -void -protected_stack_allocator::allocate( stack_context & ctx, std::size_t size) -{ - BOOST_ASSERT( minimum_stacksize() <= size); - BOOST_ASSERT( is_stack_unbounded() || ( maximum_stacksize() >= size) ); - - const std::size_t pages( page_count( size) ); // page at bottom will be used as guard-page - BOOST_ASSERT_MSG( 2 <= pages, "at least two pages must fit into stack (one page is 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(); - - 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 - - ctx.size = size_; - ctx.sp = static_cast< char * >( limit) + ctx.size; -} - -void -protected_stack_allocator::deallocate( stack_context & ctx) -{ - BOOST_ASSERT( ctx.sp); - BOOST_ASSERT( minimum_stacksize() <= ctx.size); - BOOST_ASSERT( is_stack_unbounded() || ( 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/src/segmented_stack_allocator.cpp b/src/segmented_stack_allocator.cpp deleted file mode 100644 index 29b8d8b..0000000 --- a/src/segmented_stack_allocator.cpp +++ /dev/null @@ -1,88 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include - -#include - -#include -#include - -#include - -// forward declaration for splitstack-functions defined in libgcc -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 { - -bool -segmented_stack_allocator::is_stack_unbounded() -{ 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) -{ - void * limit = __splitstack_makecontext( size, ctx.segments_ctx, & ctx.size); - if ( ! limit) throw std::bad_alloc(); - - // ctx.size is already filled by __splitstack_makecontext - 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 diff --git a/src/standard_stack_allocator.cpp b/src/standard_stack_allocator.cpp deleted file mode 100644 index 89eaa48..0000000 --- a/src/standard_stack_allocator.cpp +++ /dev/null @@ -1,68 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include - -#include -#include - -#include - -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace coroutines { - -bool -standard_stack_allocator::is_stack_unbounded() -{ return protected_stack_allocator::is_stack_unbounded(); } - -std::size_t -standard_stack_allocator::maximum_stacksize() -{ return protected_stack_allocator::maximum_stacksize(); } - -std::size_t -standard_stack_allocator::default_stacksize() -{ return protected_stack_allocator::default_stacksize(); } - -std::size_t -standard_stack_allocator::minimum_stacksize() -{ return protected_stack_allocator::minimum_stacksize(); } - -void -standard_stack_allocator::allocate( stack_context & ctx, std::size_t size) -{ - BOOST_ASSERT( minimum_stacksize() <= size); - BOOST_ASSERT( is_stack_unbounded() || ( maximum_stacksize() >= size) ); - - void * limit = std::malloc( size); - if ( ! limit) throw std::bad_alloc(); - - 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_unbounded() || ( maximum_stacksize() >= ctx.size) ); - - void * limit = static_cast< char * >( ctx.sp) - ctx.size; - std::free( limit); -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif diff --git a/src/windows/stack_traits.cpp b/src/windows/stack_traits.cpp new file mode 100644 index 0000000..1731634 --- /dev/null +++ b/src/windows/stack_traits.cpp @@ -0,0 +1,110 @@ + +// 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 "boost/coroutine/stack_traits.hpp" + +extern "C" { +#include +} + +//#if defined (BOOST_WINDOWS) || _POSIX_C_SOURCE >= 200112L + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +// 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 { + +void system_info_( SYSTEM_INFO * si) +{ ::GetSystemInfo( si); } + +SYSTEM_INFO system_info() +{ + static SYSTEM_INFO si; + static boost::once_flag flag; + boost::call_once( flag, static_cast< void(*)( SYSTEM_INFO *) >( system_info_), & si); + 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::floor( + static_cast< float >( stacksize) / pagesize() ) ); +} + +// Windows seams not to provide a limit for the stacksize +// libcoco uses 32k+4k bytes as minimum +bool +stack_traits::is_unbounded() BOOST_NOEXCEPT +{ return true; } + +std::size_t +stack_traits::page_size() BOOST_NOEXCEPT +{ return pagesize(); } + +std::size_t +stack_traits::default_size() BOOST_NOEXCEPT +{ + std::size_t size = 64 * 1024; // 64 kB + if ( is_unbounded() ) + return (std::max)( size, minimum_size() ); + + BOOST_ASSERT( maximum_size() >= minimum_size() ); + return maximum_size() == minimum_size() + ? minimum_size() + : ( std::min)( size, maximum_size() ); +} + +// because Windows seams not to provide a limit for minimum stacksize +std::size_t +stack_traits::minimum_size() BOOST_NOEXCEPT +{ return MIN_STACKSIZE; } + +// because Windows seams not to provide a limit for maximum stacksize +// maximum_size() can never be called (pre-condition ! is_unbounded() ) +std::size_t +stack_traits::maximum_size() BOOST_NOEXCEPT +{ + BOOST_ASSERT( ! is_unbounded() ); + return 1 * 1024 * 1024 * 1024; // 1GB +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/test/test_asymmetric_coroutine.cpp b/test/test_asymmetric_coroutine.cpp index c462e49..683a10f 100644 --- a/test/test_asymmetric_coroutine.cpp +++ b/test/test_asymmetric_coroutine.cpp @@ -421,7 +421,7 @@ void test_no_unwind() coro::asymmetric_coroutine< void >::push_type coro( f12, coro::attributes( - coro::stack_allocator::default_stacksize(), + coro::stack_allocator::traits_type::default_size(), coro::no_stack_unwind) ); BOOST_CHECK( coro); BOOST_CHECK_EQUAL( ( int) 0, value1); diff --git a/test/test_symmetric_coroutine.cpp b/test/test_symmetric_coroutine.cpp index 741a65f..d26d019 100644 --- a/test/test_symmetric_coroutine.cpp +++ b/test/test_symmetric_coroutine.cpp @@ -411,7 +411,7 @@ void test_no_unwind() { coro::symmetric_coroutine< void >::call_type coro( f6, coro::attributes( - coro::stack_allocator::default_stacksize(), + coro::stack_allocator::traits_type::default_size(), coro::no_stack_unwind) ); coro::symmetric_coroutine< void >::call_type coro_e( empty); BOOST_CHECK( coro);