1 2 // Copyright Oliver Kowalke 2009. 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 7 #ifndef BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H 8 #define BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H 9 10 extern "C" { 11 #include <fcntl.h> 12 #include <sys/mman.h> 13 #include <sys/stat.h> 14 #include <unistd.h> 15 } 16 17 #if defined(BOOST_USE_VALGRIND) 18 #include <valgrind/valgrind.h> 19 #endif 20 21 #include <cmath> 22 #include <cstddef> 23 #include <new> 24 25 #include <boost/assert.hpp> 26 #include <boost/config.hpp> 27 28 #include <boost/coroutine/detail/config.hpp> 29 #include <boost/coroutine/stack_context.hpp> 30 #include <boost/coroutine/stack_traits.hpp> 31 32 #ifdef BOOST_HAS_ABI_HEADERS 33 # include BOOST_ABI_PREFIX 34 #endif 35 36 namespace boost { 37 namespace coroutines { 38 39 template< typename traitsT > 40 struct basic_protected_stack_allocator 41 { 42 typedef traitsT traits_type; 43 allocateboost::coroutines::basic_protected_stack_allocator44 void allocate( stack_context & ctx, std::size_t size = traits_type::minimum_size() ) 45 { 46 BOOST_ASSERT( traits_type::minimum_size() <= size); 47 BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size) ); 48 49 // page at bottom will be used as guard-page 50 const std::size_t pages( 51 static_cast< std::size_t >( 52 std::floor( 53 static_cast< float >( size) / traits_type::page_size() ) ) ); 54 BOOST_ASSERT_MSG( 2 <= pages, "at least two pages must fit into stack (one page is guard-page)"); 55 const std::size_t size_( pages * traits_type::page_size() ); 56 BOOST_ASSERT( 0 != size && 0 != size_); 57 BOOST_ASSERT( size_ <= size); 58 59 // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) 60 #if defined(MAP_ANON) 61 void * limit = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 62 #else 63 void * limit = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 64 #endif 65 if ( MAP_FAILED == limit) throw std::bad_alloc(); 66 67 // conforming to POSIX.1-2001 68 #if defined(BOOST_DISABLE_ASSERTS) 69 ::mprotect( limit, traits_type::page_size(), PROT_NONE); 70 #else 71 const int result( ::mprotect( limit, traits_type::page_size(), PROT_NONE) ); 72 BOOST_ASSERT( 0 == result); 73 #endif 74 75 ctx.size = size_; 76 ctx.sp = static_cast< char * >( limit) + ctx.size; 77 #if defined(BOOST_USE_VALGRIND) 78 ctx.valgrind_stack_id = VALGRIND_STACK_REGISTER( ctx.sp, limit); 79 #endif 80 } 81 deallocateboost::coroutines::basic_protected_stack_allocator82 void deallocate( stack_context & ctx) 83 { 84 BOOST_ASSERT( ctx.sp); 85 BOOST_ASSERT( traits_type::minimum_size() <= ctx.size); 86 BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= ctx.size) ); 87 88 #if defined(BOOST_USE_VALGRIND) 89 VALGRIND_STACK_DEREGISTER( ctx.valgrind_stack_id); 90 #endif 91 void * limit = static_cast< char * >( ctx.sp) - ctx.size; 92 // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) 93 ::munmap( limit, ctx.size); 94 } 95 }; 96 97 typedef basic_protected_stack_allocator< stack_traits > protected_stack_allocator; 98 99 }} 100 101 #ifdef BOOST_HAS_ABI_HEADERS 102 # include BOOST_ABI_SUFFIX 103 #endif 104 105 #endif // BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H 106