From 1bf9f6dfdb8068f82a04eb05fc43b842d5567cee Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Tue, 12 Jan 2016 20:29:58 +0100 Subject: [PATCH] documentation updated --- doc/captured_context.qbk | 410 ++++ doc/context.qbk | 92 +- doc/context.xml | 1658 ++++++++++------- doc/execution_context.qbk | 237 ++- doc/fcontext.qbk | 4 +- doc/html/context/abstract_context.html | 72 + .../context/abstract_context/ccontext.html | 739 ++++++++ .../context/abstract_context/econtext.html | 737 ++++++++ doc/html/context/abstract_context/stack.html | 188 ++ .../abstract_context/stack/fixedsize.html | 113 ++ .../stack/protected_fixedsize.html | 136 ++ .../abstract_context/stack/segmented.html | 139 ++ .../abstract_context/stack/stack_context.html | 85 + .../abstract_context/stack/stack_traits.html | 159 ++ .../abstract_context/stack/valgrind.html | 49 + doc/html/context/ccontext.html | 707 +++++++ doc/html/context/context.html | 75 +- doc/html/context/econtext.html | 465 +++-- doc/html/context/overview.html | 34 +- doc/html/context/performance.html | 67 +- doc/html/context/requirements.html | 6 +- doc/html/context/stack.html | 8 +- doc/html/context/stack/valgrind.html | 6 +- doc/html/context/struct__preallocated_.html | 66 + doc/html/context_HTML.manifest | 4 +- doc/html/index.html | 6 +- doc/overview.qbk | 21 +- doc/performance.qbk | 14 +- doc/preallocated.qbk | 27 + doc/stack.qbk | 1 + 30 files changed, 5243 insertions(+), 1082 deletions(-) create mode 100644 doc/captured_context.qbk create mode 100644 doc/html/context/abstract_context.html create mode 100644 doc/html/context/abstract_context/ccontext.html create mode 100644 doc/html/context/abstract_context/econtext.html create mode 100644 doc/html/context/abstract_context/stack.html create mode 100644 doc/html/context/abstract_context/stack/fixedsize.html create mode 100644 doc/html/context/abstract_context/stack/protected_fixedsize.html create mode 100644 doc/html/context/abstract_context/stack/segmented.html create mode 100644 doc/html/context/abstract_context/stack/stack_context.html create mode 100644 doc/html/context/abstract_context/stack/stack_traits.html create mode 100644 doc/html/context/abstract_context/stack/valgrind.html create mode 100644 doc/html/context/ccontext.html create mode 100644 doc/html/context/struct__preallocated_.html create mode 100644 doc/preallocated.qbk diff --git a/doc/captured_context.qbk b/doc/captured_context.qbk new file mode 100644 index 0000000..ad69bf7 --- /dev/null +++ b/doc/captured_context.qbk @@ -0,0 +1,410 @@ +[/ + Copyright Oliver Kowalke 2014. + 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 +] + +[#ccontext] +[section:ccontext Class captured_context] + +Class __ccontext__ encapsulates __fcontext__ and manages the context' stack +(allocation/deallocation). + +__ccontext__ allocates the context stack (using its __stack_allocator__ +argument) and creates a control structure on top of it. This structure +controls the life time of the stack. The address of the control structure is +stored in the first frame of context' stack (e.g. it can not accessed by +instances of __ccontext__ directly). In contrast to __econtext__ the ownership +of the control structure is not shared +A call of__cc_op__ enters the context represented by `*this` and invalidates +`*this`. The context that has been suspended by calling __cc_op__ is passed to +the resumed context, e.g. as argument of the context-function if the context was +resumed the first time or returned by __cc_op__. +__ccontext__ is only move-constructible and move-assignable. +If the last reference (__ccontext__) goes out of scope, the control structure +is destroyed and the stack gets deallocated via the __stack_allocator__. +__ccontext__ maintains a static, thread-local pointer (smart pointer), +accessed by __ec_current__, pointing to the active context. +On each context switch the static, thread-local pointer is updated. This makes +the context switch a little bit slower, but enables faster context destruction +(stack unwinding) compared to __ccontext__. + +__ccontext__ expects a function/functor with signature +`captured_context( captured_context ctx, void * vp)`. The parameter `ctx` +represents the context from which this context was resumed (e.g. that has called +__cc_op__ on `*this`) and `vp` is the data passed to __cc_op__. The +function/functor has to return the captured_context that has to be resumed, +while this context terminates. + +[important Segemnted stacks are not supported together with __ccontext__.] + + +[heading usage of __ccontext__] + + /* + * grammar: + * P ---> E '\0' + * E ---> T {('+'|'-') T} + * T ---> S {('*'|'/') S} + * S ---> digit | '(' E ')' + */ + class Parser{ + // implementation omitted; see examples directory + }; + + std::istringstream is("1+1"); + bool done=false; + std::exception_ptr except; + + // execute parser in new execution context + boost::context::captured_context pctx( + [&is,&done,&except](ctx::captured_context mctx,void* ignored){ + // create parser with callback function + Parser p( is, + [&mctx](char ch){ + // resume main execution context + auto result = mctx( & ch); + mctx = std::move( std::get<0>( result) ); + }); + 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 + return mctx; + }); + + // user-code pulls parsed data from parser + // invert control flow + auto result = pctx(); + pctx = std::move( std::get<0>( result) ); + void * vp = std::get<1>( result); + if ( except) { + std::rethrow_exception( except); + } + while( ! done) { + printf("Parsed: %c\n",* static_cast< char* >( vp) ); + std::tie(pctx,vp) = pctx(); + if ( except) { + std::rethrow_exception( except); + } + } + + output: + Parsed: 1 + Parsed: + + Parsed: 1 + + +In this example a recursive descent parser uses a callback to emit a newly +passed symbol. Using __ccontext__ 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 __ccontext__. + +If the code executed by __ccontext__ 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. + +[heading 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 +__ccontext__ is created. +[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 { + // captured context + captured_context cctx; + + template< typename StackAllocator > + my_control_structure( void * sp, std::size_t size, stack_context sctx, StackAllocator salloc) : + // create captured context + cctx( std::allocator_arg, preallocated( sp, size, sctx), salloc, entry_func) { + } + ... + }; + +[heading exception handling] +If the function executed inside a __ccontext__ emits ans exception, the +application is terminated by calling ['std::terminate(). ['std::exception_ptr] +can be used to transfer exceptions between different execution contexts. + +[heading parameter passing] +The void pointer argument passed to __cc_op__, in one context, is passed as +the last argument of the __context_fn__ if the context is started for the +first time. +In all following invocations of __cc_op__ the void pointer passed to +__cc_op__, in one context, is returned by __cc_op__ in the other context. + + class X { + private: + std::exception_ptr excptr_; + boost::context::captured_context ctx_; + + public: + X() : + excptr_(), + ctx_( [=](ctx::captured_context ctx, void * vp)->ctx::captured_context{ + try { + for (;;) { + int i = * static_cast< int * >( vp); + std::string str = boost::lexical_cast(i); + auto result = ctx( & str); + ctx = std::move( std::get<0>( result) ); + vp = std::get<1>( result); + } + } catch ( ctx::detail::forced_unwind const&) { + throw; + } catch (...) { + excptr_=std::current_exception(); + } + return ctx; + }) + {} + + std::string operator()( int i) { + auto result = ctx_( & i); + ctx_ = std::move( std::get<0>( result) ); + void * ret = std::get<1>( result); + if(excptr_){ + std::rethrow_exception(excptr_); + } + return * static_cast< std::string * >( ret); + } + }; + + X x; + std::cout << x( 7) << std::endl; + + output: + 7 + + +[heading Class `captured_context`] + + class captured_context { + public: + template< typename Fn, typename ... Args > + captured_context( Fn && fn, Args && ... args); + + template< typename StackAlloc, typename Fn, typename ... Args > + captured_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args); + + template< typename StackAlloc, typename Fn, typename ... Args > + captured_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args); + + ~captured_context(); + + captured_context( captured_context && other) noexcept; + captured_context & operator=( captured_context && other) noexcept; + + captured_context( captured_context const& other) noexcept = delete; + captured_context & operator=( captured_context const& other) noexcept = delete; + + explicit operator bool() const noexcept; + bool operator!() const noexcept; + + std::tuple< captured_context, void * > operator()( void * data = nullptr); + + template< typename Fn, typename ... Args > + std::tuple< captured_context, void * > operator()( exec_ontop_arg_t, Fn && fn, Args && ... args); + + template< typename Fn, typename ... Args > + std::tuple< captured_context, void * > operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args); + + bool operator==( captured_context const& other) const noexcept; + + bool operator!=( captured_context const& other) const noexcept; + + bool operator<( captured_context const& other) const noexcept; + + bool operator>( captured_context const& other) const noexcept; + + bool operator<=( captured_context const& other) const noexcept; + + bool operator>=( captured_context const& other) const noexcept; + + template< typename charT, class traitsT > + friend std::basic_ostream< charT, traitsT > & + operator<<( std::basic_ostream< charT, traitsT > & os, captured_context const& other); + }; + +[constructor_heading captured_context..constructor] + + template< typename Fn, typename ... Args > + captured_context( Fn && fn, Args && ... args); + + template< typename StackAlloc, typename Fn, typename ... Args > + captured_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args); + + template< typename StackAlloc, typename Fn, typename ... Args > + captured_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args); + +[variablelist +[[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().]] +] +[[Effects:] [Creates a new execution context and prepares the context to execute +`fn`.]] +] +[[Effects:] [Creates a new execution context and prepares the context to execute +`fn`. Used to store control structures on top of the stack.]] +] + +[move_constructor_heading captured_context..move constructor] + + captured_context( captured_context && other) noexcept; + +[variablelist +[[Effects:] [Moves underlying capture record to `*this`.]] +[[Throws:] [Nothing.]] +] + +[move_assignment_heading captured_context..move assignment] + + captured_context & operator=( captured_context && other) noexcept; + +[variablelist +[[Effects:] [Moves the state of `other` to `*this` using move semantics.]] +[[Throws:] [Nothing.]] +] + +[operator_heading captured_context..operator_bool..operator bool] + + explicit operator bool() const noexcept; + +[variablelist +[[Returns:] [`true` if `*this` points to a capture record.]] +[[Throws:] [Nothing.]] +] + +[operator_heading captured_context..operator_not..operator!] + + bool operator!() const noexcept; + +[variablelist +[[Returns:] [`true` if `*this` does not point to a capture record.]] +[[Throws:] [Nothing.]] +] + +[operator_heading captured_context..operator_call..operator()] + + std::tuple< captured_context, void * > operator()( void * data = nullptr); + + template< typename Fn, typename ... Args > + std::tuple< captured_context, void * > operator()( exec_ontop_arg_t, Fn && fn, Args && ... args); + + template< typename Fn, typename ... Args > + std::tuple< captured_context, void * > operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args); + +[variablelist +[[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 `captured_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 `captured_context::current()` +returns `*this` (e.g. resuming an already running context). If the top-level context +function returns, `std::exit()` is called.]] +[[Returns:] [The tuple of void pointer argument passed to the most recent call to +`captured_context::operator()`, if any and a captured_context representing the context +that has been suspended .]] +] + +[operator_heading captured_context..operator_equal..operator==] + + bool operator==( captured_context const& other) const noexcept; + +[variablelist +[[Returns:] [`true` if `*this` and `other` represent the same execution context, +`false` otherwise.]] +[[Throws:] [Nothing.]] +] + +[operator_heading captured_context..operator_notequal..operator!=] + + bool operator!=( captured_context const& other) const noexcept; + +[variablelist +[[Returns:] [[`! (other == * this)]]] +[[Throws:] [Nothing.]] +] + +[operator_heading captured_context..operator_less..operator<] + + bool operator<( captured_context const& other) const noexcept; + +[variablelist +[[Returns:] [`true` if `*this != other` is true and the +implementation-defined total order of `captured_context` values places `*this` before +`other`, false otherwise.]] +[[Throws:] [Nothing.]] +] + +[operator_heading captured_context..operator_greater..operator>] + + bool operator>( captured_context const& other) const noexcept; + +[variablelist +[[Returns:] [`other < * this`]] +[[Throws:] [Nothing.]] +] + +[operator_heading captured_context..operator_lesseq..operator<=] + + bool operator<=( captured_context const& other) const noexcept; + +[variablelist +[[Returns:] [`! (other < * this)`]] +[[Throws:] [Nothing.]] +] + +[operator_heading captured_context..operator_greatereq..operator>=] + + bool operator>=( captured_context const& other) const noexcept; + +[variablelist +[[Returns:] [`! (* this < other)`]] +[[Throws:] [Nothing.]] +] + +[hding captured_context..Non-member function [`operator<<()]] + + template< typename charT, class traitsT > + std::basic_ostream< charT, traitsT > & + operator<<( std::basic_ostream< charT, traitsT > & os, captured_context const& other); + +[variablelist +[[Efects:] [Writes the representation of `other` to stream `os`.]] +[[Returns:] [`os`]] +] + + +[endsect] diff --git a/doc/context.qbk b/doc/context.qbk index 7c80f7e..37d695e 100644 --- a/doc/context.qbk +++ b/doc/context.qbk @@ -23,10 +23,84 @@ [def __boost_build__ [*Boost.Build]] [def __boost_context__ [*Boost.Context]] -[template cs_example_link[link_text] [link context.examples.enumerator [link_text]]] -[template context_link[link_text] [link context.context.context [link_text]]] -[template stack_link[link_text] [link context.stack [link_text]]] -[template preformance_link[link_text] [link context.performance [link_text]]] +[template mdash[] '''—'''] +[template superscript[exp] ''''''[exp]''''''] + +[template class_heading[class_name] +[hding class_[class_name]..Class [`[class_name]]] +] +[template class_link[class_name] [dblink class_[class_name]..[`[class_name]]]] + +[template template_heading[class_name] +[hding class_[class_name]..Template [`[class_name]<>]] +] +[template template_link[class_name] [dblink class_[class_name]..[`[class_name]<>]]] + +[template member_heading[class_name method_name] +[operator_heading [class_name]..[method_name]..[method_name]] +] +[template member_link[class_name method_name] [operator_link [class_name]..[method_name]..[method_name]]] + +[template operator_heading[class_name method_name method_text] +[hding [class_name]_[method_name]..Member function [`[method_text]]()] +] +[template operator_link[class_name method_name method_text] [dblink [class_name]_[method_name]..[`[class_name]::[method_text]()]]] + +[template template_member_heading[class_name method_name] +[hding [class_name]_[method_name]..Templated member function [`[method_name]]()] +] +[template template_member_link[class_name method_name] [member_link [class_name]..[method_name]]] + +[template static_member_heading[class_name method_name] +[hding [class_name]_[method_name]..Static member function [`[method_name]]()] +] +[template static_member_link[class_name method_name] [member_link [class_name]..[method_name]]] + +[template data_member_heading[class_name member_name] +[hding [class_name]_[member_name]..Data member [`[member_name]]] +] +[template data_member_link[class_name member_name] [dblink [class_name]_[member_name]..[`[class_name]::[member_name]]]] + +[template function_heading[function_name] +[hding [function_name]..Non-member function [`[function_name]()]] +] +[template function_link[function_name] [dblink [function_name]..[`[function_name]()]]] + +[template ns_function_heading[namespace function_name] +[hding [namespace]_[function_name]..Non-member function [`[namespace]::[function_name]()]] +] +[template ns_function_link[namespace function_name] [dblink [namespace]_[function_name]..[`[namespace]::[function_name]()]]] + +[template constructor_heading[class_name constructor_name] +[hding [class_name]_[constructor_name]..Constructor] +] + +[template copy_constructor_heading[class_name copy_constructor_name] +[hding [class_name]_[copy_constructor_name]..Copy constructor] +] + +[template move_constructor_heading[class_name move_constructor_name] +[hding [class_name]_[move_constructor_name]..Move constructor] +] + +[template copy_assignment_heading[class_name copy_assignment_name] +[hding [class_name]_[copy_assignment_name]..Copy assignment operator] +] + +[template move_assignment_heading[class_name move_assignment_name] +[hding [class_name]_[move_assignment_name]..Move assignment operator] +] + +[template anchor[name] ''''''] +[template hding[name title] +''' + + '''[title]''' +''' +] +[template dblink[id text] ''''''[text]''''''] +[template `[text] ''''''[text]''''''] + [def __context_fn__ ['context-function]] [def __coroutine__ ['coroutine]] @@ -35,14 +109,16 @@ [def __fls__ ['fiber-local storage]] [def __guard_page__ ['guard-page]] [def __not_a_context__ ['not-a-context]] -[def __stack__ [stack_link ['stack]]] +[def __stack__ ['stack]] [def __thread__ ['thread]] [def __threads__ ['threads]] [def __tls__ ['thread-local storage]] +[def __toe__ ['thread-of-execution]] [def __stack_allocator__ ['StackAllocator]] [def __stack_allocator_concept__ ['stack-allocator concept]] [def __stack_traits__ ['stack-traits]] +[def __ccontext__ ['captured_context]] [def __econtext__ ['execution_context]] [def __fcontext__ ['fcontext_t]] [def __ucontext__ ['ucontext_t]] @@ -55,6 +131,8 @@ [def __fls_free__ ['::FlsFree()]] [def __bad_alloc__ ['std::bad_alloc]] +[def __cc_op__ ['captured_context::operator()]] +[def __ec_current__ ['execution_context::current()]] [def __ec_op__ ['execution_context::operator()]] [def __fc_base__ ['fc_base]] [def __fc_link__ ['fc_link]] @@ -70,9 +148,11 @@ [include overview.qbk] [include requirements.qbk] -[include fcontext.qbk] +[/[include fcontext.qbk]] [include execution_context.qbk] +[include captured_context.qbk] [include stack.qbk] +[include preallocated.qbk] [include performance.qbk] [include architectures.qbk] [include rationale.qbk] diff --git a/doc/context.xml b/doc/context.xml index fb3525b..2f09b8f 100644 --- a/doc/context.xml +++ b/doc/context.xml @@ -1,6 +1,6 @@ - @@ -30,21 +30,22 @@ provides a sort of cooperative multitasking on a single thread. By providing an abstraction of the current execution state in the current thread, including the stack (with local variables) and stack pointer, all registers and CPU flags, - and the instruction pointer, a fcontext_t instance represents - a specific point in the application's execution path. This is useful for building - higher-level abstractions, like coroutines, cooperative - threads (userland threads) or an equivalent to C# + and the instruction pointer, a execution_context or captured_context + instance represents a specific point in the application's execution path. This + is useful for building higher-level abstractions, like coroutines, + cooperative threads (userland threads) or an equivalent + to C# keyword yield in C++. - A fcontext_t provides the means to suspend the current - execution path and to transfer execution control, thereby permitting another - fcontext_t to run on the current thread. This state full - transfer mechanism enables a fcontext_t to suspend execution - from within nested functions and, later, to resume from where it was suspended. - While the execution path represented by a fcontext_t only - runs on a single thread, it can be migrated to another thread at any given - time. + execution_context and captured_context + provide the means to suspend the current execution path and to transfer execution + control, thereby permitting another context to run on the current thread. This + state full transfer mechanism enables a context to suspend execution from within + nested functions and, later, to resume from where it was suspended. While the + execution path represented by a execution_context or + captured_context only runs on a single thread, it can + be migrated to another thread at any given time. A context switch between threads requires system calls (involving the OS kernel), @@ -65,6 +66,11 @@ All functions and classes are contained in the namespace boost::context. + + + execution_context requires C++11! + +
<link linkend="context.requirements">Requirements</link> @@ -108,383 +114,76 @@
-
- <link linkend="context.context">Struct fcontext_t</link> - - Each instance of fcontext_t represents a context (CPU - registers and stack space). Together with its related functions jump_fcontext() - and make_fcontext() it provides a execution control transfer - mechanism similar interface like ucontext_t. - fcontext_t and its functions are located in boost::context - and the functions are declared as extern "C". - - - - If fcontext_t is used in a multi threaded application, - it can migrated between threads, but must not reference thread-local - storage. - - - - - The low level API is the part to port to new platforms. - - - - - If fiber-local storage is used on Windows, the user - is responsible for calling ::FlsAlloc(), ::FlsFree(). - - - - Executing - a context - - - A new context supposed to execute a context-function (returning - void and accepting intptr_t as argument) will be created on top of the stack - (at 16 byte boundary) by function make_fcontext(). - -// context-function -void f(intptr); - -// creates a new stack -std::size_t size = 8192; -void* sp(std::malloc(size)); - -// context fc uses f() as context function -// fcontext_t is placed on top of context stack -// a pointer to fcontext_t is returned -fcontext_t fc(make_fcontext(sp,size,f)); - - - Calling jump_fcontext() invokes the context-function - in a newly created context complete with registers, flags, stack and instruction - pointers. When control should be returned to the original calling context, - call jump_fcontext(). The current context information - (registers, flags, and stack and instruction pointers) is saved and the original - context information is restored. Calling jump_fcontext() - again resumes execution in the second context after saving the new state of - the original context. - -boost::context::fcontext_t fcm,fc1,fc2; - -void f1(intptr_t) -{ - std::cout<<"f1: entered"<<std::endl; - std::cout<<"f1: call jump_fcontext( & fc1, fc2, 0)"<< std::endl; - boost::context::jump_fcontext(&fc1,fc2,0); - std::cout<<"f1: return"<<std::endl; - boost::context::jump_fcontext(&fc1,fcm,0); -} - -void f2(intptr_t) -{ - std::cout<<"f2: entered"<<std::endl; - std::cout<<"f2: call jump_fcontext( & fc2, fc1, 0)"<<std::endl; - boost::context::jump_fcontext(&fc2,fc1,0); - BOOST_ASSERT(false&&!"f2: never returns"); -} - -std::size_t size(8192); -void* sp1(std::malloc(size)); -void* sp2(std::malloc(size)); - -fc1=boost::context::make_fcontext(sp1,size,f1); -fc2=boost::context::make_fcontext(sp2,size,f2); - -std::cout<<"main: call jump_fcontext( & fcm, fc1, 0)"<<std::endl; -boost::context::jump_fcontext(&fcm,fc1,0); - -output: - main: call jump_fcontext( & fcm, fc1, 0) - f1: entered - f1: call jump_fcontext( & fc1, fc2, 0) - f2: entered - f2: call jump_fcontext( & fc2, fc1, 0) - f1: return - - - First call of jump_fcontext() enters the context-function - f1() - by starting context fc1 (context fcm saves the registers of main()). For jumping between context's fc1 and fc2 - jump_fcontext() - is called. Because context fcm is chained to fc1, main() is entered (returning from jump_fcontext()) - after context fc1 becomes complete (return from f1()). - - - - Calling jump_fcontext() to the same context from inside - the same context results in undefined behaviour. - - - - - The size of the stack is required to be larger than the size of fcontext_t. - - - - - In contrast to threads, which are preemtive, fcontext_t - switches are cooperative (programmer controls when switch will happen). The - kernel is not involved in the context switches. - - - - Transfer - of data - - - The third argument passed to jump_fcontext(), in one context, - is passed as the first argument of the context-function - if the context is started for the first time. In all following invocations - of jump_fcontext() the intptr_t passed to jump_fcontext(), - in one context, is returned by jump_fcontext() in the - other context. - -boost::context::fcontext_t fcm,fc; - -typedef std::pair<int,int> pair_t; - -void f(intptr_t param) -{ - pair_t* p=(pair_t*)param; - p=(pair_t*)boost::context::jump_fcontext(&fc,fcm,(intptr_t)(p->first+p->second)); - boost::context::jump_fcontext(&fc,fcm,(intptr_t)(p->first+p->second)); -} - -std::size_t size(8192); -void* sp(std::malloc(size)); - -pair_t p(std::make_pair(2,7)); -fc=boost::context::make_fcontext(sp,size,f); - -int res=(int)boost::context::jump_fcontext(&fcm,fc,(intptr_t)&p); -std::cout<<p.first<<" + "<<p.second<<" == "<<res<<std::endl; - -p=std::make_pair(5,6); -res=(int)boost::context::jump_fcontext(&fcm,fc,(intptr_t)&p); -std::cout<<p.first<<" + "<<p.second<<" == "<<res<<std::endl; - -output: - 2 + 7 == 9 - 5 + 6 == 11 - - - Exceptions - in context-function - - - If the context-function emits an exception, the behaviour - is undefined. - - - - context-function should wrap the code in a try/catch - block. - - - - - Do not jump from inside a catch block and then re-throw the exception in - another execution context. - - - - Preserving - floating point registers - - - Preserving the floating point registers increases the cycle count for a context - switch (see performance tests). The fourth argument of jump_fcontext() - controls if fpu registers should be preserved by the context jump. - - - - The use of the fpu controlling argument of jump_fcontext() - must be consistent in the application. Otherwise the behaviour is undefined. - - - - 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. - - - fcontext_t and related functions - -struct stack_t -{ - void* sp; - std::size_t size; -}; - -typedef <opaque pointer > fcontext_t; - -intptr_t jump_fcontext(fcontext_t* ofc,fcontext_t nfc,intptr_t vp,bool preserve_fpu=true); -fcontext_t make_fcontext(void* sp,std::size_t size,void(*fn)(intptr_t)); - - - sp - - - - - Member: - - - Pointer to the beginning of the stack (depending of the architecture - the stack grows downwards or upwards). - - - - - - size - - - - - Member: - - - Size of the stack in bytes. - - - - - - fc_stack - - - - - Member: - - - Tracks the memory for the context's stack. - - - - - - intptr_t jump_fcontext(fcontext_t* ofc,fcontext_t nfc,intptr_t p,bool - preserve_fpu=true) - - - - - Effects: - - - Stores the current context data (stack pointer, instruction pointer, - and CPU registers) to *ofc and restores the context data from - nfc, which implies jumping - to nfc's execution context. - The intptr_t argument, p, - is passed to the current context to be returned by the most recent call - to jump_fcontext() - in the same thread. The last argument controls if fpu registers have - to be preserved. - - - - - Returns: - - - The third pointer argument passed to the most recent call to jump_fcontext(), - if any. - - - - - - fcontext_t make_fcontext(void* - sp,std::size_t - size,void(*fn)(intptr_t)) - - - - - Precondition: - - - Stack sp and function - pointer fn are valid - (depending on the architecture sp - points to the top or bottom of the stack) and size - > 0. - - - - - Effects: - - - Creates an fcontext_t on top of the stack and prepares the stack to execute - the context-function fn. - - - - - Returns: - - - Returns a fcontext_t which is placed on the stack. - - - - -
- <link linkend="context.econtext">Class execution_context</link> - - - execution_context requires C++14. - - + <anchor id="econtext"/><link linkend="context.econtext">Class execution_context</link> 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(). + and manages the 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 controls the life + time of the 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 + (smart pointer), accessed by execution_context::current(), + pointing to the active context. On each context switch the static thread-local + 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 need + to call certain maintenance functions (__splitstack_getcontext() etc.) before + each context switch (each context switch exchanges the stack). Additionally + the destruction of execution_context and thus the stack + deallocation is faster compared to captured_context. + + + execution_context expects a function/functor with signature + void(void* vp) ( vp + is the data passed at the first invocation of execution_context::operator()()). + + + usage + of execution_context + +int n=35; +int p=0; +boost::context::execution_context mctx( boost::context::execution_context::current() ); +boost::context::execution_context ctx( + [n,&p,&mctx](void*)mutable{ + int a=0; + int b=1; + while(n-->0){ + yield(a); + auto next=a+b; + a=b; + b=next; + } + }); +for(int i=0;i<10;++i){ + ctx(); + std::cout<<p<<" "; +} + +output: + 0 1 1 2 3 5 8 13 21 34 + + + inverting + the control flow + /* * grammar: * P ---> E '\0' @@ -569,7 +268,7 @@ 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 @@ -610,7 +309,7 @@ ... }; - + exception handling @@ -620,7 +319,7 @@ std::exception_ptr can be used to transfer exceptions between different execution contexts. - + parameter passing @@ -662,13 +361,13 @@ } }; -int main() { - X x; - std::cout << x( 7) << std::endl; - std::cout << "done" << std::endl; -} +X x; +std::cout << x( 7) << std::endl; + +output: + 7 - + Class execution_context @@ -695,7 +394,13 @@ explicit operator bool() const noexcept; bool operator!() const noexcept; - void * operator()( void * vp = nullptr) noexcept; + void * operator()( void * vp = nullptr); + + template< typename Fn, typename ... Args > + void * operator()( exec_ontop_arg_t, Fn && fn, Args && ... args); + + template< typename Fn, typename ... Args > + void * operator()( void * vp, exec_ontop_arg_t, Fn && fn, Args && ... args); bool operator==( execution_context const& other) const noexcept; @@ -714,12 +419,15 @@ operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other); }; - - static execution_context - current() - + + + + Static + member function current() + + +static execution_context current() noexcept; + @@ -740,20 +448,21 @@ - - template< typname Fn, typename ... Args > execution_context( Fn && - fn, Args && - ... args) - + + + + Constructor + + +template< typename Fn, typename ... Args > +execution_context( Fn && fn, Args && ... args); + +template< typename StackAlloc, typename Fn, typename ... Args > +execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args); + +template< typename StackAlloc, typename Fn, typename ... Args > +execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args); + @@ -767,76 +476,20 @@ - - template< typename StackAlloc, typname Fn, typename - ... Args - > execution_context( std::allocator_arg_t, - StackAlloc salloc, Fn && - fn, Args && - ... args) - - - - - Effects: - - - Creates a new execution context and prepares the context to execute - fn. - - - - - - template< typename StackAlloc, typname Fn, typename - ... Args - > execution_context( std::allocator_arg_t, - 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. - - - - - - execution_context( - execution_context const& other) - + + [[Effects:] [Creates a new execution context and prepares the context to execute + fn. Used to store control structures + on top of the stack.]] ] + + + + + Copy constructor + + +execution_context( execution_context const& other) noexcept; + @@ -858,13 +511,15 @@ - - execution_context( - execution_context && - other) - + + + + Move constructor + + +execution_context( execution_context && other) noexcept; + @@ -885,15 +540,15 @@ - - execution_context & - operator=( - execution_context const& other) - + + + + Copy assignment operator + + +execution_context & operator=( execution_context const& other) noexcept; + @@ -915,14 +570,15 @@ - - execution_context & - operator=( - execution_context && - other) - + + + + Move assignment operator + + +execution_context & operator=( execution_context && other) noexcept; + @@ -944,13 +600,15 @@ - - explicit operator - bool() const noexcept - + + + + Member + function operator bool() + + +explicit operator bool() const noexcept; + @@ -971,12 +629,15 @@ - - bool operator!() const noexcept - + + + + Member + function operator!() + + +bool operator!() const noexcept; + @@ -997,14 +658,21 @@ - - void * operator()( void * - vp) noexcept - + + + + Member + function operator()() + + +void * operator()( void * vp = nullptr) noexcept; + +template< typename Fn, typename ... Args > +void * operator()( exec_ontop_arg_t, Fn && fn, Args && ... args); + +template< typename Fn, typename ... Args > +void * operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args); + @@ -1012,15 +680,18 @@ Stores internally the current context data (stack pointer, instruction - pointer, and CPU registers) to the current active context and restores + pointer, and CPU registers) of the current active context and restores the context data from *this, which implies jumping to *this's - execution context. The void pointer argument, vp, + 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. [[Note: + role="special">() in the same thread. fn + is executed with arguments args + on top of the stack of this. + [[Note: The behaviour is undefined if operator - - Throws: - - - Nothing. - - - - - operator== - + + + + Member + function operator==() + + bool operator==( execution_context const& other) const noexcept; @@ -1083,10 +748,13 @@ - - operator!= - + + + + Member + function operator!=() + + bool operator!=( execution_context const& other) const noexcept; @@ -1095,19 +763,26 @@ Returns: - [`! (other == * this) + ! (other == * this) + + + + + Throws: + + + Nothing. - [[Throws:] [Nothing.]] ] + + + Member + function operator<() + - - operator< - bool operator<( execution_context const& other) const noexcept; @@ -1134,11 +809,13 @@ - - operator> - + + + + Member + function operator>() + + bool operator>( execution_context const& other) const noexcept; @@ -1161,11 +838,13 @@ - - operator<= - + + + + Member + function operator<=() + + bool operator<=( execution_context const& other) const noexcept; @@ -1190,11 +869,13 @@ - - operator>= - + + + + Member + function operator>=() + + bool operator>=( execution_context const& other) const noexcept; @@ -1218,11 +899,13 @@ - - operator<< - + + + + Non-member function + operator<<() + + template< typename charT, class traitsT > std::basic_ostream< charT, traitsT > & operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other); @@ -1247,65 +930,722 @@ - - Struct - preallocated +
+
+ <anchor id="ccontext"/><link linkend="context.ccontext">Class captured_context</link> + + Class captured_context encapsulates fcontext_t + and manages the context' stack (allocation/deallocation). + + + captured_context allocates the context stack (using its + StackAllocator argument) and creates a control structure + on top of it. This structure controls the life time of the stack. The address + of the control structure is stored in the first frame of context' stack (e.g. + it can not accessed by instances of captured_context directly). + In contrast to execution_context the ownership of the + control structure is not shared A call ofcaptured_context::operator() + enters the context represented by *this and invalidates *this. The context that has been suspended by + calling captured_context::operator() is passed to the + resumed context, e.g. as argument of the context-function if the context was + resumed the first time or returned by captured_context::operator(). + captured_context is only move-constructible and move-assignable. + If the last reference (captured_context) goes out of scope, + the control structure is destroyed and the stack gets deallocated via the + StackAllocator. captured_context + maintains a static, thread-local pointer (smart pointer), accessed by execution_context::current(), + pointing to the active context. On each context switch the static, thread-local + pointer is updated. This makes the context switch a little bit slower, but + enables faster context destruction (stack unwinding) compared to captured_context. + + + captured_context expects a function/functor with signature + captured_context( + captured_context ctx, void * + vp). + The parameter ctx represents + the context from which this context was resumed (e.g. that has called captured_context::operator() + on *this) + and vp is the data passed to + captured_context::operator(). The function/functor has + to return the captured_context that has to be resumed, while this context terminates. + + + + Segemnted stacks are not supported together with captured_context. + + + + usage + of captured_context -struct preallocated { - void * sp; - std::size_t size; - stack_context sctx; +/* + * grammar: + * P ---> E '\0' + * E ---> T {('+'|'-') T} + * T ---> S {('*'|'/') S} + * S ---> digit | '(' E ')' + */ +class Parser{ + // implementation omitted; see examples directory +}; - preallocated( void * sp, std:size_t size, stack_allocator sctx) noexcept; +std::istringstream is("1+1"); +bool done=false; +std::exception_ptr except; + +// execute parser in new execution context +boost::context::captured_context pctx( + [&is,&done,&except](ctx::captured_context mctx,void* ignored){ + // create parser with callback function + Parser p( is, + [&mctx](char ch){ + // resume main execution context + auto result = mctx( & ch); + mctx = std::move( std::get<0>( result) ); + }); + 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 + return mctx; + }); + +// user-code pulls parsed data from parser +// invert control flow +auto result = pctx(); +pctx = std::move( std::get<0>( result) ); +void * vp = std::get<1>( result); +if ( except) { + std::rethrow_exception( except); +} +while( ! done) { + printf("Parsed: %c\n",* static_cast< char* >( vp) ); + std::tie(pctx,vp) = pctx(); + if ( except) { + std::rethrow_exception( except); + } +} + +output: + Parsed: 1 + Parsed: + + Parsed: 1 + + + In this example a recursive descent parser uses a callback to emit a newly + passed symbol. Using captured_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 captured_context. + + + If the code executed by captured_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 captured_context is created. + + + + 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 { + // captured context + captured_context cctx; + + template< typename StackAllocator > + my_control_structure( void * sp, std::size_t size, stack_context sctx, StackAllocator salloc) : + // create captured context + cctx( std::allocator_arg, preallocated( sp, size, sctx), salloc, entry_func) { + } + ... }; - - preallocated( void * sp, std:size_t size, stack_allocator - sctx) + + exception + handling + + If the function executed inside a captured_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 + + + The void pointer argument passed to captured_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 captured_context::operator() the void pointer passed + to captured_context::operator(), in one context, is returned + by captured_context::operator() in the other context. + +class X { +private: + std::exception_ptr excptr_; + boost::context::captured_context ctx_; + +public: + X() : + excptr_(), + ctx_( [=](ctx::captured_context ctx, void * vp)->ctx::captured_context{ + try { + for (;;) { + int i = * static_cast< int * >( vp); + std::string str = boost::lexical_cast<std::string>(i); + auto result = ctx( & str); + ctx = std::move( std::get<0>( result) ); + vp = std::get<1>( result); + } + } catch ( ctx::detail::forced_unwind const&) { + throw; + } catch (...) { + excptr_=std::current_exception(); + } + return ctx; + }) + {} + + std::string operator()( int i) { + auto result = ctx_( & i); + ctx_ = std::move( std::get<0>( result) ); + void * ret = std::get<1>( result); + if(excptr_){ + std::rethrow_exception(excptr_); + } + return * static_cast< std::string * >( ret); + } +}; + +X x; +std::cout << x( 7) << std::endl; + +output: +7 + + + Class + captured_context + +class captured_context { +public: + template< typename Fn, typename ... Args > + captured_context( Fn && fn, Args && ... args); + + template< typename StackAlloc, typename Fn, typename ... Args > + captured_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args); + + template< typename StackAlloc, typename Fn, typename ... Args > + captured_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args); + + ~captured_context(); + + captured_context( captured_context && other) noexcept; + captured_context & operator=( captured_context && other) noexcept; + + captured_context( captured_context const& other) noexcept = delete; + captured_context & operator=( captured_context const& other) noexcept = delete; + + explicit operator bool() const noexcept; + bool operator!() const noexcept; + + std::tuple< captured_context, void * > operator()( void * data = nullptr); + + template< typename Fn, typename ... Args > + std::tuple< captured_context, void * > operator()( exec_ontop_arg_t, Fn && fn, Args && ... args); + + template< typename Fn, typename ... Args > + std::tuple< captured_context, void * > operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args); + + bool operator==( captured_context const& other) const noexcept; + + bool operator!=( captured_context const& other) const noexcept; + + bool operator<( captured_context const& other) const noexcept; + + bool operator>( captured_context const& other) const noexcept; + + bool operator<=( captured_context const& other) const noexcept; + + bool operator>=( captured_context const& other) const noexcept; + + template< typename charT, class traitsT > + friend std::basic_ostream< charT, traitsT > & + operator<<( std::basic_ostream< charT, traitsT > & os, captured_context const& other); +}; + + + + + Constructor + + +template< typename Fn, typename ... Args > +captured_context( Fn && fn, Args && ... args); + +template< typename StackAlloc, typename Fn, typename ... Args > +captured_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args); + +template< typename StackAlloc, typename Fn, typename ... Args > +captured_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args); + Effects: - Creates an object of preallocated. + 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(). + + + + + + [[Effects:] [Creates a new execution context and prepares the context to execute + fn.]] ] [[Effects:] [Creates + a new execution context and prepares the context to execute fn. + Used to store control structures on top of the stack.]] ] + + + + + Move constructor + + +captured_context( captured_context && other) noexcept; + + + + + Effects: + + + Moves underlying capture record to *this. + + + + + Throws: + + + Nothing. + + + + + + + + Move assignment operator + + +captured_context & operator=( captured_context && other) noexcept; + + + + + Effects: + + + Moves the state of other + to *this + using move semantics. + + + + + Throws: + + + Nothing. + + + + + + + + Member + function operator bool() + + +explicit operator bool() const noexcept; + + + + + Returns: + + + true if *this points to a capture record. + + + + + Throws: + + + Nothing. + + + + + + + + Member + function operator!() + + +bool operator!() const noexcept; + + + + + Returns: + + + true if *this does not point to a capture record. + + + + + Throws: + + + Nothing. + + + + + + + + Member + function operator()() + + +std::tuple< captured_context, void * > operator()( void * data = nullptr); + +template< typename Fn, typename ... Args > +std::tuple< captured_context, void * > operator()( exec_ontop_arg_t, Fn && fn, Args && ... args); + +template< typename Fn, typename ... Args > +std::tuple< captured_context, void * > operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args); + + + + + 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 captured_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 captured_context::current() returns *this (e.g. resuming an already running + context). If the top-level context function returns, std::exit() is called. + + + + + Returns: + + + The tuple of void pointer argument passed to the most recent call to + captured_context::operator(), + if any and a captured_context representing the context that has been + suspended . + + + + + + + + Member + function operator==() + + +bool operator==( captured_context const& other) const noexcept; + + + + + Returns: + + + true if *this and other + represent the same execution context, false + otherwise. + + + + + Throws: + + + Nothing. + + + + + + + + Member + function operator!=() + + +bool operator!=( captured_context const& other) const noexcept; + + + + + Returns: + + + ! (other == * this) + + + + + Throws: + + + Nothing. + + + + + + + + Member + function operator<() + + +bool operator<( captured_context const& other) const noexcept; + + + + + Returns: + + + true if *this != other is true and the implementation-defined + total order of captured_context + values places *this + before other, false otherwise. + + + + + Throws: + + + Nothing. + + + + + + + + Member + function operator>() + + +bool operator>( captured_context const& other) const noexcept; + + + + + Returns: + + + other < + * this + + + + + Throws: + + + Nothing. + + + + + + + + Member + function operator<=() + + +bool operator<=( captured_context const& other) const noexcept; + + + + + Returns: + + + ! (other < + * this) + + + + + Throws: + + + Nothing. + + + + + + + + Member + function operator>=() + + +bool operator>=( captured_context const& other) const noexcept; + + + + + Returns: + + + ! (* + this < + other) + + + + + Throws: + + + Nothing. + + + + + + + + Non-member function + operator<<() + + +template< typename charT, class traitsT > +std::basic_ostream< charT, traitsT > & +operator<<( std::basic_ostream< charT, traitsT > & os, captured_context const& other); + + + + + Efects: + + + Writes the representation of other + to stream os. + + + + + Returns: + + + os -
- <link linkend="context.econtext.winfibers">Using WinFiber-API</link> - - Because the TIB (thread information block) is not fully described in the - MSDN, it might be possible that not all required TIB-parts are swapped. With - compiler flag BOOST_USE_WINFIBERS - execution_context uses internally - the Windows Fiber API. - - - - The first call of execution_context::operator() converts the thread into a Windows fiber - by invoking ConvertThreadToFiber(). If desired, ConvertFiberToThread() has to be called by the user explicitly - in order to release resources allocated by ConvertThreadToFiber() (e.g. after using boost.context). - - -
- <link linkend="context.stack">Stack allocation</link> + <anchor id="stack"/><link linkend="context.stack">Stack allocation</link> The memory used by the stack is allocated/deallocated via a StackAllocator which is required to model a stack-allocator concept. @@ -2017,6 +2357,33 @@
+
+ <link linkend="context.struct__preallocated_">Struct <code><phrase role="identifier">preallocated</phrase></code></link> +struct preallocated { + void * sp; + std::size_t size; + stack_context sctx; + + preallocated( void * sp, std:size_t size, stack_allocator sctx) noexcept; +}; + + + Constructor + +preallocated( void * sp, std:size_t size, stack_allocator sctx) noexcept; + + + + + Effects: + + + Creates an object of preallocated. + + + + +
<link linkend="context.performance">Performance</link> @@ -2031,7 +2398,7 @@ Performance of context switch - + @@ -2044,11 +2411,6 @@ ucontext_t - - - fcontext_t - - execution_context @@ -2056,7 +2418,7 @@ - windows fibers + captured_context @@ -2065,38 +2427,7 @@ - i386 - - AMD Athlon 64 DualCore 4400+ - - - - - - - 708 ns / 754 cycles - - - - - 37 ns / 37 cycles - - - - - ns / cycles - - - - - ns / cycles - - - - - - - x86_64 + x86_64 Intel Core2 Q6700 @@ -2110,17 +2441,12 @@ - 8 ns / 23 cycles + 51 ns / 141 cycles - 16 ns / 46 cycles - - - - - ns / cycles + 7 ns / 18 cycles diff --git a/doc/execution_context.qbk b/doc/execution_context.qbk index 9936163..00a0c17 100644 --- a/doc/execution_context.qbk +++ b/doc/execution_context.qbk @@ -5,14 +5,66 @@ http://www.boost.org/LICENSE_1_0.txt ] +[#econtext] [section:econtext Class execution_context] -[important __econtext__ requires C++11!] +Class __econtext__ encapsulates __fcontext__ and manages the context' stack +(allocation/deallocation). -Class __econtext__ encapsulates __fcontext__ and related functions ( -__jump_fcontext__ and __make_fcontext__) as well as stack management. -__econtext__ permits access to the current, active context via -`execution_context::current()`. +__econtext__ allocates the context stack (using its [link stack __stack_allocator__] +argument) and creates a control structure on top of it. This structure +controls the life time of the stack. Instances of __econtext__, 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 __stack_allocator__. + +__econtext__ is copy-constructible, move-constructible, copy-assignable and +move-assignable. + +__econtext__ maintains a static, thread-local pointer (smart pointer), +accessed by __ec_current__, pointing to the active context. +On each context switch the static thread-local 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 need to call certain +maintenance functions (__splitstack_getcontext() etc.) before each context switch +(each context switch exchanges the stack). +Additionally the destruction of __econtext__ and thus the stack deallocation is +faster compared to [link ccontext __ccontext__]. + +__econtext__ expects a function/functor with signature `void(void* vp)` ( +`vp` is the data passed at the first invocation of +[operator_link execution_context operator_call operator()]). + + +[heading usage of __econtext__] + + int n=35; + int p=0; + boost::context::execution_context mctx( boost::context::execution_context::current() ); + boost::context::execution_context ctx( + [n,&p,&mctx](void*)mutable{ + int a=0; + int b=1; + while(n-->0){ + yield(a); + auto next=a+b; + a=b; + b=next; + } + }); + for(int i=0;i<10;++i){ + ctx(); + std::cout< + void * operator()( exec_ontop_arg_t, Fn && fn, Args && ... args); + + template< typename Fn, typename ... Args > + void * operator()( void * vp, exec_ontop_arg_t, Fn && fn, Args && ... args); bool operator==( execution_context const& other) const noexcept; bool operator!=( execution_context const& other) const noexcept; - + bool operator<( execution_context const& other) const noexcept; - + bool operator>( execution_context const& other) const noexcept; - + bool operator<=( execution_context const& other) const noexcept; - + bool operator>=( execution_context const& other) const noexcept; template< typename charT, class traitsT > @@ -219,87 +277,128 @@ __ec_op__, in one context, is returned by __ec_op__ in the other context. operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other); }; -[heading `static execution_context current()`] +[static_member_heading execution_context..current] + + static execution_context current() noexcept; + [variablelist [[Returns:] [Returns an instance of excution_context pointing to the active execution context.]] [[Throws:] [Nothing.]] ] -[heading `template< typname Fn, typename ... Args > execution_context( Fn && fn, Args && ... args)`] +[constructor_heading execution_context..constructor] + + template< typename Fn, typename ... Args > + execution_context( Fn && fn, Args && ... args); + + template< typename StackAlloc, typename Fn, typename ... Args > + execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args); + + template< typename StackAlloc, typename Fn, typename ... Args > + execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args); + [variablelist [[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().]] +`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 store control +structures on top of the stack.]] ] -[heading `template< typename StackAlloc, typname Fn, typename ... Args > execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args)`] -[variablelist -[[Effects:] [Creates a new execution context and prepares the context to execute -`fn`.]] -] +[copy_constructor_heading execution_context..copy constructor] -[heading `template< typename StackAlloc, typname Fn, typename ... Args > execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args)`] -[variablelist -[[Effects:] [Creates a new execution context and prepares the context to execute -`fn`. Used to store control structures on top of the stack.]] -] + execution_context( execution_context const& other) noexcept; -[heading `execution_context( execution_context const& other)`] [variablelist [[Effects:] [Copies `other`, e.g. underlying capture record is shared with `*this`.]] [[Throws:] [Nothing.]] ] -[heading `execution_context( execution_context && other)`] +[move_constructor_heading execution_context..move constructor] + + execution_context( execution_context && other) noexcept; + [variablelist [[Effects:] [Moves underlying capture record to `*this`.]] [[Throws:] [Nothing.]] ] -[heading `execution_context & operator=( execution_context const& other)`] +[copy_assignment_heading execution_context..copy assignment] + + execution_context & operator=( execution_context const& other) noexcept; + [variablelist [[Effects:] [Copies the state of `other` to `*this`, state (capture record) is shared.]] [[Throws:] [Nothing.]] ] -[heading `execution_context & operator=( execution_context && other)`] +[move_assignment_heading execution_context..move assignment] + + execution_context & operator=( execution_context && other) noexcept; + [variablelist [[Effects:] [Moves the state of `other` to `*this` using move semantics.]] [[Throws:] [Nothing.]] ] -[heading `explicit operator bool() const noexcept`] +[operator_heading execution_context..operator_bool..operator bool] + + explicit operator bool() const noexcept; + [variablelist [[Returns:] [`true` if `*this` points to a capture record.]] [[Throws:] [Nothing.]] ] -[heading `bool operator!() const noexcept`] +[operator_heading execution_context..operator_not..operator!] + + bool operator!() const noexcept; + [variablelist [[Returns:] [`true` if `*this` does not point to a capture record.]] [[Throws:] [Nothing.]] ] -[heading `void * operator()( void * vp) noexcept`] +[operator_heading execution_context..operator_call..operator()] + + void * operator()( void * vp = nullptr) noexcept; + [variablelist [[Effects:] [Stores internally the current context data (stack pointer, -instruction pointer, and CPU registers) to the current active context and +instruction pointer, and CPU registers) of the current active context and restores the context data from `*this`, which implies jumping to `*this`'s -execution context. +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.]] -[[Throws:] [Nothing.]] ] -[heading `operator==`] +[operator_heading execution_context..operator_call..operator(exec_ontop_arg_t)] - bool operator==( execution_context const& other) const noexcept; + template< typename Fn, typename ... Args > + void * operator()( exec_ontop_arg_t, Fn && fn, Args && ... args); + + template< typename Fn, typename ... Args > + void * operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args); + +[variablelist +[[Effects:] [Same as `operator()(void*)`, additionally function `fn` is executed +with arguments `args` 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.]] +] + +[operator_heading execution_context..operator_equal..operator==] + + bool operator==( execution_context const& other) const noexcept; [variablelist [[Returns:] [`true` if `*this` and `other` represent the same execution context, @@ -307,18 +406,18 @@ function returns, `std::exit()` is called.]] [[Throws:] [Nothing.]] ] -[heading `operator!=`] +[operator_heading execution_context..operator_notequal..operator!=] - bool operator!=( execution_context const& other) const noexcept; + bool operator!=( execution_context const& other) const noexcept; [variablelist [[Returns:] [[`! (other == * this)]]] [[Throws:] [Nothing.]] ] -[heading `operator<`] +[operator_heading execution_context..operator_less..operator<] - bool operator<( execution_context const& other) const noexcept; + bool operator<( execution_context const& other) const noexcept; [variablelist [[Returns:] [`true` if `*this != other` is true and the @@ -327,38 +426,38 @@ implementation-defined total order of `execution_context` values places `*this` [[Throws:] [Nothing.]] ] -[heading `operator>`] +[operator_heading execution_context..operator_greater..operator>] - bool operator>( execution_context const& other) const noexcept; + bool operator>( execution_context const& other) const noexcept; [variablelist [[Returns:] [`other < * this`]] [[Throws:] [Nothing.]] ] -[heading `operator<=`] +[operator_heading execution_context..operator_lesseq..operator<=] - bool operator<=( execution_context const& other) const noexcept; + bool operator<=( execution_context const& other) const noexcept; [variablelist [[Returns:] [`! (other < * this)`]] [[Throws:] [Nothing.]] ] -[heading `operator>=`] +[operator_heading execution_context..operator_greatereq..operator>=] - bool operator>=( execution_context const& other) const noexcept; + bool operator>=( execution_context const& other) const noexcept; [variablelist [[Returns:] [`! (* this < other)`]] [[Throws:] [Nothing.]] ] -[heading `operator<<`] +[hding execution_context..Non-member function [`operator<<()]] - template< typename charT, class traitsT > - std::basic_ostream< charT, traitsT > & - operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other); + template< typename charT, class traitsT > + std::basic_ostream< charT, traitsT > & + operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other); [variablelist [[Efects:] [Writes the representation of `other` to stream `os`.]] @@ -366,20 +465,4 @@ implementation-defined total order of `execution_context` values places `*this` ] -[heading Struct `preallocated`] - - struct preallocated { - void * sp; - std::size_t size; - stack_context sctx; - - preallocated( void * sp, std:size_t size, stack_allocator sctx) noexcept; - }; - -[heading `preallocated( void * sp, std:size_t size, stack_allocator sctx)`] -[variablelist -[[Effects:] [Creates an object of preallocated.]] -] - - [endsect] diff --git a/doc/fcontext.qbk b/doc/fcontext.qbk index d4a6f3b..2b6f3ed 100644 --- a/doc/fcontext.qbk +++ b/doc/fcontext.qbk @@ -187,11 +187,11 @@ downwards or upwards).]] [[Member:] [Tracks the memory for the context's stack.]] ] -[heading `void * jump_fcontext(fcontext_t* ofc,fcontext_t nfc,void * p) +[heading `void * jump_fcontext(fcontext_t* ofc,fcontext_t nfc,void * p)`] [variablelist [[Effects:] [Stores the current context data (stack pointer, instruction pointer, and CPU registers) to `*ofc` and restores the context data from `nfc`, -which implies jumping to `nfc`'s execution context. The void * argument, `p`, +which implies jumping to execution context `nfc`. The void * argument, `p`, is passed to the current context to be returned by the most recent call to `jump_fcontext()` in the same thread.]] [[Returns:] [The third pointer argument passed to the most recent call to diff --git a/doc/html/context/abstract_context.html b/doc/html/context/abstract_context.html new file mode 100644 index 0000000..8deea6b --- /dev/null +++ b/doc/html/context/abstract_context.html @@ -0,0 +1,72 @@ + + + +Context classes + + + + + + + + +
+ + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ + +

+ Boost.Context provides two classes encapsulating + fcontext_t and related functions (jump_fcontext() + and make_fcontext()) and stack management - execution_context + and captured_context. execution_context + and captured_context represent one thread-of-execution. + A thread-of-execution is a single flow of control within + a programm. Each class maintains a control structure, containing the preserved + registers, the stack and the stack allocator. The main difference between + execution_context and captured_context + consists in maintaining context' control structure. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/context/abstract_context/ccontext.html b/doc/html/context/abstract_context/ccontext.html new file mode 100644 index 0000000..2136703 --- /dev/null +++ b/doc/html/context/abstract_context/ccontext.html @@ -0,0 +1,739 @@ + + + +Class captured_context + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +
+ + + + + +
[Important]Important

+ captured_context requires C++11! +

+

+ Class captured_context encapsulates fcontext_t + and manages the context' stack (allocation/deallocation). +

+

+ captured_context allocates the context stack (using + its StackAllocator argument) and creates a control structure + on top of it. This structure controls the life time of the stack. The address + of the control structure is stored in the first frame of context' stack (e.g. + it can not accessed by instances of captured_context + directly). In contrast to execution_context the ownership + of the control structure is not shared A call ofcaptured_context::operator() + enters the context represented by *this and invalidates *this. The context that has been suspended + by calling captured_context::operator() is passed to + the resumed context, e.g. as argument of the context-function if the context + was resumed the first time or returned by captured_context::operator(). + captured_context is only move-constructible and move-assignable. + If the last reference (captured_context) goes out of + scope, the control structure is destroyed and the stack gets deallocated + via the StackAllocator. captured_context + maintains a static, thread-local pointer (smart pointer), accessed by execution_context::current(), + pointing to the active context. On each context switch the static, thread-local + pointer is updated. This makes the context switch a little bit slower, but + enables faster context destruction (stack unwinding) compared to captured_context. +

+

+ captured_context expects a function/functor with signature + captured_context( + captured_context ctx, void * + vp). + The parameter ctx represents + the context from which this context was resumed (e.g. that has called captured_context::operator() + on *this) + and vp is the data passed + to captured_context::operator(). The function/functor + has to return the captured_context that has to be resumed, while this context + terminates. +

+
+ + + + + +
[Important]Important

+ Segemnted stacks are not supported together with captured_context. +

+
+ + usage + of captured_context +
+
/*
+ * grammar:
+ *   P ---> E '\0'
+ *   E ---> T {('+'|'-') T}
+ *   T ---> S {('*'|'/') S}
+ *   S ---> digit | '(' E ')'
+ */
+class Parser{
+    // implementation omitted; see examples directory
+};
+
+std::istringstream is("1+1");
+bool done=false;
+std::exception_ptr except;
+
+// execute parser in new execution context
+boost::context::captured_context pctx(
+        [&is,&done,&except](ctx::captured_context mctx,void* ignored){
+        // create parser with callback function
+        Parser p( is,
+                  [&mctx](char ch){
+                        // resume main execution context
+                        auto result = mctx( & ch);
+                        mctx = std::move( std::get<0>( result) );
+                });
+            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
+            return mctx;
+        });
+
+// user-code pulls parsed data from parser
+// invert control flow
+auto result = pctx();
+pctx = std::move( std::get<0>( result) );
+void * vp = std::get<1>( result);
+if ( except) {
+    std::rethrow_exception( except);
+}
+while( ! done) {
+    printf("Parsed: %c\n",* static_cast< char* >( vp) );
+    std::tie(pctx,vp) = pctx();
+    if ( except) {
+        std::rethrow_exception( except);
+    }
+}
+
+output:
+    Parsed: 1
+    Parsed: +
+    Parsed: 1
+
+

+ In this example a recursive descent parser uses a callback to emit a newly + passed symbol. Using captured_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 captured_context. +

+

+ If the code executed by captured_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 captured_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  {
+    // captured context
+    captured_context cctx;
+
+    template< typename StackAllocator >
+    my_control_structure( void * sp, std::size_t size, stack_context sctx, StackAllocator salloc) :
+        // create captured context
+        cctx( std::allocator_arg, preallocated( sp, size, sctx), salloc, entry_func) {
+    }
+    ...
+};
+
+
+ + exception + handling +
+

+ If the function executed inside a captured_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 +
+

+ The void pointer argument passed to captured_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 captured_context::operator() the void pointer passed + to captured_context::operator(), in one context, is + returned by captured_context::operator() in the other + context. +

+
class X {
+private:
+    std::exception_ptr excptr_;
+    boost::context::captured_context ctx_;
+
+public:
+    X() :
+        excptr_(),
+        ctx_( [=](ctx::captured_context ctx, void * vp)->ctx::captured_context{
+                    try {
+                        for (;;) {
+                            int i = * static_cast< int * >( vp);
+                            std::string str = boost::lexical_cast<std::string>(i);
+                            auto result = ctx( & str);
+                            ctx = std::move( std::get<0>( result) );
+                            vp = std::get<1>( result);
+                        }
+                    } catch ( ctx::detail::forced_unwind const&) {
+                        throw;
+                    } catch (...) {
+                        excptr_=std::current_exception();
+                    }
+                    return ctx;
+              })
+    {}
+
+    std::string operator()( int i) {
+        auto result = ctx_( & i);
+        ctx_ = std::move( std::get<0>( result) );
+        void * ret = std::get<1>( result);
+        if(excptr_){
+            std::rethrow_exception(excptr_);
+        }
+        return * static_cast< std::string * >( ret);
+    }
+};
+
+X x;
+std::cout << x( 7) << std::endl;
+
+output:
+7
+
+
+ + Class + captured_context +
+
class captured_context {
+public:
+    template< typename Fn, typename ... Args >
+    captured_context( Fn && fn, Args && ... args);
+
+    template< typename StackAlloc, typename Fn, typename ... Args >
+    captured_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args);
+
+    template< typename StackAlloc, typename Fn, typename ... Args >
+    captured_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args);
+
+    ~captured_context();
+
+    captured_context( captured_context && other) noexcept;
+    captured_context & operator=( captured_context && other) noexcept;
+
+    captured_context( captured_context const& other) noexcept = delete;
+    captured_context & operator=( captured_context const& other) noexcept = delete;
+
+    explicit operator bool() const noexcept;
+    bool operator!() const noexcept;
+
+    std::tuple< captured_context, void * > operator()( void * data = nullptr);
+
+    template< typename Fn, typename ... Args >
+    std::tuple< captured_context, void * > operator()( exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+    template< typename Fn, typename ... Args >
+    std::tuple< captured_context, void * > operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+    bool operator==( captured_context const& other) const noexcept;
+
+    bool operator!=( captured_context const& other) const noexcept;
+
+    bool operator<( captured_context const& other) const noexcept;
+
+    bool operator>( captured_context const& other) const noexcept;
+
+    bool operator<=( captured_context const& other) const noexcept;
+
+    bool operator>=( captured_context const& other) const noexcept;
+
+    template< typename charT, class traitsT >
+    friend std::basic_ostream< charT, traitsT > &
+    operator<<( std::basic_ostream< charT, traitsT > & os, captured_context const& other);
+};
+
+
+ + template< typname Fn, typename ... Args > captured_context( 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(). +

+
+
+
+ + template< typename StackAlloc, typname Fn, typename + ... Args + > captured_context( std::allocator_arg_t, + StackAlloc salloc, Fn && + fn, Args && + ... args) +
+
+

+
+
Effects:
+

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

+
+
+
+ + template< typename StackAlloc, typname Fn, typename + ... Args + > captured_context( std::allocator_arg_t, + 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. +

+
+
+
+ + captured_context( + captured_context && + other) +
+
+

+
+
Effects:
+

+ Moves underlying capture record to *this. +

+
Throws:
+

+ Nothing. +

+
+
+
+ + captured_context & + operator=( + captured_context && + other) +
+
+

+
+
Effects:
+

+ Moves the state of other + to *this + using move semantics. +

+
Throws:
+

+ Nothing. +

+
+
+
+ + explicit operator + bool() const noexcept +
+
+

+
+
Returns:
+

+ true if *this + points to a capture record. +

+
Throws:
+

+ Nothing. +

+
+
+
+ + bool operator!() const noexcept +
+
+

+
+
Returns:
+

+ true if *this + does not point to a capture record. +

+
Throws:
+

+ Nothing. +

+
+
+
+ + void * operator()( void * vp) +
+
void * operator()( void * vp = nullptr);
+
+template< typename Fn, typename ... Args >
+void * operator()( exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+template< typename Fn, typename ... Args >
+void * operator()( void * vp, exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+
+

+
+
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. The void pointer argument, vp, + is passed to the current context to be returned by the most recent + call to captured_context::operator() in the same thread. [[Note: +

+

+ The behaviour is undefined if operator()() is called while captured_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 captured_context::operator(), + if any. +

+
Throws:
+

+ Nothing. +

+
+
+
+ + std::tuple< captured_context, void > + operator()( + void * vp) +
+
std::tuple< captured_context, void * > operator()( void * data = nullptr);
+
+template< typename Fn, typename ... Args >
+std::tuple< captured_context, void * > operator()( exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+template< typename Fn, typename ... Args >
+std::tuple< captured_context, void * > operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+
+

+
+
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 captured_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 captured_context::current() returns *this (e.g. resuming an already running + context). If the top-level context function returns, std::exit() + is called. +

+
+
Returns:
+

+ The tuple of void pointer argument passed to the most recent call to + captured_context::operator(), + if any and a captured_context representing the context that has been + suspended . +

+
+
+
+ + operator== +
+
bool operator==( captured_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

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

+
Throws:
+

+ Nothing. +

+
+
+
+ + operator!= +
+
bool operator!=( captured_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

+ [`! (other == * this) +

+
+
+

+ [[Throws:] [Nothing.]] ] +

+
+ + operator< +
+
bool operator<( captured_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

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

+
Throws:
+

+ Nothing. +

+
+
+
+ + operator> +
+
bool operator>( captured_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

+ other < + * this +

+
Throws:
+

+ Nothing. +

+
+
+
+ + operator<= +
+
bool operator<=( captured_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

+ ! (other < + * this) +

+
Throws:
+

+ Nothing. +

+
+
+
+ + operator>= +
+
bool operator>=( captured_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

+ ! (* + this < + other) +

+
Throws:
+

+ Nothing. +

+
+
+
+ + operator<< +
+
template< typename charT, class traitsT >
+std::basic_ostream< charT, traitsT > &
+operator<<( std::basic_ostream< charT, traitsT > & os, captured_context const& other);
+
+
+

+
+
Efects:
+

+ Writes the representation of other + to stream os. +

+
Returns:
+

+ os +

+
+
+
+ + 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 +
+ + diff --git a/doc/html/context/abstract_context/econtext.html b/doc/html/context/abstract_context/econtext.html new file mode 100644 index 0000000..94cdbfa --- /dev/null +++ b/doc/html/context/abstract_context/econtext.html @@ -0,0 +1,737 @@ + + + +Class execution_context + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +
+ + + + + +
[Important]Important

+ execution_context requires C++11! +

+

+ Class execution_context encapsulates fcontext_t + and manages the 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 controls the life time of the 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 + (smart pointer), accessed by execution_context::current(), + pointing to the active context. On each context switch the static thread-local + 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 + need to call certain maintenance functions (__splitstack_getcontext etc.) + before each context switch (each context switch exchanges the stack). Additionally + the destruction of execution_context and thus the stack + deallocation is faster compared to captured_context. +

+

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

+
+ + usage + of execution_context +
+
/*
+ * 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");
+    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(
+            std::allocator_arg,
+            boost::context::fixedsize_stack(4096),
+            [&main_ctx,&is,&done,&except](void*){
+            // create parser with callback function
+            Parser p( is,
+                      [&main_ctx,&c](char ch){
+                            // resume main execution context
+                            main_ctx( & ch);
+                    });
+                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
+    void * vp = parser_ctx();
+    if ( except) {
+        std::rethrow_exception( except);
+    }
+    while( ! done) {
+        printf("Parsed: %c\n",* static_cast< char* >( vp) );
+        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 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. +

+

+ 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( std::allocator_arg, 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 +
+

+ 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. +

+
class X {
+private:
+    std::exception_ptr excptr_;
+    boost::context::execution_context caller_;
+    boost::context::execution_context callee_;
+
+public:
+    X() :
+        excptr_(),
+        caller_( boost::context::execution_context::current() ),
+        callee_( [=] (void * vp) {
+                    try {
+                        int i = * static_cast< int * >( vp);
+                        std::string str = boost::lexical_cast<std::string>(i);
+                        caller_( & str);
+                    } catch (...) {
+                        excptr_=std::current_exception();
+                    }
+                 })
+    {}
+
+    std::string operator()( int i) {
+        void * ret = callee_( & i);
+        if(excptr_){
+            std::rethrow_exception(excptr_);
+        }
+        return * static_cast< std::string * >( ret);
+    }
+};
+
+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 Fn, typename ... Args >
+    execution_context( Fn && fn, Args && ... args);
+
+    template< typename StackAlloc, typename Fn, typename ... Args >
+    execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args);
+
+    template< typename StackAlloc, typename Fn, typename ... Args >
+    execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args);
+
+    execution_context( execution_context const& other) noexcept;
+    execution_context( execution_context && other) noexcept;
+
+    execution_context & operator=( execution_context const& other) noexcept;
+    execution_context & operator=( execution_context && other) noexcept;
+
+    explicit operator bool() const noexcept;
+    bool operator!() const noexcept;
+
+    void * operator()( void * vp = nullptr);
+
+    template< typename Fn, typename ... Args >
+    void * operator()( exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+    template< typename Fn, typename ... Args >
+    void * operator()( void * vp, exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+    bool operator==( execution_context const& other) const noexcept;
+
+    bool operator!=( execution_context const& other) const noexcept;
+
+    bool operator<( execution_context const& other) const noexcept;
+
+    bool operator>( execution_context const& other) const noexcept;
+
+    bool operator<=( execution_context const& other) const noexcept;
+
+    bool operator>=( execution_context const& other) const noexcept;
+
+    template< typename charT, class traitsT >
+    friend std::basic_ostream< charT, traitsT > &
+    operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other);
+};
+
+
+ + static execution_context + current() +
+
+

+
+
Returns:
+

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

+
Throws:
+

+ Nothing. +

+
+
+
+ + template< typname Fn, typename ... Args > execution_context( 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(). +

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

+
+
Effects:
+

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

+
+
+
+ + template< typename StackAlloc, typname Fn, typename + ... Args + > execution_context( std::allocator_arg_t, + 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. +

+
+
+
+ + execution_context( + execution_context const& other) +
+
+

+
+
Effects:
+

+ Copies other, e.g. + underlying capture record is shared with *this. +

+
Throws:
+

+ Nothing. +

+
+
+
+ + execution_context( + execution_context && + other) +
+
+

+
+
Effects:
+

+ Moves underlying capture record to *this. +

+
Throws:
+

+ Nothing. +

+
+
+
+ + execution_context & + operator=( + execution_context const& other) +
+
+

+
+
Effects:
+

+ Copies the state of other + to *this, + state (capture record) is shared. +

+
Throws:
+

+ Nothing. +

+
+
+
+ + execution_context & + operator=( + execution_context && + other) +
+
+

+
+
Effects:
+

+ Moves the state of other + to *this + using move semantics. +

+
Throws:
+

+ Nothing. +

+
+
+
+ + explicit operator + bool() const noexcept +
+
+

+
+
Returns:
+

+ true if *this + points to a capture record. +

+
Throws:
+

+ Nothing. +

+
+
+
+ + bool operator!() const noexcept +
+
+

+
+
Returns:
+

+ true if *this + does not point to a capture record. +

+
Throws:
+

+ Nothing. +

+
+
+
+ + void * operator()( void * vp) +
+
void * operator()( void * vp = nullptr) noexcept;
+
+template< typename Fn, typename ... Args >
+void * operator()( exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+template< typename Fn, typename ... Args >
+void * operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+
+

+
+
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. +

+
+
+
+ + operator== +
+
bool operator==( execution_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

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

+
Throws:
+

+ Nothing. +

+
+
+
+ + operator!= +
+
bool operator!=( execution_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

+ [`! (other == * this) +

+
+
+

+ [[Throws:] [Nothing.]] ] +

+
+ + operator< +
+
bool operator<( execution_context const& other) const noexcept;
+
+
+

+
+
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. +

+
+
+
+ + operator> +
+
bool operator>( execution_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

+ other < + * this +

+
Throws:
+

+ Nothing. +

+
+
+
+ + operator<= +
+
bool operator<=( execution_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

+ ! (other < + * this) +

+
Throws:
+

+ Nothing. +

+
+
+
+ + operator>= +
+
bool operator>=( execution_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

+ ! (* + this < + other) +

+
Throws:
+

+ Nothing. +

+
+
+
+ + operator<< +
+
template< typename charT, class traitsT >
+std::basic_ostream< charT, traitsT > &
+operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other);
+
+
+

+
+
Efects:
+

+ Writes the representation of other + to stream os. +

+
Returns:
+

+ os +

+
+
+
+ + 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 +
+ + diff --git a/doc/html/context/abstract_context/stack.html b/doc/html/context/abstract_context/stack.html new file mode 100644 index 0000000..5e31b95 --- /dev/null +++ b/doc/html/context/abstract_context/stack.html @@ -0,0 +1,188 @@ + + + +Stack allocation + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ + +

+ The memory used by the stack is allocated/deallocated via a StackAllocator + which is required to model a stack-allocator concept. +

+
+ + stack-allocator + concept +
+

+ A StackAllocator must satisfy the stack-allocator + concept requirements shown in the following table, in which a is an object of a StackAllocator + type, sctx is a stack_context, and size + is a std::size_t: +

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +
+

+ expression +

+
+

+ return type +

+
+

+ notes +

+
+

+ a(size) +

+
+ +

+ creates a stack allocator +

+
+

+ a.allocate() +

+
+

+ stack_context +

+
+

+ creates a stack +

+
+

+ a.deallocate( + sctx) +

+
+

+ void +

+
+

+ deallocates the stack created by a.allocate() +

+
+
+ + + + + +
[Important]Important

+ The implementation of allocate() might include logic to protect against + exceeding the context's available stack size rather than leaving it as + undefined behaviour. +

+
+ + + + + +
[Important]Important

+ Calling deallocate() + with a stack_context not + set by allocate() + results in undefined behaviour. +

+
+ + + + + +
[Note]Note

+ The stack is not required to be aligned; alignment takes place inside + execution_context. +

+
+ + + + + +
[Note]Note

+ Depending on the architecture allocate() stores an address from the top of the + stack (growing downwards) or the bottom of the stack (growing upwards). +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/context/abstract_context/stack/fixedsize.html b/doc/html/context/abstract_context/stack/fixedsize.html new file mode 100644 index 0000000..3db4a34 --- /dev/null +++ b/doc/html/context/abstract_context/stack/fixedsize.html @@ -0,0 +1,113 @@ + + + +Class fixedsize_stack + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ Boost.Context provides the class fixedsize_stack + which models the stack-allocator concept. In contrast + to protected_fixedsize_stack it does not append a + guard page at the end of each stack. The memory is simply managed by std::malloc() + and std::free(). +

+
#include <boost/context/fixedsize_stack.hpp>
+
+template< typename traitsT >
+struct basic_fixedsize_stack
+{
+    typedef traitT  traits_type;
+
+    basic_fixesize_stack(std::size_t size = traits_type::default_size());
+
+    stack_context allocate();
+
+    void deallocate( stack_context &);
+}
+
+typedef basic_fixedsize_stack< stack_traits > fixedsize_stack;
+
+
+ + stack_context allocate() +
+
+

+
+
Preconditions:
+

+ traits_type::minimum:size() + <= size + and ! traits_type::is_unbounded() && + ( traits_type::maximum:size() >= + size). +

+
Effects:
+

+ Allocates memory of at least size + Bytes and stores a pointer to the stack and its actual size in sctx. Depending on the architecture + (the stack grows downwards/upwards) the stored address is the highest/lowest + address of the stack. +

+
+
+
+ + void deallocate( stack_context + & sctx) +
+
+

+
+
Preconditions:
+

+ sctx.sp is valid, traits_type::minimum:size() <= + sctx.size and ! + traits_type::is_unbounded() + && ( + traits_type::maximum:size() + >= sctx.size). +

+
Effects:
+

+ Deallocates the stack space. +

+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/context/abstract_context/stack/protected_fixedsize.html b/doc/html/context/abstract_context/stack/protected_fixedsize.html new file mode 100644 index 0000000..92c2212 --- /dev/null +++ b/doc/html/context/abstract_context/stack/protected_fixedsize.html @@ -0,0 +1,136 @@ + + + +Class protected_fixedsize + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ Boost.Context provides the class protected_fixedsize_stack + which models the stack-allocator concept. It appends + a guard page at the end of each stack to protect against exceeding the + stack. If the guard page is accessed (read or write operation) a segmentation + fault/access violation is generated by the operating system. +

+
+ + + + + +
[Important]Important

+ Using protected_fixedsize_stack is expensive. That + is, launching a new coroutine with a new stack is expensive; the allocated + stack is just as efficient to use as any other stack. +

+
+ + + + + +
[Note]Note

+ The appended guard page + is not mapped to physical memory, only + virtual addresses are used. +

+
#include <boost/context/protected_fixedsize.hpp>
+
+template< typename traitsT >
+struct basic_protected_fixedsize
+{
+    typedef traitT  traits_type;
+
+    basic_protected_fixesize(std::size_t size = traits_type::default_size());
+
+    stack_context allocate();
+
+    void deallocate( stack_context &);
+}
+
+typedef basic_protected_fixedsize< stack_traits > protected_fixedsize
+
+
+ + stack_context allocate() +
+
+

+
+
Preconditions:
+

+ traits_type::minimum:size() + <= size + and ! traits_type::is_unbounded() && + ( traits_type::maximum:size() >= + size). +

+
Effects:
+

+ Allocates memory of at least size + Bytes and stores a pointer to the stack and its actual size in sctx. Depending on the architecture + (the stack grows downwards/upwards) the stored address is the highest/lowest + address of the stack. +

+
+
+
+ + void deallocate( stack_context + & sctx) +
+
+

+
+
Preconditions:
+

+ sctx.sp is valid, traits_type::minimum:size() <= + sctx.size and ! + traits_type::is_unbounded() + && ( + traits_type::maximum:size() + >= sctx.size). +

+
Effects:
+

+ Deallocates the stack space. +

+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/context/abstract_context/stack/segmented.html b/doc/html/context/abstract_context/stack/segmented.html new file mode 100644 index 0000000..f4571b2 --- /dev/null +++ b/doc/html/context/abstract_context/stack/segmented.html @@ -0,0 +1,139 @@ + + + +Class segmented_stack + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ Boost.Context supports usage of a segmented_stack, + e. g. the size of the stack grows on demand. The coroutine is created with + a minimal stack size and will be increased as required. Class segmented_stack + models the stack-allocator concept. In contrast to + protected_fixedsize_stack and fixedsize_stack + it creates a stack which grows on demand. +

+
+ + + + + +
[Note]Note

+ Segmented stacks are currently only supported by gcc + from version 4.7 clang + from version 3.4 onwards. In order to + use a __segmented_stack__ Boost.Context + must be built with toolset=gcc segmented-stacks=on + at b2/bjam command-line. Applications must be compiled with compiler-flags + -fsplit-stack -DBOOST_USE_SEGMENTED_STACKS. +

+
#include <boost/context/segmented_stack.hpp>
+
+template< typename traitsT >
+struct basic_segmented_stack
+{
+    typedef traitT  traits_type;
+
+    basic_segmented_stack(std::size_t size = traits_type::default_size());
+
+    stack_context allocate();
+
+    void deallocate( stack_context &);
+}
+
+typedef basic_segmented_stack< stack_traits > segmented_stack;
+
+
+ + stack_context allocate() +
+
+

+
+
Preconditions:
+

+ traits_type::minimum:size() + <= size + and ! traits_type::is_unbounded() && + ( traits_type::maximum:size() >= + size). +

+
Effects:
+

+ Allocates memory of at least size + Bytes and stores a pointer to the stack and its actual size in sctx. Depending on the architecture + (the stack grows downwards/upwards) the stored address is the highest/lowest + address of the stack. +

+
+
+
+ + void deallocate( stack_context + & sctx) +
+
+

+
+
Preconditions:
+

+ sctx.sp is valid, traits_type::minimum:size() <= + sctx.size and ! + traits_type::is_unbounded() + && ( + traits_type::maximum:size() + >= sctx.size). +

+
Effects:
+

+ Deallocates the stack space. +

+
+
+
+ + + + + +
[Note]Note

+ If the library is compiled for segmented stacks, __segmented_stack__ + is the only available stack allocator. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/context/abstract_context/stack/stack_context.html b/doc/html/context/abstract_context/stack/stack_context.html new file mode 100644 index 0000000..9de0868 --- /dev/null +++ b/doc/html/context/abstract_context/stack/stack_context.html @@ -0,0 +1,85 @@ + + + +Class stack_context + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ Boost.Context provides the class stack_context + which will contain the stack pointer and the size of the stack. In case + of a segmented_stack, stack_context + contains some extra control structures. +

+
struct stack_context
+{
+    void    *   sp;
+    std::size_t size;
+
+    // might contain additional control structures
+    // for segmented stacks
+}
+
+
+ + void * sp +
+
+

+
+
Value:
+

+ Pointer to the beginning of the stack. +

+
+
+
+ + std::size_t size +
+
+

+
+
Value:
+

+ Actual size of the stack. +

+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/context/abstract_context/stack/stack_traits.html b/doc/html/context/abstract_context/stack/stack_traits.html new file mode 100644 index 0000000..4ffb1aa --- /dev/null +++ b/doc/html/context/abstract_context/stack/stack_traits.html @@ -0,0 +1,159 @@ + + + +Class stack_traits + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ stack_traits models a stack-traits + providing a way to access certain properites defined by the enironment. + Stack allocators use stack-traits to allocate stacks. +

+
#include <boost/context/stack_traits.hpp>
+
+struct stack_traits
+{
+    static bool is_unbounded() noexcept;
+
+    static std::size_t page_size() noexcept;
+
+    static std::size_t default_size() noexcept;
+
+    static std::size_t minimum_size() noexcept;
+
+    static std::size_t maximum_size() noexcept;
+}
+
+
+ + static bool is_unbounded() +
+
+

+
+
Returns:
+

+ Returns true if the + environment defines no limit for the size of a stack. +

+
Throws:
+

+ Nothing. +

+
+
+
+ + static std::size_t page_size() +
+
+

+
+
Returns:
+

+ Returns the page size in bytes. +

+
Throws:
+

+ Nothing. +

+
+
+
+ + static std::size_t default_size() +
+
+

+
+
Returns:
+

+ Returns a default stack size, which may be platform specific. If + the stack is unbounded then the present implementation returns the + maximum of 64 kB + and minimum_size(). +

+
Throws:
+

+ Nothing. +

+
+
+
+ + static std::size_t minimum_size() +
+
+

+
+
Returns:
+

+ Returns the minimum size in bytes of stack defined by the environment + (Win32 4kB/Win64 8kB, defined by rlimit on POSIX). +

+
Throws:
+

+ Nothing. +

+
+
+
+ + static std::size_t maximum_size() +
+
+

+
+
Preconditions:
+

+ is_unbounded() + returns false. +

+
Returns:
+

+ Returns the maximum size in bytes of stack defined by the environment. +

+
Throws:
+

+ Nothing. +

+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/context/abstract_context/stack/valgrind.html b/doc/html/context/abstract_context/stack/valgrind.html new file mode 100644 index 0000000..a19994b --- /dev/null +++ b/doc/html/context/abstract_context/stack/valgrind.html @@ -0,0 +1,49 @@ + + + +Support for valgrind + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ Running programs that switch stacks under valgrind causes problems. Property + (b2 command-line) valgrind=on let + valgrind treat the memory regions as stack space which suppresses the errors. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/context/ccontext.html b/doc/html/context/ccontext.html new file mode 100644 index 0000000..14755b7 --- /dev/null +++ b/doc/html/context/ccontext.html @@ -0,0 +1,707 @@ + + + +Class captured_context + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ Class captured_context encapsulates fcontext_t + and manages the context' stack (allocation/deallocation). +

+

+ captured_context allocates the context stack (using its + StackAllocator argument) and creates a control structure + on top of it. This structure controls the life time of the stack. The address + of the control structure is stored in the first frame of context' stack (e.g. + it can not accessed by instances of captured_context directly). + In contrast to execution_context the ownership of the + control structure is not shared A call ofcaptured_context::operator() + enters the context represented by *this and invalidates *this. The context that has been suspended by + calling captured_context::operator() is passed to the + resumed context, e.g. as argument of the context-function if the context was + resumed the first time or returned by captured_context::operator(). + captured_context is only move-constructible and move-assignable. + If the last reference (captured_context) goes out of scope, + the control structure is destroyed and the stack gets deallocated via the + StackAllocator. captured_context + maintains a static, thread-local pointer (smart pointer), accessed by execution_context::current(), + pointing to the active context. On each context switch the static, thread-local + pointer is updated. This makes the context switch a little bit slower, but + enables faster context destruction (stack unwinding) compared to captured_context. +

+

+ captured_context expects a function/functor with signature + captured_context( + captured_context ctx, void * + vp). + The parameter ctx represents + the context from which this context was resumed (e.g. that has called captured_context::operator() + on *this) + and vp is the data passed to + captured_context::operator(). The function/functor has + to return the captured_context that has to be resumed, while this context terminates. +

+
+ + + + + +
[Important]Important

+ Segemnted stacks are not supported together with captured_context. +

+

+ + usage + of captured_context +

+
/*
+ * grammar:
+ *   P ---> E '\0'
+ *   E ---> T {('+'|'-') T}
+ *   T ---> S {('*'|'/') S}
+ *   S ---> digit | '(' E ')'
+ */
+class Parser{
+    // implementation omitted; see examples directory
+};
+
+std::istringstream is("1+1");
+bool done=false;
+std::exception_ptr except;
+
+// execute parser in new execution context
+boost::context::captured_context pctx(
+        [&is,&done,&except](ctx::captured_context mctx,void* ignored){
+        // create parser with callback function
+        Parser p( is,
+                  [&mctx](char ch){
+                        // resume main execution context
+                        auto result = mctx( & ch);
+                        mctx = std::move( std::get<0>( result) );
+                });
+            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
+            return mctx;
+        });
+
+// user-code pulls parsed data from parser
+// invert control flow
+auto result = pctx();
+pctx = std::move( std::get<0>( result) );
+void * vp = std::get<1>( result);
+if ( except) {
+    std::rethrow_exception( except);
+}
+while( ! done) {
+    printf("Parsed: %c\n",* static_cast< char* >( vp) );
+    std::tie(pctx,vp) = pctx();
+    if ( except) {
+        std::rethrow_exception( except);
+    }
+}
+
+output:
+    Parsed: 1
+    Parsed: +
+    Parsed: 1
+
+

+ In this example a recursive descent parser uses a callback to emit a newly + passed symbol. Using captured_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 captured_context. +

+

+ If the code executed by captured_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 captured_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  {
+    // captured context
+    captured_context cctx;
+
+    template< typename StackAllocator >
+    my_control_structure( void * sp, std::size_t size, stack_context sctx, StackAllocator salloc) :
+        // create captured context
+        cctx( std::allocator_arg, preallocated( sp, size, sctx), salloc, entry_func) {
+    }
+    ...
+};
+
+

+ + exception + handling +

+

+ If the function executed inside a captured_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 +

+

+ The void pointer argument passed to captured_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 captured_context::operator() the void pointer passed + to captured_context::operator(), in one context, is returned + by captured_context::operator() in the other context. +

+
class X {
+private:
+    std::exception_ptr excptr_;
+    boost::context::captured_context ctx_;
+
+public:
+    X() :
+        excptr_(),
+        ctx_( [=](ctx::captured_context ctx, void * vp)->ctx::captured_context{
+                    try {
+                        for (;;) {
+                            int i = * static_cast< int * >( vp);
+                            std::string str = boost::lexical_cast<std::string>(i);
+                            auto result = ctx( & str);
+                            ctx = std::move( std::get<0>( result) );
+                            vp = std::get<1>( result);
+                        }
+                    } catch ( ctx::detail::forced_unwind const&) {
+                        throw;
+                    } catch (...) {
+                        excptr_=std::current_exception();
+                    }
+                    return ctx;
+              })
+    {}
+
+    std::string operator()( int i) {
+        auto result = ctx_( & i);
+        ctx_ = std::move( std::get<0>( result) );
+        void * ret = std::get<1>( result);
+        if(excptr_){
+            std::rethrow_exception(excptr_);
+        }
+        return * static_cast< std::string * >( ret);
+    }
+};
+
+X x;
+std::cout << x( 7) << std::endl;
+
+output:
+7
+
+

+ + Class + captured_context +

+
class captured_context {
+public:
+    template< typename Fn, typename ... Args >
+    captured_context( Fn && fn, Args && ... args);
+
+    template< typename StackAlloc, typename Fn, typename ... Args >
+    captured_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args);
+
+    template< typename StackAlloc, typename Fn, typename ... Args >
+    captured_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args);
+
+    ~captured_context();
+
+    captured_context( captured_context && other) noexcept;
+    captured_context & operator=( captured_context && other) noexcept;
+
+    captured_context( captured_context const& other) noexcept = delete;
+    captured_context & operator=( captured_context const& other) noexcept = delete;
+
+    explicit operator bool() const noexcept;
+    bool operator!() const noexcept;
+
+    std::tuple< captured_context, void * > operator()( void * data = nullptr);
+
+    template< typename Fn, typename ... Args >
+    std::tuple< captured_context, void * > operator()( exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+    template< typename Fn, typename ... Args >
+    std::tuple< captured_context, void * > operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+    bool operator==( captured_context const& other) const noexcept;
+
+    bool operator!=( captured_context const& other) const noexcept;
+
+    bool operator<( captured_context const& other) const noexcept;
+
+    bool operator>( captured_context const& other) const noexcept;
+
+    bool operator<=( captured_context const& other) const noexcept;
+
+    bool operator>=( captured_context const& other) const noexcept;
+
+    template< typename charT, class traitsT >
+    friend std::basic_ostream< charT, traitsT > &
+    operator<<( std::basic_ostream< charT, traitsT > & os, captured_context const& other);
+};
+
+

+

+
+ + + Constructor +
+

+

+
template< typename Fn, typename ... Args >
+captured_context( Fn && fn, Args && ... args);
+
+template< typename StackAlloc, typename Fn, typename ... Args >
+captured_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args);
+
+template< typename StackAlloc, typename Fn, typename ... Args >
+captured_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, 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(). +

+
+
+

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

+

+

+
+ + + Move constructor +
+

+

+
captured_context( captured_context && other) noexcept;
+
+
+

+
+
Effects:
+

+ Moves underlying capture record to *this. +

+
Throws:
+

+ Nothing. +

+
+
+

+

+
+ + + Move assignment operator +
+

+

+
captured_context & operator=( captured_context && other) noexcept;
+
+
+

+
+
Effects:
+

+ Moves the state of other + to *this + using move semantics. +

+
Throws:
+

+ Nothing. +

+
+
+

+

+
+ + + Member + function operator bool() +
+

+

+
explicit operator bool() const noexcept;
+
+
+

+
+
Returns:
+

+ true if *this points to a capture record. +

+
Throws:
+

+ Nothing. +

+
+
+

+

+
+ + + Member + function operator!() +
+

+

+
bool operator!() const noexcept;
+
+
+

+
+
Returns:
+

+ true if *this does not point to a capture record. +

+
Throws:
+

+ Nothing. +

+
+
+

+

+
+ + + Member + function operator()() +
+

+

+
std::tuple< captured_context, void * > operator()( void * data = nullptr);
+
+template< typename Fn, typename ... Args >
+std::tuple< captured_context, void * > operator()( exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+template< typename Fn, typename ... Args >
+std::tuple< captured_context, void * > operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+
+

+
+
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 captured_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 captured_context::current() returns *this (e.g. resuming an already running + context). If the top-level context function returns, std::exit() is called. +

+
+
Returns:
+

+ The tuple of void pointer argument passed to the most recent call to + captured_context::operator(), + if any and a captured_context representing the context that has been + suspended . +

+
+
+

+

+
+ + + Member + function operator==() +
+

+

+
bool operator==( captured_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

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

+
Throws:
+

+ Nothing. +

+
+
+

+

+
+ + + Member + function operator!=() +
+

+

+
bool operator!=( captured_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

+ ! (other == * this) +

+
Throws:
+

+ Nothing. +

+
+
+

+

+
+ + + Member + function operator<() +
+

+

+
bool operator<( captured_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

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

+
Throws:
+

+ Nothing. +

+
+
+

+

+
+ + + Member + function operator>() +
+

+

+
bool operator>( captured_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

+ other < + * this +

+
Throws:
+

+ Nothing. +

+
+
+

+

+
+ + + Member + function operator<=() +
+

+

+
bool operator<=( captured_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

+ ! (other < + * this) +

+
Throws:
+

+ Nothing. +

+
+
+

+

+
+ + + Member + function operator>=() +
+

+

+
bool operator>=( captured_context const& other) const noexcept;
+
+
+

+
+
Returns:
+

+ ! (* + this < + other) +

+
Throws:
+

+ Nothing. +

+
+
+

+

+
+ + + Non-member function + operator<<() +
+

+

+
template< typename charT, class traitsT >
+std::basic_ostream< charT, traitsT > &
+operator<<( std::basic_ostream< charT, traitsT > & os, captured_context const& other);
+
+
+

+
+
Efects:
+

+ Writes the representation of other + to stream os. +

+
Returns:
+

+ os +

+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/context/context.html b/doc/html/context/context.html index dd410a2..38d37d2 100644 --- a/doc/html/context/context.html +++ b/doc/html/context/context.html @@ -7,7 +7,7 @@ - + @@ -20,7 +20,7 @@

-PrevUpHomeNext +PrevUpHomeNext

@@ -71,7 +71,7 @@

A new context supposed to execute a context-function (returning - void and accepting intptr_t as argument) will be created on top of the stack + void and accepting void * as argument) will be created on top of the stack (at 16 byte boundary) by function make_fcontext().

// context-function
@@ -98,7 +98,7 @@
     

boost::context::fcontext_t fcm,fc1,fc2;
 
-void f1(intptr_t)
+void f1(void *)
 {
     std::cout<<"f1: entered"<<std::endl;
     std::cout<<"f1: call jump_fcontext( & fc1, fc2, 0)"<< std::endl;
@@ -107,7 +107,7 @@
     boost::context::jump_fcontext(&fc1,fcm,0);
 }
 
-void f2(intptr_t)
+void f2(void *)
 {
     std::cout<<"f2: entered"<<std::endl;
     std::cout<<"f2: call jump_fcontext( & fc2, fc1, 0)"<<std::endl;
@@ -180,7 +180,7 @@
       The third argument passed to jump_fcontext(), in one context,
       is passed as the first argument of the context-function
       if the context is started for the first time. In all following invocations
-      of jump_fcontext() the intptr_t passed to jump_fcontext(),
+      of jump_fcontext() the void * passed to jump_fcontext(),
       in one context, is returned by jump_fcontext() in the
       other context.
     

@@ -188,11 +188,11 @@ typedef std::pair<int,int> pair_t; -void f(intptr_t param) +void f(void * param) { pair_t* p=(pair_t*)param; - p=(pair_t*)boost::context::jump_fcontext(&fc,fcm,(intptr_t)(p->first+p->second)); - boost::context::jump_fcontext(&fc,fcm,(intptr_t)(p->first+p->second)); + p=(pair_t*)boost::context::jump_fcontext(&fc,fcm,(void *)(p->first+p->second)); + boost::context::jump_fcontext(&fc,fcm,(void *)(p->first+p->second)); } std::size_t size(8192); @@ -201,11 +201,11 @@ pair_t p(std::make_pair(2,7)); fc=boost::context::make_fcontext(sp,size,f); -int res=(int)boost::context::jump_fcontext(&fcm,fc,(intptr_t)&p); +int res=(int)boost::context::jump_fcontext(&fcm,fc,(void *)&p); std::cout<<p.first<<" + "<<p.second<<" == "<<res<<std::endl; p=std::make_pair(5,6); -res=(int)boost::context::jump_fcontext(&fcm,fc,(intptr_t)&p); +res=(int)boost::context::jump_fcontext(&fcm,fc,(void *)&p); std::cout<<p.first<<" + "<<p.second<<" == "<<res<<std::endl; output: @@ -243,26 +243,6 @@

- Preserving - floating point registers -

-

- Preserving the floating point registers increases the cycle count for a context - switch (see performance tests). The fourth argument of jump_fcontext() - controls if fpu registers should be preserved by the context jump. -

-
- - - - - -
[Important]Important

- The use of the fpu controlling argument of jump_fcontext() - must be consistent in the application. Otherwise the behaviour is undefined. -

-

- Stack unwinding

@@ -272,7 +252,7 @@ The user is responsible for this task.

- + fcontext_t and related functions

struct stack_t
@@ -283,11 +263,11 @@
 
 typedef <opaque pointer > fcontext_t;
 
-intptr_t jump_fcontext(fcontext_t* ofc,fcontext_t nfc,intptr_t vp,bool preserve_fpu=true);
-fcontext_t make_fcontext(void* sp,std::size_t size,void(*fn)(intptr_t));
+void * jump_fcontext(fcontext_t* ofc,fcontext_t nfc,void * vp);
+fcontext_t make_fcontext(void* sp,std::size_t size,void(*fn)(void *));
 

- + sp

@@ -301,7 +281,7 @@

- + size

@@ -314,7 +294,7 @@

- + fc_stack

@@ -327,9 +307,9 @@

- - intptr_t jump_fcontext(fcontext_t* ofc,fcontext_t nfc,intptr_t p,bool - preserve_fpu=true) + + void * jump_fcontext(fcontext_t* ofc,fcontext_t nfc,void * + p)

@@ -339,12 +319,11 @@ Stores the current context data (stack pointer, instruction pointer, and CPU registers) to *ofc and restores the context data from nfc, which implies jumping - to nfc's execution context. - The intptr_t argument, p, + to execution context nfc. + The void * argument, p, is passed to the current context to be returned by the most recent call to jump_fcontext() - in the same thread. The last argument controls if fpu registers have - to be preserved. + in the same thread.

Returns:

@@ -354,10 +333,10 @@

- - fcontext_t make_fcontext(void* + + fcontext_t make_fcontext(void* sp,std::size_t - size,void(*fn)(intptr_t)) + size,void(*fn)(void *))

@@ -392,7 +371,7 @@
-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/context/econtext.html b/doc/html/context/econtext.html index 3b6f159..e25e9bd 100644 --- a/doc/html/context/econtext.html +++ b/doc/html/context/econtext.html @@ -6,8 +6,8 @@ - - + + @@ -20,28 +20,79 @@

-PrevUpHomeNext +PrevUpHomeNext
- -
- - - - - -
[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(). + and manages the 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 controls the life + time of the 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 + (smart pointer), accessed by execution_context::current(), + pointing to the active context. On each context switch the static thread-local + 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 need + to call certain maintenance functions (__splitstack_getcontext() etc.) before + each context switch (each context switch exchanges the stack). Additionally + the destruction of execution_context and thus the stack + deallocation is faster compared to captured_context. +

+

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

+

+ + usage + of execution_context +

+
int n=35;
+int p=0;
+boost::context::execution_context mctx( boost::context::execution_context::current() );
+boost::context::execution_context ctx(
+    [n,&p,&mctx](void*)mutable{
+        int a=0;
+        int b=1;
+        while(n-->0){
+            yield(a);
+            auto next=a+b;
+            a=b;
+            b=next;
+        }
+    });
+for(int i=0;i<10;++i){
+    ctx();
+    std::cout<<p<<" ";
+}
+
+output:
+    0 1 1 2 3 5 8 13 21 34
+
+

+ + inverting + the control flow +

/*
  * grammar:
  *   P ---> E '\0'
@@ -127,7 +178,7 @@
       The user is responsible for this task.
     

- + allocating control structures on top of stack

@@ -172,7 +223,7 @@ };

- + exception handling

@@ -183,7 +234,7 @@ between different execution contexts.

- + parameter passing

@@ -225,14 +276,14 @@ } }; -int main() { - X x; - std::cout << x( 7) << std::endl; - std::cout << "done" << std::endl; -} +X x; +std::cout << x( 7) << std::endl; + +output: + 7

- + Class execution_context

@@ -258,7 +309,13 @@ explicit operator bool() const noexcept; bool operator!() const noexcept; - void * operator()( void * vp = nullptr) noexcept; + void * operator()( void * vp = nullptr); + + template< typename Fn, typename ... Args > + void * operator()( exec_ontop_arg_t, Fn && fn, Args && ... args); + + template< typename Fn, typename ... Args > + void * operator()( void * vp, exec_ontop_arg_t, Fn && fn, Args && ... args); bool operator==( execution_context const& other) const noexcept; @@ -277,11 +334,18 @@ operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other); }; -

- - static execution_context - current() -

+

+

+
+ + + Static + member function current() +
+

+

+
static execution_context current() noexcept;
+

@@ -296,12 +360,24 @@

-

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

+

+

+
+ + + Constructor +
+

+

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

@@ -313,50 +389,22 @@

-

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

-
-

-
-
Effects:
-

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

-
-
-

- - template< typename StackAlloc, typname Fn, typename - ... Args - > execution_context( std::allocator_arg_t, - 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. -

-
-
-

- - execution_context( - execution_context const& other) -

+

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

+

+

+
+ + + Copy constructor +
+

+

+
execution_context( execution_context const& other) noexcept;
+

@@ -371,12 +419,17 @@

-

- - execution_context( - execution_context && - other) -

+

+

+
+ + + Move constructor +
+

+

+
execution_context( execution_context && other) noexcept;
+

@@ -390,12 +443,17 @@

-

- - execution_context & - operator=( - execution_context const& other) -

+

+

+
+ + + Copy assignment operator +
+

+

+
execution_context & operator=( execution_context const& other) noexcept;
+

@@ -411,13 +469,17 @@

-

- - execution_context & - operator=( - execution_context && - other) -

+

+

+
+ + + Move assignment operator +
+

+

+
execution_context & operator=( execution_context && other) noexcept;
+

@@ -433,11 +495,18 @@

-

- - explicit operator - bool() const noexcept -

+

+

+
+ + + Member + function operator bool() +
+

+

+
explicit operator bool() const noexcept;
+

@@ -451,10 +520,18 @@

-

- - bool operator!() const noexcept -

+

+

+
+ + + Member + function operator!() +
+

+

+
bool operator!() const noexcept;
+

@@ -468,11 +545,24 @@

-

- - void * operator()( void * - vp) noexcept -

+

+

+
+ + + Member + function operator()() +
+

+

+
void * operator()( void * vp = nullptr) noexcept;
+
+template< typename Fn, typename ... Args >
+void * operator()( exec_ontop_arg_t, Fn && fn, Args && ... args);
+
+template< typename Fn, typename ... Args >
+void * operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args);
+

@@ -480,11 +570,14 @@

Stores internally the current context data (stack pointer, instruction - pointer, and CPU registers) to the current active context and restores + pointer, and CPU registers) of the current active context and restores the context data from *this, which implies jumping to *this's - execution context. The void pointer argument, vp, + 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. [[Note: + 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 @@ -496,16 +589,18 @@ The void pointer argument passed to the most recent call to execution_context::operator(), if any.

-
Throws:
-

- Nothing. -

-

- - operator== -

+

+

+
+ + + Member + function operator==() +
+

+

bool operator==( execution_context const& other) const noexcept;
 
@@ -523,10 +618,16 @@

-

- - operator!= -

+

+

+
+ + + Member + function operator!=() +
+

+

bool operator!=( execution_context const& other) const noexcept;
 
@@ -534,17 +635,24 @@
Returns:

- [`! (other == * this) + ! (other == * this) +

+
Throws:
+

+ Nothing.

- [[Throws:] [Nothing.]] ] +

+
+ + + Member + function operator<() +
+

-

- - operator< -

bool operator<( execution_context const& other) const noexcept;
 
@@ -563,10 +671,16 @@

-

- - operator> -

+

+

+
+ + + Member + function operator>() +
+

+

bool operator>( execution_context const& other) const noexcept;
 
@@ -583,10 +697,16 @@

-

- - operator<= -

+

+

+
+ + + Member + function operator<=() +
+

+

bool operator<=( execution_context const& other) const noexcept;
 
@@ -603,10 +723,16 @@

-

- - operator>= -

+

+

+
+ + + Member + function operator>=() +
+

+

bool operator>=( execution_context const& other) const noexcept;
 
@@ -624,10 +750,16 @@

-

- - operator<< -

+

+

+
+ + + Non-member function + operator<<() +
+

+

template< typename charT, class traitsT >
 std::basic_ostream< charT, traitsT > &
 operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other);
@@ -646,33 +778,6 @@
           

-

- - 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. -

-
-
@@ -684,7 +789,7 @@

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/context/overview.html b/doc/html/context/overview.html index 799e83a..102ccea 100644 --- a/doc/html/context/overview.html +++ b/doc/html/context/overview.html @@ -31,21 +31,22 @@ provides a sort of cooperative multitasking on a single thread. By providing an abstraction of the current execution state in the current thread, including the stack (with local variables) and stack pointer, all registers and CPU flags, - and the instruction pointer, a fcontext_t instance represents - a specific point in the application's execution path. This is useful for building - higher-level abstractions, like coroutines, cooperative - threads (userland threads) or an equivalent to C# + and the instruction pointer, a execution_context or captured_context + instance represents a specific point in the application's execution path. This + is useful for building higher-level abstractions, like coroutines, + cooperative threads (userland threads) or an equivalent + to C# keyword yield in C++.

- A fcontext_t provides the means to suspend the current - execution path and to transfer execution control, thereby permitting another - fcontext_t to run on the current thread. This state full - transfer mechanism enables a fcontext_t to suspend execution - from within nested functions and, later, to resume from where it was suspended. - While the execution path represented by a fcontext_t only - runs on a single thread, it can be migrated to another thread at any given - time. + execution_context and captured_context + provide the means to suspend the current execution path and to transfer execution + control, thereby permitting another context to run on the current thread. This + state full transfer mechanism enables a context to suspend execution from within + nested functions and, later, to resume from where it was suspended. While the + execution path represented by a execution_context or + captured_context only runs on a single thread, it can + be migrated to another thread at any given time.

A context switch between threads requires system calls (involving the OS kernel), @@ -66,6 +67,15 @@

All functions and classes are contained in the namespace boost::context.

+
+ + + + + +
[Important]Important

+ execution_context requires C++11! +

diff --git a/doc/html/context/performance.html b/doc/html/context/performance.html index 3ac6b04..ec999eb 100644 --- a/doc/html/context/performance.html +++ b/doc/html/context/performance.html @@ -6,7 +6,7 @@ - + @@ -20,7 +20,7 @@

-PrevUpHomeNext +PrevUpHomeNext

@@ -42,7 +42,6 @@ - @@ -55,11 +54,6 @@ ucontext_t

- -

- fcontext_t -

-

execution_context @@ -67,42 +61,14 @@

- windows fibers + captured_context

- - +

- i386 [a] -

- - -

- 708 ns / 754 cycles -

- - -

- 37 ns / 37 cycles -

- - -

- ns / cycles -

- - -

- ns / cycles -

- - - - -

- x86_64 [b] + x86_64 [a]

@@ -112,29 +78,18 @@

- 8 ns / 23 cycles + 51 ns / 141 cycles

- 16 ns / 46 cycles + 7 ns / 18 cycles

- -

- ns / cycles -

- - - - -

[a] - AMD Athlon 64 DualCore 4400+ -

-

[b] + +

[a] Intel Core2 Q6700 -

- +


@@ -149,7 +104,7 @@
-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/context/requirements.html b/doc/html/context/requirements.html index b39a8b9..4f6f01f 100644 --- a/doc/html/context/requirements.html +++ b/doc/html/context/requirements.html @@ -7,7 +7,7 @@ - + @@ -20,7 +20,7 @@

-PrevUpHomeNext +PrevUpHomeNext

@@ -85,7 +85,7 @@
-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/context/stack.html b/doc/html/context/stack.html index 4ca25a4..0f29684 100644 --- a/doc/html/context/stack.html +++ b/doc/html/context/stack.html @@ -6,7 +6,7 @@ - + @@ -20,11 +20,11 @@
-PrevUpHomeNext +PrevUpHomeNext
Class protected_fixedsize
@@ -177,7 +177,7 @@
-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/context/stack/valgrind.html b/doc/html/context/stack/valgrind.html index e06a713..de93ed0 100644 --- a/doc/html/context/stack/valgrind.html +++ b/doc/html/context/stack/valgrind.html @@ -7,7 +7,7 @@ - + @@ -20,7 +20,7 @@

-PrevUpHomeNext +PrevUpHomeNext

@@ -42,7 +42,7 @@
-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/context/struct__preallocated_.html b/doc/html/context/struct__preallocated_.html new file mode 100644 index 0000000..6e18b61 --- /dev/null +++ b/doc/html/context/struct__preallocated_.html @@ -0,0 +1,66 @@ + + + +Struct preallocated + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +
struct preallocated {
+    void        *   sp;
+    std::size_t     size;
+    stack_context   sctx;
+
+    preallocated( void * sp, std:size_t size, stack_allocator sctx) noexcept;
+};
+
+

+ + Constructor +

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

+
+
Effects:
+

+ Creates an object of preallocated. +

+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/context_HTML.manifest b/doc/html/context_HTML.manifest index 7b69d8f..b4efb04 100644 --- a/doc/html/context_HTML.manifest +++ b/doc/html/context_HTML.manifest @@ -1,9 +1,8 @@ index.html context/overview.html context/requirements.html -context/context.html context/econtext.html -context/econtext/winfibers.html +context/ccontext.html context/stack.html context/stack/protected_fixedsize.html context/stack/fixedsize.html @@ -11,6 +10,7 @@ context/stack/segmented.html context/stack/stack_traits.html context/stack/stack_context.html context/stack/valgrind.html +context/struct__preallocated_.html context/performance.html context/architectures.html context/architectures/crosscompiling.html diff --git a/doc/html/index.html b/doc/html/index.html index 2284c79..218de72 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -38,9 +38,8 @@
Overview
Requirements
-
Struct fcontext_t
Class execution_context
-
Using WinFiber-API
+
Class captured_context
Stack allocation
Class protected_fixedsize
@@ -50,6 +49,7 @@
Class stack_context
Support for valgrind
+
Struct preallocated
Performance
Architectures
Cross compiling
@@ -65,7 +65,7 @@

- +

Last revised: October 18, 2015 at 18:54:04 GMT

Last revised: January 12, 2016 at 19:06:41 GMT


diff --git a/doc/overview.qbk b/doc/overview.qbk index e281041..6d31f4c 100644 --- a/doc/overview.qbk +++ b/doc/overview.qbk @@ -11,18 +11,19 @@ __boost_context__ is a foundational library that provides a sort of cooperative multitasking on a single thread. By providing an abstraction of the current execution state in the current thread, including the stack (with local variables) and stack pointer, all registers and CPU flags, and the instruction -pointer, a __fcontext__ instance represents a specific point in the application's -execution path. This is useful for building higher-level abstractions, like -__coroutines__, __coop_threads__ or an equivalent to +pointer, a __econtext__ or __ccontext__ instance represents a specific point in +the application's execution path. This is useful for building higher-level +abstractions, like __coroutines__, __coop_threads__ or an equivalent to [@http://msdn.microsoft.com/en-us/library/9k7k7cf0%28v=vs.80%29.aspx C# keyword __yield__] in C++. -A __fcontext__ provides the means to suspend the current execution path and to -transfer execution control, thereby permitting another __fcontext__ to run on the -current thread. This state full transfer mechanism enables a __fcontext__ to -suspend execution from within nested functions and, later, to resume from where -it was suspended. While the execution path represented by a __fcontext__ only -runs on a single thread, it can be migrated to another thread at any given time. +__econtext__ and __ccontext__ provide the means to suspend the current execution +path and to transfer execution control, thereby permitting another context to +run on the current thread. This state full transfer mechanism enables a context +to suspend execution from within nested functions and, later, to resume from +where it was suspended. While the execution path represented by a +__econtext__ or __ccontext__ only runs on a single thread, it can be migrated to +another thread at any given time. A context switch between threads requires system calls (involving the OS kernel), which can cost more than thousand CPU cycles on x86 CPUs. By contrast, @@ -39,4 +40,6 @@ which includes all the other headers in turn. All functions and classes are contained in the namespace __context_ns__. +[important __econtext__ requires C++11!] + [endsect] diff --git a/doc/performance.qbk b/doc/performance.qbk index d70738b..738a91f 100644 --- a/doc/performance.qbk +++ b/doc/performance.qbk @@ -16,20 +16,12 @@ to a single CPU. The code was compiled using the build options, 'variant = release cxxflags = -DBOOST_DISABLE_ASSERTS'. [table Performance of context switch - [[Platform] [ucontext_t] [fcontext_t] [execution_context] [windows fibers]] - [ - [i386 [footnote AMD Athlon 64 DualCore 4400+]] - [708 ns / 754 cycles] - [37 ns / 37 cycles] - [ ns / cycles] - [ ns / cycles] - ] + [[Platform] [ucontext_t] [execution_context] [captured_context]] [ [x86_64 [footnote Intel Core2 Q6700]] [547 ns / 1433 cycles] - [8 ns / 23 cycles] - [16 ns / 46 cycles] - [ ns / cycles] + [51 ns / 141 cycles] + [7 ns / 18 cycles] ] ] diff --git a/doc/preallocated.qbk b/doc/preallocated.qbk new file mode 100644 index 0000000..4ab11ca --- /dev/null +++ b/doc/preallocated.qbk @@ -0,0 +1,27 @@ +[/ + Copyright Oliver Kowalke 2014. + 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 +] + +[section Struct `preallocated`] + + struct preallocated { + void * sp; + std::size_t size; + stack_context sctx; + + preallocated( void * sp, std:size_t size, stack_allocator sctx) noexcept; + }; + +[heading Constructor] + + preallocated( void * sp, std:size_t size, stack_allocator sctx) noexcept; + +[variablelist +[[Effects:] [Creates an object of preallocated.]] +] + + +[endsect] diff --git a/doc/stack.qbk b/doc/stack.qbk index 61af78e..4babcfd 100644 --- a/doc/stack.qbk +++ b/doc/stack.qbk @@ -5,6 +5,7 @@ http://www.boost.org/LICENSE_1_0.txt ] +[#stack] [section:stack Stack allocation] The memory used by the stack is allocated/deallocated via a __stack_allocator__