Back to Arangodb

Class execution_context (version 1)

3rdParty/boost/1.78.0/libs/context/doc/html/context/ecv1.html

3.12.9.116.0 KB
Original Source

| | Home | Libraries | People | FAQ | More |


Class execution_context (version 1)

| | Warning | |

execution_context (v1) is deprecated (does not prevent UB).

|

| | Note | |

execution_context (v1) is the reference implementation of C++ proposal P099R0: A low-level API for stackful context switching.

|

| | Note | |

execution_context (v1) resides in sub-namespace v1.

|

| | Note | |

Segmented stacks (segmented-stacks=on), e.g. on demand growing stacks, can be used with execution_context (v1).

|

Class execution_context encapsulates context switching and manages the associated context' stack (allocation/deallocation).

execution_context allocates the context stack (using its StackAllocator argument) and creates a control structure on top of it. This structure is responsible for managing context' stack. Instances of execution_context, associated with a specific context, share the ownership of the control structure. If the last reference goes out of scope, the control structure is destroyed and the stack gets deallocated via the StackAllocator.

execution_context is copy-constructible, move-constructible, copy-assignable and move-assignable.

execution_context maintains a static (thread-local) pointer, accessed by execution_context::current(), pointing to the active context. On each context switch the pointer is updated. The usage of this global pointer makes the context switch a little bit slower (due access of thread local storage) but has some advantages. It allows to access the control structure of the current active context from arbitrary code paths required in order to support segmented stacks, which require to call certain maintenance functions (like __splitstack_getcontext() etc.) before each context switch (each context switch exchanges the stack).

execution_context expects a function/functor with signature void(void* vp) (vp is the data passed at the first invocation of ecv1::operator()()).

[usage of execution_context](ecv1.html#context.ecv1.usage_of emphasis_execution_context emphasis_)

intn=35;boost::context::v1::execution\_contextsink(boost::context::v1::execution\_context::current());boost::context::v1::execution\_contextsource([n,&sink](void\*)mutable{inta=0;intb=1;while(n--\>0){sink(&a);autonext=a+b;a=b;b=next;}});for(inti=0;i\<10;++i){std::cout\<\<\*(int\*)source()\<\<" ";}output:0112358132134

This simple example demonstrates the basic usage of execution_context. The context sink, returned by execution_context::current(), represents the main-context (function main() running) and is one of the captured parameters in the lambda expression. The lambda that calculates the Fibonacci numbers is executed inside the context represented by source. Calculated Fibonacci numbers are transferred between the two context' via expression sink(&a) (and returned by source()).

The locale variables a, b and next remain their values during each context switch (yield(a)). This is possible because ctx owns a stack (exchanged by context switch).

inverting the control flow

/\* \* grammar: \* P ---\> E '\0' \* E ---\> T {('+'|'-') T} \* T ---\> S {('\*'|'/') S} \* S ---\> digit | '(' E ')' \*/classParser{// implementation omitted; see examples directory};std::istringstreamis("1+1");booldone=false;std::exception\_ptrexcept;// create handle to main execution contextautomain\_ctx(boost::context::v1::execution\_context::current());// execute parser in new execution contextboost::context::v1::execution\_contextsource([&sink,&is,&done,&except](void\*){// create parser with callback functionParserp(is,[&sink](charch){// resume main execution contextsink(&ch);});try{// start recursive parsingp.run();}catch(...){// store other exceptions in exception-pointerexcept=std::current\_exception();}// set termination flagdone=true;// resume main execution contextsink();});// user-code pulls parsed data from parser// invert control flowvoid\*vp=source();if(except){std::rethrow\_exception(except);}while(!done){printf("Parsed: %c\n",\*static\_cast\<char\*\>(vp));vp=source();if(except){std::rethrow\_exception(except);}}output:Parsed:1Parsed:+Parsed:1

In this example a recursive descent parser uses a callback to emit a newly passed symbol. Using execution_context the control flow can be inverted, e.g. the user-code pulls parsed symbols from the parser - instead to get pushed from the parser (via callback).

The data (character) is transferred between the two execution_context.

If the code executed by execution_context emits an exception, the application is terminated. std::exception_ptr can be used to transfer exceptions between different execution contexts.

stack unwinding

Sometimes it is necessary to unwind the stack of an unfinished context to destroy local stack variables so they can release allocated resources (RAII pattern). The user is responsible for this task.

allocating control structures on top of stack

Allocating control structures on top of the stack requires to allocated the stack_context and create the control structure with placement new before execution_context is created.

| | Note | |

The user is responsible for destructing the control structure at the top of the stack.

|

// stack-allocator used for (de-)allocating stackfixedsize\_stacksalloc(4048);// allocate stack spacestack\_contextsctx(salloc.allocate());// reserve space for control structure on top of the stackvoid\*sp=static\_cast\<char\*\>(sctx.sp)-sizeof(my\_control\_structure);std::size\_tsize=sctx.size-sizeof(my\_control\_structure);// placement new creates control structure on reserved spacemy\_control\_structure\*cs=new(sp)my\_control\_structure(sp,size,sctx,salloc);...// destructing the control structurecs-\>~my\_control\_structure();...structmy\_control\_structure{// execution contextexecution\_contextectx;template\<typenameStackAllocator\>my\_control\_structure(void\*sp,std::size\_tsize,stack\_contextsctx,StackAllocatorsalloc):// create execution contextectx(std::allocator\_arg,preallocated(sp,size,sctx),salloc,entry\_func){}...};

exception handling

If the function executed inside a execution_context emits an exception, the application is terminated by calling std::terminate(). std::exception_ptr can be used to transfer exceptions between different execution contexts.

| | Important | |

Do not jump from inside a catch block and then re-throw the exception in another execution context.

|

parameter passing

The void pointer argument passed to execution_context::operator(), in one context, is passed as the last argument of the context-function if the context is started for the first time. In all following invocations of execution_context::operator() the void pointer passed to execution_context::operator(), in one context, is returned by execution_context::operator() in the other context.

classX{private:std::exception\_ptrexcptr\_;boost::context::v1::execution\_contextcaller\_;boost::context::v1::execution\_contextcallee\_;public:X():excptr\_(),caller\_(boost::context::v1::execution\_context::current()),callee\_([=](void\*vp){try{inti=\*static\_cast\<int\*\>(vp);std::stringstr=boost::lexical\_cast\<std::string\>(i);caller\_(&str);}catch(std::bad\_castconst&){excptr\_=std::current\_exception();}}){}std::stringoperator()(inti){void\*ret=callee\_(&i);if(excptr\_){std::rethrow\_exception(excptr\_);}return\*static\_cast\<std::string\*\>(ret);}};Xx;std::cout\<\<x(7)\<\<std::endl;output:7

[Class execution_context](ecv1.html#context.ecv1.class code phrase_role identifier execution_context phrase_ code_)

classexecution\_context{public:staticexecution\_contextcurrent()noexcept;template\<typenameFn,typename...Args\>execution\_context(Fn&&fn,Args&&...args);template\<typenameStackAlloc,typenameFn,typename...Args\>execution\_context(std::allocator\_arg\_t,StackAllocsalloc,Fn&&fn,Args&&...args);template\<typenameStackAlloc,typenameFn,typename...Args\>execution\_context(std::allocator\_arg\_t,preallocatedpalloc,StackAllocsalloc,Fn&&fn,Args&&...args);execution\_context(execution\_contextconst&other)noexcept;execution\_context(execution\_context&&other)noexcept;execution\_context&operator=(execution\_contextconst&other)noexcept;execution\_context&operator=(execution\_context&&other)noexcept;explicitoperatorbool()constnoexcept;booloperator!()constnoexcept;void\*operator()(void\*vp=nullptr);template\<typenameFn\>void\*operator()(exec\_ontop\_arg\_t,Fn&&fn,void\*vp=nullptr);booloperator==(execution\_contextconst&other)constnoexcept;booloperator!=(execution\_contextconst&other)constnoexcept;booloperator\<(execution\_contextconst&other)constnoexcept;booloperator\>(execution\_contextconst&other)constnoexcept;booloperator\<=(execution\_contextconst&other)constnoexcept;booloperator\>=(execution\_contextconst&other)constnoexcept;template\<typenamecharT,classtraitsT\>friendstd::basic\_ostream\<charT,traitsT\>&operator\<\<(std::basic\_ostream\<charT,traitsT\>&os,execution\_contextconst&other);};
Static member function current()
staticexecution\_contextcurrent()noexcept;

Returns:

Returns an instance of excution_context pointing to the active execution context.

Throws:

Nothing.

Constructor
template\<typenameFn,typename...Args\>execution\_context(Fn&&fn,Args&&...args);template\<typenameStackAlloc,typenameFn,typename...Args\>execution\_context(std::allocator\_arg\_t,StackAllocsalloc,Fn&&fn,Args&&...args);template\<typenameStackAlloc,typenameFn,typename...Args\>execution\_context(std::allocator\_arg\_t,preallocatedpalloc,StackAllocsalloc,Fn&&fn,Args&&...args);

Effects:

Creates a new execution context and prepares the context to execute fn. fixedsize_stack is used as default stack allocator (stack size == fixedsize_stack::traits::default_size()). The constructor with argument type preallocated, is used to create a user defined data (for instance additional control structures) on top of the stack.

Copy constructor
execution\_context(execution\_contextconst&other)noexcept;

Effects:

Copies other, e.g. underlying control structure is shared with *this.

Throws:

Nothing.

Move constructor
execution\_context(execution\_context&&other)noexcept;

Effects:

Moves underlying control structure to *this.

Throws:

Nothing.

Copy assignment operator
execution\_context&operator=(execution\_contextconst&other)noexcept;

Effects:

Copies the state of other to *this, control structure is shared.

Throws:

Nothing.

Move assignment operator
execution\_context&operator=(execution\_context&&other)noexcept;

Effects:

Moves the control structure of other to *this using move semantics.

Throws:

Nothing.

Member function operator bool()
explicitoperatorbool()constnoexcept;

Returns:

true if *this points to a control structure.

Throws:

Nothing.

Member function operator!()
booloperator!()constnoexcept;

Returns:

true if *this does not point to a control structure.

Throws:

Nothing.

Member function operator()()
void\*operator()(void\*vp=nullptr)noexcept;

Effects:

Stores internally the current context data (stack pointer, instruction pointer, and CPU registers) of the current active context and restores the context data from *this, which implies jumping to *this's context. The void pointer argument, vp, is passed to the current context to be returned by the most recent call to execution_context::operator() in the same thread. fn is executed with arguments args on top of the stack of this.

Note:

The behaviour is undefined if operator()() is called while execution_context::current() returns *this (e.g. resuming an already running context). If the top-level context function returns, std::exit() is called.

Returns:

The void pointer argument passed to the most recent call to execution_context::operator(), if any.

Member function operator(exec_ontop_arg_t)()
template\<typenameFn\>void\*operator()(exec\_ontop\_arg\_t,Fn&&fn,void\*vp=nullptr);

Effects:

Same as execution_context::operator(). Additionally, function fn is executed with arguments vp in the context of *this (e.g. the stack frame of fn is allocated on stack of *this).

Returns:

The void pointer argument passed to the most recent call to execution_context::operator(), if any.

Member function operator==()
booloperator==(execution\_contextconst&other)constnoexcept;

Returns:

true if *this and other represent the same execution context, false otherwise.

Throws:

Nothing.

Member function operator!=()
booloperator!=(execution\_contextconst&other)constnoexcept;

Returns:

! (other == * this)

Throws:

Nothing.

Member function operator<()
booloperator\<(execution\_contextconst&other)constnoexcept;

Returns:

true if *this != other is true and the implementation-defined total order of execution_context values places *this before other, false otherwise.

Throws:

Nothing.

Member function operator>()
booloperator\>(execution\_contextconst&other)constnoexcept;

Returns:

other < * this

Throws:

Nothing.

Member function operator<=()
booloperator\<=(execution\_contextconst&other)constnoexcept;

Returns:

! (other < * this)

Throws:

Nothing.

Member function operator>=()
booloperator\>=(execution\_contextconst&other)constnoexcept;

Returns:

! (* this < other)

Throws:

Nothing.

Non-member function operator<<()
template\<typenamecharT,classtraitsT\>std::basic\_ostream\<charT,traitsT\>&operator\<\<(std::basic\_ostream\<charT,traitsT\>&os,execution\_contextconst&other);

Efects:

Writes the representation of other to stream os.

Returns:

os

| | Copyright © 2014 Oliver Kowalke

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)

|