summaryrefslogtreecommitdiff
path: root/libs/context/doc/stack.qbk
blob: b0461716f34eb048c67532043f627bad030d17bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
[/
          Copyright Oliver Kowalke 2014.
 Distributed under the Boost Software License, Version 1.0.
    (See accompanying file LICENSE_1_0.txt or copy at
          http://www.boost.org/LICENSE_1_0.txt
]

[section:stack Stack allocation]

The memory used by the stack is allocated/deallocated via a __stack_allocator__
which is required to model a __stack_allocator_concept__.


[heading __stack_allocator_concept__]
A __stack_allocator__ must satisfy the __stack_allocator_concept__ requirements
shown in the following table, in which `a` is an object of a
__stack_allocator__ type, `sctx` is a `stack_context`, and `size` is a `std::size_t`:

[table
    [[expression][return type][notes]]
    [
        [`a(size)`]
        []
        [creates a stack allocator]
    ]
    [
        [`a.allocate()`]
        [`stack_context`]
        [creates a stack]
    ]
    [
        [`a.deallocate( sctx)`]
        [`void`]
        [deallocates the stack created by `a.allocate()`]
    ]
]

[important The implementation of `allocate()` might include logic to protect
against exceeding the context's available stack size rather than leaving it as
undefined behaviour.]

[important Calling `deallocate()` with a `stack_context` not set by `allocate()`
results in undefined behaviour.]

[note The stack is not required to be aligned; alignment takes place inside
__econtext__.]

[note Depending on the architecture `allocate()` stores an address from the
top of the stack (growing downwards) or the bottom of the stack (growing
upwards).]


[section:protected_fixedsize Class ['protected_fixedsize]]

__boost_context__ provides the class __protected_fixedsize__ which models
the __stack_allocator_concept__.
It appends a guard page at the end of each stack to protect against exceeding
the stack. If the guard page is accessed (read or write operation) a
segmentation fault/access violation is generated by the operating system.

[important Using __protected_fixedsize__ is expensive. That is, launching a
new coroutine with a new stack is expensive; the allocated stack is just as
efficient to use as any other stack.]

[note The appended `guard page` is [*not] mapped to physical memory, only
virtual addresses are used.]

        #include <boost/context/protected_fixedsize.hpp>

        template< typename traitsT >
        struct basic_protected_fixedsize
        {
            typedef traitT  traits_type;

            basic_protected_fixesize(std::size_t size = traits_type::default_size());

            stack_context allocate();

            void deallocate( stack_context &);
        }

        typedef basic_protected_fixedsize< stack_traits > protected_fixedsize

[heading `stack_context allocate()`]
[variablelist
[[Preconditions:] [`traits_type::minimum:size() <= size` and
`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= size)`.]]
[[Effects:] [Allocates memory of at least `size` Bytes and stores a pointer
to the stack and its actual size in `sctx`. Depending
on the architecture (the stack grows downwards/upwards) the stored address is
the highest/lowest address of the stack.]]
]

[heading `void deallocate( stack_context & sctx)`]
[variablelist
[[Preconditions:] [`sctx.sp` is valid, `traits_type::minimum:size() <= sctx.size` and
`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= sctx.size)`.]]
[[Effects:] [Deallocates the stack space.]]
]

[endsect]


[section:fixedsize Class ['fixedsize_stack]]

__boost_context__ provides the class __fixedsize__ which models
the __stack_allocator_concept__.
In contrast to __protected_fixedsize__ it does not append a guard page at the
end of each stack. The memory is simply managed by `std::malloc()` and
`std::free()`.

        #include <boost/context/fixedsize_stack.hpp>

        template< typename traitsT >
        struct basic_fixedsize_stack
        {
            typedef traitT  traits_type;

            basic_fixesize_stack(std::size_t size = traits_type::default_size());

            stack_context allocate();

            void deallocate( stack_context &);
        }

        typedef basic_fixedsize_stack< stack_traits > fixedsize_stack;

[heading `stack_context allocate()`]
[variablelist
[[Preconditions:] [`traits_type::minimum:size() <= size` and
`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= size)`.]]
[[Effects:] [Allocates memory of at least `size` Bytes and stores a pointer to
the stack and its actual size in `sctx`. Depending on the architecture (the
stack grows downwards/upwards) the stored address is the highest/lowest
address of the stack.]]
]

[heading `void deallocate( stack_context & sctx)`]
[variablelist
[[Preconditions:] [`sctx.sp` is valid, `traits_type::minimum:size() <= sctx.size` and
`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= sctx.size)`.]]
[[Effects:] [Deallocates the stack space.]]
]

[endsect]


[section:segmented Class ['segmented_stack]]

__boost_context__ supports usage of a __segmented__, e. g. the size of
the stack grows on demand. The coroutine is created with a minimal stack size
and will be increased as required.
Class __segmented__ models the __stack_allocator_concept__.
In contrast to __protected_fixedsize__ and __fixedsize__ it creates a
stack which grows on demand.

[note Segmented stacks are currently only supported by [*gcc] from version
[*4.7] [*clang] from version [*3.4] onwards. In order to use a
__segmented_stack__ __boost_context__ must be built with
[*toolset=gcc segmented-stacks=on] at b2/bjam command-line. Applications
must be compiled with compiler-flags
[*-fsplit-stack -DBOOST_USE_SEGMENTED_STACKS].]

        #include <boost/context/segmented_stack.hpp>

        template< typename traitsT >
        struct basic_segmented_stack
        {
            typedef traitT  traits_type;

            basic_segmented_stack(std::size_t size = traits_type::default_size());

            stack_context allocate();

            void deallocate( stack_context &);
        }

        typedef basic_segmented_stack< stack_traits > segmented_stack;

[heading `stack_context allocate()`]
[variablelist
[[Preconditions:] [`traits_type::minimum:size() <= size` and
`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= size)`.]]
[[Effects:] [Allocates memory of at least `size` Bytes and stores a pointer to
the stack and its actual size in `sctx`. Depending on the architecture (the
stack grows downwards/upwards) the stored address is the highest/lowest
address of the stack.]]
]

[heading `void deallocate( stack_context & sctx)`]
[variablelist
[[Preconditions:] [`sctx.sp` is valid, `traits_type::minimum:size() <= sctx.size` and
`! traits_type::is_unbounded() && ( traits_type::maximum:size() >= sctx.size)`.]]
[[Effects:] [Deallocates the stack space.]]
]

[endsect]


[section:stack_traits Class ['stack_traits]]

['stack_traits] models a __stack_traits__ providing a way to access certain
properites defined by the enironment. Stack allocators use __stack_traits__ to
allocate stacks.

        #include <boost/context/stack_traits.hpp>

        struct stack_traits
        {
            static bool is_unbounded() noexcept;

            static std::size_t page_size() noexcept;

            static std::size_t default_size() noexcept;

            static std::size_t minimum_size() noexcept;

            static std::size_t maximum_size() noexcept;
        }


[heading `static bool is_unbounded()`]
[variablelist
[[Returns:] [Returns `true` if the environment defines no limit for the size of
a stack.]]
[[Throws:] [Nothing.]]
]

[heading `static std::size_t page_size()`]
[variablelist
[[Returns:] [Returns the page size in bytes.]]
[[Throws:] [Nothing.]]
]

[heading `static std::size_t default_size()`]
[variablelist
[[Returns:] [Returns a default stack size, which may be platform specific.
If the stack is unbounded then the present implementation returns the maximum of
`64 kB` and `minimum_size()`.]]
[[Throws:] [Nothing.]]
]

[heading `static std::size_t minimum_size()`]
[variablelist
[[Returns:] [Returns the minimum size in bytes of stack defined by the
environment (Win32 4kB/Win64 8kB, defined by rlimit on POSIX).]]
[[Throws:] [Nothing.]]
]

[heading `static std::size_t maximum_size()`]
[variablelist
[[Preconditions:] [`is_unbounded()` returns `false`.]]
[[Returns:] [Returns the maximum size in bytes of stack defined by the
environment.]]
[[Throws:] [Nothing.]]
]


[endsect]


[section:stack_context Class ['stack_context]]

__boost_context__ provides the class __stack_context__ which will contain
the stack pointer and the size of the stack.
In case of a __segmented__, __stack_context__ contains some extra control
structures.

        struct stack_context
        {
            void    *   sp;
            std::size_t size;

            // might contain additional control structures
            // for segmented stacks
        }

[heading `void * sp`]
[variablelist
[[Value:] [Pointer to the beginning of the stack.]]
]

[heading `std::size_t size`]
[variablelist
[[Value:] [Actual size of the stack.]]
]

[endsect]


[section:valgrind Support for valgrind]

Running programs that switch stacks under valgrind causes problems.
Property (b2 command-line) `valgrind=on` let valgrind treat the memory regions
as stack space which suppresses the errors.

[endsect]


[endsect]