1 2 // Copyright Oliver Kowalke 2014. 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_CONTEXT_POOLED_pooled_fixedsize_H 8 #define BOOST_CONTEXT_POOLED_pooled_fixedsize_H 9 10 #include <atomic> 11 #include <cstddef> 12 #include <cstdlib> 13 #include <new> 14 15 #include <boost/assert.hpp> 16 #include <boost/config.hpp> 17 #include <boost/intrusive_ptr.hpp> 18 #include <boost/pool/pool.hpp> 19 20 #include <boost/context/detail/config.hpp> 21 #include <boost/context/stack_context.hpp> 22 #include <boost/context/stack_traits.hpp> 23 24 #if defined(BOOST_CONTEXT_USE_MAP_STACK) 25 extern "C" { 26 #include <sys/mman.h> 27 #include <stdlib.h> 28 } 29 #endif 30 31 #if defined(BOOST_USE_VALGRIND) 32 #include <valgrind/valgrind.h> 33 #endif 34 35 #ifdef BOOST_HAS_ABI_HEADERS 36 # include BOOST_ABI_PREFIX 37 #endif 38 39 namespace boost { 40 namespace context { 41 42 #if defined(BOOST_CONTEXT_USE_MAP_STACK) 43 namespace detail { 44 template< typename traitsT > 45 struct map_stack_allocator { 46 typedef std::size_t size_type; 47 typedef std::ptrdiff_t difference_type; 48 mallocboost::context::detail::map_stack_allocator49 static char * malloc( const size_type bytes) { 50 void * block; 51 if ( ::posix_memalign( &block, traitsT::page_size(), bytes) != 0) { 52 return 0; 53 } 54 if ( mmap( block, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_STACK, -1, 0) == MAP_FAILED) { 55 std::free( block); 56 return 0; 57 } 58 return reinterpret_cast< char * >( block); 59 } freeboost::context::detail::map_stack_allocator60 static void free( char * const block) { 61 std::free( block); 62 } 63 }; 64 } 65 #endif 66 67 template< typename traitsT > 68 class basic_pooled_fixedsize_stack { 69 private: 70 class storage { 71 private: 72 std::atomic< std::size_t > use_count_; 73 std::size_t stack_size_; 74 #if defined(BOOST_CONTEXT_USE_MAP_STACK) 75 boost::pool< detail::map_stack_allocator< traitsT > > storage_; 76 #else 77 boost::pool< boost::default_user_allocator_malloc_free > storage_; 78 #endif 79 80 public: storage(std::size_t stack_size,std::size_t next_size,std::size_t max_size)81 storage( std::size_t stack_size, std::size_t next_size, std::size_t max_size) : 82 use_count_( 0), 83 stack_size_( stack_size), 84 storage_( stack_size, next_size, max_size) { 85 BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= stack_size_) ); 86 } 87 allocate()88 stack_context allocate() { 89 void * vp = storage_.malloc(); 90 if ( ! vp) { 91 throw std::bad_alloc(); 92 } 93 stack_context sctx; 94 sctx.size = stack_size_; 95 sctx.sp = static_cast< char * >( vp) + sctx.size; 96 #if defined(BOOST_USE_VALGRIND) 97 sctx.valgrind_stack_id = VALGRIND_STACK_REGISTER( sctx.sp, vp); 98 #endif 99 return sctx; 100 } 101 deallocate(stack_context & sctx)102 void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { 103 BOOST_ASSERT( sctx.sp); 104 BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= sctx.size) ); 105 106 #if defined(BOOST_USE_VALGRIND) 107 VALGRIND_STACK_DEREGISTER( sctx.valgrind_stack_id); 108 #endif 109 void * vp = static_cast< char * >( sctx.sp) - sctx.size; 110 storage_.free( vp); 111 } 112 intrusive_ptr_add_ref(storage * s)113 friend void intrusive_ptr_add_ref( storage * s) noexcept { 114 ++s->use_count_; 115 } 116 intrusive_ptr_release(storage * s)117 friend void intrusive_ptr_release( storage * s) noexcept { 118 if ( 0 == --s->use_count_) { 119 delete s; 120 } 121 } 122 }; 123 124 intrusive_ptr< storage > storage_; 125 126 public: 127 typedef traitsT traits_type; 128 basic_pooled_fixedsize_stack(std::size_t stack_size=traits_type::default_size (),std::size_t next_size=32,std::size_t max_size=0)129 basic_pooled_fixedsize_stack( std::size_t stack_size = traits_type::default_size(), 130 std::size_t next_size = 32, 131 std::size_t max_size = 0) BOOST_NOEXCEPT_OR_NOTHROW : 132 storage_( new storage( stack_size, next_size, max_size) ) { 133 } 134 allocate()135 stack_context allocate() { 136 return storage_->allocate(); 137 } 138 deallocate(stack_context & sctx)139 void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { 140 storage_->deallocate( sctx); 141 } 142 }; 143 144 typedef basic_pooled_fixedsize_stack< stack_traits > pooled_fixedsize_stack; 145 146 }} 147 148 #ifdef BOOST_HAS_ABI_HEADERS 149 # include BOOST_ABI_SUFFIX 150 #endif 151 152 #endif // BOOST_CONTEXT_POOLED_pooled_fixedsize_H 153