Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

This is the documentation for an old version of boost. Click here for the latest Boost documentation.
PrevUpHomeNext

Class execution_context

Using WinFiber-API
[Important] Important

execution_context requires C++14.

Class execution_context encapsulates fcontext_t and related functions ( jump_fcontext() and make_fcontext()) as well as stack management. execution_context permits access to the current, active context via execution_context::current().

/*
 * grammar:
 *   P ---> E '\0'
 *   E ---> T {('+'|'-') T}
 *   T ---> S {('*'|'/') S}
 *   S ---> digit | '(' E ')'
 */
class Parser{
    // implementation omitted; see examples directory
};

int main() {
    std::istringstream is("1+1");
    char c;
    bool done=false;
    std::exception_ptr except;

    // create handle to main execution context
    auto main_ctx( boost::context::execution_context::current() );

    // execute parser in new execution context
    boost::context::execution_context parser_ctx(
            boost::context::fixedsize_stack(),
            [&main_ctx,&is,&c,&done,&except](){
            // create parser with callback function
            Parser p( is,
                      [&main_ctx,&c](char ch){
                            c=ch;
                            // resume main execution context
                            main_ctx();
                    });
                try {
                    // start recursive parsing
                    p.run();
                } catch ( ... ) {
                    // store other exceptions in exception-pointer
                    except = std::current_exception();
                }
                // set termination flag
                done=true;
                // resume main execution context
                main_ctx();
            });

    // user-code pulls parsed data from parser
    // invert control flow
    parser_ctx();
    if ( except) {
        std::rethrow_exception( except);
    }
    while( ! done) {
        printf("Parsed: %c\n",c);
        parser_ctx();
        if ( except) {
            std::rethrow_exception( except);
        }
    }

    std::cout << "main: done" << std::endl;
}

output:
    Parsed: 1
    Parsed: +
    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 interface of execution_context does not transfer data. This is not required because usually sharing data's address (pointer/reference of lvalues) is sufficient.

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.

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] Note

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

// stack-allocator used for (de-)allocating stack
fixedsize_stack salloc( 4048);
// allocate stack space
stack_context sctx( salloc.allocate() );
// reserve space for control structure on top of the stack
void * sp = static_cast< char * >( sctx.sp) - sizeof( my_control_structure);
std::size_t size = sctx.size - sizeof( my_control_structure);
// placement new creates control structure on reserved space
my_control_structure * cs = new ( sp) my_control_structure( sp, size, sctx, salloc);
...
// destructing the control structure
cs->~my_control_structure();
...
struct my_control_structure  {
    // execution context
    execution_context ectx;

    template< typename StackAllocator >
    my_control_structure( void * sp, std::size_t size, stack_context sctx, StackAllocator salloc) :
        // create execution context
        ectx( preallocated( sp, size, sctx), salloc, entry_func) {
    }
    ...
};

exception handling

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

parameter passing

Input and output parameters are transferred via a lambda capture list and references/pointers.

class X {
private:
    int * inp_;
    std::string outp_;
    std::exception_ptr excptr_;
    boost::context::execution_context caller_;
    boost::context::execution_context callee_;

public:
    X() :
        inp_( nullptr),
        outp_(),
        excptr_(),
        caller_( boost::context::execution_context::current() ),
        callee_( boost::context::fixedsize_stack(),
                 [=] () {
                    try {
                        int i = * inp_;
                        outp_ = boost::lexical_cast< std::string >( i);
                        caller_();
                    } catch (...) {
                        excptr_=std::current_exception();
                    }
                 })
    {}

    std::string operator()( int i) {
        inp_ = & i;
        callee_();
        if(excptr_){
            std::rethrow_exception(excptr_);
        }
        return outp_;
    }
};

int main() {
    X x;
    std::cout << x( 7) << std::endl;
    std::cout << "done" << std::endl;
}

Class execution_context

class execution_context {
public:
    static execution_context current() noexcept;

    template< typename StackAlloc, typename Fn >
    execution_context( StackAlloc salloc, Fn && fn);

    template< typename StackAlloc, typename Fn, typename ... Args >
    execution_context( StackAlloc salloc, Fn && fn, Args && ... args);

    template< typename StackAlloc, typename Fn >
    execution_context( preallocated palloc, StackAlloc salloc, Fn && fn);

    template< typename StackAlloc, typename Fn, typename ... Args >
    execution_context( preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args);

    void operator()() noexcept;
};

static execution_context current()

Returns:

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

Throws:

Nothing.

template< typename StackAlloc, typname Fn > execution_context( StackAlloc salloc, Fn && fn)

Effects:

Creates a new execution context and prepares the context to execute fn.

template< typename StackAlloc, typname Fn, typename ... Args > execution_context( StackAlloc salloc, Fn && fn, Args && ... args)

Effects:

Creates a new execution context and prepares the context to execute fn.

template< typename StackAlloc, typname Fn > execution_context( preallocated palloc, StackAlloc salloc, Fn && fn)

Effects:

Creates a new execution context and prepares the context to execute fn. Used to store control structures on top of the stack.

template< typename StackAlloc, typname Fn, typename ... Args > execution_context( preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args)

Effects:

Creates a new execution context and prepares the context to execute fn. Used to store control structures on top of the stack.

void operator()() noexcept

Effects:

Stores internally the current context data (stack pointer, instruction pointer, and CPU registers) to the current active context and restores the context data from *this, which implies jumping to *this's execution context.

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:

Reference to *this.

Throws:

Nothing.

Struct preallocated

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

    preallocated( void * sp, std:size_t size, stack_allocator sctx) noexcept;
};

preallocated( void * sp, std:size_t size, stack_allocator sctx)

Effects:

Creates an object of preallocated.


PrevUpHomeNext