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
9 [section:ecv1 Class execution_context (version 1)]
11 [note This class is only enabled if property ['segmented-stacks=on] (enables
12 segmented stacks) or compiler flag ['BOOST_EXECUTION_CONTEXT=1] is specified
15 Class __econtext__ encapsulates context switching and manages the associated
16 context' stack (allocation/deallocation).
18 __econtext__ allocates the context stack (using its [link stack
19 __stack_allocator__] argument) and creates a control structure on top of it.
20 This structure is responsible for managing context' stack. Instances of
21 __econtext__, associated with a specific context, share the ownership of the
22 control structure. If the last reference goes out of scope, the control
23 structure is destroyed and the stack gets deallocated via the
26 __econtext__ is copy-constructible, move-constructible, copy-assignable and
29 __econtext__ maintains a static (thread-local) pointer, accessed by
30 __ec_current__, pointing to the active context. On each context switch the
32 The 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
34 access the control structure of the current active context from arbitrary code
35 paths required in order to support segmented stacks, which require to call
36 certain maintenance functions (like __splitstack_getcontext() etc.) before each
37 context switch (each context switch exchanges the stack).
39 __econtext__ expects a function/functor with signature `void(void* vp)` (`vp`
40 is the data passed at the first invocation of
41 [operator_link ecv1 operator_call operator()]).
44 [heading usage of __econtext__]
47 boost::context::execution_context sink(boost::context::execution_context::current());
48 boost::context::execution_context source(
49 [n,&sink](void*)mutable{
59 for(int i=0;i<10;++i){
60 std::cout<<*(int*)source()<<" ";
64 0 1 1 2 3 5 8 13 21 34
66 This 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
69 expression. The lambda that calculates the Fibonacci numbers is executed inside
70 the context represented by `source`. Calculated Fibonacci numbers are
71 transferred between the two context' via expression ['sink(&a)] (and returned by
74 The locale variables `a`, `b` and ` next` remain their values during each
75 context switch (['yield(a)]). This is possible because `ctx` owns a stack
76 (exchanged by context switch).
78 [heading inverting the control flow]
83 * E ---> T {('+'|'-') T}
84 * T ---> S {('*'|'/') S}
85 * S ---> digit | '(' E ')'
88 // implementation omitted; see examples directory
91 std::istringstream is("1+1");
93 std::exception_ptr except;
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
103 // resume main execution context
107 // start recursive parsing
110 // store other exceptions in exception-pointer
111 except = std::current_exception();
113 // set termination flag
115 // resume main execution context
119 // user-code pulls parsed data from parser
120 // invert control flow
123 std::rethrow_exception(except);
126 printf("Parsed: %c\n",* static_cast<char*>(vp));
129 std::rethrow_exception(except);
139 In this example a recursive descent parser uses a callback to emit a newly
140 passed symbol. Using __econtext__ the control flow can be inverted, e.g. the
141 user-code pulls parsed symbols from the parser - instead to get pushed from the
142 parser (via callback).
144 The data (character) is transferred between the two __econtext__.
146 If the code executed by __econtext__ emits an exception, the application is
147 terminated. ['std::exception_ptr] can be used to transfer exceptions between
148 different execution contexts.
150 [heading stack unwinding]
151 Sometimes it is necessary to unwind the stack of an unfinished context to
152 destroy local stack variables so they can release allocated resources (RAII
153 pattern). The user is responsible for this task.
156 [heading allocating control structures on top of stack]
157 Allocating 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
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);
173 // destructing the control structure
174 cs->~my_control_structure();
176 struct my_control_structure {
178 execution_context ectx;
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) {
188 [heading exception handling]
189 If the function executed inside a __econtext__ emits ans exception, the
190 application is terminated by calling ['std::terminate()]. ['std::exception_ptr]
191 can be used to transfer exceptions between different execution contexts.
193 [important Do not jump from inside a catch block and then re-throw the exception
194 in another execution context.]
196 [heading parameter passing]
197 The void pointer argument passed to __ec_op__, in one context, is passed as
198 the last argument of the __context_fn__ if the context is started for the
200 In 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.
205 std::exception_ptr excptr_;
206 boost::context::execution_context caller_;
207 boost::context::execution_context callee_;
212 caller_( boost::context::execution_context::current() ),
213 callee_( [=] (void * vp) {
215 int i = * static_cast< int * >( vp);
216 std::string str = boost::lexical_cast<std::string>(i);
218 } catch (std::bad_cast const&) {
219 excptr_=std::current_exception();
224 std::string operator()( int i) {
225 void * ret = callee_( & i);
227 std::rethrow_exception(excptr_);
229 return * static_cast< std::string * >( ret);
234 std::cout << x( 7) << std::endl;
240 [heading Class `execution_context`]
242 class execution_context {
244 static execution_context current() noexcept;
246 template< typename Fn, typename ... Args >
247 execution_context( Fn && fn, Args && ... args);
249 template< typename StackAlloc, typename Fn, typename ... Args >
250 execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args);
252 template< typename StackAlloc, typename Fn, typename ... Args >
253 execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args);
255 execution_context( execution_context const& other) noexcept;
256 execution_context( execution_context && other) noexcept;
258 execution_context & operator=( execution_context const& other) noexcept;
259 execution_context & operator=( execution_context && other) noexcept;
261 explicit operator bool() const noexcept;
262 bool operator!() const noexcept;
264 void * operator()( void * vp = nullptr);
266 template< typename Fn >
267 void * operator()( exec_ontop_arg_t, Fn && fn, void * vp = nullptr);
269 bool operator==( execution_context const& other) const noexcept;
271 bool operator!=( execution_context const& other) const noexcept;
273 bool operator<( execution_context const& other) const noexcept;
275 bool operator>( execution_context const& other) const noexcept;
277 bool operator<=( execution_context const& other) const noexcept;
279 bool operator>=( execution_context const& other) const noexcept;
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);
286 [static_member_heading ecv1..current]
288 static execution_context current() noexcept;
291 [[Returns:] [Returns an instance of excution_context pointing to the active
293 [[Throws:] [Nothing.]]
296 [constructor_heading ecv1..constructor]
298 template< typename Fn, typename ... Args >
299 execution_context( Fn && fn, Args && ... args);
301 template< typename StackAlloc, typename Fn, typename ... Args >
302 execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args);
304 template< typename StackAlloc, typename Fn, typename ... Args >
305 execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args);
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()).
311 The constructor with argument type `preallocated`, is used to create a user
312 defined data [link ecv1_prealloc (for instance additional control structures)] on
316 [copy_constructor_heading ecv1..copy constructor]
318 execution_context( execution_context const& other) noexcept;
321 [[Effects:] [Copies `other`, e.g. underlying control structure is shared with
323 [[Throws:] [Nothing.]]
326 [move_constructor_heading ecv1..move constructor]
328 execution_context( execution_context && other) noexcept;
331 [[Effects:] [Moves underlying control structure to `*this`.]]
332 [[Throws:] [Nothing.]]
335 [copy_assignment_heading ecv1..copy assignment]
337 execution_context & operator=( execution_context const& other) noexcept;
340 [[Effects:] [Copies the state of `other` to `*this`, control structure is
342 [[Throws:] [Nothing.]]
345 [move_assignment_heading ecv1..move assignment]
347 execution_context & operator=( execution_context && other) noexcept;
350 [[Effects:] [Moves the control structure of `other` to `*this` using move
352 [[Throws:] [Nothing.]]
355 [operator_heading ecv1..operator_bool..operator bool]
357 explicit operator bool() const noexcept;
360 [[Returns:] [`true` if `*this` points to a control structure.]]
361 [[Throws:] [Nothing.]]
364 [operator_heading ecv1..operator_not..operator!]
366 bool operator!() const noexcept;
369 [[Returns:] [`true` if `*this` does not point to a control structure.]]
370 [[Throws:] [Nothing.]]
373 [operator_heading ecv1..operator_call..operator()]
375 void * operator()( void * vp = nullptr) noexcept;
378 [[Effects:] [Stores internally the current context data (stack pointer,
379 instruction pointer, and CPU registers) of the current active context and
380 restores the context data from `*this`, which implies jumping to `*this`'s
382 The void pointer argument, `vp`, is passed to the current context to be returned
383 by 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
387 the top-level context function returns, `std::exit()` is called.]]
388 [[Returns:] [The void pointer argument passed to the most recent call to
392 [operator_heading ecv1..operator_call_ontop..operator(exec_ontop_arg_t)]
394 template< typename Fn >
395 void * operator()( exec_ontop_arg_t, Fn && fn, void * vp = nullptr);
398 [[Effects:] [Same as __ec_op__. Additionally, function `fn` is executed with
399 arguments `vp` in the context of `*this` (e.g. the stack frame of `fn` is
400 allocated on stack of `*this`).]]
401 [[Returns:] [The void pointer argument passed to the most recent call to
405 [operator_heading ecv1..operator_equal..operator==]
407 bool operator==( execution_context const& other) const noexcept;
410 [[Returns:] [`true` if `*this` and `other` represent the same execution context,
412 [[Throws:] [Nothing.]]
415 [operator_heading ecv1..operator_notequal..operator!=]
417 bool operator!=( execution_context const& other) const noexcept;
420 [[Returns:] [[`! (other == * this)]]]
421 [[Throws:] [Nothing.]]
424 [operator_heading ecv1..operator_less..operator<]
426 bool operator<( execution_context const& other) const noexcept;
429 [[Returns:] [`true` if `*this != other` is true and the
430 implementation-defined total order of `execution_context` values places `*this`
431 before `other`, false otherwise.]]
432 [[Throws:] [Nothing.]]
435 [operator_heading ecv1..operator_greater..operator>]
437 bool operator>( execution_context const& other) const noexcept;
440 [[Returns:] [`other < * this`]]
441 [[Throws:] [Nothing.]]
444 [operator_heading ecv1..operator_lesseq..operator<=]
446 bool operator<=( execution_context const& other) const noexcept;
449 [[Returns:] [`! (other < * this)`]]
450 [[Throws:] [Nothing.]]
453 [operator_heading ecv1..operator_greatereq..operator>=]
455 bool operator>=( execution_context const& other) const noexcept;
458 [[Returns:] [`! (* this < other)`]]
459 [[Throws:] [Nothing.]]
462 [hding ecv1_..Non-member function [`operator<<()]]
464 template< typename charT, class traitsT >
465 std::basic_ostream< charT, traitsT > &
466 operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other);
469 [[Efects:] [Writes the representation of `other` to stream `os`.]]