]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/context/doc/execution_context_v1.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / context / doc / execution_context_v1.qbk
CommitLineData
7c673cae
FG
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[#ecv1]
9[section:ecv1 Class execution_context (version 1)]
10
11[note This class is only enabled if property ['segmented-stacks=on] (enables
12segmented stacks) or compiler flag ['BOOST_EXECUTION_CONTEXT=1] is specified
13at b2-commandline.]
14
15Class __econtext__ encapsulates context switching and manages the associated
16context' stack (allocation/deallocation).
17
18__econtext__ allocates the context stack (using its [link stack
19__stack_allocator__] argument) and creates a control structure on top of it.
20This structure is responsible for managing context' stack. Instances of
21__econtext__, associated with a specific context, share the ownership of the
22control structure. If the last reference goes out of scope, the control
23structure is destroyed and the stack gets deallocated via the
24__stack_allocator__.
25
26__econtext__ is copy-constructible, move-constructible, copy-assignable and
27move-assignable.
28
29__econtext__ maintains a static (thread-local) pointer, accessed by
30__ec_current__, pointing to the active context. On each context switch the
31pointer is updated.
32The usage of this global pointer makes the context switch a little bit slower
33(due access of thread local storage) but has some advantages. It allows to
34access the control structure of the current active context from arbitrary code
35paths required in order to support segmented stacks, which require to call
36certain maintenance functions (like __splitstack_getcontext() etc.) before each
37context switch (each context switch exchanges the stack).
38
39__econtext__ expects a function/functor with signature `void(void* vp)` (`vp`
40is the data passed at the first invocation of
41[operator_link ecv1 operator_call operator()]).
42
43
44[heading usage of __econtext__]
45
46 int n=35;
47 boost::context::execution_context sink(boost::context::execution_context::current());
48 boost::context::execution_context source(
49 [n,&sink](void*)mutable{
50 int a=0;
51 int b=1;
52 while(n-->0){
53 sink(&a);
54 auto next=a+b;
55 a=b;
56 b=next;
57 }
58 });
59 for(int i=0;i<10;++i){
60 std::cout<<*(int*)source()<<" ";
61 }
62
63 output:
64 0 1 1 2 3 5 8 13 21 34
65
66This simple example demonstrates the basic usage of __econtext__. The context
67`sink`, returned by __ec_current__, represents the ['main]-context (function
68['main()] running) and is one of the captured parameters in the lambda
69expression. The lambda that calculates the Fibonacci numbers is executed inside
70the context represented by `source`. Calculated Fibonacci numbers are
71transferred between the two context' via expression ['sink(&a)] (and returned by
72['source()]).
73
74The locale variables `a`, `b` and ` next` remain their values during each
75context switch (['yield(a)]). This is possible because `ctx` owns a stack
76(exchanged by context switch).
77
78[heading inverting the control flow]
79
80 /*
81 * grammar:
82 * P ---> E '\0'
83 * E ---> T {('+'|'-') T}
84 * T ---> S {('*'|'/') S}
85 * S ---> digit | '(' E ')'
86 */
87 class Parser{
88 // implementation omitted; see examples directory
89 };
90
91 std::istringstream is("1+1");
92 bool done=false;
93 std::exception_ptr except;
94
95 // create handle to main execution context
96 auto main_ctx(boost::context::execution_context::current());
97 // execute parser in new execution context
98 boost::context::execution_context source(
99 [&sink,&is,&done,&except](void*){
100 // create parser with callback function
101 Parser p(is,
102 [&sink](char ch){
103 // resume main execution context
104 sink(&ch);
105 });
106 try {
107 // start recursive parsing
108 p.run();
109 } catch (...) {
110 // store other exceptions in exception-pointer
111 except = std::current_exception();
112 }
113 // set termination flag
114 done=true;
115 // resume main execution context
116 sink();
117 });
118
119 // user-code pulls parsed data from parser
120 // invert control flow
121 void* vp = source();
122 if (except) {
123 std::rethrow_exception(except);
124 }
125 while( ! done) {
126 printf("Parsed: %c\n",* static_cast<char*>(vp));
127 vp = source();
128 if (except) {
129 std::rethrow_exception(except);
130 }
131 }
132
133 output:
134 Parsed: 1
135 Parsed: +
136 Parsed: 1
137
138
139In this example a recursive descent parser uses a callback to emit a newly
140passed symbol. Using __econtext__ the control flow can be inverted, e.g. the
141user-code pulls parsed symbols from the parser - instead to get pushed from the
142parser (via callback).
143
144The data (character) is transferred between the two __econtext__.
145
146If the code executed by __econtext__ emits an exception, the application is
147terminated. ['std::exception_ptr] can be used to transfer exceptions between
148different execution contexts.
149
150[heading stack unwinding]
151Sometimes it is necessary to unwind the stack of an unfinished context to
152destroy local stack variables so they can release allocated resources (RAII
153pattern). The user is responsible for this task.
154
155[#ecv1_prealloc]
156[heading allocating control structures on top of stack]
157Allocating control structures on top of the stack requires to allocated the
158__stack_context__ and create the control structure with placement new before
159__econtext__ is created.
160[note The user is responsible for destructing the control structure at the top
161of the stack.]
162
163 // stack-allocator used for (de-)allocating stack
164 fixedsize_stack salloc( 4048);
165 // allocate stack space
166 stack_context sctx( salloc.allocate() );
167 // reserve space for control structure on top of the stack
168 void * sp = static_cast< char * >( sctx.sp) - sizeof( my_control_structure);
169 std::size_t size = sctx.size - sizeof( my_control_structure);
170 // placement new creates control structure on reserved space
171 my_control_structure * cs = new ( sp) my_control_structure( sp, size, sctx, salloc);
172 ...
173 // destructing the control structure
174 cs->~my_control_structure();
175 ...
176 struct my_control_structure {
177 // execution context
178 execution_context ectx;
179
180 template< typename StackAllocator >
181 my_control_structure( void * sp, std::size_t size, stack_context sctx, StackAllocator salloc) :
182 // create execution context
183 ectx( std::allocator_arg, preallocated( sp, size, sctx), salloc, entry_func) {
184 }
185 ...
186 };
187
188[heading exception handling]
189If the function executed inside a __econtext__ emits ans exception, the
190application is terminated by calling ['std::terminate()]. ['std::exception_ptr]
191can be used to transfer exceptions between different execution contexts.
192
193[important Do not jump from inside a catch block and then re-throw the exception
194in another execution context.]
195
196[heading parameter passing]
197The void pointer argument passed to __ec_op__, in one context, is passed as
198the last argument of the __context_fn__ if the context is started for the
199first time.
200In all following invocations of __ec_op__ the void pointer passed to
201__ec_op__, in one context, is returned by __ec_op__ in the other context.
202
203 class X {
204 private:
205 std::exception_ptr excptr_;
206 boost::context::execution_context caller_;
207 boost::context::execution_context callee_;
208
209 public:
210 X() :
211 excptr_(),
212 caller_( boost::context::execution_context::current() ),
213 callee_( [=] (void * vp) {
214 try {
215 int i = * static_cast< int * >( vp);
216 std::string str = boost::lexical_cast<std::string>(i);
217 caller_( & str);
218 } catch (std::bad_cast const&) {
219 excptr_=std::current_exception();
220 }
221 })
222 {}
223
224 std::string operator()( int i) {
225 void * ret = callee_( & i);
226 if(excptr_){
227 std::rethrow_exception(excptr_);
228 }
229 return * static_cast< std::string * >( ret);
230 }
231 };
232
233 X x;
234 std::cout << x( 7) << std::endl;
235
236 output:
237 7
238
239
240[heading Class `execution_context`]
241
242 class execution_context {
243 public:
244 static execution_context current() noexcept;
245
246 template< typename Fn, typename ... Args >
247 execution_context( Fn && fn, Args && ... args);
248
249 template< typename StackAlloc, typename Fn, typename ... Args >
250 execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args);
251
252 template< typename StackAlloc, typename Fn, typename ... Args >
253 execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args);
254
255 execution_context( execution_context const& other) noexcept;
256 execution_context( execution_context && other) noexcept;
257
258 execution_context & operator=( execution_context const& other) noexcept;
259 execution_context & operator=( execution_context && other) noexcept;
260
261 explicit operator bool() const noexcept;
262 bool operator!() const noexcept;
263
264 void * operator()( void * vp = nullptr);
265
266 template< typename Fn >
267 void * operator()( exec_ontop_arg_t, Fn && fn, void * vp = nullptr);
268
269 bool operator==( execution_context const& other) const noexcept;
270
271 bool operator!=( execution_context const& other) const noexcept;
272
273 bool operator<( execution_context const& other) const noexcept;
274
275 bool operator>( execution_context const& other) const noexcept;
276
277 bool operator<=( execution_context const& other) const noexcept;
278
279 bool operator>=( execution_context const& other) const noexcept;
280
281 template< typename charT, class traitsT >
282 friend std::basic_ostream< charT, traitsT > &
283 operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other);
284 };
285
286[static_member_heading ecv1..current]
287
288 static execution_context current() noexcept;
289
290[variablelist
291[[Returns:] [Returns an instance of excution_context pointing to the active
292execution context.]]
293[[Throws:] [Nothing.]]
294]
295
296[constructor_heading ecv1..constructor]
297
298 template< typename Fn, typename ... Args >
299 execution_context( Fn && fn, Args && ... args);
300
301 template< typename StackAlloc, typename Fn, typename ... Args >
302 execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args);
303
304 template< typename StackAlloc, typename Fn, typename ... Args >
305 execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args);
306
307[variablelist
308[[Effects:] [Creates a new execution context and prepares the context to execute
309`fn`. `fixedsize_stack` is used as default stack allocator
310(stack size == fixedsize_stack::traits::default_size()).
311The constructor with argument type `preallocated`, is used to create a user
312defined data [link ecv1_prealloc (for instance additional control structures)] on
313top of the stack.]]
314]
315
316[copy_constructor_heading ecv1..copy constructor]
317
318 execution_context( execution_context const& other) noexcept;
319
320[variablelist
321[[Effects:] [Copies `other`, e.g. underlying control structure is shared with
322`*this`.]]
323[[Throws:] [Nothing.]]
324]
325
326[move_constructor_heading ecv1..move constructor]
327
328 execution_context( execution_context && other) noexcept;
329
330[variablelist
331[[Effects:] [Moves underlying control structure to `*this`.]]
332[[Throws:] [Nothing.]]
333]
334
335[copy_assignment_heading ecv1..copy assignment]
336
337 execution_context & operator=( execution_context const& other) noexcept;
338
339[variablelist
340[[Effects:] [Copies the state of `other` to `*this`, control structure is
341shared.]]
342[[Throws:] [Nothing.]]
343]
344
345[move_assignment_heading ecv1..move assignment]
346
347 execution_context & operator=( execution_context && other) noexcept;
348
349[variablelist
350[[Effects:] [Moves the control structure of `other` to `*this` using move
351semantics.]]
352[[Throws:] [Nothing.]]
353]
354
355[operator_heading ecv1..operator_bool..operator bool]
356
357 explicit operator bool() const noexcept;
358
359[variablelist
360[[Returns:] [`true` if `*this` points to a control structure.]]
361[[Throws:] [Nothing.]]
362]
363
364[operator_heading ecv1..operator_not..operator!]
365
366 bool operator!() const noexcept;
367
368[variablelist
369[[Returns:] [`true` if `*this` does not point to a control structure.]]
370[[Throws:] [Nothing.]]
371]
372
373[operator_heading ecv1..operator_call..operator()]
374
375 void * operator()( void * vp = nullptr) noexcept;
376
377[variablelist
378[[Effects:] [Stores internally the current context data (stack pointer,
379instruction pointer, and CPU registers) of the current active context and
380restores the context data from `*this`, which implies jumping to `*this`'s
381context.
382The void pointer argument, `vp`, is passed to the current context to be returned
383by the most recent call to `execution_context::operator()` in the same thread.
384`fn` is executed with arguments `args` on top of the stack of `this`.]]
385[[Note:] [The behaviour is undefined if `operator()()` is called while
386__ec_current__ returns `*this` (e.g. resuming an already running context). If
387the top-level context function returns, `std::exit()` is called.]]
388[[Returns:] [The void pointer argument passed to the most recent call to
389__ec_op__, if any.]]
390]
391
392[operator_heading ecv1..operator_call_ontop..operator(exec_ontop_arg_t)]
393
394 template< typename Fn >
395 void * operator()( exec_ontop_arg_t, Fn && fn, void * vp = nullptr);
396
397[variablelist
398[[Effects:] [Same as __ec_op__. Additionally, function `fn` is executed with
399arguments `vp` in the context of `*this` (e.g. the stack frame of `fn` is
400allocated on stack of `*this`).]]
401[[Returns:] [The void pointer argument passed to the most recent call to
402__ec_op__, if any.]]
403]
404
405[operator_heading ecv1..operator_equal..operator==]
406
407 bool operator==( execution_context const& other) const noexcept;
408
409[variablelist
410[[Returns:] [`true` if `*this` and `other` represent the same execution context,
411`false` otherwise.]]
412[[Throws:] [Nothing.]]
413]
414
415[operator_heading ecv1..operator_notequal..operator!=]
416
417 bool operator!=( execution_context const& other) const noexcept;
418
419[variablelist
420[[Returns:] [[`! (other == * this)]]]
421[[Throws:] [Nothing.]]
422]
423
424[operator_heading ecv1..operator_less..operator<]
425
426 bool operator<( execution_context const& other) const noexcept;
427
428[variablelist
429[[Returns:] [`true` if `*this != other` is true and the
430implementation-defined total order of `execution_context` values places `*this`
431before `other`, false otherwise.]]
432[[Throws:] [Nothing.]]
433]
434
435[operator_heading ecv1..operator_greater..operator>]
436
437 bool operator>( execution_context const& other) const noexcept;
438
439[variablelist
440[[Returns:] [`other < * this`]]
441[[Throws:] [Nothing.]]
442]
443
444[operator_heading ecv1..operator_lesseq..operator<=]
445
446 bool operator<=( execution_context const& other) const noexcept;
447
448[variablelist
449[[Returns:] [`! (other < * this)`]]
450[[Throws:] [Nothing.]]
451]
452
453[operator_heading ecv1..operator_greatereq..operator>=]
454
455 bool operator>=( execution_context const& other) const noexcept;
456
457[variablelist
458[[Returns:] [`! (* this < other)`]]
459[[Throws:] [Nothing.]]
460]
461
462[hding ecv1_..Non-member function [`operator<<()]]
463
464 template< typename charT, class traitsT >
465 std::basic_ostream< charT, traitsT > &
466 operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other);
467
468[variablelist
469[[Efects:] [Writes the representation of `other` to stream `os`.]]
470[[Returns:] [`os`]]
471]
472
473
474[endsect]