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