diff --git a/boost/fiber/attributes.hpp b/boost/fiber/attributes.hpp new file mode 100644 index 00000000..df651cac --- /dev/null +++ b/boost/fiber/attributes.hpp @@ -0,0 +1,85 @@ + +// 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_FIBERS_ATTRIBUTES_H +#define BOOST_FIBERS_ATTRIBUTES_H + +#include + +#include + +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace fibers { + +struct attributes +{ + std::size_t size; + flag_unwind_t do_unwind; + flag_fpu_t preserve_fpu; + + attributes() BOOST_NOEXCEPT : + size( stack_allocator::default_stacksize() ), + do_unwind( stack_unwind), + preserve_fpu( fpu_preserved) + {} + + explicit attributes( std::size_t size_) BOOST_NOEXCEPT : + size( size_), + do_unwind( stack_unwind), + preserve_fpu( fpu_preserved) + {} + + explicit attributes( flag_unwind_t do_unwind_) BOOST_NOEXCEPT : + size( stack_allocator::default_stacksize() ), + do_unwind( do_unwind_), + preserve_fpu( fpu_preserved) + {} + + explicit attributes( flag_fpu_t preserve_fpu_) BOOST_NOEXCEPT : + size( stack_allocator::default_stacksize() ), + do_unwind( stack_unwind), + preserve_fpu( preserve_fpu_) + {} + + explicit attributes( + std::size_t size_, + flag_unwind_t do_unwind_) BOOST_NOEXCEPT : + size( size_), + do_unwind( do_unwind_), + preserve_fpu( fpu_preserved) + {} + + explicit attributes( + std::size_t size_, + flag_fpu_t preserve_fpu_) BOOST_NOEXCEPT : + size( size_), + do_unwind( stack_unwind), + preserve_fpu( preserve_fpu_) + {} + + explicit attributes( + flag_unwind_t do_unwind_, + flag_fpu_t preserve_fpu_) BOOST_NOEXCEPT : + size( stack_allocator::default_stacksize() ), + do_unwind( do_unwind_), + preserve_fpu( preserve_fpu_) + {} +}; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_FIBERS_ATTRIBUTES_H diff --git a/boost/fiber/detail/stack_allocator_posix.hpp b/boost/fiber/detail/stack_allocator_posix.hpp new file mode 100644 index 00000000..3b663678 --- /dev/null +++ b/boost/fiber/detail/stack_allocator_posix.hpp @@ -0,0 +1,161 @@ + +// 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_FIBERS_DETAIL_STACK_ALLOCATOR_H +#define BOOST_FIBERS_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 fibers { +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 + const int result = ::getrlimit( RLIMIT_STACK, & limit); + BOOST_ASSERT( 0 == result); + 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() ) ); +} + +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 + const int result( ::mprotect( limit, pagesize(), PROT_NONE) ); + BOOST_ASSERT( 0 == result); + + 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_FIBERS_DETAIL_STACK_ALLOCATOR_H diff --git a/boost/fiber/detail/stack_allocator_windows.hpp b/boost/fiber/detail/stack_allocator_windows.hpp new file mode 100644 index 00000000..76aa5e75 --- /dev/null +++ b/boost/fiber/detail/stack_allocator_windows.hpp @@ -0,0 +1,156 @@ + +// 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_FIBERS_DETAIL_STACK_ALLOCATOR_H +#define BOOST_FIBERS_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 fibers { +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() ) ); +} + +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() + { + using namespace std; + + std::size_t size = 64 * 1024; // 64 kB + if ( is_stack_unbound() ) + return max( size, minimum_stacksize() ); + + BOOST_ASSERT( maximum_stacksize() >= minimum_stacksize() ); + return maximum_stacksize() == minimum_stacksize() + ? minimum_stacksize() + : 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; + const BOOL result = ::VirtualProtect( + limit, pagesize(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); + BOOST_ASSERT( FALSE != result); + + 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_FIBERS_DETAIL_STACK_ALLOCATOR_H diff --git a/boost/fiber/fiber.hpp b/boost/fiber/fiber.hpp index 57dbeeae..8b73b174 100644 --- a/boost/fiber/fiber.hpp +++ b/boost/fiber/fiber.hpp @@ -46,7 +46,7 @@ private: friend class detail::scheduler; typedef detail::fiber_base base_t; - typedef base_t::ptr_t ptr_t; + typedef base_t::ptr_t ptr_t; ptr_t impl_; diff --git a/boost/fiber/stack_allocator.hpp b/boost/fiber/stack_allocator.hpp new file mode 100644 index 00000000..4f498cba --- /dev/null +++ b/boost/fiber/stack_allocator.hpp @@ -0,0 +1,23 @@ + +// 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_FIBERS_STACK_ALLOCATOR_H +#define BOOST_FIBERS_STACK_ALLOCATOR_H + +#include + +#if defined (BOOST_WINDOWS) +#include +#else +#include +#endif + +namespace boost { +namespace coroutines { +using detail::stack_allocator; +}} + +#endif // BOOST_FIBERS_STACK_ALLOCATOR_H