Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / context / pooled_fixedsize_stack.hpp
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
49     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     }
60     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:
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
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
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
113         friend void intrusive_ptr_add_ref( storage * s) noexcept {
114             ++s->use_count_;
115         }
116
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
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
135     stack_context allocate() {
136         return storage_->allocate();
137     }
138
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