diff --git a/.gitignore b/.gitignore
index b72f9be2..12cd3d29 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
*~
*.swp
+doc/html
diff --git a/doc/callcc.qbk b/doc/callcc.qbk
index 0b097092..4c2f146f 100644
--- a/doc/callcc.qbk
+++ b/doc/callcc.qbk
@@ -234,7 +234,7 @@ an exception.
my_exception: abc
In this exception `my_exception` is throw from a function invoked on-top of
-continuation `c` and catched inside the `for`-loop.
+continuation `c` and caught inside the `for`-loop.
[heading Stack unwinding]
On construction of __con__ a stack is allocated.
@@ -397,7 +397,7 @@ of the stack.]
In this example a recursive descent parser uses a callback to emit a newly
passed symbol. Using __callcc__ the control flow can be inverted, e.g. the
-user-code pulls parsed symbols from the parser - instead to get pushed from the
+user-code pulls parsed symbols from the parser - instead of getting pushed from the
parser (via callback).
The data (character) is transferred between the two continuations.
diff --git a/doc/context.xml b/doc/context.xml
deleted file mode 100644
index fb4931d1..00000000
--- a/doc/context.xml
+++ /dev/null
@@ -1,3913 +0,0 @@
-
-
- must be
- given to bjam command line on 64bit Windows for 64bit build; otherwise 32bit
- code will be generated.
- , , ,
- and .
- .
- The parameter represents
- the current fiber from which this fiber was resumed (e.g. that has called
- /.
-
- represents the ).
- is captured (current-fiber) by invoking after each call. In
- order to express the invalidation of the resumed fiber, the member functions
-
- and
- are rvalue-ref qualified. Both functions bind only to rvalues. Thus an lvalue
- fiber must be casted to an rvalue via .
- . Calculated
- Fibonacci numbers are transferred between the two fibers via variable (lambda capture reference).
- and
- remain their values during
- each context switch. This is possible due
- has its own stack and the stack is exchanged by each context switch.
- ) or lambda captures.
-
- enters the lambda in fiber represented by
- with lambda capture reference . The expression
-
- resumes the fiber . On return
- of ,
- the variable has the value
- of .
- .
- can be used to transfer exceptions between different fibers.
- .
-
- executes a lambda on top of fiber ,
- e.g. an additional stack frame is allocated on top of the stack. This lambda
- assigns
- to and returns to the
- second invocation of .
-
- is throw from a function invoked on-top of fiber
- and catched inside the -loop.
- ) is called, the stack will be destructed
- too.
-
- and b2 property .
- and
- b2 property
- Win32-Fibers are used as implementation for . If desired, has to be called by the user explicitly
- in order to release resources allocated by (e.g. after using boost.context).
- .
- is used as default stack allocator (stack size == fixedsize_stack::traits::default_size()).
- The constructor with argument type ,
- is used to create a user defined data (for
- instance additional control structures) on top of the stack.
- is a valid fiber, e.g. .
- .
-
- to
- using move semantics.
- operator()()
-. The function ,
- is used to execute function
- in the execution context of (e.g. the stack frame of is allocated on stack of ).
-
- gets invalidated, and are rvalue-ref qualified and bind
- only to rvalues.
- needs to
- return .
- .
- operator bool()
- if
- points to a captured fiber.
- operator!()
- if
- does not point to a captured fiber.
- operator==()
- if
- and represent
- the same fiber,
- otherwise.
- operator!=()
-! (other == * this)
- operator<()
- if
- is true and the implementation-defined total order of values places
- before , false
- otherwise.
- operator>()
-
- operator<=()
-
- operator>=()
-
- operator<<()
-
- to stream .
-
- . The parameter
- represents the current continuation from which this continuation was resumed
- (e.g. that has called /.
-
- represents the ).
- is captured (current-continuation)
- by invoking after each call.
- . Calculated
- Fibonacci numbers are transferred between the two continuations via variable
- (lambda capture reference).
- and
- remain their values during
- each context switch. This is possible due
- has its own stack and the stack is exchanged by each context switch.
- ) or lambda captures.
-
- enters the lambda in continuation represented by
- with lambda capture reference . The expression
-
- resumes the continuation .
- On return of ,
- the variable has the value
- of .
- .
- can be used to transfer exceptions between different continuations.
- .
-
- executes a lambda on top of continuation ,
- e.g. an additional stack frame is allocated on top of the stack. This lambda
- assigns
- to and returns to the
- second invocation of .
-
- is throw from a function invoked on-top of continuation
- and catched inside the -loop.
- ) is called, the stack will
- be destructed too.
-
- and b2 property .
- and
- b2 property
- Win32-Fibers are used as implementation for . If desired, has to be called by the user explicitly
- in order to release resources allocated by (e.g. after using boost.context).
- is a valid continuation, e.g.
- .
- .
-
- to
- using move semantics.
- operator()()
-. The function ,
- is used to execute function
- in the execution context of (e.g. the stack frame of is allocated on stack of ).
- needs to
- return .
- .
- operator bool()
- if
- points to a captured continuation.
- operator!()
- if
- does not point to a captured continuation.
- operator==()
- if
- and represent
- the same continuation,
- otherwise.
- operator!=()
-! (other == * this)
- operator<()
- if
- is true and the implementation-defined total order of values places
- before , false
- otherwise.
- operator>()
-
- operator<=()
-
- operator>=()
-
- operator<<()
-
- to stream .
-
- . is used as default
- stack allocator (stack size == fixedsize_stack::traits::default_size()).
- The function with argument type ,
- is used to create a user defined data (for
- instance additional control structures) on top of the stack.
- .
- is an object of a is a , and
- is a :
-
-
-
-
-
-
- might include logic to protect against
- exceeding the context's available stack size rather than leaving it as undefined
- behaviour.
-
- with a not
- set by
- results in undefined behaviour.
- stores an address from the top of the stack
- (growing downwards) or the bottom of the stack (growing upwards).
-
- is
-
- and .
-
- Bytes and stores a pointer to the stack and its actual size in . Depending on the architecture
- (the stack grows downwards/upwards) the stored address is the highest/lowest
- address of the stack.
-
- is valid, and .
-
-
- and .
-
- Bytes and stores a pointer to the stack and its actual size in . Depending on the architecture
- (the stack grows downwards/upwards) the stored address is the highest/lowest
- address of the stack. Argument
- determines the number of stacks to request from the system the first
- time that
- needs to allocate system memory. The third argument
- controls how many memory might be allocated for stacks - a value of
- zero means no upper limit.
-
- .
-
- Bytes and stores a pointer to the stack and its actual size in . Depending on the architecture
- (the stack grows downwards/upwards) the stored address is the highest/lowest
- address of the stack.
-
- is valid, .
- and .
-
-
- and .
-
- Bytes and stores a pointer to the stack and its actual size in . Depending on the architecture
- (the stack grows downwards/upwards) the stored address is the highest/lowest
- address of the stack.
-
- is valid, and .
- ,
- e.g.
- at b2/bjam command line.
-
-
- and .
-
- Bytes and stores a pointer to the stack and its actual size in . Depending on the architecture
- (the stack grows downwards/upwards) the stored address is the highest/lowest
- address of the stack.
-
- is valid, and .
-
- if the environment
- defines no limit for the size of a stack.
-
-
-
- and .
-
-
-
- returns .
-
-
- let
- valgrind treat the memory regions as stack space which suppresses the errors.
- Users must define
- before including any Boost.Context headers when linking against Boost binaries
- compiled with .
- and compilers sanitizer options.
- Users must define
- before including any Boost.Context headers when linking against Boost binaries.
- ,
- with overhead corrections. The code was compiled with gcc-6.3.1, using build
- options: variant = release, optimization = speed. Tests were executed on dual
- Intel XEON E5 2620v4 2.2GHz, 16C/32T, 64GB RAM, running Linux (x86_64).
-
-
-
-
- and b2 property .
- /
- to provide non-local jumps but it does not require that
- is deprecated and was removed in POSIX.1-2008! The function signature of
-
- is:
- specifies the number of integer arguments
- that follow which will require function pointer cast if
- will accept those arguments which is undefined in C99 preserves signal
- mask between context switches which involves system calls consuming a lot
- of CPU cycles (ucontext_t is slower; a context switch takes does not accept a pointer to user allocated
- stack space preventing the reuse of stacks for other context instances. Because
- the Windows Fiber API requires to call if is called for a thread which has not been
- converted to a fiber. For the same reason must be called after return from
- if the thread was forced to be converted to a fiber before (which is inefficient).
-
- is met function is provided in order to detect if the current
- thread was already converted. Unfortunately Windows XP + SP 2/3 defines
- without providing
- .
-
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- I'd like to thank Adreas Fett, Artyom Beilis, Daniel Larimer, David Deakins, - Evgeny Shapovalov, Fernando Pelliccioni, Giovanni Piero Deretta, Gordon Woodhull, - Helge Bahmann, Holger Grund, Jeffrey Lee Hellrung (Jr.), Keith Jeffery, Martin - Husemann, Phil Endecott, Robert Stewart, Sergey Cheban, Steven Watanabe, Vicente - J. Botet Escriba, Wayne Piekarski. -
-| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- Boost.Context, using fcontext_t, - supports following architectures: -
-Table 1.2. Supported architectures (<ABI|binary format>)
-|
- - Architecture - - |
-
- - LINUX (UNIX) - - |
-
- - Windows - - |
-
- - MacOS X - - |
-
- - iOS - - |
-
|---|---|---|---|---|
|
- - arm (aarch32) - - |
-
- - AAPCS|ELF - - |
-
- - AAPCS|PE - - |
-
- - - - - |
-
- - AAPCS|MACH-O - - |
-
|
- - arm (aarch64) - - |
-
- - AAPCS|ELF - - |
-
- - - - - |
-
- - - - - |
-
- - AAPCS|MACH-O - - |
-
|
- - i386 - - |
-
- - SYSV|ELF - - |
-
- - MS|PE - - |
-
- - SYSV|MACH-O - - |
-
- - - - - |
-
|
- - loongarch64 - - |
-
- - SYSV|ELF - - |
-
- - - - - |
-
- - - - - |
-
- - - - - |
-
|
- - mips - - |
-
- - O32,N64|ELF - - |
-
- - - - - |
-
- - - - - |
-
- - - - - |
-
|
- - ppc32 - - |
-
- - SYSV|ELF,XCOFF - - |
-
- - - - - |
-
- - SYSV|MACH-O - - |
-
- - - - - |
-
|
- - ppc64 - - |
-
- - SYSV|ELF,XCOFF - - |
-
- - - - - |
-
- - SYSV|MACH-O - - |
-
- - - - - |
-
|
- - riscv64 - - |
-
- - SYSV|ELF - - |
-
- - - - - |
-
- - SYSV - - |
-
- - - - - |
-
|
- - s390x - - |
-
- - SYSV|ELF - - |
-
- - - - - |
-
- - - - - |
-
- - - - - |
-
|
- - sparc - - |
-
- - - - - |
-
- - - - - |
-
- - - - - |
-
- - - - - |
-
|
- - x86_64 - - |
-
- - SYSV,X32|ELF - - |
-
- - MS|PE - - |
-
- - SYSV|MACH-O - - |
-
- - - - - |
-
![]() |
-Note | -
|---|---|
- If the architecture is not supported but the platform provides ucontext_t,
- Boost.Context should be compiled with |
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- Cross compiling the library requires to specify the build properties <architecture>, - <address-model>, <binary-format> and <abi> at b2 command - line. -
-| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
![]() |
-Note | -
|---|---|
- call/cc is the reference implementation of C++ proposal - P0534R3: - call/cc (call-with-current-continuation): A low-level API for stackful context - switching. - |
- call/cc (call with current continuation) is a universal - control operator (well-known from the programming language Scheme) that captures - the current continuation as a first-class object and pass it as an argument - to another continuation. -
-- A continuation (abstract concept of functional programming languages) represents - the state of the control flow of a program at a given point in time. Continuations - can be suspended and resumed later in order to change the control flow of a - program. -
-- Modern micro-processors are registers machines; the content of processor registers - represent a continuation of the executed program at a given point in time. - Operating systems simulate parallel execution of programs on a single processor - by switching between programs (context switch) by preserving and restoring - the continuation, e.g. the content of all registers. -
-- callcc() is the C++ equivalent - to Scheme's call/cc operator. It captures the current - continuation (the rest of the computation; code after callcc()) - and triggers a context switch. The context switch is achieved by preserving - certain registers (including instruction and stack pointer), defined by the - calling convention of the ABI, of the current continuation and restoring those - registers of the resumed continuation. The control flow of the resumed continuation - continues. The current continuation is suspended and passed as argument to - the resumed continuation. -
-
- callcc() expects a context-function
- with signature 'continuation(continuation &&
- c)'. The parameter c
- represents the current continuation from which this continuation was resumed
- (e.g. that has called callcc()).
-
- On return the context-function of the current continuation - has to specify an continuation - to which the execution control is transferred after termination of the current - continuation. -
-- If an instance with valid state goes out of scope and the context-function - has not yet returned, the stack is traversed in order to access the control - structure (address stored at the first stack frame) and continuation's stack - is deallocated via the StackAllocator. -
-![]() |
-Note | -
|---|---|
- Segmented stacks are - supported by callcc() using - ucontext_t. - |
- continuation represents a continuation; - it contains the content of preserved registers and manages the associated stack - (allocation/deallocation). continuation - is a one-shot continuation - it can be used only once, after calling continuation::resume() - or continuation::resume_with() it is invalidated. -
-- continuation is only move-constructible - and move-assignable. -
-- As a first-class object continuation - can be applied to and returned from a function, assigned to a variable or stored - in a container. -
-
- A continuation is continued by calling resume()/resume_with().
-
namespace ctx=boost::context; -int a; -ctx::continuation source=ctx::callcc( - [&a](ctx::continuation && sink){ - a=0; - int b=1; - for(;;){ - sink=sink.resume(); - int next=a+b; - a=b; - b=next; - } - return std::move(sink); - }); -for (int j=0;j<10;++j) { - std::cout << a << " "; - source=source.resume(); -} - -output: - 0 1 1 2 3 5 8 13 21 34 --
- This simple example demonstrates the basic usage of call/cc
- as a generator. The continuation sink
- represents the main-continuation (function main()).
- sink is captured (current-continuation)
- by invoking callcc() and passed
- as parameter to the lambda.
-
- Because the state is invalidated (one-shot continuation) by each call of continuation::resume(),
- the new state of the continuation,
- returned by continuation::resume(), needs to be assigned
- to sink after each call.
-
- The lambda that calculates the Fibonacci numbers is executed inside the continuation
- represented by source. Calculated
- Fibonacci numbers are transferred between the two continuations via variable
- a (lambda capture reference).
-
- The locale variables b and
- next remain their values during
- each context switch. This is possible due source
- has its own stack and the stack is exchanged by each context switch.
-
- Data can be transferred between two continuations via global pointers, calling
- wrappers (like std::bind) or lambda captures.
-
namespace ctx=boost::context; -int i=1; -ctx::continuation c1=callcc([&i](ctx::continuation && c2){ - std::printf("inside c1,i==%d\n",i); - i+=1; - return c2.resume(); - }); -std::printf("i==%d\n",i); - -output: - inside c1,i==1 - i==2 --
- callcc(<lambda>)
- enters the lambda in continuation represented by c1
- with lambda capture reference i=1. The expression
- c2.resume()
- resumes the continuation c2.
- On return of callcc(<lambda>),
- the variable i has the value
- of i+1.
-
- If the function executed inside a context-function emits
- an exception, the application is terminated by calling std::terminate(). std::exception_ptr
- can be used to transfer exceptions between different continuations.
-
![]() |
-Important | -
|---|---|
- Do not jump from inside a catch block and then re-throw the exception in - another continuation. - |
- Sometimes it is useful to execute a new function on top of a resumed continuation.
- For this purpose continuation::resume_with() has to be
- used. The function passed as argument must accept a rvalue reference to continuation and return void.
-
namespace ctx=boost::context; -int data=0; -ctx::continuation c=ctx::callcc([&data](ctx::continuation && c) { - std::cout << "f1: entered first time: " << data << std::endl; - data+=1; - c=c.resume(); - std::cout << "f1: entered second time: " << data << std::endl; - data+=1; - c=c.resume(); - std::cout << "f1: entered third time: " << data << std::endl; - return std::move(c); - }); -std::cout << "f1: returned first time: " << data << std::endl; -data+=1; -c=c.resume(); -std::cout << "f1: returned second time: " << data << std::endl; -data+=1; -c=c.resume_with([&data](ctx::continuation && c){ - std::cout << "f2: entered: " << data << std::endl; - data=-1; - return std::move( c); - }); -std::cout << "f1: returned third time" << std::endl; - -output: - f1: entered first time: 0 - f1: returned first time: 1 - f1: entered second time: 2 - f1: returned second time: 3 - f2: entered: 4 - f1: entered third time: -1 - f1: returned third time --
- The expression c.resume_with(...)
- executes a lambda on top of continuation c,
- e.g. an additional stack frame is allocated on top of the stack. This lambda
- assigns -1
- to data and returns to the
- second invocation of c.resume().
-
- Another option is to execute a function on top of the continuation that throws - an exception. -
-namespace ctx=boost::context; -struct my_exception : public std::runtime_error { - ctx::continuation c; - my_exception(ctx::continuation && c_,std::string const& what) : - std::runtime_error{ what }, - c{ std::move( c_) } { - } -}; - -ctx::continuation c=ctx::callcc([](ctx::continuation && c) { - for (;;) { - try { - std::cout << "entered" << std::endl; - c=c.resume(); - } catch (my_exception & ex) { - std::cerr << "my_exception: " << ex.what() << std::endl; - return std::move(ex.c); - } - } - return std::move(c); -}); -c = c.resume_with( - [](ctx::continuation && c){ - throw my_exception(std::move(c),"abc"); - return std::move( c); - }); - -output: - entered - my_exception: abc --
- In this exception my_exception
- is throw from a function invoked on-top of continuation c
- and catched inside the for-loop.
-
- On construction of continuation
- a stack is allocated. If the context-function returns
- the stack will be destructed. If the context-function
- has not yet returned and the destructor of an valid continuation
- instance (e.g. continuation::operator bool() returns
- true) is called, the stack will
- be destructed too.
-
![]() |
-Important | -
|---|---|
- Code executed by context-function must not prevent the - propagation ofs the detail::forced_unwind exception. - Absorbing that exception will cause stack unwinding to fail. Thus, any code - that catches all exceptions must re-throw any pending detail::forced_unwind - exception. - |
- Allocating control structures on top of the stack requires to allocated the - stack_context and create the control structure with placement - new before continuation is created. -
-![]() |
-Note | -
|---|---|
- The user is responsible for destructing the control structure at the top - of the stack. - |
namespace ctx=boost::context; -// 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 continuation - ctx::continuation c; - - template< typename StackAllocator > - my_control_structure(void * sp,std::size_t size,stack_context sctx,StackAllocator salloc) : - // create captured continuation - c{} { - c=ctx::callcc(std::allocator_arg,preallocated(sp,size,sctx),salloc,entry_func); - } - ... -}; --
namespace ctx=boost::context; -/* - * grammar: - * P ---> E '\0' - * E ---> T {('+'|'-') T} - * T ---> S {('*'|'/') S} - * S ---> digit | '(' E ')' - */ -class Parser{ - char next; - std::istream& is; - std::function<void(char)> cb; - - char pull(){ - return std::char_traits<char>::to_char_type(is.get()); - } - - void scan(){ - do{ - next=pull(); - } - while(isspace(next)); - } - -public: - Parser(std::istream& is_,std::function<void(char)> cb_) : - next(), is(is_), cb(cb_) - {} - - void run() { - scan(); - E(); - } - -private: - void E(){ - T(); - while (next=='+'||next=='-'){ - cb(next); - scan(); - T(); - } - } - - void T(){ - S(); - while (next=='*'||next=='/'){ - cb(next); - scan(); - S(); - } - } - - void S(){ - if (isdigit(next)){ - cb(next); - scan(); - } - else if(next=='('){ - cb(next); - scan(); - E(); - if (next==')'){ - cb(next); - scan(); - }else{ - throw std::runtime_error("parsing failed"); - } - } - else{ - throw std::runtime_error("parsing failed"); - } - } -}; - -std::istringstream is("1+1"); -// execute parser in new continuation -ctx::continuation source; -// user-code pulls parsed data from parser -// invert control flow -char c; -bool done=false; -source=ctx::callcc( - [&is,&c,&done](ctx::continuation && sink){ - // create parser with callback function - Parser p(is, - [&sink,&c](char c_){ - // resume main continuation - c=c_; - sink=sink.resume(); - }); - // start recursive parsing - p.run(); - // signal termination - done=true; - // resume main continuation - return std::move(sink); - }); -while(!done){ - printf("Parsed: %c\n",c); - source=source.resume(); -} - -output: - Parsed: 1 - Parsed: + - Parsed: 1 --
- In this example a recursive descent parser uses a callback to emit a newly - passed symbol. Using call/cc 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 continuations. -
-| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
#include <boost/context/continuation.hpp> - -class continuation { -public: - continuation() noexcept = default; - - ~continuation(); - - continuation(continuation && other) noexcept; - - continuation & operator=(continuation && other) noexcept; - - continuation(continuation const& other) noexcept = delete; - continuation & operator=(continuation const& other) noexcept = delete; - - continuation resume(); - - template<typename Fn> - continuation resume_with(Fn && fn); - - explicit operator bool() const noexcept; - - bool operator!() const noexcept; - - bool operator==(continuation const& other) const noexcept; - - bool operator!=(continuation const& other) const noexcept; - - bool operator<(continuation const& other) const noexcept; - - bool operator>(continuation const& other) const noexcept; - - bool operator<=(continuation const& other) const noexcept; - - bool operator>=(continuation const& other) const noexcept; - - template<typename charT,class traitsT> - friend std::basic_ostream<charT,traitsT> & - operator<<(std::basic_ostream<charT,traitsT> & os,continuation const& other) { - - void swap(continuation & other) noexcept; -}; --
-
--
-continuation() noexcept; --
-
- Creates a invalid continuation. -
- Nothing. -
-
--
-~continuation(); --
-
- Destructs the associated stack if *this is a valid continuation, e.g.
- continuation::operator bool() returns true.
-
- Nothing. -
-
--
-continuation(continuation && other) noexcept; --
-
- Moves underlying capture continuation to *this.
-
- Nothing. -
-
--
-continuation & operator=(continuation && other) noexcept; --
-
- Moves the state of other
- to *this
- using move semantics.
-
- Nothing. -
-
-operator()()
--
-continuation resume(); - -template<typename Fn> -continuation resume_with(Fn && fn); --
-
- Captures current continuation and resumes *this. The function resume_with,
- is used to execute function fn
- in the execution context of *this (e.g. the stack frame of fn is allocated on stack of *this).
-
- The continuation representing the continuation that has been suspended. -
- Function fn needs to
- return continuation.
-
- The returned continuation indicates if the suspended continuation has
- terminated (return from context-function) via bool
- operator().
-
-
-operator bool()
--
-explicit operator bool() const noexcept; --
-
- true if *this
- points to a captured continuation.
-
- Nothing. -
-
-operator!()
--
-bool operator!() const noexcept; --
-
- true if *this
- does not point to a captured continuation.
-
- Nothing. -
-
-operator==()
--
-bool operator==(continuation const& other) const noexcept; --
-
- true if *this
- and other represent
- the same continuation, false
- otherwise.
-
- Nothing. -
-
-operator!=()
--
-bool operator!=(continuation const& other) const noexcept; --
-
- ! (other == * this)
-
- Nothing. -
-
-operator<()
--
-bool operator<(continuation const& other) const noexcept; --
-
- true if *this != other
- is true and the implementation-defined total order of continuation values places *this
- before other, false
- otherwise.
-
- Nothing. -
-
-operator>()
--
-bool operator>(continuation const& other) const noexcept; --
-
- other <
- * this
-
- Nothing. -
-
-operator<=()
--
-bool operator<=(continuation const& other) const noexcept; --
-
- ! (other <
- * this)
-
- Nothing. -
-
-operator>=()
--
-bool operator>=(continuation const& other) const noexcept; --
-
- ! (*
- this <
- other)
-
- Nothing. -
-
-operator<<()
--
-template<typename charT,class traitsT> -std::basic_ostream<charT,traitsT> & -operator<<(std::basic_ostream<charT,traitsT> & os,continuation const& other); --
-
- Writes the representation of other
- to stream os.
-
- os
-
#include <boost/context/continuation.hpp> - -template<typename Fn> -continuation callcc(Fn && fn); - -template<typename StackAlloc,typename Fn> -continuation callcc(std::allocator_arg_t,StackAlloc salloc,Fn && fn); - -template<typename StackAlloc,typename Fn> -continuation callcc(std::allocator_arg_t,preallocated palloc,StackAlloc salloc,Fn && fn); --
-
- Captures current continuation and creates a new continuation prepared
- to execute fn. fixedsize_stack is used as default
- stack allocator (stack size == fixedsize_stack::traits::default_size()).
- The function with argument type preallocated,
- is used to create a user defined data (for
- instance additional control structures) on top of the stack.
-
- The continuation representing the contexcontinuation that has been - suspended. -
- The returned continuation indicates if the suspended continuation has
- terminated (return from context-function) via bool
- operator().
-
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- The implementation uses fcontext_t per default. fcontext_t - is based on assembler and not available for all platforms. It provides a - much better performance than ucontext_t (the context - switch takes two magnitudes of order less CPU cycles; see section performance) - and WinFiber. -
-![]() |
-Note | -
|---|---|
- Because the TIB (thread information block on Windows) is not fully described - in the MSDN, it might be possible that not all required TIB-parts are swapped. - Using WinFiber implementation might be an alternative. - |
- As an alternative, ucontext_t
- can be used by compiling with BOOST_USE_UCONTEXT
- and b2 property context-impl=ucontext.
- ucontext_t might be available on a broader range of
- POSIX-platforms but has some disadvantages
- (for instance deprecated since POSIX.1-2003, not C99 conform).
-
![]() |
-Note | -
|---|---|
- callcc() supports Segmented stacks only with - ucontext_t as its implementation. - |
- With BOOST_USE_WINFIB and
- b2 property context-impl=winfib
- Win32-Fibers are used as implementation for callcc().
-
![]() |
-Note | -
|---|---|
- The first call of callcc()
- converts the thread into a Windows fiber by invoking |
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
![]() |
-Warning | -
|---|---|
- execution_context (v1) is deprecated (does not prevent - UB). - |
![]() |
-Note | -
|---|---|
- execution_context (v1) is the reference implementation - of C++ proposal P099R0: - A low-level API for stackful context switching. - |
![]() |
-Note | -
|---|---|
- execution_context (v1) resides in sub-namespace |
![]() |
-Note | -
|---|---|
- Segmented stacks (segmented-stacks=on), e.g. on demand - growing stacks, can be used with execution_context (v1). - |
- Class execution_context encapsulates context switching - and manages the associated context' stack (allocation/deallocation). -
-- execution_context allocates the context stack (using its - StackAllocator argument) - and creates a control structure on top of it. This structure is responsible - for managing context' stack. Instances of execution_context, - associated with a specific context, share the ownership of the control structure. - If the last reference goes out of scope, the control structure is destroyed - and the stack gets deallocated via the StackAllocator. -
-- execution_context is copy-constructible, move-constructible, - copy-assignable and move-assignable. -
-- execution_context maintains a static (thread-local) pointer, - accessed by execution_context::current(), pointing to - the active context. On each context switch the pointer is updated. The usage - of this global pointer makes the context switch a little bit slower (due access - of thread local storage) but has some advantages. It allows to access the control - structure of the current active context from arbitrary code paths required - in order to support segmented stacks, which require to call certain maintenance - functions (like __splitstack_getcontext() etc.) before each context switch - (each context switch exchanges the stack). -
-
- execution_context expects a function/functor with signature
- void(void* vp) (vp
- is the data passed at the first invocation of ecv1::operator()()).
-
int n=35; -boost::context::v1::execution_context sink(boost::context::v1::execution_context::current()); -boost::context::v1::execution_context source( - [n,&sink](void*)mutable{ - int a=0; - int b=1; - while(n-->0){ - sink(&a); - auto next=a+b; - a=b; - b=next; - } - }); -for(int i=0;i<10;++i){ - std::cout<<*(int*)source()<<" "; -} - -output: - 0 1 1 2 3 5 8 13 21 34 --
- This simple example demonstrates the basic usage of execution_context.
- The context sink, returned
- by execution_context::current(), represents the main-context
- (function main() running) and is one of the captured parameters
- in the lambda expression. The lambda that calculates the Fibonacci numbers
- is executed inside the context represented by source.
- Calculated Fibonacci numbers are transferred between the two context' via expression
- sink(&a) (and returned by source()).
-
- The locale variables a, b and next
- remain their values during each context switch (yield(a)).
- This is possible because ctx
- owns a stack (exchanged by context switch).
-
/* - * 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; - -// create handle to main execution context -auto main_ctx(boost::context::v1::execution_context::current()); -// execute parser in new execution context -boost::context::v1::execution_context source( - [&sink,&is,&done,&except](void*){ - // create parser with callback function - Parser p(is, - [&sink](char ch){ - // resume main execution context - sink(&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 - sink(); - }); - -// user-code pulls parsed data from parser -// invert control flow -void* vp = source(); -if (except) { - std::rethrow_exception(except); -} -while( ! done) { - printf("Parsed: %c\n",* static_cast<char*>(vp)); - vp = source(); - if (except) { - std::rethrow_exception(except); - } -} - -output: - Parsed: 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 the stack requires to allocated the - stack_context and create the control structure with placement - new before execution_context is created. -
-![]() |
-Note | -
|---|---|
- The user is responsible for destructing the control structure at the top - of the stack. - |
// stack-allocator used for (de-)allocating 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) { - } - ... -}; --
- If the function executed inside a execution_context emits - an exception, the application is terminated by calling std::terminate(). - std::exception_ptr can be used to transfer exceptions - between different execution contexts. -
-![]() |
-Important | -
|---|---|
- Do not jump from inside a catch block and then re-throw the exception in - another execution context. - |
- 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::v1::execution_context caller_; - boost::context::v1::execution_context callee_; - -public: - X() : - excptr_(), - caller_( boost::context::v1::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 (std::bad_cast const&) { - 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); - } -}; - -X x; -std::cout << x( 7) << std::endl; - -output: - 7 --
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 > - void * operator()( exec_ontop_arg_t, Fn && fn, void * vp = nullptr); - - 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); -}; --
-
-current()
--
-static execution_context current() noexcept; --
-
- Returns an instance of excution_context pointing to the active execution - context. -
- Nothing. -
-
--
-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); --
-
- Creates a new execution context and prepares the context to execute
- fn. fixedsize_stack
- is used as default stack allocator (stack size == fixedsize_stack::traits::default_size()).
- The constructor with argument type preallocated,
- is used to create a user defined data (for
- instance additional control structures) on top of the stack.
-
-
--
-execution_context( execution_context const& other) noexcept; --
-
- Copies other, e.g. underlying
- control structure is shared with *this.
-
- Nothing. -
-
--
-execution_context( execution_context && other) noexcept; --
-
- Moves underlying control structure to *this.
-
- Nothing. -
-
--
-execution_context & operator=( execution_context const& other) noexcept; --
-
- Copies the state of other
- to *this,
- control structure is shared.
-
- Nothing. -
-
--
-execution_context & operator=( execution_context && other) noexcept; --
-
- Moves the control structure of other
- to *this
- using move semantics.
-
- Nothing. -
-
-operator bool()
--
-explicit operator bool() const noexcept; --
-
- true if *this points to a control structure.
-
- Nothing. -
-
-operator!()
--
-bool operator!() const noexcept; --
-
- true if *this does not point to a control structure.
-
- Nothing. -
-
-operator()()
--
-void * operator()( void * vp = nullptr) noexcept; --
-
- 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.
-
- 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.
-
- The void pointer argument passed to the most recent call to execution_context::operator(), - if any. -
-
-operator(exec_ontop_arg_t)()
--
-template< typename Fn > -void * operator()( exec_ontop_arg_t, Fn && fn, void * vp = nullptr); --
-
- Same as execution_context::operator(). Additionally,
- function fn is executed
- with arguments vp in
- the context of *this
- (e.g. the stack frame of fn
- is allocated on stack of *this).
-
- 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; --
-
- true if *this and other
- represent the same execution context, false
- otherwise.
-
- Nothing. -
-
-operator!=()
--
-bool operator!=( execution_context const& other) const noexcept; --
-
- ! (other == * this)
-
- Nothing. -
-
-operator<()
--
-bool operator<( execution_context const& other) const noexcept; --
-
- true if *this != other is true and the implementation-defined
- total order of execution_context
- values places *this
- before other, false otherwise.
-
- Nothing. -
-
-operator>()
--
-bool operator>( execution_context const& other) const noexcept; --
-
- other <
- * this
-
- Nothing. -
-
-operator<=()
--
-bool operator<=( execution_context const& other) const noexcept; --
-
- ! (other <
- * this)
-
- Nothing. -
-
-operator>=()
--
-bool operator>=( execution_context const& other) const noexcept; --
-
- ! (*
- this <
- other)
-
- Nothing. -
-
-operator<<()
--
-template< typename charT, class traitsT > -std::basic_ostream< charT, traitsT > & -operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other); --
-
- Writes the representation of other
- to stream os.
-
- os
-
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
![]() |
-Note | -
|---|---|
- execution_context (v2) is the reference implementation - of C++ proposal P099R1: - A low-level API for stackful context switching. - |
![]() |
-Note | -
|---|---|
- execution_context (v2) resides in the inlined sub-namespace
- |
![]() |
-Note | -
|---|---|
- Segmented stacks (segmented-stacks=on), e.g. on demand - growing stacks, are not supported by execution_context - (v2). - |
- Class execution_context encapsulates context switching - and manages the associated context' stack (allocation/deallocation). -
-
- execution_context allocates the context stack (using its
- StackAllocator argument)
- and creates a control structure on top of it. This structure is responsible
- for managing context' stack. The address of the control structure is stored
- in the first frame of context' stack (e.g. it can not directly accessed from
- within execution_context). In contrast to execution_context
- (v1) the ownership of the control structure is not shared (no member
- variable to control structure in execution_context).
- execution_context keeps internally a state that is moved
- by a call of execution_context::operator() (*this will be
- invalidated), e.g. after a calling execution_context::operator(),
- *this
- can not be used for an additional context switch.
-
- execution_context is only move-constructible and move-assignable. -
-- The moved state is assigned to a new instance of execution_context. - This object becomes the first argument of the context-function, if the context - was resumed the first time, or the first element in a tuple returned by execution_context::operator() - that has been called in the resumed context. In contrast to execution_context - (v1), the context switch is faster because no global pointer etc. is - involved. -
-![]() |
-Important | -
|---|---|
- Segmented stacks are not supported by execution_context - (v2). - |
- On return the context-function of the current context has to specify an execution_context - to which the execution control is transferred after termination of the current - context. -
-- If an instance with valid state goes out of scope and the context-function - has not yet returned, the stack is traversed in order to access the control - structure (address stored at the first stack frame) and context' stack is deallocated - via the StackAllocator. The stack walking makes the destruction - of execution_context slow and should be prevented if possible. -
-
- execution_context expects a context-function
- with signature execution_context(execution_context
- ctx, Args ... args). The
- parameter ctx represents the
- context from which this context was resumed (e.g. that has called execution_context::operator()
- on *this)
- and args are the data passed
- to execution_context::operator(). The return value represents
- the execution_context that has to be resumed, after termination of this context.
-
- Benefits of execution_context (v2) - over execution_context (v1) - are: faster context switch, type-safety of passed/returned arguments. -
-int n=35; -ctx::execution_context<int> source( - [n](ctx::execution_context<int> && sink,int) mutable { - int a=0; - int b=1; - while(n-->0){ - auto result=sink(a); - sink=std::move(std::get<0>(result)); - auto next=a+b; - a=b; - b=next; - } - return std::move(sink); - }); -for(int i=0;i<10;++i){ - auto result=source(i); - source=std::move(std::get<0>(result)); - std::cout<<std::get<1>(result)<<" "; -} - -output: - 0 1 1 2 3 5 8 13 21 34 --
- This simple example demonstrates the basic usage of execution_context
- as a generator. The context sink
- represents the main-context (function main()
- running). sink is generated
- by the framework (first element of lambda's parameter list). Because the state
- is invalidated (== changed) by each call of execution_context::operator(),
- the new state of the execution_context, returned by execution_context::operator(),
- needs to be assigned to sink
- after each call.
-
- The lambda that calculates the Fibonacci numbers is executed inside the context
- represented by source. Calculated
- Fibonacci numbers are transferred between the two context' via expression
- sink(a) (and returned by source()).
- Note that this example represents a generator thus the
- value transferred into the lambda via source() is not
- used. Using boost::optional<> as transferred type,
- might also appropriate to express this fact.
-
- The locale variables a, b and next
- remain their values during each context switch (yield(a)).
- This is possible due source
- has its own stack and the stack is exchanged by each context switch.
-
- With execution_context<void> no
- data will be transferred, only the context switch is executed.
-
boost::context::execution_context<void> ctx1([](boost::context::execution_context<void> && ctx2){ - std::printf("inside ctx1\n"); - return ctx2(); - }); -ctx1(); - -output: - inside ctx1 --
- ctx1()
- resumes ctx1, e.g. the lambda
- passed at the constructor of ctx1
- is entered. Argument ctx2 represents
- the context that has been suspended with the invocation of ctx1(). When the lambda returns ctx2,
- context ctx1 will be terminated
- while the context represented by ctx2
- is resumed, hence the control of execution returns from ctx1().
-
- The arguments passed to execution_context::operator(), - in one context, is passed as the last arguments of the context-function - if the context is started for the first time. In all following invocations - of execution_context::operator() the arguments passed - to execution_context::operator(), in one context, is returned - by execution_context::operator() in the other context. -
-boost::context::execution_context<int> ctx1([](boost::context::execution_context<int> && ctx2,int j){ - std::printf("inside ctx1,j==%d\n",j); - std::tie(ctx2,j)=ctx2(j+1); - return std::move(ctx2); - }); -int i=1; -std::tie(ctx1,i)=ctx1(i); -std::printf("i==%d\n",i); - -output: - inside ctx1,j==1 - i==2 --
- ctx1(i) enters
- the lambda in context ctx1
- with argument j=1. The expression ctx2(j+1) resumes the
- context represented by ctx2
- and transfers back an integer of j+1. On return
- of ctx1(i), the variable
- i contains the value of j+1.
-
- If more than one argument has to be transferred, the signature of the context-function - is simply extended. -
-boost::context::execution_context<int,int> ctx1([](boost::context::execution_context<int,int> && ctx2,int i,int j){ - std::printf("inside ctx1,i==%d,j==%d\n",i,j); - std::tie(ctx2,i,j)=ctx2(i+j,i-j); - return std::move(ctx2); - }); -int i=2,j=1; -std::tie(ctx1,i,j)=ctx1(i,j); -std::printf("i==%d,j==%d\n",i,j); - -output: - inside ctx1,i==2,j==1 - i==3,j==1 --
- For use-cases, that require to transfer data of different type in each direction, - boost::variant<> could be used. -
-class X{ -private: - std::exception_ptr excptr_; - boost::context::execution_context<boost::variant<int,std::string>> ctx_; - -public: - X(): - excptr_(), - ctx_([=](boost::context::execution_context<boost::variant<int,std::string>> && ctx,boost::variant<int,std::string> data){ - try { - for (;;) { - int i=boost::get<int>(data); - data=boost::lexical_cast<std::string>(i); - auto result=ctx(data); - ctx=std::move(std::get<0>(result)); - data=std::get<1>(result); - } catch (std::bad_cast const&) { - excptr_=std::current_exception(); - } - return std::move(ctx); - }) - {} - - std::string operator()(int i){ - boost::variant<int,std::string> data=i; - auto result=ctx_(data); - ctx_=std::move(std::get<0>(result)); - data=std::get<1>(result); - if(excptr_){ - std::rethrow_exception(excptr_); - } - return boost::get<std::string>(data); - } -}; - -X x; -std::cout << x(7) << std::endl; - -output: -7 --
- In the case of unidirectional transfer of data, boost::optional<> - or a pointer are appropriate. -
-- If the function executed inside a execution_context emits - an exception, the application is terminated by calling std::terminate(). - std::exception_ptr can be used to transfer exceptions - between different execution contexts. -
-![]() |
-Important | -
|---|---|
- Do not jump from inside a catch block and then re-throw the exception in - another execution context. - |
- Sometimes it is useful to execute a new function on top of a resumed context.
- For this purpose execution_context::operator() with first
- argument exec_ontop_arg has
- to be used. The function passed as argument must return a tuple of execution_context
- and arguments.
-
boost::context::execution_context<int> f1(boost::context::execution_context<int> && ctx,int data) { - std::cout << "f1: entered first time: " << data << std::endl; - std::tie(ctx,data)=ctx(data+1); - std::cout << "f1: entered second time: " << data << std::endl; - std::tie(ctx,data)=ctx(data+1); - std::cout << "f1: entered third time: " << data << std::endl; - return std::move(ctx); -} - -int f2(int data) { - std::cout << "f2: entered: " << data << std::endl; - return -1; -} - -int data=0; -boost::context::execution_context< int > ctx(f1); -std::tie(ctx,data)=ctx(data+1); -std::cout << "f1: returned first time: " << data << std::endl; -std::tie(ctx,data)=ctx(data+1); -std::cout << "f1: returned second time: " << data << std::endl; -std::tie(ctx,data)=ctx(ctx::exec_ontop_arg,f2,data+1); - -output: - f1: entered first time: 1 - f1: returned first time: 2 - f1: entered second time: 3 - f1: returned second time: 4 - f2: entered: 5 - f1: entered third time: -1 --
- The expression ctx(ctx::exec_ontop_arg,f2,data+1) executes f2() on top of context ctx,
- e.g. an additional stack frame is allocated on top of the context stack (in
- front of f1()).
- f2()
- returns argument -1
- that will returned by the second invocation of ctx(data+1) in f1().
-
-
--
-~execution_context(); --
-
- Destructs the associated stack if *this is a valid context, e.g. execution_context::operator
- bool() returns true.
-
- Nothing. -
-
--
-execution_context( execution_context && other) noexcept; --
-
- Moves underlying capture record to *this.
-
- Nothing. -
-
--
-execution_context & operator=( execution_context && other) noexcept; --
-
- Moves the state of other
- to *this
- using move semantics.
-
- Nothing. -
-
-operator bool()
--
-explicit operator bool() const noexcept; --
-
- true if *this points to a capture record.
-
- Nothing. -
-
-operator!()
--
-bool operator!() const noexcept; --
-
- true if *this does not point to a capture record.
-
- Nothing. -
-
-operator()()
--
-std::tuple< execution_context< Args ... >, Args ... > operator()( Args ... args); // member of generic execution_context template - -execution_context< void > operator()(); // member of execution_context< void > --
-
- 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 arguments, ... args, are passed to the current context
- to be returned by the most recent call to execution_context::operator() in the same thread.
-
- The tuple of execution_context and returned arguments passed to the most
- recent call to execution_context::operator(), if any and a execution_context representing
- the context that has been suspended.
-
- The returned execution_context indicates if the suspended context has
- terminated (return from context-function) via bool
- operator().
- If the returned execution_context has terminated no data are transferred
- in the returned tuple.
-
-
-operator()()
--
-template< typename Fn > -std::tuple< execution_context< Args ... >, Args ... > operator()( exec_ontop_arg_t, Fn && fn, Args ... args); // member of generic execution_context - -template< typename Fn > -execution_context< void > operator()( exec_ontop_arg_t, Fn && fn); // member of execution_context< void > --
-
- Same as execution_context::operator(). Additionally,
- function fn is executed
- in the context of *this
- (e.g. the stack frame of fn
- is allocated on stack of *this).
-
- The tuple of execution_context and returned arguments passed to the most
- recent call to execution_context::operator(), if any and a execution_context representing
- the context that has been suspended .
-
- The tuple of execution_context and returned arguments from fn are passed as arguments to the context-function
- of resumed context (if the context is entered the first time) or those
- arguments are returned from execution_context::operator() within the resumed context.
-
- Function fn needs to
- return a tuple of arguments (see description).
-
- The context calling this function must not be destroyed before the arguments,
- that will be returned from fn,
- are preserved at least in the stack frame of the resumed context.
-
- The returned execution_context indicates if the suspended context has
- terminated (return from context-function) via bool
- operator().
- If the returned execution_context has terminated no data are transferred
- in the returned tuple.
-
-
-operator==()
--
-bool operator==( execution_context const& other) const noexcept; --
-
- true if *this and other
- represent the same execution context, false
- otherwise.
-
- Nothing. -
-
-operator!=()
--
-bool operator!=( execution_context const& other) const noexcept; --
-
- ! (other == * this)
-
- Nothing. -
-
-operator<()
--
-bool operator<( execution_context const& other) const noexcept; --
-
- true if *this != other is true and the implementation-defined
- total order of execution_context
- values places *this
- before other, false otherwise.
-
- Nothing. -
-
-operator>()
--
-bool operator>( execution_context const& other) const noexcept; --
-
- other <
- * this
-
- Nothing. -
-
-operator<=()
--
-bool operator<=( execution_context const& other) const noexcept; --
-
- ! (other <
- * this)
-
- Nothing. -
-
-operator>=()
--
-bool operator>=( execution_context const& other) const noexcept; --
-
- ! (*
- this <
- other)
-
- Nothing. -
-
-operator<<()
--
-template< typename charT, class traitsT > -std::basic_ostream< charT, traitsT > & -operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other); --
-
- Writes the representation of other
- to stream os.
-
- os
-
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
![]() |
-Note | -
|---|---|
- fiber is the reference implementation of C++ proposal - P0876R0: - fibers without scheduler. - |
- A fiber represents the state of the control flow of a - program at a given point in time. Fibers can be suspended and resumed later - in order to change the control flow of a program. -
-- Modern micro-processors are registers machines; the content of processor registers - represent a fiber of the executed program at a given point in time. Operating - systems simulate parallel execution of programs on a single processor by switching - between programs (context switch) by preserving and restoring the fiber, e.g. - the content of all registers. -
-- fiber captures the current fiber - (the rest of the computation; code after fiber) - and triggers a context switch. The context switch is achieved by preserving - certain registers (including instruction and stack pointer), defined by the - calling convention of the ABI, of the current fiber and restoring those registers - of the resumed fiber. The control flow of the resumed fiber continues. The - current fiber is suspended and passed as argument to the resumed fiber. -
-
- fiber expects a context-function
- with signature 'fiber(fiber && f)'.
- The parameter f represents
- the current fiber from which this fiber was resumed (e.g. that has called
- fiber).
-
- On return the context-function of the current fiber has - to specify an fiber to which - the execution control is transferred after termination of the current fiber. -
-- If an instance with valid state goes out of scope and the context-function - has not yet returned, the stack is traversed in order to access the control - structure (address stored at the first stack frame) and fiber's stack is deallocated - via the StackAllocator. -
-![]() |
-Note | -
|---|---|
- Segmented stacks are - supported by fiber using - ucontext_t. - |
- fiber represents a fiber; - it contains the content of preserved registers and manages the associated stack - (allocation/deallocation). fiber - is a one-shot fiber - it can be used only once, after calling continuation::resume() - or continuation::resume_with() it is invalidated. -
-- fiber is only move-constructible - and move-assignable. -
-- As a first-class object fiber - can be applied to and returned from a function, assigned to a variable or stored - in a container. -
-
- A fiber is continued by calling resume()/resume_with().
-
namespace ctx=boost::context; -int a; -ctx::fiber source{[&a](ctx::fiber&& sink){ - a=0; - int b=1; - for(;;){ - sink=std::move(sink).resume(); - int next=a+b; - a=b; - b=next; - } - return std::move(sink); -}}; -for (int j=0;j<10;++j) { - source=std::move(source).resume(); - std::cout << a << " "; -} - -output: - 0 1 1 2 3 5 8 13 21 34 --
- This simple example demonstrates the basic usage of fiber
- as a generator. The fiber sink
- represents the main-fiber (function main()). sink
- is captured (current-fiber) by invoking fiber
- and passed as parameter to the lambda.
-
- Because the state is invalidated (one-shot fiber) by each call of continuation::resume(),
- the new state of the fiber,
- returned by continuation::resume(), needs to be assigned
- to sink after each call. In
- order to express the invalidation of the resumed fiber, the member functions
- resume()
- and resume_with()
- are rvalue-ref qualified. Both functions bind only to rvalues. Thus an lvalue
- fiber must be casted to an rvalue via std::move().
-
- The lambda that calculates the Fibonacci numbers is executed inside the fiber
- represented by source. Calculated
- Fibonacci numbers are transferred between the two fibers via variable a (lambda capture reference).
-
- The locale variables b and
- next remain their values during
- each context switch. This is possible due source
- has its own stack and the stack is exchanged by each context switch.
-
- Data can be transferred between two fibers via global pointers, calling wrappers
- (like std::bind) or lambda captures.
-
namespace ctx=boost::context; -int i=1; -ctx::fiber f1{[&i](ctx::fiber&& f2){ - std::printf("inside f1,i==%d\n",i); - i+=1; - return std::move(f2).resume(); -}}; -f1=std::move(f1).resume(); -std::printf("i==%d\n",i); - -output: - inside c1,i==1 - i==2 --
- f1.resume()
- enters the lambda in fiber represented by f1
- with lambda capture reference i=1. The expression
- f2.resume()
- resumes the fiber f2. On return
- of f1.resume(),
- the variable i has the value
- of i+1.
-
- If the function executed inside a context-function emits
- an exception, the application is terminated by calling std::terminate(). std::exception_ptr
- can be used to transfer exceptions between different fibers.
-
![]() |
-Important | -
|---|---|
- Do not jump from inside a catch block and then re-throw the exception in - another fiber. - |
- Sometimes it is useful to execute a new function on top of a resumed fiber.
- For this purpose continuation::resume_with() has to be
- used. The function passed as argument must accept a rvalue reference to fiber and return void.
-
namespace ctx=boost::context; -int data=0; -ctx::fiber f1{[&data](ctx::fiber&& f2) { - std::cout << "f1: entered first time: " << data << std::endl; - data+=1; - f2=std::move(f2).resume(); - std::cout << "f1: entered second time: " << data << std::endl; - data+=1; - f2=std::move(f2).resume(); - std::cout << "f1: entered third time: " << data << std::endl; - return std::move(f2); -}}; -f1=std::move(f1).resume(); -std::cout << "f1: returned first time: " << data << std::endl; -data+=1; -f1=std::move(f1).resume(); -std::cout << "f1: returned second time: " << data << std::endl; -data+=1; -f1=f1.resume_with([&data](ctx::fiber&& f2){ - std::cout << "f2: entered: " << data << std::endl; - data=-1; - return std::move(f2); -}); -std::cout << "f1: returned third time" << std::endl; - -output: - f1: entered first time: 0 - f1: returned first time: 1 - f1: entered second time: 2 - f1: returned second time: 3 - f2: entered: 4 - f1: entered third time: -1 - f1: returned third time --
- The expression f1.resume_with(...)
- executes a lambda on top of fiber f1,
- e.g. an additional stack frame is allocated on top of the stack. This lambda
- assigns -1
- to data and returns to the
- second invocation of f1.resume().
-
- Another option is to execute a function on top of the fiber that throws an - exception. -
-namespace ctx=boost::context; -struct my_exception : public std::runtime_error { - ctx::fiber f; - my_exception(ctx::fiber&& f_,std::string const& what) : - std::runtime_error{ what }, - f{ std::move(f_) } { - } -}; - -ctx::fiber f{[](ctx::fiber && f) ->ctx::fiber { - std::cout << "entered" << std::endl; - try { - f=std::move(f).resume(); - } catch (my_exception & ex) { - std::cerr << "my_exception: " << ex.what() << std::endl; - return std::move(ex.f); - } - return {}; -}); -f=std::move(f).resume(); -f=std::move(f).resume_with([](ctx::fiber && f) ->ctx::fiber { - throw my_exception(std::move(f),"abc"); - return {}; -}); - -output: - entered - my_exception: abc --
- In this exception my_exception
- is throw from a function invoked on-top of fiber f
- and catched inside the for-loop.
-
- On construction of fiber a stack
- is allocated. If the context-function returns the stack
- will be destructed. If the context-function has not yet
- returned and the destructor of an valid fiber
- instance (e.g. fiber::operator bool() returns true) is called, the stack will be destructed
- too.
-
![]() |
-Important | -
|---|---|
- Code executed by context-function must not prevent the - propagation ofs the detail::forced_unwind exception. - Absorbing that exception will cause stack unwinding to fail. Thus, any code - that catches all exceptions must re-throw any pending detail::forced_unwind - exception. - |
- Allocating control structures on top of the stack requires to allocated the - stack_context and create the control structure with placement - new before fiber is created. -
-![]() |
-Note | -
|---|---|
- The user is responsible for destructing the control structure at the top - of the stack. - |
namespace ctx=boost::context; -// 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 fiber - ctx::fiber f; - - template< typename StackAllocator > - my_control_structure(void * sp,std::size_t size,stack_context sctx,StackAllocator salloc) : - // create captured fiber - f{std::allocator_arg,preallocated(sp,size,sctx),salloc,entry_func} { - } - ... -}; --
namespace ctx=boost::context; -/* - * grammar: - * P ---> E '\0' - * E ---> T {('+'|'-') T} - * T ---> S {('*'|'/') S} - * S ---> digit | '(' E ')' - */ -class Parser{ - char next; - std::istream& is; - std::function<void(char)> cb; - - char pull(){ - return std::char_traits<char>::to_char_type(is.get()); - } - - void scan(){ - do{ - next=pull(); - } - while(isspace(next)); - } - -public: - Parser(std::istream& is_,std::function<void(char)> cb_) : - next(), is(is_), cb(cb_) - {} - - void run() { - scan(); - E(); - } - -private: - void E(){ - T(); - while (next=='+'||next=='-'){ - cb(next); - scan(); - T(); - } - } - - void T(){ - S(); - while (next=='*'||next=='/'){ - cb(next); - scan(); - S(); - } - } - - void S(){ - if (isdigit(next)){ - cb(next); - scan(); - } - else if(next=='('){ - cb(next); - scan(); - E(); - if (next==')'){ - cb(next); - scan(); - }else{ - throw std::runtime_error("parsing failed"); - } - } - else{ - throw std::runtime_error("parsing failed"); - } - } -}; - -std::istringstream is("1+1"); -// user-code pulls parsed data from parser -// invert control flow -char c; -bool done=false; -// execute parser in new fiber -ctx::fiber source{[&is,&c,&done](ctx::fiber&& sink){ - // create parser with callback function - Parser p(is, - [&sink,&c](char c_){ - // resume main fiber - c=c_; - sink=std::move(sink).resume(); - }); - // start recursive parsing - p.run(); - // signal termination - done=true; - // resume main fiber - return std::move(sink); -}}; -source=std::move(source).resume(); -while(!done){ - printf("Parsed: %c\n",c); - source=std::Move(source).resume(); -} - -output: - Parsed: 1 - Parsed: + - Parsed: 1 --
- In this example a recursive descent parser uses a callback to emit a newly - passed symbol. Using fiber 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 fibers. -
-| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
fiber
-#include <boost/context/fiber.hpp> - -class fiber { -public: - fiber() noexcept; - - template<typename Fn> - fiber(Fn && fn); - - template<typename StackAlloc, typename Fn> - fiber(std::allocator_arg_t, StackAlloc && salloc, Fn && fn); - - ~fiber(); - - fiber(fiber && other) noexcept; - - fiber & operator=(fiber && other) noexcept; - - fiber(fiber const& other) noexcept = delete; - fiber & operator=(fiber const& other) noexcept = delete; - - fiber resume() &&; - - template<typename Fn> - fiber resume_with(Fn && fn) &&; - - explicit operator bool() const noexcept; - - bool operator!() const noexcept; - - bool operator==(fiber const& other) const noexcept; - - bool operator!=(fiber const& other) const noexcept; - - bool operator<(fiber const& other) const noexcept; - - bool operator>(fiber const& other) const noexcept; - - bool operator<=(fiber const& other) const noexcept; - - bool operator>=(fiber const& other) const noexcept; - - template<typename charT,class traitsT> - friend std::basic_ostream<charT,traitsT> & - operator<<(std::basic_ostream<charT,traitsT> & os,fiber const& other) { - - void swap(fiber & other) noexcept; -}; --
-
--
-fiber() noexcept; --
-
- Creates a invalid fiber. -
- Nothing. -
-
--
-template<typename Fn> -fiber(Fn && fn); - -template<typename StackAlloc, typename Fn> -fiber(std::allocator_arg_t, StackAlloc && salloc, Fn && fn); --
-
- Creates a new fiber and prepares the context to execute fn. fixedsize_stack
- is used as default stack allocator (stack size == fixedsize_stack::traits::default_size()).
- The constructor with argument type preallocated,
- is used to create a user defined data (for
- instance additional control structures) on top of the stack.
-
-
--
-~fiber(); --
-
- Destructs the associated stack if *this is a valid fiber, e.g. fiber::operator
- bool() returns true.
-
- Nothing. -
-
--
-fiber(fiber && other) noexcept; --
-
- Moves underlying capture fiber to *this.
-
- Nothing. -
-
--
-fiber & operator=(fiber && other) noexcept; --
-
- Moves the state of other
- to *this
- using move semantics.
-
- Nothing. -
-
-operator()()
--
-fiber resume() &&; - -template<typename Fn> -fiber resume_with(Fn && fn) &&; --
-
- Captures current fiber and resumes *this. The function resume_with,
- is used to execute function fn
- in the execution context of *this (e.g. the stack frame of fn is allocated on stack of *this).
-
- The fiber representing the fiber that has been suspended. -
- Because *this
- gets invalidated, resume() and resume_with() are rvalue-ref qualified and bind
- only to rvalues.
-
- Function fn needs to
- return fiber.
-
- The returned fiber indicates if the suspended fiber has terminated
- (return from context-function) via bool
- operator().
-
-
-operator bool()
--
-explicit operator bool() const noexcept; --
-
- true if *this
- points to a captured fiber.
-
- Nothing. -
-
-operator!()
--
-bool operator!() const noexcept; --
-
- true if *this
- does not point to a captured fiber.
-
- Nothing. -
-
-operator==()
--
-bool operator==(fiber const& other) const noexcept; --
-
- true if *this
- and other represent
- the same fiber, false
- otherwise.
-
- Nothing. -
-
-operator!=()
--
-bool operator!=(fiber const& other) const noexcept; --
-
- ! (other == * this)
-
- Nothing. -
-
-operator<()
--
-bool operator<(fiber const& other) const noexcept; --
-
- true if *this != other
- is true and the implementation-defined total order of fiber values places *this
- before other, false
- otherwise.
-
- Nothing. -
-
-operator>()
--
-bool operator>(fiber const& other) const noexcept; --
-
- other <
- * this
-
- Nothing. -
-
-operator<=()
--
-bool operator<=(fiber const& other) const noexcept; --
-
- ! (other <
- * this)
-
- Nothing. -
-
-operator>=()
--
-bool operator>=(fiber const& other) const noexcept; --
-
- ! (*
- this <
- other)
-
- Nothing. -
-
-operator<<()
--
-template<typename charT,class traitsT> -std::basic_ostream<charT,traitsT> & -operator<<(std::basic_ostream<charT,traitsT> & os,fiber const& other); --
-
- Writes the representation of other
- to stream os.
-
- os
-
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- The implementation uses fcontext_t per default. fcontext_t - is based on assembler and not available for all platforms. It provides a - much better performance than ucontext_t (the context - switch takes two magnitudes of order less CPU cycles; see section performance) - and WinFiber. -
-![]() |
-Note | -
|---|---|
- Because the TIB (thread information block on Windows) is not fully described - in the MSDN, it might be possible that not all required TIB-parts are swapped. - Using WinFiber implementation might be an alternative. - |
- As an alternative, ucontext_t
- can be used by compiling with BOOST_USE_UCONTEXT
- and b2 property context-impl=ucontext.
- ucontext_t might be available on a broader range of
- POSIX-platforms but has some disadvantages
- (for instance deprecated since POSIX.1-2003, not C99 conform).
-
![]() |
-Note | -
|---|---|
- fiber supports Segmented - stacks only with ucontext_t as its - implementation. - |
- With BOOST_USE_WINFIB and
- b2 property context-impl=winfib
- Win32-Fibers are used as implementation for fiber.
-
![]() |
-Note | -
|---|---|
- The first call of fiber
- converts the thread into a Windows fiber by invoking |
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
![]() |
-Note | -
|---|---|
- __fiber__ is the reference implementation of C++ proposal P0876R0: - fibers without scheduler. - |
- A fiber represents the state of the control flow of a program at a given point - in time. Fibers can be suspended and resumed later in order to change the control - flow of a program. -
-- Modern micro-processors are registers machines; the content of processor registers - represent a fiber of the executed program at a given point in time. Operating - systems simulate parallel execution of programs on a single processor by switching - between programs (context switch) by preserving and restoring the fiber, e.g. - the content of all registers. -
-- __fiber__ captures the current fiber (the rest of the computation; code after - __fiber__) and triggers a context switch. The context switch is achieved by - preserving certain registers (including instruction and stack pointer), defined - by the calling convention of the ABI, of the current fiber and restoring those - registers of the resumed fiber. The control flow of the resumed fiber continues. - The current fiber is suspended and passed as argument to the resumed fiber. -
-
- __fiber__ expects a context-function with signature 'fiber(fiber && f)'. The parameter f represents the current fiber from which
- this fiber was resumed (e.g. that has called __fiber__).
-
- On return the context-function of the current fiber has - to specify an continuation to - which the execution control is transferred after termination of the current - fiber. -
-- If an instance with valid state goes out of scope and the context-function - has not yet returned, the stack is traversed in order to access the control - structure (address stored at the first stack frame) and fiber's stack is deallocated - via the StackAllocator. -
-![]() |
-Note | -
|---|---|
- Segmented stacks are - supported by __fiber__ using ucontext_t. - |
- continuation represents a fiber; - it contains the content of preserved registers and manages the associated stack - (allocation/deallocation). continuation - is a one-shot fiber - it can be used only once, after calling continuation::resume() - or continuation::resume_with() it is invalidated. -
-- continuation is only move-constructible - and move-assignable. -
-- As a first-class object continuation - can be applied to and returned from a function, assigned to a variable or stored - in a container. -
-
- A fiber is continued by calling resume()/resume_with().
-
namespace ctx=boost::context; -int a; -ctx::fiber source{[&a](ctx::fiber && sink){ - a=0; - int b=1; - for(;;){ - sink=sink.resume(); - int next=a+b; - a=b; - b=next; - } - return std::move(sink); -}}; -for (int j=0;j<10;++j) { - source=source.resume(); - std::cout << a << " "; -} - -output: - 0 1 1 2 3 5 8 13 21 34 --
- This simple example demonstrates the basic usage of __fiber__ as a generator.
- The fiber sink represents the
- main-fiber (function main()). sink
- is captured (current-fiber) by invoking __fiber__ and passed as parameter to
- the lambda.
-
- Because the state is invalidated (one-shot fiber) by each call of continuation::resume(),
- the new state of the continuation,
- returned by continuation::resume(), needs to be assigned
- to sink after each call.
-
- The lambda that calculates the Fibonacci numbers is executed inside the fiber
- represented by source. Calculated
- Fibonacci numbers are transferred between the two fibers via variable a (lambda capture reference).
-
- The locale variables b and
- next remain their values during
- each context switch. This is possible due source
- has its own stack and the stack is exchanged by each context switch.
-
- Data can be transferred between two fibers via global pointers, calling wrappers
- (like std::bind) or lambda captures.
-
namespace ctx=boost::context; -int i=1; -ctx::fiber f1{[&i](ctx::fiber && f2){ - std::printf("inside f1,i==%d\n",i); - i+=1; - return f2.resume(); -}}; -f1=f1.resume(); -std::printf("i==%d\n",i); - -output: - inside c1,i==1 - i==2 --
- callcc(<lambda>)
- enters the lambda in fiber represented by c1
- with lambda capture reference i=1. The expression
- c2.resume()
- resumes the fiber c2. On return
- of callcc(<lambda>),
- the variable i has the value
- of i+1.
-
- If the function executed inside a context-function emits
- an exception, the application is terminated by calling std::terminate(). std::exception_ptr
- can be used to transfer exceptions between different fibers.
-
![]() |
-Important | -
|---|---|
- Do not jump from inside a catch block and then re-throw the exception in - another fiber. - |
- Sometimes it is useful to execute a new function on top of a resumed fiber.
- For this purpose continuation::resume_with() has to be
- used. The function passed as argument must accept a rvalue reference to continuation and return void.
-
namespace ctx=boost::context; -int data=0; -ctx::fiber f1{[&data](ctx::fiber && f2) { - std::cout << "f1: entered first time: " << data << std::endl; - data+=1; - f2=f2.resume(); - std::cout << "f1: entered second time: " << data << std::endl; - data+=1; - f2=f2.resume(); - std::cout << "f1: entered third time: " << data << std::endl; - return std::move(f2); -}}; -f1=f1.resume(); -std::cout << "f1: returned first time: " << data << std::endl; -data+=1; -f1=f1.resume(); -std::cout << "f1: returned second time: " << data << std::endl; -data+=1; -f1=f1.resume_with([&data](ctx::fiber && f2){ - std::cout << "f2: entered: " << data << std::endl; - data=-1; - return std::move( f2); -}); -std::cout << "f1: returned third time" << std::endl; - -output: - f1: entered first time: 0 - f1: returned first time: 1 - f1: entered second time: 2 - f1: returned second time: 3 - f2: entered: 4 - f1: entered third time: -1 - f1: returned third time --
- The expression f1.resume_with(...)
- executes a lambda on top of fiber f1,
- e.g. an additional stack frame is allocated on top of the stack. This lambda
- assigns -1
- to data and returns to the
- second invocation of f1.resume().
-
- Another option is to execute a function on top of the fiber that throws an - exception. -
-namespace ctx=boost::context; -struct my_exception : public std::runtime_error { - ctx::fiber f; - my_exception(ctx::fiber && f_,std::string const& what) : - std::runtime_error{ what }, - f{ std::move( f_) } { - } -}; - -ctx::fiber f{[](ctx::fiber && f) ->ctx::fiber { - std::cout << "entered" << std::endl; - try { - f=f.resume(); - } catch (my_exception & ex) { - std::cerr << "my_exception: " << ex.what() << std::endl; - return std::move(ex.f); - } - return {}; -}); -f = f.resume(); -f = f.resume_with([](ctx::fiber && f) ->ctx::fiber { - throw my_exception(std::move(f),"abc"); - return {}; -}); - -output: - entered - my_exception: abc --
- In this exception my_exception
- is throw from a function invoked on-top of fiber c
- and catched inside the for-loop.
-
- On construction of continuation
- a stack is allocated. If the context-function returns
- the stack will be destructed. If the context-function
- has not yet returned and the destructor of an valid continuation
- instance (e.g. fiber::operator bool() returns true) is called, the stack will be destructed
- too.
-
![]() |
-Important | -
|---|---|
- Code executed by context-function must not prevent the - propagation ofs the detail::forced_unwind exception. - Absorbing that exception will cause stack unwinding to fail. Thus, any code - that catches all exceptions must re-throw any pending detail::forced_unwind - exception. - |
- Allocating control structures on top of the stack requires to allocated the - stack_context and create the control structure with placement - new before continuation is created. -
-![]() |
-Note | -
|---|---|
- The user is responsible for destructing the control structure at the top - of the stack. - |
namespace ctx=boost::context; -// 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 fiber - ctx::fiber f; - - template< typename StackAllocator > - my_control_structure(void * sp,std::size_t size,stack_context sctx,StackAllocator salloc) : - // create captured fiber - f{std::allocator_arg,preallocated(sp,size,sctx),salloc,entry_func} { - } - ... -}; --
namespace ctx=boost::context; -/* - * grammar: - * P ---> E '\0' - * E ---> T {('+'|'-') T} - * T ---> S {('*'|'/') S} - * S ---> digit | '(' E ')' - */ -class Parser{ - char next; - std::istream& is; - std::function<void(char)> cb; - - char pull(){ - return std::char_traits<char>::to_char_type(is.get()); - } - - void scan(){ - do{ - next=pull(); - } - while(isspace(next)); - } - -public: - Parser(std::istream& is_,std::function<void(char)> cb_) : - next(), is(is_), cb(cb_) - {} - - void run() { - scan(); - E(); - } - -private: - void E(){ - T(); - while (next=='+'||next=='-'){ - cb(next); - scan(); - T(); - } - } - - void T(){ - S(); - while (next=='*'||next=='/'){ - cb(next); - scan(); - S(); - } - } - - void S(){ - if (isdigit(next)){ - cb(next); - scan(); - } - else if(next=='('){ - cb(next); - scan(); - E(); - if (next==')'){ - cb(next); - scan(); - }else{ - throw std::runtime_error("parsing failed"); - } - } - else{ - throw std::runtime_error("parsing failed"); - } - } -}; - -std::istringstream is("1+1"); -// user-code pulls parsed data from parser -// invert control flow -char c; -bool done=false; -// execute parser in new fiber -ctx::fiber source{[&is,&c,&done](ctx::fiber && sink){ - // create parser with callback function - Parser p(is, - [&sink,&c](char c_){ - // resume main fiber - c=c_; - sink=sink.resume(); - }); - // start recursive parsing - p.run(); - // signal termination - done=true; - // resume main fiber - return std::move(sink); -}}; -source = source.resume(); -while(!done){ - printf("Parsed: %c\n",c); - source=source.resume(); -} - -output: - Parsed: 1 - Parsed: + - Parsed: 1 --
- In this example a recursive descent parser uses a callback to emit a newly - passed symbol. Using __fiber__ 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 fibers. -
-| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
fiber
-#include <boost/context/fiber.hpp> - -class fiber { -public: - fiber() noexcept = default; - - ~fiber(); - - fiber(fiber && other) noexcept; - - fiber & operator=(fiber && other) noexcept; - - fiber(fiber const& other) noexcept = delete; - fiber & operator=(fiber const& other) noexcept = delete; - - fiber resume(); - - template<typename Fn> - fiber resume_with(Fn && fn); - - explicit operator bool() const noexcept; - - bool operator!() const noexcept; - - bool operator==(fiber const& other) const noexcept; - - bool operator!=(fiber const& other) const noexcept; - - bool operator<(fiber const& other) const noexcept; - - bool operator>(fiber const& other) const noexcept; - - bool operator<=(fiber const& other) const noexcept; - - bool operator>=(fiber const& other) const noexcept; - - template<typename charT,class traitsT> - friend std::basic_ostream<charT,traitsT> & - operator<<(std::basic_ostream<charT,traitsT> & os,fiber const& other) { - - void swap(fiber & other) noexcept; -}; --
-
--
-fiber() noexcept; --
-
- Creates a invalid fiber. -
- Nothing. -
-
--
-~fiber(); --
-
- Destructs the associated stack if *this is a valid fiber, e.g. fiber::operator
- bool() returns true.
-
- Nothing. -
-
--
-fiber(fiber && other) noexcept; --
-
- Moves underlying capture fiber to *this.
-
- Nothing. -
-
--
-fiber & operator=(fiber && other) noexcept; --
-
- Moves the state of other
- to *this
- using move semantics.
-
- Nothing. -
-
-operator()()
--
-fiber resume(); - -template<typename Fn> -fiber resume_with(Fn && fn); --
-
- Captures current fiber and resumes *this. The function resume_with,
- is used to execute function fn
- in the execution context of *this (e.g. the stack frame of fn is allocated on stack of *this).
-
- The fiber representing the fiber that has been suspended. -
- Function fn needs to
- return fiber.
-
- The returned fiber indicates if the suspended fiber has terminated
- (return from context-function) via bool
- operator().
-
-
-operator bool()
--
-explicit operator bool() const noexcept; --
-
- true if *this
- points to a captured fiber.
-
- Nothing. -
-
-operator!()
--
-bool operator!() const noexcept; --
-
- true if *this
- does not point to a captured fiber.
-
- Nothing. -
-
-operator==()
--
-bool operator==(fiber const& other) const noexcept; --
-
- true if *this
- and other represent
- the same fiber, false
- otherwise.
-
- Nothing. -
-
-operator!=()
--
-bool operator!=(fiber const& other) const noexcept; --
-
- ! (other == * this)
-
- Nothing. -
-
-operator<()
--
-bool operator<(fiber const& other) const noexcept; --
-
- true if *this != other
- is true and the implementation-defined total order of fiber values places *this
- before other, false
- otherwise.
-
- Nothing. -
-
-operator>()
--
-bool operator>(fiber const& other) const noexcept; --
-
- other <
- * this
-
- Nothing. -
-
-operator<=()
--
-bool operator<=(fiber const& other) const noexcept; --
-
- ! (other <
- * this)
-
- Nothing. -
-
-operator>=()
--
-bool operator>=(fiber const& other) const noexcept; --
-
- ! (*
- this <
- other)
-
- Nothing. -
-
-operator<<()
--
-template<typename charT,class traitsT> -std::basic_ostream<charT,traitsT> & -operator<<(std::basic_ostream<charT,traitsT> & os,fiber const& other); --
-
- Writes the representation of other
- to stream os.
-
- os
-
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- The implementation uses fcontext_t per default. fcontext_t - is based on assembler and not available for all platforms. It provides a - much better performance than ucontext_t (the context - switch takes two magnitudes of order less CPU cycles; see section performance) - and WinFiber. -
-![]() |
-Note | -
|---|---|
- Because the TIB (thread information block on Windows) is not fully described - in the MSDN, it might be possible that not all required TIB-parts are swapped. - Using WinFiber implementation might be an alternative. - |
- As an alternative, ucontext_t
- can be used by compiling with BOOST_USE_UCONTEXT
- and b2 property context-impl=ucontext.
- ucontext_t might be available on a broader range of
- POSIX-platforms but has some disadvantages
- (for instance deprecated since POSIX.1-2003, not C99 conform).
-
![]() |
-Note | -
|---|---|
- __fiber__ supports Segmented stacks - only with ucontext_t as its implementation. - |
- With BOOST_USE_WINFIB and
- b2 property context-impl=winfib
- Win32-Fibers are used as implementation for __fiber__.
-
![]() |
-Note | -
|---|---|
- The first call of __fiber__ converts the thread into a Windows fiber by
- invoking |
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- 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 execution context 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++. -
-- callcc()/continuation - provides 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 continuation - 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, transferring control - vias callcc()/continuation - requires only few CPU cycles because it does not involve system calls as it - is done within a single thread. -
-- All functions and classes are contained in the namespace boost::context. -
-![]() |
-Note | -
|---|---|
- This library requires C++11! - |
![]() |
-Important | -
|---|---|
- Windows using fcontext_t: turn off global program optimization (/GL) and - change /EHsc (compiler assumes that functions declared as extern "C" - never throw a C++ exception) to /EHs (tells compiler assumes that functions - declared as extern "C" may throw an exception). - |
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- Performance measurements were taken using std::chrono::highresolution_clock,
- with overhead corrections. The code was compiled with gcc-6.3.1, using build
- options: variant = release, optimization = speed. Tests were executed on dual
- Intel XEON E5 2620v4 2.2GHz, 16C/32T, 64GB RAM, running Linux (x86_64).
-
Table 1.1. Performance of context switch
-|
- - callcc()/continuation (fcontext_t) - - |
-
- - callcc()/continuation (ucontext_t) - - |
-
- - callcc()/continuation (Windows-Fiber) - - |
-
|---|---|---|
|
- - 9 ns / 19 CPU cycles - - |
-
- - 547 ns / 1130 CPU cycles - - |
-
- - 49 ns / 98 CPU cycles - - |
-
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- Some newer compiler (for instance MSVC 10 for x86_64 and itanium) do not support - inline assembler. [1]. Inlined assembler generates code bloating which is not welcome - on embedded systems. -
-- Boost.Context provides the low level API fcontext_t - which is implemented in assembler to provide context swapping operations. fcontext_t - is the part to port to new platforms. -
-![]() |
-Note | -
|---|---|
- Context switches do not preserve the signal mask on UNIX systems. - |
- fcontext_t is an opaque pointer. -
- -| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- C99 defines setjmp()/longjmp()
- to provide non-local jumps but it does not require that longjmp()
- preserves the current stack frame. Therefore, jumping into a function which
- was exited via a call to longjmp() is undefined [2].
-
- Since POSIX.1-2004 ucontext_t
- is deprecated and was removed in POSIX.1-2008! The function signature of
- makecontext()
- is:
-
void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...); --
- The third argument of makecontext() specifies the number of integer arguments
- that follow which will require function pointer cast if func
- will accept those arguments which is undefined in C99 [3].
-
- The arguments in the var-arg list are required to be integers, passing pointers - in var-arg list is not guaranteed to work, especially it will fail for architectures - where pointers are larger than integers. -
-
- ucontext_t preserves signal
- mask between context switches which involves system calls consuming a lot
- of CPU cycles (ucontext_t is slower; a context switch takes two
- magnitutes of order more CPU cycles more than fcontext_t).
-
- A drawback of Windows Fiber API is that CreateFiber() does not accept a pointer to user allocated
- stack space preventing the reuse of stacks for other context instances. Because
- the Windows Fiber API requires to call ConvertThreadToFiber() if SwitchFiber() is called for a thread which has not been
- converted to a fiber. For the same reason ConvertFiberToThread() must be called after return from SwitchFiber()
- if the thread was forced to be converted to a fiber before (which is inefficient).
-
if ( ! is_a_fiber() ) -{ - ConvertThreadToFiber( 0); - SwitchToFiber( ctx); - ConvertFiberToThread(); -} --
- If the condition _WIN32_WINNT >= _WIN32_WINNT_VISTA
- is met function IsThreadAFiber() is provided in order to detect if the current
- thread was already converted. Unfortunately Windows XP + SP 2/3 defines
- _WIN32_WINNT >=
- _WIN32_WINNT_VISTA without providing
- IsThreadAFiber().
-
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- "The FpCsr and the MxCsr register must be saved and restored before - any call or return by any procedure that needs to modify them ..." - [4]. -
-- MxCsr - "A callee that modifies any of the non-volatile fields within - MxCsr must restore them before returning to its caller. Furthermore, a caller - that has modified any of these fields must restore them to their standard - values before invoking a callee ..." [5]. -
-- FpCsr - "A callee that modifies any of the fields within FpCsr must - restore them before returning to its caller. Furthermore, a caller that has - modified any of these fields must restore them to their standard values before - invoking a callee ..." [6]. -
-- "The MMX and floating-point stack registers (MM0-MM7/ST0-ST7) are preserved - across context switches. There is no explicit calling convention for these - registers." [7]. -
-- "The 64-bit Microsoft compiler does not use ST(0)-ST(7)/MM0-MM7". - [8]. -
-- "XMM6-XMM15 must be preserved" [9] -
-- "The control bits of the MxCsr register are callee-saved (preserved - across calls), while the status bits are caller-saved (not preserved). The - x87 status word register is caller-saved, whereas the x87 control word (FpCsr) - is callee-saved." [10]. -
-[4] - 'Calling Conventions', Agner Fog -
[5] - MSDN - article 'MxCsr' -
[6] - MSDN - article 'FpCsr' -
[8] - 'Calling Conventions', Agner Fog -
[10] - SysV ABI AMD64 Architecture Processor Supplement Draft Version 0.99.4, - 3.2.1 -
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- If Boost.Context uses fcontext_t (the default) - as its implementation, it must be built for the particular compiler(s) and - CPU architecture(s) being targeted. Using fcontext_t, - Boost.Context includes assembly code and, - therefore, requires GNU as and GNU preprocessor for supported POSIX systems, - MASM for Windows/x86 systems and ARMasm for Windows/arm systems. -
-![]() |
-Note | -
|---|---|
- MASM64 (ml64.exe) is a part of Microsoft's Windows Driver Kit. - |
![]() |
-Important | -
|---|---|
- Please note that |
![]() |
-Important | -
|---|---|
- For cross-compiling the lib you must specify certain additional properties
- at bjam command line: |
![]() |
-Important | -
|---|---|
- Windows using fcontext_t: for safe SEH the property 'asmflags=\safeseh' must - be specified at bjam command line. - |
![]() |
-Important | -
|---|---|
- Windows using fcontext_t: turn off global program optimization (/GL) and - change /EHsc (compiler assumes that functions declared as extern "C" - never throw a C++ exception) to /EHs (tells compiler assumes that functions - declared as extern "C" may throw an exception). - |
- Because this library uses C++11 extensively, it requires a compatible compiler. - Known minimum working versions are as follows: Microsoft Visual Studio 2015 - (msvc-14.0), GCC 4.8 (with -std=c++11), Clang 3.4 (with -std=c++11). Other - compilers may work, if they support the following language features: auto declarations, - constexpr, defaulted functions, final, hdr thread, hdr tuple, lambdas, noexcept, - nullptr, rvalue references, template aliases. thread local, variadic templates. -
-| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- The memory used by the stack is allocated/deallocated via a StackAllocator - which is required to model a 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 - - |
-
|---|---|---|
|
-
- |
-- | -
- - creates a stack allocator - - |
-
|
-
- |
-
-
- |
-
- - creates a stack - - |
-
|
-
- |
-
-
- |
-
-
- deallocates the stack created by |
-
![]() |
-Important | -
|---|---|
- The implementation of |
![]() |
-Important | -
|---|---|
- Calling |
![]() |
-Note | -
|---|---|
- Depending on the architecture |
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- 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()
- -
- traits_type::minimum:size()
- <= size
- and ! traits_type::is_unbounded() &&
- ( traits_type::maximum:size() >= size).
-
- 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)
- -
- sctx.sp is valid, traits_type::minimum:size() <= sctx.size and !
- traits_type::is_unbounded()
- && (
- traits_type::maximum:size()
- >= sctx.size).
-
- Deallocates the stack space. -
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- Boost.Context provides the class pooled_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 managed internally by boost::pool<>.
-
#include <boost/context/pooled_fixedsize_stack.hpp> - -template< typename traitsT > -struct basic_pooled_fixedsize_stack { - typedef traitT traits_type; - - basic_pooled_fixedsize_stack(std::size_t stack_size = traits_type::default_size(), std::size_t next_size = 32, std::size_t max_size = 0); - - stack_context allocate(); - - void deallocate( stack_context &); -} - -typedef basic_pooled_fixedsize_stack< stack_traits > pooled_fixedsize_stack; --
basic_pooled_fixedsize_stack(std::size_t
- stack_size,
- std::size_t next_size, std::size_t max_size)
- -
- ! traits_type::is_unbounded() &&
- ( traits_type::maximum:size() >= stack_size)
- and 0 <
- nest_size.
-
- Allocates memory of at least stack_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. Argument next_size
- determines the number of stacks to request from the system the first
- time that *this
- needs to allocate system memory. The third argument max_size
- controls how many memory might be allocated for stacks - a value of
- zero means no upper limit.
-
stack_context allocate()
- -
- ! traits_type::is_unbounded() &&
- ( traits_type::maximum:size() >= stack_size).
-
- Allocates memory of at least stack_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)
- -
- sctx.sp is valid, !
- traits_type::is_unbounded()
- && (
- traits_type::maximum:size()
- >= sctx.size).
-
- Deallocates the stack space. -
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- 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 | -
|---|---|
- 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 | -
|---|---|
- The appended |
#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()
- -
- traits_type::minimum:size()
- <= size
- and ! traits_type::is_unbounded() &&
- ( traits_type::maximum:size() >= size).
-
- 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)
- -
- sctx.sp is valid, traits_type::minimum:size() <= sctx.size and !
- traits_type::is_unbounded()
- && (
- traits_type::maximum:size()
- >= sctx.size).
-
- Deallocates the stack space. -
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- Sanitizers (GCC/Clang) are confused by the stack switches. The library is
- required to be compiled with property (b2 command-line) context-impl=ucontext and compilers sanitizer options.
- Users must define BOOST_USE_ASAN
- before including any Boost.Context headers when linking against Boost binaries.
-
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- 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 | -
|---|---|
- 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 property |
![]() |
-Note | -
|---|---|
- Segmented stacks can only be used with callcc() - (using ucontext_t) - |
- . -
-#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()
- -
- traits_type::minimum:size()
- <= size
- and ! traits_type::is_unbounded() &&
- ( traits_type::maximum:size() >= size).
-
- 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)
- -
- sctx.sp is valid, traits_type::minimum:size() <= sctx.size and !
- traits_type::is_unbounded()
- && (
- traits_type::maximum:size()
- >= sctx.size).
-
- Deallocates the stack space. -
![]() |
-Note | -
|---|---|
- If the library is compiled for segmented stacks, segmented_stack - is the only available stack allocator. - |
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- 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
- -
- Pointer to the beginning of the stack. -
std::size_t
- size
- -
- Actual size of the stack. -
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- stack_traits models a stack-traits - providing a way to access certain properties defined by the environment. 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 true if the environment
- defines no limit for the size of a stack.
-
- Nothing. -
static std::size_t page_size()
- -
- Returns the page size in bytes. -
- Nothing. -
static std::size_t default_size()
- -
- 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().
-
- Nothing. -
static std::size_t minimum_size()
- -
- Returns the minimum size in bytes of stack defined by the environment - (Win32 4kB/Win64 8kB, defined by rlimit on POSIX). -
- Nothing. -
static std::size_t maximum_size()
- -
- is_unbounded()
- returns false.
-
- Returns the maximum size in bytes of stack defined by the environment. -
- Nothing. -
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
- 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.
- Users must define BOOST_USE_VALGRIND
- before including any Boost.Context headers when linking against Boost binaries
- compiled with valgrind=on.
-
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
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) noexcept; --
-
- Creates an object of preallocated. -
| - | - |
![]() |
-Home | -Libraries | -People | -FAQ | -More | -
Copyright © 2014 Oliver Kowalke
- Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -
-Table of Contents
- -Last revised: October 02, 2019 at 06:15:46 GMT |
-- |