mirror of
https://github.com/boostorg/context.git
synced 2026-01-26 06:22:42 +00:00
1470 lines
86 KiB
XML
1470 lines
86 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE article PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
|
|
<article id="context" last-revision="$Date: 2012/04/25 17:23:32 $" xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
<title>Context</title>
|
|
<articleinfo>
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>Oliver</firstname> <surname>Kowalke</surname>
|
|
</author>
|
|
</authorgroup>
|
|
<copyright>
|
|
<year>2009</year> <holder>Oliver Kowalke</holder>
|
|
</copyright>
|
|
<legalnotice>
|
|
<para>
|
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
file LICENSE_1_0.txt or copy at <ulink url="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</ulink>)
|
|
</para>
|
|
</legalnotice>
|
|
<articlepurpose>
|
|
C++ Library for swiching different user ctx
|
|
</articlepurpose>
|
|
<articlecategory name="category:text"></articlecategory>
|
|
</articleinfo>
|
|
<section id="context.overview">
|
|
<title><link linkend="context.overview">Overview</link></title>
|
|
<para>
|
|
<emphasis role="bold">Boost.Context</emphasis> 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 <emphasis>fcontext_t</emphasis> instance represents
|
|
a specific point in the application's execution path. This is useful for building
|
|
higher-level abstractions, like <emphasis>coroutines</emphasis>, <emphasis>cooperative
|
|
threads (userland threads)</emphasis> or an aquivalent to <ulink url="http://msdn.microsoft.com/en-us/library/9k7k7cf0%28v=vs.80%29.aspx">C#
|
|
keyword <emphasis>yield</emphasis></ulink> in C++.
|
|
</para>
|
|
<para>
|
|
A <emphasis>fcontext_t</emphasis> provides the means to suspend the current
|
|
execution path and to transfer execution control, thereby permitting another
|
|
<emphasis>fcontext_t</emphasis> to run on the current thread. This stateful
|
|
transfer mechanism enables a <emphasis>fcontext_t</emphasis> to suspend execution
|
|
from within nested functions and, later, to resume from where it was suspended.
|
|
While the execution path represented by a <emphasis>fcontext_t</emphasis> only
|
|
runs on a single thread, it can be migrated to another thread at any given
|
|
time.
|
|
</para>
|
|
<para>
|
|
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 among them requires only fewer than hundred CPU cycles because it does
|
|
not involve system calls as it is done within a single thread.
|
|
</para>
|
|
<para>
|
|
In order to use the classes and functions described here, you can either include
|
|
the specific headers specified by the descriptions of each class or function,
|
|
or include the master library header:
|
|
</para>
|
|
|
|
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">context</phrase><phrase role="special">/</phrase><phrase role="identifier">all</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
|
|
</programlisting>
|
|
<para>
|
|
which includes all the other headers in turn.
|
|
</para>
|
|
<para>
|
|
All functions and classes are contained in the namespace <emphasis>boost::ctx</emphasis>.
|
|
</para>
|
|
</section>
|
|
<section id="context.requirements">
|
|
<title><link linkend="context.requirements">Requirements</link></title>
|
|
<para>
|
|
<emphasis role="bold">Boost.Context</emphasis> must be built for the particular
|
|
compiler(s) and CPU architecture(s)s being targeted. <emphasis role="bold">Boost.Context</emphasis>
|
|
includes assembly code and, therefore, requires GNU AS for supported POSIX
|
|
systems, and MASM for Windows systems.
|
|
</para>
|
|
<important>
|
|
<para>
|
|
Please note that address-model=64 must be given to bjam command line on 64bit
|
|
Windows (boost-build issue).
|
|
</para>
|
|
</important>
|
|
</section>
|
|
<section id="context.context">
|
|
<title><link linkend="context.context">Context</link></title>
|
|
<para>
|
|
Each instance of <emphasis>fcontext_t</emphasis> represents a context (CPU
|
|
registers and stack space). Together with its related functions <emphasis>jump_fcontext()</emphasis>
|
|
and <emphasis>make_fcontext()</emphasis> it provides a execution control transfer
|
|
mechanism similar interface like <ulink url="http://www.kernel.org/doc/man-pages/online/pages/man2/getcontext.2.html">ucontext_t</ulink>.
|
|
<emphasis>fcontext_t</emphasis> and its functions are located in <emphasis>boost::ctx</emphasis>
|
|
and the functions are declared as extern "C".
|
|
</para>
|
|
<warning>
|
|
<para>
|
|
If <emphasis>fcontext_t</emphasis> is used in a multithreaded application,
|
|
it can migrated between threads, but must not reference <emphasis>thread-local
|
|
storage</emphasis>.
|
|
</para>
|
|
</warning>
|
|
<note>
|
|
<para>
|
|
If <emphasis>fiber-local storage</emphasis> is used on Windows, the user
|
|
is responsible for calling <emphasis>::FlsAlloc()</emphasis>, <emphasis>::FlsFree()</emphasis>.
|
|
</para>
|
|
</note>
|
|
<important>
|
|
<para>
|
|
The low level API is the part to port to new platforms.
|
|
</para>
|
|
</important>
|
|
<anchor id="context.context.executing_a_context"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.context.executing_a_context">Executing a context</link>
|
|
</bridgehead>
|
|
<para>
|
|
A new context supposed to execute a <emphasis>context-function</emphasis> (returning
|
|
void and accepting intptr_t as argument) must be initialized by function <emphasis>make_fcontext()</emphasis>.
|
|
</para>
|
|
|
|
<programlisting><phrase role="comment">// context-function
|
|
</phrase><phrase role="keyword">void</phrase> <phrase role="identifier">f</phrase><phrase role="special">(</phrase> <phrase role="identifier">intptr</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="comment">// creates and manages a protected stack (with guard page)
|
|
</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">protected_stack</phrase> <phrase role="identifier">stack</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">default_stacksize</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
|
|
|
|
<phrase role="comment">// let fcontext_t fc use stack
|
|
</phrase><phrase role="identifier">fc</phrase><phrase role="special">.</phrase><phrase role="identifier">fc_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">base</phrase> <phrase role="special">=</phrase> <phrase role="identifier">stack</phrase><phrase role="special">.</phrase><phrase role="identifier">address</phrase><phrase role="special">();</phrase>
|
|
<phrase role="identifier">fc</phrase><phrase role="special">.</phrase><phrase role="identifier">fc_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">limit</phrase> <phrase role="special">=</phrase>
|
|
<phrase role="keyword">static_cast</phrase><phrase role="special"><</phrase> <phrase role="keyword">char</phrase> <phrase role="special">*</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">fc</phrase><phrase role="special">.</phrase><phrase role="identifier">fc_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">base</phrase><phrase role="special">)</phrase> <phrase role="special">-</phrase> <phrase role="identifier">stack</phrase><phrase role="special">.</phrase><phrase role="identifier">size</phrase><phrase role="special">();</phrase>
|
|
|
|
<phrase role="comment">// context fc uses f() as context function
|
|
</phrase><phrase role="identifier">make_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc</phrase><phrase role="special">,</phrase> <phrase role="identifier">f</phrase><phrase role="special">);</phrase>
|
|
</programlisting>
|
|
<para>
|
|
<emphasis>fcontext_t</emphasis> requires a pointer to the top of the stack
|
|
(<emphasis>fc_base</emphasis>) as well as a pointer to the lower bound of the
|
|
stack (<emphasis>fc_limit</emphasis>).
|
|
</para>
|
|
<para>
|
|
Calling <emphasis>jump_fcontext()</emphasis> invokes the <emphasis>context-function</emphasis>
|
|
in a newly created context complete with registers, flags, stack and instruction
|
|
pointers. When control should be returned to the original calling context,
|
|
call <emphasis>jump_fcontext()</emphasis>. The current context information
|
|
(registers, flags, and stack and instruction pointers) is saved and the original
|
|
context information is restored. Calling <emphasis>jump_fcontext()</emphasis>
|
|
again resumes execution in the second context after saving the new state of
|
|
the original context.
|
|
</para>
|
|
|
|
<programlisting><phrase role="keyword">namespace</phrase> <phrase role="identifier">ctx</phrase> <phrase role="special">=</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">ctx</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">fcontext_t</phrase> <phrase role="identifier">fcm</phrase><phrase role="special">,</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="identifier">fc2</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">f1</phrase><phrase role="special">(</phrase> <phrase role="identifier">intptr_t</phrase><phrase role="special">)</phrase>
|
|
<phrase role="special">{</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"f1: entered"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"f1: call jump_fcontext( & fc1, & fc2, 0)"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
|
|
<phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">jump_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc2</phrase><phrase role="special">,</phrase> <phrase role="number">0</phrase><phrase role="special">);</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"f1: return"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
|
|
<phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">jump_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fcm</phrase><phrase role="special">,</phrase> <phrase role="number">0</phrase><phrase role="special">);</phrase>
|
|
<phrase role="special">}</phrase>
|
|
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">f2</phrase><phrase role="special">(</phrase> <phrase role="identifier">intptr_t</phrase><phrase role="special">)</phrase>
|
|
<phrase role="special">{</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"f2: entered"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"f2: call jump_fcontext( & fc2, & fc1, 0)"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
|
|
<phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">jump_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc2</phrase><phrase role="special">,</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="number">0</phrase><phrase role="special">);</phrase>
|
|
<phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="keyword">false</phrase> <phrase role="special">&&</phrase> <phrase role="special">!</phrase> <phrase role="string">"f2: never returns"</phrase><phrase role="special">);</phrase>
|
|
<phrase role="special">}</phrase>
|
|
|
|
<phrase role="keyword">int</phrase> <phrase role="identifier">main</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">argc</phrase><phrase role="special">,</phrase> <phrase role="keyword">char</phrase> <phrase role="special">*</phrase> <phrase role="identifier">argv</phrase><phrase role="special">[])</phrase>
|
|
<phrase role="special">{</phrase>
|
|
<phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">stack_allocator</phrase> <phrase role="identifier">alloc1</phrase><phrase role="special">,</phrase> <phrase role="identifier">alloc2</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="identifier">fc1</phrase><phrase role="special">.</phrase><phrase role="identifier">fc_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">base</phrase> <phrase role="special">=</phrase> <phrase role="identifier">alloc1</phrase><phrase role="special">.</phrase><phrase role="identifier">allocate</phrase><phrase role="special">(</phrase><phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">minimum_stacksize</phrase><phrase role="special">());</phrase>
|
|
<phrase role="identifier">fc1</phrase><phrase role="special">.</phrase><phrase role="identifier">fc_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">limit</phrase> <phrase role="special">=</phrase>
|
|
<phrase role="keyword">static_cast</phrase><phrase role="special"><</phrase> <phrase role="keyword">char</phrase> <phrase role="special">*</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">.</phrase><phrase role="identifier">fc_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">base</phrase><phrase role="special">)</phrase> <phrase role="special">-</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">minimum_stacksize</phrase><phrase role="special">();</phrase>
|
|
<phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">make_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="identifier">f1</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="identifier">fc2</phrase><phrase role="special">.</phrase><phrase role="identifier">fc_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">base</phrase> <phrase role="special">=</phrase> <phrase role="identifier">alloc2</phrase><phrase role="special">.</phrase><phrase role="identifier">allocate</phrase><phrase role="special">(</phrase><phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">minimum_stacksize</phrase><phrase role="special">());</phrase>
|
|
<phrase role="identifier">fc2</phrase><phrase role="special">.</phrase><phrase role="identifier">fc_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">limit</phrase> <phrase role="special">=</phrase>
|
|
<phrase role="keyword">static_cast</phrase><phrase role="special"><</phrase> <phrase role="keyword">char</phrase> <phrase role="special">*</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">fc2</phrase><phrase role="special">.</phrase><phrase role="identifier">fc_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">base</phrase><phrase role="special">)</phrase> <phrase role="special">-</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">minimum_stacksize</phrase><phrase role="special">();</phrase>
|
|
<phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">make_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc2</phrase><phrase role="special">,</phrase> <phrase role="identifier">f2</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"main: call jump_fcontext( & fcm, & fc1, 0)"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
|
|
<phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">jump_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fcm</phrase><phrase role="special">,</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="number">0</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"main: done"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="keyword">return</phrase> <phrase role="identifier">EXIT_SUCCESS</phrase><phrase role="special">;</phrase>
|
|
<phrase role="special">}</phrase>
|
|
|
|
<phrase role="identifier">output</phrase><phrase role="special">:</phrase>
|
|
<phrase role="identifier">main</phrase><phrase role="special">:</phrase> <phrase role="identifier">call</phrase> <phrase role="identifier">jump_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fcm</phrase><phrase role="special">,</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="number">0</phrase><phrase role="special">)</phrase>
|
|
<phrase role="identifier">f1</phrase><phrase role="special">:</phrase> <phrase role="identifier">entered</phrase>
|
|
<phrase role="identifier">f1</phrase><phrase role="special">:</phrase> <phrase role="identifier">call</phrase> <phrase role="identifier">jump_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc2</phrase><phrase role="special">,</phrase> <phrase role="number">0</phrase><phrase role="special">)</phrase>
|
|
<phrase role="identifier">f2</phrase><phrase role="special">:</phrase> <phrase role="identifier">entered</phrase>
|
|
<phrase role="identifier">f2</phrase><phrase role="special">:</phrase> <phrase role="identifier">call</phrase> <phrase role="identifier">jump_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc2</phrase><phrase role="special">,</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="number">0</phrase><phrase role="special">)</phrase>
|
|
<phrase role="identifier">f1</phrase><phrase role="special">:</phrase> <phrase role="keyword">return</phrase>
|
|
<phrase role="identifier">main</phrase><phrase role="special">:</phrase> <phrase role="identifier">done</phrase>
|
|
</programlisting>
|
|
<para>
|
|
First call of <emphasis>jump_fcontext()</emphasis> enters the <emphasis>context-function</emphasis>
|
|
<code><phrase role="identifier">f1</phrase><phrase role="special">()</phrase></code>
|
|
by starting context fc1 (context fcm saves the registers of <code><phrase role="identifier">main</phrase><phrase
|
|
role="special">()</phrase></code>). For jumping between context's fc1 and fc2
|
|
<code><phrase role="identifier">jump_fcontext</phrase><phrase role="special">()</phrase></code>
|
|
is called. Because context fcm is chained to fc1, <code><phrase role="identifier">main</phrase><phrase
|
|
role="special">()</phrase></code> is entered (returning from <emphasis>jump_fcontext()</emphasis>)
|
|
after context fc1 becomes complete (return from <code><phrase role="identifier">f1</phrase><phrase
|
|
role="special">()</phrase></code>).
|
|
</para>
|
|
<warning>
|
|
<para>
|
|
Calling <emphasis>jump_fcontext()</emphasis> to the same context from inside
|
|
the same context results in undefined behaviour.
|
|
</para>
|
|
</warning>
|
|
<note>
|
|
<para>
|
|
In contrast to threads, which are preemtive, <emphasis>fcontext_t</emphasis>
|
|
switches are cooperative (programmer controls when switch will happen). The
|
|
kernel is not involved in the context switches.
|
|
</para>
|
|
</note>
|
|
<anchor id="context.context.transfer_of_data"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.context.transfer_of_data">Transfer of data</link>
|
|
</bridgehead>
|
|
<para>
|
|
The third argument passed to <emphasis>jump_fcontext()</emphasis>, in one context,
|
|
is passed as the first argument of the <emphasis>context-function</emphasis>
|
|
if the context is started for the first time. In all following invocations
|
|
of <emphasis>jump_fcontext()</emphasis> the intptr_t passed to <emphasis>jump_fcontext()</emphasis>,
|
|
in one context, is returned by <emphasis>jump_fcontext()</emphasis> in the
|
|
other context.
|
|
</para>
|
|
|
|
<programlisting><phrase role="keyword">namespace</phrase> <phrase role="identifier">ctx</phrase> <phrase role="special">=</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">ctx</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">fcontext_t</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="identifier">fcm</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">pair</phrase><phrase role="special"><</phrase> <phrase role="keyword">int</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">></phrase> <phrase role="identifier">pair_t</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">f1</phrase><phrase role="special">(</phrase> <phrase role="identifier">intptr_t</phrase> <phrase role="identifier">param</phrase><phrase role="special">)</phrase>
|
|
<phrase role="special">{</phrase>
|
|
<phrase role="identifier">pair_t</phrase> <phrase role="special">*</phrase> <phrase role="identifier">p</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase> <phrase role="identifier">pair_t</phrase> <phrase role="special">*)</phrase> <phrase role="identifier">param</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="identifier">p</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase> <phrase role="identifier">pair_t</phrase> <phrase role="special">*)</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">jump_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fcm</phrase><phrase role="special">,</phrase> <phrase role="special">(</phrase> <phrase role="identifier">intptr_t</phrase><phrase role="special">)</phrase> <phrase role="special">(</phrase> <phrase role="identifier">p</phrase><phrase role="special">-></phrase><phrase role="identifier">first</phrase> <phrase role="special">+</phrase> <phrase role="identifier">p</phrase><phrase role="special">-></phrase><phrase role="identifier">second</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
|
|
|
|
<phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">jump_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fcm</phrase><phrase role="special">,</phrase> <phrase role="special">(</phrase> <phrase role="identifier">intptr_t</phrase><phrase role="special">)</phrase> <phrase role="special">(</phrase> <phrase role="identifier">p</phrase><phrase role="special">-></phrase><phrase role="identifier">first</phrase> <phrase role="special">+</phrase> <phrase role="identifier">p</phrase><phrase role="special">-></phrase><phrase role="identifier">second</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
|
|
<phrase role="special">}</phrase>
|
|
|
|
<phrase role="keyword">int</phrase> <phrase role="identifier">main</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">argc</phrase><phrase role="special">,</phrase> <phrase role="keyword">char</phrase> <phrase role="special">*</phrase> <phrase role="identifier">argv</phrase><phrase role="special">[])</phrase>
|
|
<phrase role="special">{</phrase>
|
|
<phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">stack_allocator</phrase> <phrase role="identifier">alloc</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="identifier">fc1</phrase><phrase role="special">.</phrase><phrase role="identifier">fc_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">base</phrase> <phrase role="special">=</phrase> <phrase role="identifier">alloc</phrase><phrase role="special">.</phrase><phrase role="identifier">allocate</phrase><phrase role="special">(</phrase><phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">minimum_stacksize</phrase><phrase role="special">());</phrase>
|
|
<phrase role="identifier">fc1</phrase><phrase role="special">.</phrase><phrase role="identifier">fc_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">limit</phrase> <phrase role="special">=</phrase>
|
|
<phrase role="keyword">static_cast</phrase><phrase role="special"><</phrase> <phrase role="keyword">char</phrase> <phrase role="special">*</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">.</phrase><phrase role="identifier">fc_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">base</phrase><phrase role="special">)</phrase> <phrase role="special">-</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">minimum_stacksize</phrase><phrase role="special">();</phrase>
|
|
<phrase role="identifier">fc1</phrase><phrase role="special">.</phrase><phrase role="identifier">fc_link</phrase> <phrase role="special">=</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fcm</phrase><phrase role="special">;</phrase>
|
|
<phrase role="identifier">pair_t</phrase> <phrase role="identifier">p</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_pair</phrase><phrase role="special">(</phrase> <phrase role="number">2</phrase><phrase role="special">,</phrase> <phrase role="number">7</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
|
|
<phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">make_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="identifier">f1</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">int</phrase> <phrase role="identifier">res</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">)</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">jump_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fcm</phrase><phrase role="special">,</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="special">(</phrase> <phrase role="identifier">intptr_t</phrase><phrase role="special">)</phrase> <phrase role="special">&</phrase> <phrase role="identifier">p</phrase><phrase role="special">);</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">p</phrase><phrase role="special">.</phrase><phrase role="identifier">first</phrase> <phrase role="special"><<</phrase> <phrase role="string">" + "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">p</phrase><phrase role="special">.</phrase><phrase role="identifier">second</phrase> <phrase role="special"><<</phrase> <phrase role="string">" == "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">res</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="identifier">p</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_pair</phrase><phrase role="special">(</phrase> <phrase role="number">5</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase>
|
|
<phrase role="identifier">res</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">)</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">::</phrase><phrase role="identifier">jump_fcontext</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fcm</phrase><phrase role="special">,</phrase> <phrase role="special">&</phrase> <phrase role="identifier">fc1</phrase><phrase role="special">,</phrase> <phrase role="special">(</phrase> <phrase role="identifier">intptr_t</phrase><phrase role="special">)</phrase> <phrase role="special">&</phrase> <phrase role="identifier">p</phrase><phrase role="special">);</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">p</phrase><phrase role="special">.</phrase><phrase role="identifier">first</phrase> <phrase role="special"><<</phrase> <phrase role="string">" + "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">p</phrase><phrase role="special">.</phrase><phrase role="identifier">second</phrase> <phrase role="special"><<</phrase> <phrase role="string">" == "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">res</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"main: done"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="keyword">return</phrase> <phrase role="identifier">EXIT_SUCCESS</phrase><phrase role="special">;</phrase>
|
|
<phrase role="special">}</phrase>
|
|
|
|
<phrase role="identifier">output</phrase><phrase role="special">:</phrase>
|
|
<phrase role="number">2</phrase> <phrase role="special">+</phrase> <phrase role="number">7</phrase> <phrase role="special">==</phrase> <phrase role="number">9</phrase>
|
|
<phrase role="number">5</phrase> <phrase role="special">+</phrase> <phrase role="number">6</phrase> <phrase role="special">==</phrase> <phrase role="number">11</phrase>
|
|
<phrase role="identifier">main</phrase><phrase role="special">:</phrase> <phrase role="identifier">done</phrase>
|
|
</programlisting>
|
|
<anchor id="context.context.exceptions_in__emphasis_context_function__emphasis_"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.context.exceptions_in__emphasis_context_function__emphasis_">Exceptions
|
|
in <emphasis>context-function</emphasis></link>
|
|
</bridgehead>
|
|
<para>
|
|
If the <emphasis>context-function</emphasis> emits an exception, the application
|
|
will terminate.
|
|
</para>
|
|
<anchor id="context.context.preserving_floating_point_registers"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.context.preserving_floating_point_registers">Preserving
|
|
floating point registers</link>
|
|
</bridgehead>
|
|
<para>
|
|
Preserving the floating point registers increases the cycle count for a context
|
|
switch (see performance tests). The foruth argument of <emphasis>jump_fcontext()</emphasis>
|
|
controls if fpu registers should be preserved by the context jump.
|
|
</para>
|
|
<important>
|
|
<para>
|
|
The use of the fpu controling argument of <emphasis>jump_fcontext()</emphasis>
|
|
must be consistent in the application. Otherwise the behaviour is undefined.
|
|
</para>
|
|
</important>
|
|
<anchor id="context.context.stack_unwinding"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.context.stack_unwinding">Stack unwinding</link>
|
|
</bridgehead>
|
|
<para>
|
|
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.
|
|
</para>
|
|
<section id="context.context.boost_fcontext">
|
|
<title><link linkend="context.context.boost_fcontext">Struct <code><phrase
|
|
role="identifier">fcontext_t</phrase></code> and related functions</link></title>
|
|
|
|
<programlisting><phrase role="keyword">struct</phrase> <phrase role="identifier">stack_t</phrase>
|
|
<phrase role="special">{</phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="special">*</phrase> <phrase role="identifier">base</phrase><phrase role="special">;</phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="special">*</phrase> <phrase role="identifier">limit</phrase><phrase role="special">;</phrase>
|
|
<phrase role="special">};</phrase>
|
|
|
|
<phrase role="keyword">struct</phrase> <phrase role="identifier">fcontext_t</phrase>
|
|
<phrase role="special">{</phrase>
|
|
<phrase role="special"><</phrase> <phrase role="identifier">platform</phrase> <phrase role="identifier">specific</phrase> <phrase role="special">></phrase>
|
|
|
|
<phrase role="identifier">stack_t</phrase> <phrase role="identifier">fc_stack</phrase><phrase role="special">;</phrase>
|
|
<phrase role="special">};</phrase>
|
|
|
|
<phrase role="identifier">intptr_t</phrase> <phrase role="identifier">jump_fcontext</phrase><phrase role="special">(</phrase> <phrase role="identifier">fcontext_t</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ofc</phrase><phrase role="special">,</phrase> <phrase role="identifier">fcontext_t</phrase> <phrase role="keyword">const</phrase><phrase role="special">*</phrase> <phrase role="identifier">nfc</phrase><phrase role="special">,</phrase> <phrase role="identifier">intptr_t</phrase> <phrase role="identifier">vp</phrase><phrase role="special">);</phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">make_fcontext</phrase><phrase role="special">(</phrase> <phrase role="identifier">fcontext_t</phrase> <phrase role="special">*</phrase> <phrase role="identifier">fc</phrase><phrase role="special">,</phrase> <phrase role="keyword">void</phrase><phrase role="special">(*</phrase> <phrase role="identifier">fn</phrase><phrase role="special">)(</phrase><phrase role="identifier">intptr_t</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
|
|
</programlisting>
|
|
<anchor id="context.context.boost_fcontext._code__phrase_role__identifier__base__phrase___code_"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.context.boost_fcontext._code__phrase_role__identifier__base__phrase___code_"><code><phrase
|
|
role="identifier">base</phrase></code></link>
|
|
</bridgehead>
|
|
<variablelist>
|
|
<title></title>
|
|
<varlistentry>
|
|
<term>Member:</term>
|
|
<listitem>
|
|
<para>
|
|
Pointer to the top of the stack.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
<anchor id="context.context.boost_fcontext._code__phrase_role__identifier__limit__phrase___code_"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.context.boost_fcontext._code__phrase_role__identifier__limit__phrase___code_"><code><phrase
|
|
role="identifier">limit</phrase></code></link>
|
|
</bridgehead>
|
|
<variablelist>
|
|
<title></title>
|
|
<varlistentry>
|
|
<term>Member:</term>
|
|
<listitem>
|
|
<para>
|
|
Pointer to the bottom of the stack.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
<anchor id="context.context.boost_fcontext._code__phrase_role__identifier__fc_stack__phrase___code_"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.context.boost_fcontext._code__phrase_role__identifier__fc_stack__phrase___code_"><code><phrase
|
|
role="identifier">fc_stack</phrase></code></link>
|
|
</bridgehead>
|
|
<variablelist>
|
|
<title></title>
|
|
<varlistentry>
|
|
<term>Member:</term>
|
|
<listitem>
|
|
<para>
|
|
Tracks the memory for the context's stack.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
<anchor id="context.context.boost_fcontext._code__phrase_role__identifier__intptr_t__phrase___phrase_role__identifier__jump_fcontext__phrase__phrase_role__special_____phrase___phrase_role__identifier__fcontext_t__phrase___phrase_role__special_____phrase___phrase_role__identifier__ofc__phrase__phrase_role__special_____phrase___phrase_role__identifier__fcontext_t__phrase___phrase_role__special_____phrase___phrase_role__identifier__nfc__phrase__phrase_role__special_____phrase___phrase_role__identifier__intptr_t__phrase___phrase_role__identifier__p__phrase__phrase_role__special_____phrase___phrase_role__keyword__bool__phrase___phrase_role__identifier__preserve_fpu__phrase__phrase_role__special_____phrase___code_"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.context.boost_fcontext._code__phrase_role__identifier__intptr_t__phrase___phrase_role__identifier__jump_fcontext__phrase__phrase_role__special_____phrase___phrase_role__identifier__fcontext_t__phrase___phrase_role__special_____phrase___phrase_role__identifier__ofc__phrase__phrase_role__special_____phrase___phrase_role__identifier__fcontext_t__phrase___phrase_role__special_____phrase___phrase_role__identifier__nfc__phrase__phrase_role__special_____phrase___phrase_role__identifier__intptr_t__phrase___phrase_role__identifier__p__phrase__phrase_role__special_____phrase___phrase_role__keyword__bool__phrase___phrase_role__identifier__preserve_fpu__phrase__phrase_role__special_____phrase___code_"><code><phrase
|
|
role="identifier">intptr_t</phrase> <phrase role="identifier">jump_fcontext</phrase><phrase
|
|
role="special">(</phrase> <phrase role="identifier">fcontext_t</phrase>
|
|
<phrase role="special">*</phrase> <phrase role="identifier">ofc</phrase><phrase
|
|
role="special">,</phrase> <phrase role="identifier">fcontext_t</phrase>
|
|
<phrase role="special">*</phrase> <phrase role="identifier">nfc</phrase><phrase
|
|
role="special">,</phrase> <phrase role="identifier">intptr_t</phrase> <phrase
|
|
role="identifier">p</phrase><phrase role="special">,</phrase> <phrase role="keyword">bool</phrase>
|
|
<phrase role="identifier">preserve_fpu</phrase><phrase role="special">)</phrase></code></link>
|
|
</bridgehead>
|
|
<variablelist>
|
|
<title></title>
|
|
<varlistentry>
|
|
<term>Effects:</term>
|
|
<listitem>
|
|
<para>
|
|
Stores the current context data (stack pointer, instruction pointer,
|
|
and CPU registers) to <code><phrase role="special">*</phrase><phrase
|
|
role="identifier">ofc</phrase></code> and restores the context data
|
|
from <code><phrase role="special">*</phrase><phrase role="identifier">nfc</phrase></code>,
|
|
which implies jumping to <code><phrase role="special">*</phrase><phrase
|
|
role="identifier">nfc</phrase></code>'s execution context. The intptr_t
|
|
argument, <code><phrase role="identifier">p</phrase></code>, is passed
|
|
to the current context to be returned by the most recent call to <code><phrase
|
|
role="identifier">jump_fcontext</phrase><phrase role="special">()</phrase></code>
|
|
in the same thread. The last argument controls if fpu registers have
|
|
to be preserved.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>Returns:</term>
|
|
<listitem>
|
|
<para>
|
|
The third pointer argument passed to the most recent call to <code><phrase
|
|
role="identifier">jump_fcontext</phrase><phrase role="special">()</phrase></code>,
|
|
if any.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
<anchor id="context.context.boost_fcontext._code__phrase_role__keyword__void__phrase___phrase_role__identifier__make_fcontext__phrase__phrase_role__special_____phrase___phrase_role__identifier__fcontext_t__phrase___phrase_role__special_____phrase___phrase_role__identifier__fc__phrase__phrase_role__special_____phrase___phrase_role__keyword__void__phrase__phrase_role__special______phrase__phrase_role__identifier__fn__phrase__phrase_role__special______phrase__phrase_role__identifier__intptr_t__phrase__phrase_role__special______phrase___code_"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.context.boost_fcontext._code__phrase_role__keyword__void__phrase___phrase_role__identifier__make_fcontext__phrase__phrase_role__special_____phrase___phrase_role__identifier__fcontext_t__phrase___phrase_role__special_____phrase___phrase_role__identifier__fc__phrase__phrase_role__special_____phrase___phrase_role__keyword__void__phrase__phrase_role__special______phrase__phrase_role__identifier__fn__phrase__phrase_role__special______phrase__phrase_role__identifier__intptr_t__phrase__phrase_role__special______phrase___code_"><code><phrase
|
|
role="keyword">void</phrase> <phrase role="identifier">make_fcontext</phrase><phrase
|
|
role="special">(</phrase> <phrase role="identifier">fcontext_t</phrase>
|
|
<phrase role="special">*</phrase> <phrase role="identifier">fc</phrase><phrase
|
|
role="special">,</phrase> <phrase role="keyword">void</phrase><phrase role="special">(*</phrase><phrase
|
|
role="identifier">fn</phrase><phrase role="special">)(</phrase><phrase role="identifier">intptr_t</phrase><phrase
|
|
role="special">))</phrase></code></link>
|
|
</bridgehead>
|
|
<variablelist>
|
|
<title></title>
|
|
<varlistentry>
|
|
<term>Precondition:</term>
|
|
<listitem>
|
|
<para>
|
|
A stack is applied to <code><phrase role="special">*</phrase><phrase
|
|
role="identifier">fc</phrase></code> before <code><phrase role="identifier">make_fcontext</phrase><phrase
|
|
role="special">()</phrase></code> is called.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>Effects:</term>
|
|
<listitem>
|
|
<para>
|
|
Modifies <code><phrase role="special">*</phrase><phrase role="identifier">fc</phrase></code>
|
|
in order to execute <code><phrase role="identifier">fn</phrase></code>
|
|
when the context is activated next.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
</section>
|
|
</section>
|
|
<section id="context.stack">
|
|
<title><link linkend="context.stack">Stack allocation</link></title>
|
|
<para>
|
|
A <emphasis>fcontext_t</emphasis> requires a stack which will be allocated/deallocated
|
|
by a <emphasis>StackAllocator</emphasis>. <emphasis role="bold">Boost.Context</emphasis>
|
|
uses <code><phrase role="identifier">stack_allocator</phrase></code> by default
|
|
but a customized <code><phrase role="identifier">stack</phrase> <phrase role="identifier">allocator</phrase></code>
|
|
can be passed to the context constructor instead. If a context is constructed
|
|
it invokes <emphasis>allocate()</emphasis> function and by its destruction
|
|
the stack gets released by <emphasis>deallocate()</emphasis>.
|
|
</para>
|
|
<anchor id="context.stack._emphasis_stackallocator_concept__emphasis_"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.stack._emphasis_stackallocator_concept__emphasis_"><emphasis>StackAllocator
|
|
concept</emphasis></link>
|
|
</bridgehead>
|
|
<para>
|
|
A <emphasis>StackAllocator</emphasis> must satisfy the <emphasis>StackAllocator
|
|
concept</emphasis> requirements shown in the following table, in which <code><phrase
|
|
role="identifier">a</phrase></code> is an object of a <emphasis>StackAllocator</emphasis>
|
|
type, <code><phrase role="identifier">p</phrase></code> is a <code><phrase
|
|
role="keyword">void</phrase> <phrase role="special">*</phrase></code>, and
|
|
<code><phrase role="identifier">s</phrase></code> is a <code><phrase role="identifier">std</phrase><phrase
|
|
role="special">::</phrase><phrase role="identifier">size_t</phrase></code>:
|
|
</para>
|
|
<informaltable frame="all">
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
expression
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
return type
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
notes
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
<code><phrase role="identifier">a</phrase><phrase role="special">.</phrase><phrase
|
|
role="identifier">allocate</phrase><phrase role="special">(</phrase>
|
|
<phrase role="identifier">s</phrase><phrase role="special">)</phrase></code>
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
<code><phrase role="keyword">void</phrase> <phrase role="special">*</phrase></code>
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
returns a pointer to <code><phrase role="identifier">s</phrase></code>
|
|
bytes allocated from the stack
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
<code><phrase role="identifier">a</phrase><phrase role="special">.</phrase><phrase
|
|
role="identifier">deallocate</phrase><phrase role="special">(</phrase>
|
|
<phrase role="identifier">p</phrase><phrase role="special">,</phrase>
|
|
<phrase role="identifier">s</phrase><phrase role="special">)</phrase></code>
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
<code><phrase role="keyword">void</phrase></code>
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
deallocates <code><phrase role="identifier">s</phrase></code> bytes
|
|
of memory beginning at <code><phrase role="identifier">p</phrase></code>,
|
|
a pointer previously returned by <code><phrase role="identifier">a</phrase><phrase
|
|
role="special">.</phrase><phrase role="identifier">allocate</phrase><phrase
|
|
role="special">()</phrase></code>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
<important>
|
|
<para>
|
|
The implementation of <code><phrase role="identifier">allocate</phrase><phrase
|
|
role="special">()</phrase></code> might include logic to protect against
|
|
exceeding the context's available stack size rather than leaving it as undefined
|
|
behaviour.
|
|
</para>
|
|
</important>
|
|
<important>
|
|
<para>
|
|
Calling <code><phrase role="identifier">deallocate</phrase><phrase role="special">()</phrase></code>
|
|
with a pointer not returned by <code><phrase role="identifier">allocate</phrase><phrase
|
|
role="special">()</phrase></code> results in undefined behaviour.
|
|
</para>
|
|
</important>
|
|
<note>
|
|
<para>
|
|
The stack is not required to be aligned; alignment takes place inside <code><phrase
|
|
role="identifier">make_fcontext</phrase><phrase role="special">()</phrase></code>.
|
|
</para>
|
|
</note>
|
|
<section id="context.stack.stack_allocator">
|
|
<title><link linkend="context.stack.stack_allocator">Class <code><phrase role="identifier">stack_allocator</phrase></code></link></title>
|
|
<para>
|
|
<emphasis role="bold">Boost.Context</emphasis> provides a <emphasis>StackAllocator</emphasis>
|
|
<code><phrase role="identifier">stack_allocator</phrase></code> which models
|
|
the <emphasis>StackAllocator concept</emphasis> concept. It appends a <emphasis>guard-page</emphasis>
|
|
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.
|
|
</para>
|
|
</section>
|
|
<section id="context.stack.stack_helper">
|
|
<title><link linkend="context.stack.stack_helper">Helper functions</link></title>
|
|
<para>
|
|
<emphasis role="bold">Boost.Context</emphasis> provides easy access to the
|
|
stack related limits defined by the environment.
|
|
</para>
|
|
|
|
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">default_stacksize</phrase><phrase role="special">();</phrase>
|
|
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">minimum_stacksize</phrase><phrase role="special">();</phrase>
|
|
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">maximum_stacksize</phrase><phrase role="special">();</phrase>
|
|
|
|
<phrase role="keyword">bool</phrase> <phrase role="identifier">is_stack_unbound</phrase><phrase role="special">();</phrase>
|
|
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">pagesize</phrase><phrase role="special">();</phrase>
|
|
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">page_count</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">stacksize</phrase><phrase role="special">);</phrase>
|
|
</programlisting>
|
|
<anchor id="context.stack.stack_helper._code__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__default_stacksize__phrase__phrase_role__special______phrase___code_"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.stack.stack_helper._code__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__default_stacksize__phrase__phrase_role__special______phrase___code_"><code><phrase
|
|
role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase>
|
|
<phrase role="identifier">default_stacksize</phrase><phrase role="special">()</phrase></code></link>
|
|
</bridgehead>
|
|
<variablelist>
|
|
<title></title>
|
|
<varlistentry>
|
|
<term>Returns:</term>
|
|
<listitem>
|
|
<para>
|
|
Returns a default stack size, which may be platform specific. The present
|
|
implementation returns a value of 256 kB.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
<anchor id="context.stack.stack_helper._code__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__minimum_stacksize__phrase__phrase_role__special______phrase___code_"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.stack.stack_helper._code__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__minimum_stacksize__phrase__phrase_role__special______phrase___code_"><code><phrase
|
|
role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase>
|
|
<phrase role="identifier">minimum_stacksize</phrase><phrase role="special">()</phrase></code></link>
|
|
</bridgehead>
|
|
<variablelist>
|
|
<title></title>
|
|
<varlistentry>
|
|
<term>Returns:</term>
|
|
<listitem>
|
|
<para>
|
|
Returns the minimum size in bytes of stack defined by the environment.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>Throws:</term>
|
|
<listitem>
|
|
<para>
|
|
Nothing.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
<anchor id="context.stack.stack_helper._code__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__maximum_stacksize__phrase__phrase_role__special______phrase___code_"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.stack.stack_helper._code__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__maximum_stacksize__phrase__phrase_role__special______phrase___code_"><code><phrase
|
|
role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase>
|
|
<phrase role="identifier">maximum_stacksize</phrase><phrase role="special">()</phrase></code></link>
|
|
</bridgehead>
|
|
<variablelist>
|
|
<title></title>
|
|
<varlistentry>
|
|
<term>Preconditions:</term>
|
|
<listitem>
|
|
<para>
|
|
<code><phrase role="identifier">is_stack_unbound</phrase><phrase role="special">()</phrase></code>
|
|
returns <code><phrase role="keyword">false</phrase></code>.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>Returns:</term>
|
|
<listitem>
|
|
<para>
|
|
Returns the maximum size in bytes of stack defined by the environment.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>Throws:</term>
|
|
<listitem>
|
|
<para>
|
|
Nothing.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
<anchor id="context.stack.stack_helper._code__phrase_role__keyword__bool__phrase___phrase_role__identifier__is_stack_unbound__phrase__phrase_role__special______phrase___code_"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.stack.stack_helper._code__phrase_role__keyword__bool__phrase___phrase_role__identifier__is_stack_unbound__phrase__phrase_role__special______phrase___code_"><code><phrase
|
|
role="keyword">bool</phrase> <phrase role="identifier">is_stack_unbound</phrase><phrase
|
|
role="special">()</phrase></code></link>
|
|
</bridgehead>
|
|
<variablelist>
|
|
<title></title>
|
|
<varlistentry>
|
|
<term>Returns:</term>
|
|
<listitem>
|
|
<para>
|
|
Returns <code><phrase role="keyword">true</phrase></code> if the environment
|
|
defines no limit for the size of a stack.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>Throws:</term>
|
|
<listitem>
|
|
<para>
|
|
Nothing.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
<anchor id="context.stack.stack_helper._code__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__pagesize__phrase__phrase_role__special______phrase___code_"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.stack.stack_helper._code__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__pagesize__phrase__phrase_role__special______phrase___code_"><code><phrase
|
|
role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase>
|
|
<phrase role="identifier">pagesize</phrase><phrase role="special">()</phrase></code></link>
|
|
</bridgehead>
|
|
<variablelist>
|
|
<title></title>
|
|
<varlistentry>
|
|
<term>Returns:</term>
|
|
<listitem>
|
|
<para>
|
|
Returns how many bytes the operating system allocates for one page.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>Throws:</term>
|
|
<listitem>
|
|
<para>
|
|
Nothing.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
<anchor id="context.stack.stack_helper._code__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__page_count__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__stacksize__phrase__phrase_role__special_____phrase___code_"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.stack.stack_helper._code__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__page_count__phrase__phrase_role__special_____phrase___phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__size_t__phrase___phrase_role__identifier__stacksize__phrase__phrase_role__special_____phrase___code_"><code><phrase
|
|
role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase>
|
|
<phrase role="identifier">page_count</phrase><phrase role="special">(</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
|
|
role="identifier">size_t</phrase> <phrase role="identifier">stacksize</phrase><phrase
|
|
role="special">)</phrase></code></link>
|
|
</bridgehead>
|
|
<variablelist>
|
|
<title></title>
|
|
<varlistentry>
|
|
<term>Returns:</term>
|
|
<listitem>
|
|
<para>
|
|
Returns how many pages have to be allocated for a stack of <code><phrase
|
|
role="identifier">stacksize</phrase></code> bytes.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>Throws:</term>
|
|
<listitem>
|
|
<para>
|
|
Nothing.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
</section>
|
|
</section>
|
|
<section id="context.performance">
|
|
<title><link linkend="context.performance">Performance</link></title>
|
|
<para>
|
|
Performance of <emphasis role="bold">Boost.Context</emphasis> was measured
|
|
on the platforms shown in the following table. Performance measurements were
|
|
taken using <code><phrase role="identifier">rdtsc</phrase></code>, with overhead
|
|
corrections, on x86 platforms. In each case, stack protection was active, cache
|
|
warm-up was accounted for, and the one running thread was pinned to a single
|
|
CPU. The code was compiled using the build options, 'variant = release cxxflags
|
|
= -DBOOST_DISABLE_ASSERTS'.
|
|
</para>
|
|
<para>
|
|
The numbers in the table are the number of cycles per iteration, based upon
|
|
an average computed over 10 iterations.
|
|
</para>
|
|
<table frame="all">
|
|
<title>Perfomance of context switch</title>
|
|
<tgroup cols="5">
|
|
<thead>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
Platform
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
ucontext_t
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
fcontext_t with fpu
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
fcontext_t without fpu
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
boost::function
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
AMD Athlon 64 DualCore 4400+ (32bit Linux)
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
846 cycles
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
65 cycles
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
46 cycles
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
43 cycles
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
Intel Core2 Q6700 (64bit Linux)
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
1472 cycles
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
172 cycles
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
63 cycles
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
60 cycles
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
<section id="context.tested">
|
|
<title><link linkend="context.tested">Tested Platforms</link></title>
|
|
<informaltable frame="all">
|
|
<tgroup cols="4">
|
|
<thead>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
Platform
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
OS
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
Compiler
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
ABI
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
ARM (ARM926EJ-S)
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
Debian GNU/Linux (Lenny)
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
GCC 4.4.4
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
ARM APCS (Linux)
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
MIPS (MIPS 24K)
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
Debian GNU/Linux (Lenny)
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
GCC 4.3.2
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
O32
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
MIPS (O2 / MIPS R5000)
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
Debian GNU/Linux (Lenny)
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
GCC 4.3.2
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
O32
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
PowerPC (7400)
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
Debian GNU/Linux (Lenny)
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
GCC 4.3.2
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
SYSV
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
X86_64 (Intel Core2 Quad)
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
Ubuntu GNU/Linux (Lucid Lynx)
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
GCC 4.4.3
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
SYSV
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
X86_64
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
Windows 7
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
MS VC 10.0
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
PE
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
I386
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
Debian GNU/Linux (Lenny)
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
GCC 4.4.3
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
SYSV
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
I386
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
FreeBSD 8.0
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
GCC 4.2.1
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
SYSV
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
I386
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
OpenSolaris 2009.06
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
GCC 4.3.2
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
SYSV
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para>
|
|
I386
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
Windows XP
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
MSVC 9.0
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
PE
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</section>
|
|
<section id="context.rationale">
|
|
<title><link linkend="context.rationale">Rationale</link></title> <anchor id="context.rationale.no_inline_assembler"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.rationale.no_inline_assembler">No inline-assembler</link>
|
|
</bridgehead>
|
|
<para>
|
|
Some newer compiler (for instance MSVC 10 for x86_64 and itanium) do not support
|
|
inline assembler. <footnote>
|
|
<para>
|
|
<ulink url="http://msdn.microsoft.com/en-us/library/4ks26t93.aspx">MSDN article
|
|
'Inline Assembler'</ulink>
|
|
</para>
|
|
</footnote>.
|
|
</para>
|
|
<anchor id="context.rationale.fcontext_t"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.rationale.fcontext_t">fcontext_t</link>
|
|
</bridgehead>
|
|
<para>
|
|
<emphasis role="bold">Boost.Context</emphasis> 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.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
Context switches do not preserve the signal mask on UNIX systems.
|
|
</para>
|
|
</note>
|
|
<para>
|
|
Because the assembler code uses the byte layout of <emphasis>fcontext_t</emphasis>
|
|
to access its members <emphasis>fcontext_t</emphasis> must be a POD. This requires
|
|
that <emphasis>fcontext_t</emphasis> has only a default constructor, no visibility
|
|
keywords (e.g. private, public, protected), no virtual methods and all members
|
|
and base clases are PODs too.
|
|
</para>
|
|
<anchor id="context.rationale.protecting_the_stack"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.rationale.protecting_the_stack">Protecting the stack</link>
|
|
</bridgehead>
|
|
<para>
|
|
Because the stack's size is fixed -- there is no support for split stacks yet
|
|
-- it is important to protect against exceeding the stack's bounds. Otherwise,
|
|
in the best case, overrunning the stack's memory will result in a segmentation
|
|
fault or access violation and, in the worst case, the application's memory
|
|
will be overwritten. <code><phrase role="identifier">stack_allocator</phrase></code>
|
|
appends a guard page to the stack to help detect overruns. The guard page consumes
|
|
no physical memory, but generates a segmentation fault or access violation
|
|
on access to the virtual memory addresses within it.
|
|
</para>
|
|
<section id="context.rationale.other_apis_">
|
|
<title><link linkend="context.rationale.other_apis_">Other APIs </link></title>
|
|
<anchor id="context.rationale.other_apis_.setjmp___longjmp__"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.rationale.other_apis_.setjmp___longjmp__">setjmp()/longjmp()</link>
|
|
</bridgehead>
|
|
<para>
|
|
C99 defines <code><phrase role="identifier">setjmp</phrase><phrase role="special">()</phrase></code>/<code><phrase
|
|
role="identifier">longjmp</phrase><phrase role="special">()</phrase></code>
|
|
to provide non-local jumps but it does not require that <emphasis>longjmp()</emphasis>
|
|
preserves the current stack frame. Therefore, jumping into a function which
|
|
was exited via a call to <emphasis>longjmp()</emphasis> is undefined <footnote>
|
|
<para>
|
|
<ulink url="boost:/libs/context/doc/pdf/iso_c99.pdf">ISO/IEC 9899:1999,
|
|
2005</ulink>, 7.13.2.1:2
|
|
</para>
|
|
</footnote>.
|
|
</para>
|
|
<anchor id="context.rationale.other_apis_.ucontext_t"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.rationale.other_apis_.ucontext_t">ucontext_t</link>
|
|
</bridgehead>
|
|
<para>
|
|
Since POSIX.1-2003 <code><phrase role="identifier">ucontext_t</phrase></code>
|
|
is deprecated and was removed in POSIX.1-2008! The function signature of
|
|
<code><phrase role="identifier">makecontext</phrase><phrase role="special">()</phrase></code>
|
|
is:
|
|
</para>
|
|
|
|
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">makecontext</phrase><phrase role="special">(</phrase><phrase role="identifier">ucontext_t</phrase> <phrase role="special">*</phrase><phrase role="identifier">ucp</phrase><phrase role="special">,</phrase> <phrase role="keyword">void</phrase> <phrase role="special">(*</phrase><phrase role="identifier">func</phrase><phrase role="special">)(),</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">argc</phrase><phrase role="special">,</phrase> <phrase role="special">...);</phrase>
|
|
</programlisting>
|
|
<para>
|
|
The third argument of <code><phrase role="identifier">makecontext</phrase><phrase
|
|
role="special">()</phrase></code> specifies the number of integer arguments
|
|
that follow which will require function pointer cast if <code><phrase role="identifier">func</phrase></code>
|
|
will accept those arguments which is undefined in C99 <footnote>
|
|
<para>
|
|
<ulink url="boost:/libs/context/doc/pdf/iso_c99.pdf">ISO/IEC 9899:1999,
|
|
2005</ulink>, J.2
|
|
</para>
|
|
</footnote>.
|
|
</para>
|
|
<para>
|
|
The arguments in the var-arg list are required to be integers, passing pointers
|
|
in var-arg list is not guarantied to work, especially it will fail for architectures
|
|
where pointers are larger than integers.
|
|
</para>
|
|
<para>
|
|
<code><phrase role="identifier">ucontext_t</phrase></code> preserves signal
|
|
mask between context switches which involes system calls consuming a lot
|
|
of CPU cycles (ucontext_t is slower by perfomance_link[factor 13x] relative
|
|
to <code><phrase role="identifier">fcontext_t</phrase></code>).
|
|
</para>
|
|
<anchor id="context.rationale.other_apis_.windows_fibers"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.rationale.other_apis_.windows_fibers">Windows fibers</link>
|
|
</bridgehead>
|
|
<para>
|
|
A drawback of Windows Fiber API is that <code><phrase role="identifier">CreateFiber</phrase><phrase
|
|
role="special">()</phrase></code> 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 <code><phrase role="identifier">ConvertThreadToFiber</phrase><phrase
|
|
role="special">()</phrase></code> if <code><phrase role="identifier">SwitchFiber</phrase><phrase
|
|
role="special">()</phrase></code> is called for a thread which has not been
|
|
converted to a fiber. For the same reason <code><phrase role="identifier">ConvertFiberToThread</phrase><phrase
|
|
role="special">()</phrase></code> must be called after return from <code><phrase
|
|
role="identifier">SwitchFiber</phrase><phrase role="special">()</phrase></code>
|
|
if the thread was forced to be converted to a fiber before (which is inefficient).
|
|
</para>
|
|
|
|
<programlisting><phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">is_a_fiber</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase>
|
|
<phrase role="special">{</phrase>
|
|
<phrase role="identifier">ConvertThreadToFiber</phrase><phrase role="special">(</phrase> <phrase role="number">0</phrase><phrase role="special">);</phrase>
|
|
<phrase role="identifier">SwitchToFiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">);</phrase>
|
|
<phrase role="identifier">ConvertFiberToThread</phrase><phrase role="special">();</phrase>
|
|
<phrase role="special">}</phrase>
|
|
</programlisting>
|
|
<para>
|
|
If the condition <code><phrase role="identifier">_WIN32_WINNT</phrase> <phrase
|
|
role="special">>=</phrase> <phrase role="identifier">_WIN32_WINNT_VISTA</phrase></code>
|
|
is met function <code><phrase role="identifier">IsThreadAFiber</phrase><phrase
|
|
role="special">()</phrase></code> is provided in order to detect if the current
|
|
thread was already converted. Unfortunately Windows XP + SP 2/3 defines
|
|
<code><phrase role="identifier">_WIN32_WINNT</phrase> <phrase role="special">>=</phrase>
|
|
<phrase role="identifier">_WIN32_WINNT_VISTA</phrase></code> without providing
|
|
<code><phrase role="identifier">IsThreadAFiber</phrase><phrase role="special">()</phrase></code>.
|
|
</para>
|
|
</section>
|
|
<section id="context.rationale.x86_and_floating_point_env">
|
|
<title><link linkend="context.rationale.x86_and_floating_point_env">x86 and
|
|
floating-point env</link></title> <anchor id="context.rationale.x86_and_floating_point_env.i386"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.rationale.x86_and_floating_point_env.i386">i386</link>
|
|
</bridgehead>
|
|
<para>
|
|
"The FpCsr and the MxCsr register must be saved and restored before
|
|
any call or return by any procedure that needs to modify them ..."
|
|
<footnote>
|
|
<para>
|
|
<ulink url="boost:/libs/context/doc/pdf/calling-conventions.pdf">'Calling
|
|
Conventions', Agner Fog</ulink>
|
|
</para>
|
|
</footnote>.
|
|
</para>
|
|
<anchor id="context.rationale.x86_and_floating_point_env.x86_64"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.rationale.x86_and_floating_point_env.x86_64">x86_64</link>
|
|
</bridgehead>
|
|
<anchor id="context.rationale.x86_and_floating_point_env.windows"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.rationale.x86_and_floating_point_env.windows">Windows</link>
|
|
</bridgehead>
|
|
<para>
|
|
MxCsr - "A callee that modifies any of the nonvolatile 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 ..." <footnote>
|
|
<para>
|
|
<ulink url="http://http://msdn.microsoft.com/en-us/library/yxty7t75.aspx">MSDN
|
|
article 'MxCsr'</ulink>
|
|
</para>
|
|
</footnote>.
|
|
</para>
|
|
<para>
|
|
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 ..." <footnote>
|
|
<para>
|
|
<ulink url="http://http://msdn.microsoft.com/en-us/library/ms235300.aspx">MSDN
|
|
article 'FpCsr'</ulink>
|
|
</para>
|
|
</footnote>.
|
|
</para>
|
|
<para>
|
|
"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." <footnote>
|
|
<para>
|
|
<ulink url="http://msdn.microsoft.com/en-us/library/a32tsf7t%28VS.80%29.aspx">MSDN
|
|
article 'Legacy Floating-Point Support'</ulink>
|
|
</para>
|
|
</footnote>.
|
|
</para>
|
|
<para>
|
|
"The 64-bit Microsoft compiler does not use ST(0)-ST(7)/MM0-MM7".
|
|
<footnote>
|
|
<para>
|
|
<ulink url="boost:/libs/context/doc/pdf/calling-conventions.pdf">'Calling
|
|
Conventions', Agner Fog</ulink>
|
|
</para>
|
|
</footnote>.
|
|
</para>
|
|
<para>
|
|
"XMM6-XMM15 must be preserved" <footnote>
|
|
<para>
|
|
<ulink url="http://msdn.microsoft.com/en-us/library/9z1stfyw%28v=vs.100%29.aspx">MSDN
|
|
article 'Register Usage'</ulink>
|
|
</para>
|
|
</footnote>
|
|
</para>
|
|
<anchor id="context.rationale.x86_and_floating_point_env.sysv"/>
|
|
<bridgehead renderas="sect4">
|
|
<link linkend="context.rationale.x86_and_floating_point_env.sysv">SysV</link>
|
|
</bridgehead>
|
|
<para>
|
|
"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." <footnote>
|
|
<para>
|
|
<ulink url="boost:/libs/context/doc/pdf/x86_64-sysv.pdf">SysV ABI AMD64
|
|
Architecture Processor Supplement Draft Version 0.99.4, 3.2.1</ulink>
|
|
</para>
|
|
</footnote>.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
<section id="context.reference">
|
|
<title><link linkend="context.reference">Reference</link></title> <anchor id="context.reference.arm"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.reference.arm">ARM</link>
|
|
</bridgehead>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara>
|
|
AAPCS ABI: <ulink url="boost:/libs/context/doc/pdf/arm-aapcs.pdf">Procedure
|
|
Call Standard for the ARM Architecture</ulink>
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
AAPCS/LINUX: <ulink url="boost:/libs/context/doc/pdf/arm-linux-aapcs.pdf">ARM
|
|
GNU/Linux Application Binary Interface Supplement</ulink>
|
|
</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<anchor id="context.reference.mips"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.reference.mips">MIPS</link>
|
|
</bridgehead>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara>
|
|
O32 ABI: <ulink url="boost:/libs/context/doc/pdf/mips-o32.pdf">SYSTEM V
|
|
APPLICATION BINARY INTERFACE, MIPS RISC Processor Supplement</ulink>
|
|
</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<anchor id="context.reference.powerpc32"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.reference.powerpc32">PowerPC32</link>
|
|
</bridgehead>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara>
|
|
SYSV ABI: <ulink url="boost:/libs/context/doc/pdf/ppc32-sysv.pdf">SYSTEM
|
|
V APPLICATION BINARY INTERFACE PowerPC Processor Supplement</ulink>
|
|
</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<anchor id="context.reference.powerpc64"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.reference.powerpc64">PowerPC64</link>
|
|
</bridgehead>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara>
|
|
SYSV ABI: <ulink url="boost:/libs/context/doc/pdf/ppc64-sysv.pdf">PowerPC
|
|
User Instruction Set Architecture, Book I</ulink>
|
|
</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<anchor id="context.reference.x86_32"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.reference.x86_32">X86-32</link>
|
|
</bridgehead>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara>
|
|
SYSV ABI: <ulink url="boost:/libs/context/doc/pdf/x86_32-sysv.pdf">SYSTEM
|
|
V APPLICATION BINARY INTERFACE, Intel386TM Architecture Processor Supplement</ulink>
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
MS PE: <ulink url="http://msdn.microsoft.com/en-us/library/k2b2ssfy.aspx">Calling
|
|
Conventions</ulink>
|
|
</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<anchor id="context.reference.x86_64"/>
|
|
<bridgehead renderas="sect3">
|
|
<link linkend="context.reference.x86_64">X86-64</link>
|
|
</bridgehead>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara>
|
|
SYSV ABI: <ulink url="boost:/libs/context/doc/pdf/x86_64-sysv.pdf">System
|
|
V Application Binary Interface, AMD64 Architecture Processor Supplement</ulink>
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
MS PE: <ulink url="http://msdn.microsoft.com/en-us/library/7kcdt6fy%28VS.80%29.aspx">x64
|
|
Software Conventions</ulink>
|
|
</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
<section id="context.todo">
|
|
<title><link linkend="context.todo">Todo</link></title>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara>
|
|
provide support for SPARC
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
support split-stack feature from gcc/gold linker
|
|
</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
<section id="context.acknowledgements">
|
|
<title><link linkend="context.acknowledgements">Acknowledgments</link></title>
|
|
<para>
|
|
I'd like to thank Adreas Fett, Artyom Beilis, Fernando Pelliccioni, Giovanni
|
|
Piero Deretta, Gordon Woodhull, Helge Bahmann, Holger Grund, Jeffrey Lee Hellrung
|
|
(Jr.), Keith Jeffery, Phil Endecott, Robert Stewart, Steven Watanabe, Vicente
|
|
J. Botet Escriba.
|
|
</para>
|
|
</section>
|
|
</article>
|