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 8[section:stack Stack allocation] 9 10A __coro__ uses internally a __ctx__ which manages a set of registers and a stack. 11The memory used by the stack is allocated/deallocated via a __stack_allocator__ 12which is required to model a __stack_allocator_concept__. 13 14 15[heading __stack_allocator_concept__] 16A __stack_allocator__ must satisfy the __stack_allocator_concept__ requirements 17shown in the following table, in which `a` is an object of a 18__stack_allocator__ type, `sctx` is a `stack_context`, and `size` is a `std::size_t`: 19 20[table 21 [[expression][return type][notes]] 22 [ 23 [`a.allocate( sctx, size)`] 24 [`void`] 25 [creates a stack of at least `size` bytes and stores its pointer and 26 length in `sctx`] 27 ] 28 [ 29 [`a.deallocate( sctx)`] 30 [`void`] 31 [deallocates the stack created by `a.allocate()`] 32 ] 33] 34 35[important The implementation of `allocate()` might include logic to protect 36against exceeding the context's available stack size rather than leaving it as 37undefined behaviour.] 38 39[important Calling `deallocate()` with a `stack_context` not set by `allocate()` 40results in undefined behaviour.] 41 42[note The stack is not required to be aligned; alignment takes place inside 43__coro__.] 44 45[note Depending on the architecture `allocate()` stores an address from the 46top of the stack (growing downwards) or the bottom of the stack (growing 47upwards).] 48 49class __coro_allocator__ is a typedef of __standard_allocator__. 50 51 52[section:protected_stack_allocator Class ['protected_stack_allocator]] 53 54__boost_coroutine__ provides the class __protected_allocator__ which models 55the __stack_allocator_concept__. 56It appends a guard page at the end of each stack to protect against exceeding 57the stack. If the guard page is accessed (read or write operation) a 58segmentation fault/access violation is generated by the operating system. 59 60[important Using __protected_allocator__ is expensive. That is, launching a 61new coroutine with a new stack is expensive; the allocated stack is just as 62efficient to use as any other stack.] 63 64[note The appended `guard page` is [*not] mapped to physical memory, only 65virtual addresses are used.] 66 67 #include <boost/coroutine/protected_stack_allocator.hpp> 68 69 template< typename traitsT > 70 struct basic_protected_stack_allocator 71 { 72 typedef traitT traits_type; 73 74 void allocate( stack_context &, std::size_t size); 75 76 void deallocate( stack_context &); 77 } 78 79 typedef basic_protected_stack_allocator< stack_traits > protected_stack_allocator 80 81[heading `void allocate( stack_context & sctx, std::size_t size)`] 82[variablelist 83[[Preconditions:] [`traits_type::minimum_size() <= size` and 84`! traits_type::is_unbounded() && ( traits_type::maximum_size() >= size)`.]] 85[[Effects:] [Allocates memory of at least `size` bytes and stores a pointer 86to the stack and its actual size in `sctx`. Depending 87on the architecture (the stack grows downwards/upwards) the stored address is 88the highest/lowest address of the stack.]] 89] 90 91[heading `void deallocate( stack_context & sctx)`] 92[variablelist 93[[Preconditions:] [`sctx.sp` is valid, `traits_type::minimum_size() <= sctx.size` and 94`! traits_type::is_unbounded() && ( traits_type::maximum_size() >= sctx.size)`.]] 95[[Effects:] [Deallocates the stack space.]] 96] 97 98[endsect] 99 100 101[section:standard_stack_allocator Class ['standard_stack_allocator]] 102 103__boost_coroutine__ provides the class __standard_allocator__ which models 104the __stack_allocator_concept__. 105In contrast to __protected_allocator__ it does not append a guard page at the 106end of each stack. The memory is simply managed by `std::malloc()` and 107`std::free()`. 108 109[note The __standard_allocator__ is the default stack allocator.] 110 111 #include <boost/coroutine/standard_stack_allocator.hpp> 112 113 template< typename traitsT > 114 struct standard_stack_allocator 115 { 116 typedef traitT traits_type; 117 118 void allocate( stack_context &, std::size_t size); 119 120 void deallocate( stack_context &); 121 } 122 123 typedef basic_standard_stack_allocator< stack_traits > standard_stack_allocator 124 125[heading `void allocate( stack_context & sctx, std::size_t size)`] 126[variablelist 127[[Preconditions:] [`traits_type::minimum_size() <= size` and 128`! traits_type::is_unbounded() && ( traits_type::maximum_size() >= size)`.]] 129[[Effects:] [Allocates memory of at least `size` bytes and stores a pointer to 130the stack and its actual size in `sctx`. Depending on the architecture (the 131stack grows downwards/upwards) the stored address is the highest/lowest 132address of the stack.]] 133] 134 135[heading `void deallocate( stack_context & sctx)`] 136[variablelist 137[[Preconditions:] [`sctx.sp` is valid, `traits_type::minimum_size() <= sctx.size` and 138`! traits_type::is_unbounded() && ( traits_type::maximum_size() >= sctx.size)`.]] 139[[Effects:] [Deallocates the stack space.]] 140] 141 142[endsect] 143 144 145[section:segmented_stack_allocator Class ['segmented_stack_allocator]] 146 147__boost_coroutine__ supports usage of a __segmented_stack__, e. g. the size of 148the stack grows on demand. The coroutine is created with a minimal stack size 149and will be increased as required. 150Class __segmented_allocator__ models the __stack_allocator_concept__. 151In contrast to __protected_allocator__ and __standard_allocator__ it creates a 152stack which grows on demand. 153 154[note Segmented stacks are currently only supported by [*gcc] from version 155[*4.7] and [*clang] from version [*3.4] onwards. In order to use a 156__segmented_stack__ __boost_coroutine__ must be built with 157[*toolset=gcc segmented-stacks=on] at b2/bjam command-line. Applications 158must be compiled with compiler-flags 159[*-fsplit-stack -DBOOST_USE_SEGMENTED_STACKS].] 160 161 #include <boost/coroutine/segmented_stack_allocator.hpp> 162 163 template< typename traitsT > 164 struct basic_segmented_stack_allocator 165 { 166 typedef traitT traits_type; 167 168 void allocate( stack_context &, std::size_t size); 169 170 void deallocate( stack_context &); 171 } 172 173 typedef basic_segmented_stack_allocator< stack_traits > segmented_stack_allocator; 174 175[heading `void allocate( stack_context & sctx, std::size_t size)`] 176[variablelist 177[[Preconditions:] [`traits_type::minimum_size() <= size` and 178`! traits_type::is_unbounded() && ( traits_type::maximum_size() >= size)`.]] 179[[Effects:] [Allocates memory of at least `size` bytes and stores a pointer to 180the stack and its actual size in `sctx`. Depending on the architecture (the 181stack grows downwards/upwards) the stored address is the highest/lowest 182address of the stack.]] 183] 184 185[heading `void deallocate( stack_context & sctx)`] 186[variablelist 187[[Preconditions:] [`sctx.sp` is valid, `traits_type::minimum_size() <= sctx.size` and 188`! traits_type::is_unbounded() && ( traits_type::maximum_size() >= sctx.size)`.]] 189[[Effects:] [Deallocates the stack space.]] 190] 191 192[endsect] 193 194 195[section:stack_traits Class ['stack_traits]] 196 197['stack_traits] models a __stack_traits__ providing a way to access certain 198properites defined by the enironment. Stack allocators use __stack_traits__ to 199allocate stacks. 200 201 #include <boost/coroutine/stack_traits.hpp> 202 203 struct stack_traits 204 { 205 static bool is_unbounded() noexcept; 206 207 static std::size_t page_size() noexcept; 208 209 static std::size_t default_size() noexcept; 210 211 static std::size_t minimum_size() noexcept; 212 213 static std::size_t maximum_size() noexcept; 214 } 215 216 217[heading `static bool is_unbounded()`] 218[variablelist 219[[Returns:] [Returns `true` if the environment defines no limit for the size of 220a stack.]] 221[[Throws:] [Nothing.]] 222] 223 224[heading `static std::size_t page_size()`] 225[variablelist 226[[Returns:] [Returns the page size in bytes.]] 227[[Throws:] [Nothing.]] 228] 229 230[heading `static std::size_t default_size()`] 231[variablelist 232[[Returns:] [Returns a default stack size, which may be platform specific. 233If the stack is unbounded then the present implementation returns the maximum of 234`64 kB` and `minimum_size()`.]] 235[[Throws:] [Nothing.]] 236] 237 238[heading `static std::size_t minimum_size()`] 239[variablelist 240[[Returns:] [Returns the minimum size in bytes of stack defined by the 241environment (Win32 4kB/Win64 8kB, defined by rlimit on POSIX).]] 242[[Throws:] [Nothing.]] 243] 244 245[heading `static std::size_t maximum_size()`] 246[variablelist 247[[Preconditions:] [`is_unbounded()` returns `false`.]] 248[[Returns:] [Returns the maximum size in bytes of stack defined by the 249environment.]] 250[[Throws:] [Nothing.]] 251] 252 253 254[endsect] 255 256 257[section:stack_context Class ['stack_context]] 258 259__boost_coroutine__ provides the class __stack_context__ which will contain 260the stack pointer and the size of the stack. 261In case of a __segmented_stack__, __stack_context__ contains some extra control 262structures. 263 264 struct stack_context 265 { 266 void * sp; 267 std::size_t size; 268 269 // might contain additional control structures 270 // for instance for segmented stacks 271 } 272 273[heading `void * sp`] 274[variablelist 275[[Value:] [Pointer to the beginning of the stack.]] 276] 277 278[heading `std::size_t size`] 279[variablelist 280[[Value:] [Actual size of the stack.]] 281] 282 283[endsect] 284 285 286[section:valgrind Support for valgrind] 287 288Running programs that switch stacks under valgrind causes problems. 289Property (b2 command-line) `valgrind=on` let valgrind treat the memory regions 290as stack space which suppresses the errors. 291 292[endsect] 293 294 295[endsect] 296