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 8[section:stack Stack allocation] 9 10The memory used by the stack is allocated/deallocated via a __stack_allocator__ 11which is required to model a __stack_allocator_concept__. 12 13 14[heading __stack_allocator_concept__] 15A __stack_allocator__ must satisfy the __stack_allocator_concept__ requirements 16shown in the following table, in which `a` is an object of a 17__stack_allocator__ type, `sctx` is a `stack_context`, and `size` is a `std::size_t`: 18 19[table 20 [[expression][return type][notes]] 21 [ 22 [`a(size)`] 23 [] 24 [creates a stack allocator] 25 ] 26 [ 27 [`a.allocate()`] 28 [`stack_context`] 29 [creates a stack] 30 ] 31 [ 32 [`a.deallocate( sctx)`] 33 [`void`] 34 [deallocates the stack created by `a.allocate()`] 35 ] 36] 37 38[important The implementation of `allocate()` might include logic to protect 39against exceeding the context's available stack size rather than leaving it as 40undefined behaviour.] 41 42[important Calling `deallocate()` with a `stack_context` not set by `allocate()` 43results in undefined behaviour.] 44 45[note The stack is not required to be aligned; alignment takes place inside 46__econtext__.] 47 48[note Depending on the architecture `allocate()` stores an address from the 49top of the stack (growing downwards) or the bottom of the stack (growing 50upwards).] 51 52 53[section:protected_fixedsize Class ['protected_fixedsize]] 54 55__boost_coroutine__ provides the class __protected_fixedsize__ which models 56the __stack_allocator_concept__. 57It appends a guard page at the end of each stack to protect against exceeding 58the stack. If the guard page is accessed (read or write operation) a 59segmentation fault/access violation is generated by the operating system. 60 61[important Using __protected_fixedsize__ is expensive. That is, launching a 62new coroutine with a new stack is expensive; the allocated stack is just as 63efficient to use as any other stack.] 64 65[note The appended `guard page` is [*not] mapped to physical memory, only 66virtual addresses are used.] 67 68 #include <boost/coroutine2/protected_fixedsize.hpp> 69 70 struct protected_fixedsize { 71 protected_fixesize(std::size_t size = traits_type::default_size()); 72 73 stack_context allocate(); 74 75 void deallocate( stack_context &); 76 } 77 78[heading `stack_context allocate()`] 79[variablelist 80[[Preconditions:] [`traits_type::minimum:size() <= size` and 81`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= size)`.]] 82[[Effects:] [Allocates memory of at least `size` bytes and stores a pointer 83to the stack and its actual size in `sctx`. Depending 84on the architecture (the stack grows downwards/upwards) the stored address is 85the highest/lowest address of the stack.]] 86] 87 88[heading `void deallocate( stack_context & sctx)`] 89[variablelist 90[[Preconditions:] [`sctx.sp` is valid, `traits_type::minimum:size() <= sctx.size` and 91`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= sctx.size)`.]] 92[[Effects:] [Deallocates the stack space.]] 93] 94 95[endsect] 96 97 98[section:pooled_fixedsize Class ['pooled_fixedsize_stack]] 99 100__boost_coroutine__ provides the class __pooled_fixedsize__ which models 101the __stack_allocator_concept__. 102In contrast to __protected_fixedsize__ it does not append a guard page at the 103end of each stack. The memory is managed internally by 104[@http://www.boost.org/doc/libs/release/libs/pool/doc/html/boost/pool.html `boost::pool<>`]. 105 106 #include <boost/coroutine2/pooled_fixedsize_stack.hpp> 107 108 struct pooled_fixedsize_stack { 109 pooled_fixedsize_stack(std::size_t size = traits_type::default_size()); 110 111 stack_context allocate(); 112 113 void deallocate( stack_context &); 114 } 115 116[heading `pooled_fixedsize_stack(std::size_t stack_size, std::size_t next_size, std::size_t max_size)`] 117[variablelist 118[[Preconditions:] [`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= stack_size)` 119and `0 < nest_size`.]] 120[[Effects:] [Allocates memory of at least `stack_size` Bytes and stores a pointer to 121the stack and its actual size in `sctx`. Depending on the architecture (the 122stack grows downwards/upwards) the stored address is the highest/lowest 123address of the stack. Argument `next_size` determines the number of stacks to 124request from the system the first time that `*this` needs to allocate system 125memory. The third argument `max_size` controls how many memory might be 126allocated for stacks - a value of zero means no uper limit.]] 127] 128 129[heading `stack_context allocate()`] 130[variablelist 131[[Preconditions:] [`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= size)`.]] 132[[Effects:] [Allocates memory of at least `size` bytes and stores a pointer to 133the stack and its actual size in `sctx`. Depending on the architecture (the 134stack grows downwards/upwards) the stored address is the highest/lowest 135address of the stack.]] 136] 137 138[heading `void deallocate( stack_context & sctx)`] 139[variablelist 140[[Preconditions:] [`sctx.sp` is valid, 141`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= sctx.size)`.]] 142[[Effects:] [Deallocates the stack space.]] 143] 144 145[endsect] 146 147 148[section:fixedsize Class ['fixedsize_stack]] 149 150__boost_coroutine__ provides the class __fixedsize__ which models 151the __stack_allocator_concept__. 152In contrast to __protected_fixedsize__ it does not append a guard page at the 153end of each stack. The memory is simply managed by `std::malloc()` and 154`std::free()`. 155 156 #include <boost/context/fixedsize_stack.hpp> 157 158 struct fixedsize_stack { 159 fixedsize_stack(std::size_t size = traits_type::default_size()); 160 161 stack_context allocate(); 162 163 void deallocate( stack_context &); 164 } 165 166[heading `stack_context allocate()`] 167[variablelist 168[[Preconditions:] [`traits_type::minimum:size() <= size` and 169`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= size)`.]] 170[[Effects:] [Allocates memory of at least `size` Bytes and stores a pointer to 171the stack and its actual size in `sctx`. Depending on the architecture (the 172stack grows downwards/upwards) the stored address is the highest/lowest 173address of the stack.]] 174] 175 176[heading `void deallocate( stack_context & sctx)`] 177[variablelist 178[[Preconditions:] [`sctx.sp` is valid, `traits_type::minimum:size() <= sctx.size` and 179`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= sctx.size)`.]] 180[[Effects:] [Deallocates the stack space.]] 181] 182 183[endsect] 184 185 186[#segmented] 187[section:segmented Class ['segmented_stack]] 188 189__boost_coroutine__ supports usage of a __segmented__, e. g. the size of 190the stack grows on demand. The coroutine is created with a minimal stack size 191and will be increased as required. 192Class __segmented__ models the __stack_allocator_concept__. 193In contrast to __protected_fixedsize__ and __fixedsize__ it creates a 194stack which grows on demand. 195 196[note Segmented stacks are currently only supported by [*gcc] from version 197[*4.7] [*clang] from version [*3.4] onwards. In order to use a 198__segmented_stack__ __boost_context__ must be built with 199property `segmented-stacks`, e.g. [*toolset=gcc segmented-stacks=on] and 200applying `BOOST_USE_SEGMENTED_STACKS` and `BOOST_USE_UCONTEXT` at b2/bjam 201command line.] 202 203 204 #include <boost/coroutine2/segmented_stack.hpp> 205 206 struct segmented_stack { 207 segmented_stack(std::size_t size = traits_type::default_size()); 208 209 stack_context allocate(); 210 211 void deallocate( stack_context &); 212 } 213 214[heading `stack_context allocate()`] 215[variablelist 216[[Preconditions:] [`traits_type::minimum:size() <= size` and 217`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= size)`.]] 218[[Effects:] [Allocates memory of at least `size` bytes and stores a pointer to 219the stack and its actual size in `sctx`. Depending on the architecture (the 220stack grows downwards/upwards) the stored address is the highest/lowest 221address of the stack.]] 222] 223 224[heading `void deallocate( stack_context & sctx)`] 225[variablelist 226[[Preconditions:] [`sctx.sp` is valid, `traits_type::minimum:size() <= sctx.size` and 227`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= sctx.size)`.]] 228[[Effects:] [Deallocates the stack space.]] 229] 230 231[note If the library is compiled for segmented stacks, __segmented_stack__ is the only 232available stack allocator.] 233 234[endsect] 235 236 237[section:stack_traits Class ['stack_traits]] 238 239['stack_traits] models a __stack_traits__ providing a way to access certain 240properites defined by the enironment. Stack allocators use __stack_traits__ to 241allocate stacks. 242 243 struct stack_traits 244 { 245 static bool is_unbounded() noexcept; 246 247 static std::size_t page_size() noexcept; 248 249 static std::size_t default_size() noexcept; 250 251 static std::size_t minimum_size() noexcept; 252 253 static std::size_t maximum_size() noexcept; 254 } 255 256 257[heading `static bool is_unbounded()`] 258[variablelist 259[[Returns:] [Returns `true` if the environment defines no limit for the size of 260a stack.]] 261[[Throws:] [Nothing.]] 262] 263 264[heading `static std::size_t page_size()`] 265[variablelist 266[[Returns:] [Returns the page size in bytes.]] 267[[Throws:] [Nothing.]] 268] 269 270[heading `static std::size_t default_size()`] 271[variablelist 272[[Returns:] [Returns a default stack size, which may be platform specific. 273If the stack is unbounded then the present implementation returns the maximum of 274`64 kB` and `minimum_size()`.]] 275[[Throws:] [Nothing.]] 276] 277 278[heading `static std::size_t minimum_size()`] 279[variablelist 280[[Returns:] [Returns the minimum size in bytes of stack defined by the 281environment (Win32 4kB/Win64 8kB, defined by rlimit on POSIX).]] 282[[Throws:] [Nothing.]] 283] 284 285[heading `static std::size_t maximum_size()`] 286[variablelist 287[[Preconditions:] [`is_unbounded()` returns `false`.]] 288[[Returns:] [Returns the maximum size in bytes of stack defined by the 289environment.]] 290[[Throws:] [Nothing.]] 291] 292 293 294[endsect] 295 296 297[section:stack_context Class ['stack_context]] 298 299__boost_coroutine__ provides the class __stack_context__ which will contain 300the stack pointer and the size of the stack. 301In case of a __segmented__, __stack_context__ contains some extra control 302structures. 303 304 struct stack_context 305 { 306 void * sp; 307 std::size_t size; 308 309 // might contain additional control structures 310 // for segmented stacks 311 } 312 313[heading `void * sp`] 314[variablelist 315[[Value:] [Pointer to the beginning of the stack.]] 316] 317 318[heading `std::size_t size`] 319[variablelist 320[[Value:] [Actual size of the stack.]] 321] 322 323[endsect] 324 325 326[section:valgrind Support for valgrind] 327 328Running programs that switch stacks under valgrind causes problems. 329Property (b2 command-line) `valgrind=on` let valgrind treat the memory regions 330as stack space which suppresses the errors. 331 332[endsect] 333 334 335[section:sanitizers Support for sanitizers] 336 337Sanitizers (GCC/Clang) are confused by the stack switches. 338The library (and Boost.Context too) is required to be compiled with property (b2 command-line) 339`context-impl=ucontext` and compilers santizer options. 340Users must define `BOOST_USE_ASAN` before including any Boost.Context headers 341when linking against Boost binaries. 342 343[endsect] 344 345 346 347[endsect] 348