2
0
mirror of https://github.com/boostorg/context.git synced 2026-01-19 04:02:17 +00:00

Merge branch 'develop' into mips

This commit is contained in:
Oliver Kowalke
2021-08-06 07:41:02 +02:00
committed by GitHub
112 changed files with 3517 additions and 6460 deletions

29
.drone.star Normal file
View File

@@ -0,0 +1,29 @@
# Use, modification, and distribution are
# subject to the Boost Software License, Version 1.0. (See accompanying
# file LICENSE.txt)
#
# Copyright Rene Rivera 2020.
# For Drone CI we use the Starlark scripting language to reduce duplication.
# As the yaml syntax for Drone CI is rather limited.
#
#
globalenv={}
linuxglobalimage="cppalliance/droneubuntu1604:1"
windowsglobalimage="cppalliance/dronevs2019"
def main(ctx):
return [
linux_cxx("TOOLSET=gcc COMPILER=g++ CXXSTD=11 Job 0", "g++", packages="", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'TOOLSET': 'gcc', 'COMPILER': 'g++', 'CXXSTD': '11', 'DRONE_JOB_UUID': 'b6589fc6ab'}, globalenv=globalenv),
linux_cxx("TOOLSET=gcc COMPILER=g++-5 CXXSTD=11,14,1z Job 1", "g++-5", packages="g++-5", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-5', 'CXXSTD': '11,14,1z', 'DRONE_JOB_UUID': '356a192b79'}, globalenv=globalenv),
linux_cxx("TOOLSET=gcc COMPILER=g++-6 CXXSTD=11,14,1z Job 2", "g++-6", packages="g++-6", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-6', 'CXXSTD': '11,14,1z', 'DRONE_JOB_UUID': 'da4b9237ba'}, globalenv=globalenv),
linux_cxx("TOOLSET=gcc COMPILER=g++-7 CXXSTD=11,14,17 Job 3", "g++-7", packages="g++-7", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-7', 'CXXSTD': '11,14,17', 'DRONE_JOB_UUID': '77de68daec'}, globalenv=globalenv),
linux_cxx("TOOLSET=clang COMPILER=clang++ CXXSTD=11 Job 4", "clang++", packages="", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'TOOLSET': 'clang', 'COMPILER': 'clang++', 'CXXSTD': '11', 'DRONE_JOB_UUID': '1b64538924'}, globalenv=globalenv),
linux_cxx("TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=11, Job 5", "clang++-4.0", packages="clang-4.0 libstdc++-6-dev", llvm_os="xenial", llvm_ver="4.0", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'TOOLSET': 'clang', 'COMPILER': 'clang++-4.0', 'CXXSTD': '11,14,1z', 'DRONE_JOB_UUID': 'ac3478d69a'}, globalenv=globalenv),
linux_cxx("TOOLSET=clang COMPILER=clang++-5.0 CXXSTD=11, Job 6", "clang++-5.0", packages="clang-5.0 libstdc++-7-dev", llvm_os="xenial", llvm_ver="5.0", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'TOOLSET': 'clang', 'COMPILER': 'clang++-5.0', 'CXXSTD': '11,14,1z', 'DRONE_JOB_UUID': 'c1dfd96eea'}, globalenv=globalenv),
osx_cxx("TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1 Job 7", "clang++", packages="", buildtype="boost", buildscript="drone", xcode_version="8.3", environment={'TOOLSET': 'clang', 'COMPILER': 'clang++', 'CXXSTD': '11,14,1z', 'DRONE_JOB_UUID': '902ba3cda1'}, globalenv=globalenv),
osx_cxx("TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1 Job 8", "clang++", packages="", buildtype="boost", buildscript="drone", xcode_version="9.1", environment={'TOOLSET': 'clang', 'COMPILER': 'clang++', 'CXXSTD': '11,14,1z', 'DRONE_JOB_UUID': 'fe5dbbcea5'}, globalenv=globalenv),
]
# from https://github.com/boostorg/boost-ci
load("@boost_ci//ci/drone/:functions.star", "linux_cxx","windows_cxx","osx_cxx","freebsd_cxx")

37
.drone/drone.sh Executable file
View File

@@ -0,0 +1,37 @@
#!/bin/bash
# Copyright 2020 Rene Rivera, Sam Darwin
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSE_1_0.txt)
set -e
export TRAVIS_BUILD_DIR=$(pwd)
export DRONE_BUILD_DIR=$(pwd)
export TRAVIS_BRANCH=$DRONE_BRANCH
export VCS_COMMIT_ID=$DRONE_COMMIT
export GIT_COMMIT=$DRONE_COMMIT
export REPO_NAME=$DRONE_REPO
export PATH=~/.local/bin:/usr/local/bin:$PATH
if [ "$DRONE_JOB_BUILDTYPE" == "boost" ]; then
echo '==================================> INSTALL'
BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
cd ..
git clone -b $BOOST_BRANCH https://github.com/boostorg/boost.git boost-root
cd boost-root
git submodule update --init tools/build
git submodule update --init libs/config
git submodule update --init tools/boostdep
cp -r $TRAVIS_BUILD_DIR/* libs/context
python tools/boostdep/depinst/depinst.py context
./bootstrap.sh
./b2 headers
echo '==================================> SCRIPT'
echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam
./b2 -j 3 libs/context/test toolset=$TOOLSET cxxstd=$CXXSTD
fi

309
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,309 @@
name: GitHub Actions CI
on:
pull_request:
push:
branches:
- master
- develop
- githubactions*
- feature/**
- fix/**
- pr/**
jobs:
posix:
strategy:
fail-fast: false
matrix:
include:
- name: "TOOLSET=gcc COMPILER=g++ CXXSTD=11 Job 0"
buildtype: "boost"
packages: ""
packages_to_remove: ""
os: "ubuntu-20.04"
container: "ubuntu:16.04"
cxx: "g++"
sources: ""
llvm_os: ""
llvm_ver: ""
toolset: "gcc"
compiler: "g++"
cxxstd: "11"
- name: "TOOLSET=gcc COMPILER=g++-5 CXXSTD=11,14,1z Job 1"
buildtype: "boost"
packages: "g++-5"
packages_to_remove: ""
os: "ubuntu-20.04"
container: "ubuntu:16.04"
cxx: "g++-5"
sources: ""
llvm_os: ""
llvm_ver: ""
toolset: "gcc"
compiler: "g++-5"
cxxstd: "11,14,1z"
- name: "TOOLSET=gcc COMPILER=g++-6 CXXSTD=11,14,1z Job 2"
buildtype: "boost"
packages: "g++-6"
packages_to_remove: ""
os: "ubuntu-20.04"
container: "ubuntu:16.04"
cxx: "g++-6"
sources: ""
llvm_os: ""
llvm_ver: ""
toolset: "gcc"
compiler: "g++-6"
cxxstd: "11,14,1z"
- name: "TOOLSET=gcc COMPILER=g++-7 CXXSTD=11,14,17 Job 3"
buildtype: "boost"
packages: "g++-7"
packages_to_remove: ""
os: "ubuntu-20.04"
container: "ubuntu:16.04"
cxx: "g++-7"
sources: ""
llvm_os: ""
llvm_ver: ""
toolset: "gcc"
compiler: "g++-7"
cxxstd: "11,14,17"
- name: "TOOLSET=clang COMPILER=clang++ CXXSTD=11 Job 4"
buildtype: "boost"
packages: ""
packages_to_remove: ""
os: "ubuntu-18.04"
cxx: "clang++"
sources: ""
llvm_os: ""
llvm_ver: ""
toolset: "clang"
compiler: "clang++"
cxxstd: "11"
- name: "TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=11, Job 5"
buildtype: "boost"
packages: "clang-4.0 libstdc++-6-dev"
packages_to_remove: ""
os: "ubuntu-20.04"
container: "ubuntu:16.04"
cxx: "clang++-4.0"
sources: ""
llvm_os: "xenial"
llvm_ver: "4.0"
toolset: "clang"
compiler: "clang++-4.0"
cxxstd: "11,14"
- name: "TOOLSET=clang COMPILER=clang++-5.0 CXXSTD=11, Job 6"
buildtype: "boost"
packages: "clang-5.0 libstdc++-7-dev"
packages_to_remove: ""
os: "ubuntu-20.04"
container: "ubuntu:16.04"
cxx: "clang++-5.0"
sources: ""
llvm_os: "xenial"
llvm_ver: "5.0"
toolset: "clang"
compiler: "clang++-5.0"
cxxstd: "11,14,1z"
runs-on: ${{ matrix.os }}
container: ${{ matrix.container }}
steps:
- name: Check if running in container
if: matrix.container != ''
run: echo "GHA_CONTAINER=${{ matrix.container }}" >> $GITHUB_ENV
- name: If running in container, upgrade packages
if: matrix.container != ''
run: |
apt-get -o Acquire::Retries=3 update && DEBIAN_FRONTEND=noninteractive apt-get -y install tzdata && apt-get -o Acquire::Retries=3 install -y sudo software-properties-common wget curl apt-transport-https make apt-file sudo unzip libssl-dev build-essential autotools-dev autoconf automake g++ libc++-helpers python ruby cpio gcc-multilib g++-multilib pkgconf python3 ccache libpython-dev
sudo apt-add-repository ppa:git-core/ppa
sudo apt-get -o Acquire::Retries=3 update && apt-get -o Acquire::Retries=3 -y install git
python_version=$(python3 -c 'import sys; print("{0.major}.{0.minor}".format(sys.version_info))')
sudo wget https://bootstrap.pypa.io/pip/$python_version/get-pip.py
sudo python3 get-pip.py
sudo /usr/local/bin/pip install cmake
- uses: actions/checkout@v2
- name: linux
shell: bash
env:
CXX: ${{ matrix.cxx }}
SOURCES: ${{ matrix.sources }}
LLVM_OS: ${{ matrix.llvm_os }}
LLVM_VER: ${{ matrix.llvm_ver }}
PACKAGES: ${{ matrix.packages }}
PACKAGES_TO_REMOVE: ${{ matrix.packages_to_remove }}
JOB_BUILDTYPE: ${{ matrix.buildtype }}
TOOLSET: ${{ matrix.toolset }}
COMPILER: ${{ matrix.compiler }}
CXXSTD: ${{ matrix.cxxstd }}
TRAVIS_BRANCH: ${{ github.base_ref }}
TRAVIS_OS_NAME: "linux"
run: |
echo '==================================> SETUP'
echo '==================================> PACKAGES'
set -e
if [ -n "$PACKAGES_TO_REMOVE" ]; then sudo apt-get purge -y $PACKAGES_TO_REMOVE; fi
echo ">>>>> APT: REPO.."
for i in {1..3}; do sudo -E apt-add-repository -y "ppa:ubuntu-toolchain-r/test" && break || sleep 2; done
if test -n "${LLVM_OS}" ; then
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
if test -n "${LLVM_VER}" ; then
sudo -E apt-add-repository "deb http://apt.llvm.org/${LLVM_OS}/ llvm-toolchain-${LLVM_OS}-${LLVM_VER} main"
else
# Snapshot (i.e. trunk) build of clang
sudo -E apt-add-repository "deb http://apt.llvm.org/${LLVM_OS}/ llvm-toolchain-${LLVM_OS} main"
fi
fi
echo ">>>>> APT: UPDATE.."
sudo -E apt-get -o Acquire::Retries=3 update
if test -n "${SOURCES}" ; then
echo ">>>>> APT: INSTALL SOURCES.."
for SOURCE in $SOURCES; do
sudo -E apt-add-repository ppa:$SOURCE
done
fi
echo ">>>>> APT: INSTALL ${PACKAGES}.."
sudo -E DEBIAN_FRONTEND=noninteractive apt-get -o Acquire::Retries=3 -y --no-install-suggests --no-install-recommends install ${PACKAGES}
echo '==================================> INSTALL AND COMPILE'
set -e
export TRAVIS_BUILD_DIR=$(pwd)
export TRAVIS_BRANCH=${TRAVIS_BRANCH:-$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')}
export VCS_COMMIT_ID=$GITHUB_SHA
export GIT_COMMIT=$GITHUB_SHA
export REPO_NAME=$(basename $GITHUB_REPOSITORY)
export USER=$(whoami)
export CC=${CC:-gcc}
export PATH=~/.local/bin:/usr/local/bin:$PATH
if [ "$JOB_BUILDTYPE" == "boost" ]; then
echo '==================================> INSTALL'
BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
cd ..
git clone -b $BOOST_BRANCH https://github.com/boostorg/boost.git boost-root
cd boost-root
git submodule update --init tools/build
git submodule update --init libs/config
git submodule update --init tools/boostdep
cp -r $TRAVIS_BUILD_DIR/* libs/context
python tools/boostdep/depinst/depinst.py context
./bootstrap.sh
./b2 headers
echo '==================================> SCRIPT'
echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam
./b2 -j 3 libs/context/test toolset=$TOOLSET cxxstd=$CXXSTD
fi
#
# osx:
# strategy:
# fail-fast: false
# matrix:
# include:
#
# Github Actions only supports certain Xcode versions
# Change (or delete) the Xcode version for this job.
#
# - name: "TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1 Job 7"
# buildtype: "boost"
# packages: ""
# os: "macos-10.15"
# cxx: "clang++"
# sources: ""
# llvm_os: ""
# llvm_ver: ""
# xcode_version: "8.3"
# toolset: "clang"
# compiler: "clang++"
# cxxstd: "11,14,1z"
#
# Github Actions only supports certain Xcode versions
# Change (or delete) the Xcode version for this job.
#
# - name: "TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1 Job 8"
# buildtype: "boost"
# packages: ""
# os: "macos-10.15"
# cxx: "clang++"
# sources: ""
# llvm_os: ""
# llvm_ver: ""
# xcode_version: "9.1"
# toolset: "clang"
# compiler: "clang++"
# cxxstd: "11,14,1z"
#
#
# runs-on: ${{ matrix.os }}
#
# steps:
# - uses: actions/checkout@v2
#
# - name: Set DEVELOPER_DIR
# if: matrix.xcode_version != ''
# run: echo "DEVELOPER_DIR=/Applications/Xcode_${{ matrix.xcode_version }}.app/Contents/Developer" >> $GITHUB_ENV
# - name: Test DEVELOPER_DIR
# run: echo $DEVELOPER_DIR
#
# - name: "osx"
# shell: bash
# env:
# CXX: ${{ matrix.cxx }}
# SOURCES: ${{ matrix.sources }}
# LLVM_OS: ${{ matrix.llvm_os }}
# LLVM_VER: ${{ matrix.llvm_ver }}
# PACKAGES: ${{ matrix.packages }}
# JOB_BUILDTYPE: ${{ matrix.buildtype }}
# TOOLSET: ${{ matrix.toolset }}
# COMPILER: ${{ matrix.compiler }}
# CXXSTD: ${{ matrix.cxxstd }}
# TRAVIS_BRANCH: ${{ github.base_ref }}
# TRAVIS_OS_NAME: "osx"
# run: |
# echo '==================================> SETUP'
# set -e
# sudo mv /Library/Developer/CommandLineTools /Library/Developer/CommandLineTools.bck
# echo '==================================> PACKAGES'
# echo '==================================> INSTALL AND COMPILE'
# set -e
# export TRAVIS_BUILD_DIR=$(pwd)
# export TRAVIS_BRANCH=${TRAVIS_BRANCH:-$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')}
# export VCS_COMMIT_ID=$GITHUB_SHA
# export GIT_COMMIT=$GITHUB_SHA
# export REPO_NAME=$(basename $GITHUB_REPOSITORY)
# export USER=$(whoami)
# export CC=${CC:-gcc}
# export PATH=~/.local/bin:/usr/local/bin:$PATH
#
# if [ "$JOB_BUILDTYPE" == "boost" ]; then
#
# echo '==================================> INSTALL'
#
# BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
# cd ..
# git clone -b $BOOST_BRANCH https://github.com/boostorg/boost.git boost-root
# cd boost-root
# git submodule update --init tools/build
# git submodule update --init libs/config
# git submodule update --init tools/boostdep
# cp -r $TRAVIS_BUILD_DIR/* libs/context
# python tools/boostdep/depinst/depinst.py context
# ./bootstrap.sh
# ./b2 headers
#
# echo '==================================> SCRIPT'
#
# echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam
# ./b2 -j 3 libs/context/test toolset=$TOOLSET cxxstd=$CXXSTD
#
# fi

202
CMakeLists.txt Normal file
View File

@@ -0,0 +1,202 @@
# Copyright 2020, 2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.5...3.16)
project(boost_context VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
# Build features
## Binary format
if(WIN32)
set(_default_binfmt pe)
elseif(APPLE)
set(_default_binfmt mach-o)
else()
set(_default_binfmt elf)
endif()
set(BOOST_CONTEXT_BINARY_FORMAT "${_default_binfmt}" CACHE STRING "Boost.Context binary format (elf, mach-o, pe, xcoff)")
set_property(CACHE BOOST_CONTEXT_BINARY_FORMAT PROPERTY STRINGS elf mach-o pe xcoff)
unset(_default_binfmt)
## ABI
if(WIN32)
set(_default_abi ms)
else()
set(_default_abi sysv)
endif()
set(BOOST_CONTEXT_ABI "${_default_abi}" CACHE STRING "Boost.Context ABI (aapcs, eabi, ms, n32, n64, o32, o64, sysv, x32)")
set_property(CACHE BOOST_CONTEXT_ABI PROPERTY STRINGS aapcs eabi ms n32 n64 o32 o64 sysv x32)
unset(_default_abi)
## Arch-and-model
math(EXPR _bits "${CMAKE_SIZEOF_VOID_P}*8")
if(_bits EQUAL 32)
set(_default_arch i386)
else()
set(_default_arch x86_64)
endif()
set(BOOST_CONTEXT_ARCHITECTURE "${_default_arch}" CACHE STRING "Boost.Context architecture (arm, arm64, mips32, mips64, ppc32, ppc64, riscv64, s390x, i386, x86_64, combined)")
set_property(CACHE BOOST_CONTEXT_ARCHITECTURE PROPERTY STRINGS arm arm64 mips32 mips64 ppc32 ppc64 riscv64 s390x i386 x86_64 combined)
unset(_bits)
unset(_default_arch)
## Assembler type
if(MSVC)
set(_default_asm masm)
else()
set(_default_asm gas)
endif()
set(BOOST_CONTEXT_ASSEMBLER "${_default_asm}" CACHE STRING "Boost.Context assembler (masm, gas, armasm)")
set_property(CACHE BOOST_CONTEXT_ASSEMBLER PROPERTY STRINGS masm gas armasm)
unset(_default_asm)
## Assembler source suffix
if(BOOST_CONTEXT_BINARY_FORMAT STREQUAL pe)
set(_default_ext .asm)
elseif(BOOST_CONTEXT_ASSEMBLER STREQUAL gas)
set(_default_ext .S)
else()
set(_default_ext .asm)
endif()
set(BOOST_CONTEXT_ASM_SUFFIX "${_default_ext}" CACHE STRING "Boost.Context assembler source suffix (.asm, .S)")
set_property(CACHE BOOST_CONTEXT_ASM_SUFFIX PROPERTY STRINGS .asm .S)
unset(_default_ext)
## Implementation
set(_default_impl fcontext)
set(BOOST_CONTEXT_IMPLEMENTATION "${_default_impl}" CACHE STRING "Boost.Context implementation (fcontext, ucontext, winfib)")
set_property(CACHE BOOST_CONTEXT_IMPLEMENTATION PROPERTY STRINGS fcontext ucontext winfib)
unset(_default_impl)
#
message(STATUS "Boost.Context: "
"architecture ${BOOST_CONTEXT_ARCHITECTURE}, "
"binary format ${BOOST_CONTEXT_BINARY_FORMAT}, "
"ABI ${BOOST_CONTEXT_ABI}, "
"assembler ${BOOST_CONTEXT_ASSEMBLER}, "
"suffix ${BOOST_CONTEXT_ASM_SUFFIX}, "
"implementation ${BOOST_CONTEXT_IMPLEMENTATION}")
# Enable the right assembler
if(BOOST_CONTEXT_IMPLEMENTATION STREQUAL "fcontext")
if(BOOST_CONTEXT_ASSEMBLER STREQUAL gas)
if(CMAKE_CXX_PLATFORM_ID MATCHES "Cygwin")
enable_language(ASM-ATT)
else()
enable_language(ASM)
endif()
else()
enable_language(ASM_MASM)
endif()
endif()
# Choose .asm sources
if(BOOST_CONTEXT_BINARY_FORMAT STREQUAL mach-o)
set(BOOST_CONTEXT_BINARY_FORMAT macho)
endif()
set(_asm_suffix ${BOOST_CONTEXT_ARCHITECTURE}_${BOOST_CONTEXT_ABI}_${BOOST_CONTEXT_BINARY_FORMAT}_${BOOST_CONTEXT_ASSEMBLER}${BOOST_CONTEXT_ASM_SUFFIX})
set(ASM_SOURCES
src/asm/make_${_asm_suffix}
src/asm/jump_${_asm_suffix}
src/asm/ontop_${_asm_suffix}
)
unset(_asm_suffix)
#
if(BOOST_CONTEXT_IMPLEMENTATION STREQUAL "fcontext")
set(IMPL_SOURCES ${ASM_SOURCES})
if(BOOST_CONTEXT_ASSEMBLER STREQUAL masm AND BOOST_CONTEXT_ARCHITECTURE STREQUAL i386)
set_source_files_properties(${ASM_SOURCES} PROPERTIES COMPILE_FLAGS "/safeseh")
endif()
else()
set(IMPL_SOURCES
src/continuation.cpp
src/fiber.cpp
)
endif()
if(WIN32 AND NOT CMAKE_CXX_PLATFORM_ID MATCHES "Cygwin")
set(STACK_TRAITS_SOURCES
src/windows/stack_traits.cpp
)
else()
set(STACK_TRAITS_SOURCES
src/posix/stack_traits.cpp
)
endif()
add_library(boost_context
${IMPL_SOURCES}
${STACK_TRAITS_SOURCES}
)
add_library(Boost::context ALIAS boost_context)
target_include_directories(boost_context PUBLIC include)
target_link_libraries(boost_context
PUBLIC
Boost::assert
Boost::config
Boost::core
Boost::mp11
Boost::pool
Boost::predef
Boost::smart_ptr
)
target_compile_definitions(boost_context
PUBLIC BOOST_CONTEXT_NO_LIB
PRIVATE BOOST_CONTEXT_SOURCE
)
if(BUILD_SHARED_LIBS)
target_compile_definitions(boost_context PUBLIC BOOST_CONTEXT_DYN_LINK BOOST_CONTEXT_EXPORT=EXPORT)
else()
target_compile_definitions(boost_context PUBLIC BOOST_CONTEXT_STATIC_LINK BOOST_CONTEXT_EXPORT=)
endif()
if(BOOST_CONTEXT_IMPLEMENTATION STREQUAL "ucontext")
target_compile_definitions(boost_context PUBLIC BOOST_USE_UCONTEXT)
endif()
if(BOOST_CONTEXT_IMPLEMENTATION STREQUAL "winfib")
target_compile_definitions(boost_context PUBLIC BOOST_USE_WINFIB)
endif()
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)
endif()

View File

@@ -8,14 +8,14 @@ instance represents a specific point in the application's execution path. This i
higher-level abstractions, like coroutines, cooperative threads (userland threads) or an equivalent to
C# keyword yield in C++.
A execution_context provides the means to suspend the current execution path and to transfer execution control,
thereby permitting another execution_context to run on the current thread. This state full transfer mechanism
enables a execution_context to suspend execution from within nested functions and, later, to resume from where it
was suspended. While the execution path represented by a execution_context only runs on a single thread, it can be
A fiber provides the means to suspend the current execution path and to transfer execution control,
thereby permitting another fiber to run on the current thread. This state full transfer mechanism
enables a fiber to suspend execution from within nested functions and, later, to resume from where it
was suspended. While the execution path represented by a fiber 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 among them requires only fewer than
thousand CPU cycles on x86 CPUs. By contrast, transferring control among fibers requires only fewer than
hundred CPU cycles because it does not involve system calls as it is done within a single thread.
boost.context requires C++11!

View File

@@ -26,8 +26,8 @@ feature.compose <valgrind>on : <define>BOOST_USE_VALGRIND ;
project boost/context
: requirements
<target-os>windows:<define>_WIN32_WINNT=0x0601
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<target-os>linux,<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<target-os>linux,<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>gcc,<segmented-stacks>on:<linkflags>"-static-libgcc"
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
@@ -38,9 +38,14 @@ project boost/context
<toolset>msvc,<link>static:<define>BOOST_CONTEXT_EXPORT=
<toolset>clang-win,<link>shared:<define>BOOST_CONTEXT_EXPORT=EXPORT
<toolset>clang-win,<link>static:<define>BOOST_CONTEXT_EXPORT=
<toolset>embarcadero,<address-model>32,<link>shared:<define>BOOST_CONTEXT_EXPORT=EXPORT
<toolset>embarcadero,<address-model>32,<link>static:<define>BOOST_CONTEXT_EXPORT=
<toolset>borland,<link>shared:<define>BOOST_CONTEXT_EXPORT=EXPORT
<toolset>borland,<link>static:<define>BOOST_CONTEXT_EXPORT=
<link>shared:<define>BOOST_CONTEXT_DYN_LINK=1
<define>BOOST_CONTEXT_SOURCE
<threading>multi
<toolset>msvc,<address-model>32:<asmflags>/safeseh
: usage-requirements
<link>shared:<define>BOOST_CONTEXT_DYN_LINK=1
<optimization>speed:<define>BOOST_DISABLE_ASSERTS
@@ -75,7 +80,8 @@ local rule default_abi ( )
if [ os.name ] = "NT" { tmp = ms ; }
else if [ os.name ] = "CYGWIN" { tmp = ms ; }
else if [ os.platform ] = "ARM" { tmp = aapcs ; }
else if [ os.platform ] = "MIPS" { tmp = o32 ; }
else if [ os.platform ] = "MIPS32" { tmp = o32 ; }
else if [ os.platform ] = "MIPS64" { tmp = n64 ; }
return $(tmp) ;
}
@@ -276,6 +282,7 @@ alias asm_sources
: asm/make_ppc32_sysv_elf_gas.S
asm/jump_ppc32_sysv_elf_gas.S
asm/ontop_ppc32_sysv_elf_gas.S
asm/tail_ppc32_sysv_elf_gas.cpp
: <abi>sysv
<address-model>32
<architecture>power
@@ -287,6 +294,7 @@ alias asm_sources
: asm/make_ppc32_sysv_elf_gas.S
asm/jump_ppc32_sysv_elf_gas.S
asm/ontop_ppc32_sysv_elf_gas.S
asm/tail_ppc32_sysv_elf_gas.cpp
: <abi>sysv
<address-model>32
<architecture>power
@@ -412,6 +420,32 @@ alias asm_sources
<binary-format>mach-o
;
# RISCV64
# RISCV64/SYSV/ELF
alias asm_sources
: asm/make_riscv64_sysv_elf_gas.S
asm/jump_riscv64_sysv_elf_gas.S
asm/ontop_riscv64_sysv_elf_gas.S
: <abi>sysv
<address-model>64
<architecture>riscv
<binary-format>elf
<toolset>gcc
;
# S390X
# S390X/SYSV/ELF
alias asm_sources
: asm/make_s390x_sysv_elf_gas.S
asm/jump_s390x_sysv_elf_gas.S
asm/ontop_s390x_sysv_elf_gas.S
: <abi>sysv
<address-model>64
<architecture>s390x
<binary-format>elf
<toolset>gcc
;
# X86
# X86/SYSV/ELF
alias asm_sources
@@ -531,6 +565,40 @@ alias asm_sources
<toolset>msvc
;
# Embarcadero on Windows for 32-bits, bcc32x, uses tasm32,
# which is masm compatible
# This is configured in the embarcadero toolset as using
# 'tasm32 /ml'
alias asm_sources
: asm/make_i386_ms_pe_masm.asm
asm/jump_i386_ms_pe_masm.asm
asm/ontop_i386_ms_pe_masm.asm
dummy.cpp
: <abi>ms
<address-model>32
<architecture>x86
<binary-format>pe
<toolset>embarcadero
;
# Borland on Windows for 32-bits, bcc32c, uses tasm32,
# which is masm compatible
# This is configured in the borland toolset as using
# 'tasm32 /ml'
alias asm_sources
: asm/make_i386_ms_pe_masm.asm
asm/jump_i386_ms_pe_masm.asm
asm/ontop_i386_ms_pe_masm.asm
dummy.cpp
: <abi>ms
<address-model>32
<architecture>x86
<binary-format>pe
<toolset>borland
;
# X86_64
# X86_64/SYSV/ELF
alias asm_sources
@@ -578,6 +646,17 @@ alias asm_sources
<toolset>clang
;
alias asm_sources
: asm/make_x86_64_sysv_macho_gas.S
asm/jump_x86_64_sysv_macho_gas.S
asm/ontop_x86_64_sysv_macho_gas.S
: <abi>sysv
<address-model>64
<architecture>x86
<binary-format>mach-o
<toolset>gcc
;
alias asm_sources
: asm/make_x86_64_sysv_macho_gas.S
asm/jump_x86_64_sysv_macho_gas.S
@@ -660,6 +739,21 @@ alias asm_sources
<binary-format>pe
<toolset>msvc
;
# Embarcadero on Windows, bcc64, uses the sysv-elf format for 64-bits
# This is configured in the embarcadero toolset as using bcc64 with the
# command line option '-x assembler-with-cpp'.
alias asm_sources
: asm/make_x86_64_sysv_elf_gas.S
asm/jump_x86_64_sysv_elf_gas.S
asm/ontop_x86_64_sysv_elf_gas.S
: <abi>ms
<address-model>64
<architecture>x86
<binary-format>pe
<toolset>embarcadero
;
# X86_64/SYSV/X32
alias asm_sources
@@ -767,33 +861,19 @@ alias impl_sources
explicit impl_sources ;
obj cxx11_hdr_mutex_check : ../build/cxx11_hdr_mutex.cpp ;
explicit cxx11_hdr_mutex_check ;
local cxx11_mutex = [ check-target-builds
cxx11_hdr_mutex_check "C++11 mutex"
:
: <library>/boost/thread//boost_thread
] ;
alias stack_traits_sources
: windows/stack_traits.cpp
: <target-os>windows
:
: $(cxx11_mutex)
;
alias stack_traits_sources
: posix/stack_traits.cpp
:
:
: $(cxx11_mutex)
;
explicit stack_traits_sources ;
lib boost_context
: impl_sources
execution_context.cpp
stack_traits_sources
;

View File

@@ -63,6 +63,14 @@ rule deduce-architecture ( properties * )
{
return <architecture>power ;
}
else if [ configure.builds /boost/architecture//riscv : $(properties) : riscv ]
{
return <architecture>riscv ;
}
else if [ configure.builds /boost/architecture//s390x : $(properties) : s390x ]
{
return <architecture>s390x ;
}
else if [ configure.builds /boost/architecture//sparc : $(properties) : sparc ]
{
return <architecture>sparc ;

View File

@@ -1,10 +0,0 @@
// Copyright Kohei Takahashi 2016.
// 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)
#include <boost/config.hpp>
#ifdef BOOST_NO_CXX11_HDR_MUTEX
#error "C++11 <mutex> is not available."
#endif

View File

@@ -11,15 +11,17 @@ __boost_context__, using [link implementation ['fcontext_t]], supports following
architectures:
[table 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] [-]]
[[mips] [O32,N64|ELF] [-] [-] [-]]
[[ppc32] [SYSV|ELF,XCOFF] [-] [SYSV|MACH-O] [-]]
[[ppc64] [SYSV|ELF,XCOFF] [-] [SYSV|MACH-O] [-]]
[[sparc] [-] [-] [-] [-]]
[[x86_64] [SYSV,X32|ELF] [MS|PE] [SYSV|MACH-O] [-]]
[[Architecture] [LINUX (UNIX)] [Windows] [MacOS X] [iOS]]
[[arm (aarch32)] [AAPCS|ELF] [AAPCS|PE] [-] [AAPCS|MACH-O]]
[[arm (aarch64)] [AAPCS|ELF] [-] [AAPCS|MACH-O] [AAPCS|MACH-O]]
[[i386] [SYSV|ELF] [MS|PE] [SYSV|MACH-O] [-]]
[[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

View File

@@ -149,8 +149,7 @@ If the function executed inside a __context_fn__ 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.]
[important Do not jump from inside a catch block.]
[#cc_ontop]
@@ -159,7 +158,7 @@ in another continuation.]
Sometimes it is useful to execute a new function on top of a resumed
continuation. For this purpose __resume_with__ has to be used.
The function passed as argument must accept a rvalue reference to __con__ and
return `void`.
return __con__.
namespace ctx=boost::context;
int data=0;

View File

@@ -126,9 +126,6 @@
[def __cc__ [link cc ['callcc()]]]
[def __con__ [link cc ['continuation]]]
[def __econtext__ ['execution_context]]
[def __ecv1__ [link ecv1 ['execution_context] (v1)]]
[def __ecv2__ [link ecv2 ['execution_context] (v2)]]
[def __fib__ [link ff ['fiber]]]
[def __fcontext__ ['fcontext_t]]
[def __forced_unwind__ ['detail::forced_unwind]]
@@ -166,8 +163,6 @@
[include requirements.qbk]
[include fiber.qbk]
[include callcc.qbk]
[include execution_context_v2.qbk]
[include execution_context_v1.qbk]
[include stack.qbk]
[include preallocated.qbk]
[include performance.qbk]

File diff suppressed because it is too large Load Diff

View File

@@ -1,481 +0,0 @@
[/
Copyright Oliver Kowalke 2014.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt
]
[#ecv1]
[section:ecv1 Class execution_context (version 1)]
[warning __econtext__ (v1) is deprecated (does not prevent UB).]
[note __econtext__ (v1) is the reference implementation of C++ proposal
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0099r0.pdf P099R0: A
low-level API for stackful context switching].]
[note __econtext__ (v1) resides in sub-namespace `v1`.]
[note Segmented stacks (['segmented-stacks=on]), e.g. on demand growing stacks,
can be used with __econtext__ (v1).]
Class __econtext__ encapsulates context switching and manages the associated
context' stack (allocation/deallocation).
__econtext__ allocates the context stack (using its [link stack
__stack_allocator__] argument) and creates a control structure on top of it.
This structure is responsible for managing context' stack. Instances of
__econtext__, associated with a specific context, share the ownership of the
control structure. If the last reference goes out of scope, the control
structure is destroyed and the stack gets deallocated via the
__stack_allocator__.
__econtext__ is copy-constructible, move-constructible, copy-assignable and
move-assignable.
__econtext__ maintains a static (thread-local) pointer, accessed by
__ec_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).
__econtext__ expects a function/functor with signature `void(void* vp)` (`vp`
is the data passed at the first invocation of
[operator_link ecv1 operator_call operator()]).
[heading usage of __econtext__]
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 __econtext__. The context
`sink`, returned by __ec_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).
[heading inverting the control flow]
/*
* 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 __econtext__ 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 __econtext__.
If the code executed by __econtext__ emits an exception, the application is
terminated. ['std::exception_ptr] can be used to transfer exceptions between
different execution contexts.
[heading stack unwinding]
Sometimes it is necessary to unwind the stack of an unfinished context to
destroy local stack variables so they can release allocated resources (RAII
pattern). The user is responsible for this task.
[#ecv1_prealloc]
[heading allocating control structures on top of stack]
Allocating control structures on top of the stack requires to allocated the
__stack_context__ and create the control structure with placement new before
__econtext__ 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) {
}
...
};
[heading exception handling]
If the function executed inside a __econtext__ emits ans 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.]
[heading parameter passing]
The void pointer argument passed to __ec_op__, in one context, is passed as
the last argument of the __context_fn__ if the context is started for the
first time.
In all following invocations of __ec_op__ the void pointer passed to
__ec_op__, in one context, is returned by __ec_op__ 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
[heading Class `execution_context`]
class execution_context {
public:
static execution_context current() noexcept;
template< typename Fn, typename ... Args >
execution_context( Fn && fn, Args && ... args);
template< typename StackAlloc, typename Fn, typename ... Args >
execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args);
template< typename StackAlloc, typename Fn, typename ... Args >
execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args);
execution_context( execution_context const& other) noexcept;
execution_context( execution_context && other) noexcept;
execution_context & operator=( execution_context const& other) noexcept;
execution_context & operator=( execution_context && other) noexcept;
explicit operator bool() const noexcept;
bool operator!() const noexcept;
void * operator()( void * vp = nullptr);
template< typename Fn >
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);
};
[static_member_heading ecv1..current]
static execution_context current() noexcept;
[variablelist
[[Returns:] [Returns an instance of excution_context pointing to the active
execution context.]]
[[Throws:] [Nothing.]]
]
[constructor_heading ecv1..constructor]
template< typename Fn, typename ... Args >
execution_context( Fn && fn, Args && ... args);
template< typename StackAlloc, typename Fn, typename ... Args >
execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args);
template< typename StackAlloc, typename Fn, typename ... Args >
execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args);
[variablelist
[[Effects:] [Creates a new execution context and prepares the context to execute
`fn`. `fixedsize_stack` is used as default stack allocator
(stack size == fixedsize_stack::traits::default_size()).
The constructor with argument type `preallocated`, is used to create a user
defined data [link ecv1_prealloc (for instance additional control structures)] on
top of the stack.]]
]
[copy_constructor_heading ecv1..copy constructor]
execution_context( execution_context const& other) noexcept;
[variablelist
[[Effects:] [Copies `other`, e.g. underlying control structure is shared with
`*this`.]]
[[Throws:] [Nothing.]]
]
[move_constructor_heading ecv1..move constructor]
execution_context( execution_context && other) noexcept;
[variablelist
[[Effects:] [Moves underlying control structure to `*this`.]]
[[Throws:] [Nothing.]]
]
[copy_assignment_heading ecv1..copy assignment]
execution_context & operator=( execution_context const& other) noexcept;
[variablelist
[[Effects:] [Copies the state of `other` to `*this`, control structure is
shared.]]
[[Throws:] [Nothing.]]
]
[move_assignment_heading ecv1..move assignment]
execution_context & operator=( execution_context && other) noexcept;
[variablelist
[[Effects:] [Moves the control structure of `other` to `*this` using move
semantics.]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv1..operator_bool..operator bool]
explicit operator bool() const noexcept;
[variablelist
[[Returns:] [`true` if `*this` points to a control structure.]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv1..operator_not..operator!]
bool operator!() const noexcept;
[variablelist
[[Returns:] [`true` if `*this` does not point to a control structure.]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv1..operator_call..operator()]
void * operator()( void * vp = nullptr) noexcept;
[variablelist
[[Effects:] [Stores internally the current context data (stack pointer,
instruction pointer, and CPU registers) of the current active context and
restores the context data from `*this`, which implies jumping to `*this`'s
context.
The void pointer argument, `vp`, is passed to the current context to be returned
by the most recent call to `execution_context::operator()` in the same thread.
`fn` is executed with arguments `args` on top of the stack of `this`.]]
[[Note:] [The behaviour is undefined if `operator()()` is called while
__ec_current__ returns `*this` (e.g. resuming an already running context). If
the top-level context function returns, `std::exit()` is called.]]
[[Returns:] [The void pointer argument passed to the most recent call to
__ec_op__, if any.]]
]
[operator_heading ecv1..operator_call_ontop..operator(exec_ontop_arg_t)]
template< typename Fn >
void * operator()( exec_ontop_arg_t, Fn && fn, void * vp = nullptr);
[variablelist
[[Effects:] [Same as __ec_op__. Additionally, function `fn` is executed with
arguments `vp` in the context of `*this` (e.g. the stack frame of `fn` is
allocated on stack of `*this`).]]
[[Returns:] [The void pointer argument passed to the most recent call to
__ec_op__, if any.]]
]
[operator_heading ecv1..operator_equal..operator==]
bool operator==( execution_context const& other) const noexcept;
[variablelist
[[Returns:] [`true` if `*this` and `other` represent the same execution context,
`false` otherwise.]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv1..operator_notequal..operator!=]
bool operator!=( execution_context const& other) const noexcept;
[variablelist
[[Returns:] [[`! (other == * this)]]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv1..operator_less..operator<]
bool operator<( execution_context const& other) const noexcept;
[variablelist
[[Returns:] [`true` if `*this != other` is true and the
implementation-defined total order of `execution_context` values places `*this`
before `other`, false otherwise.]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv1..operator_greater..operator>]
bool operator>( execution_context const& other) const noexcept;
[variablelist
[[Returns:] [`other < * this`]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv1..operator_lesseq..operator<=]
bool operator<=( execution_context const& other) const noexcept;
[variablelist
[[Returns:] [`! (other < * this)`]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv1..operator_greatereq..operator>=]
bool operator>=( execution_context const& other) const noexcept;
[variablelist
[[Returns:] [`! (* this < other)`]]
[[Throws:] [Nothing.]]
]
[hding ecv1_..Non-member function [`operator<<()]]
template< typename charT, class traitsT >
std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other);
[variablelist
[[Efects:] [Writes the representation of `other` to stream `os`.]]
[[Returns:] [`os`]]
]
[endsect]

View File

@@ -1,677 +0,0 @@
[/
Copyright Oliver Kowalke 2014.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt
]
[#ecv2]
[section:ecv2 Class execution_context (version 2)]
[note __econtext__ (v2) is the reference implementation of C++ proposal
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0099r1.pdf P099R1: A
low-level API for stackful context switching].]
[note __econtext__ (v2) resides in the inlined sub-namespace `v2`.]
[note Segmented stacks (['segmented-stacks=on]), e.g. on demand growing stacks,
are not supported by __econtext__ (v2).]
Class __econtext__ encapsulates context switching and manages the associated
context' stack (allocation/deallocation).
__econtext__ allocates the context stack (using its [link stack
__stack_allocator__] 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 __econtext__). In contrast to __ecv1__ the
ownership of the control structure is not shared (no member variable to control
structure in __econtext__). __econtext__ keeps internally a state that is moved
by a call of __ec_op__ (`*this` will be invalidated), e.g. after a calling
__ec_op__, `*this` can not be used for an additional context switch.
__econtext__ is only move-constructible and move-assignable.
The moved state is assigned to a new instance of __econtext__. 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 __ec_op__ that has
been called in the resumed context.
In contrast to __ecv1__, the context switch is faster because no global pointer
etc. is involved.
[important Segmented stacks are not supported by __econtext__ (v2).]
On return the context-function of the current context has to specify an
__econtext__ 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 __stack_allocator__. The stack walking makes the destruction
of __econtext__ slow and should be prevented if possible.
__econtext__ expects a __context_fn__ 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
__ec_op__ on `*this`) and `args` are the data passed to __ec_op__. The return
value represents the execution_context that has to be resumed, after termiantion
of this context.
Benefits of __ecv2__ over __ecv1__ are: faster context switch, type-safety of
passed/returned arguments.
[heading usage of __econtext__]
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 __econtext__ 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 __ec_op__, the new
state of the __econtext__, returned by __ec_op__, 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.
[heading parameter passing]
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 __ec_op__, in one context, is passed as the last
arguments of the __context_fn__ if the context is started for the first time.
In all following invocations of __ec_op__ the arguments passed to __ec_op__, in
one context, is returned by __ec_op__ 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.
[heading exception handling]
If the function executed inside a __econtext__ emits ans 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.]
[#ecv2_ontop]
[heading Executing function on top of a context]
Sometimes it is useful to execute a new function on top of a resumed context.
For this purpose __ec_op__ 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()`.
[/
Another option is to execute a function on top of the context that throws an
exception. The thrown exception is catched and re-thrown as nested exception of
__ot_error__ from __ec_op__. __ot_error__ gives access to the context that has
resumed the current context.
struct my_exception : public std::runtime_error {
my_exception( std::string const& what) :
std::runtime_error{ what } {
}
};
boost::context::execution_context<void> ctx([](boost::context::execution_context<void> && ctx) {
for (;;) {
try {
std::cout << "entered" << std::endl;
ctx = ctx();
}
} catch ( boost::context::ontop_error const& e) {
try {
std::rethrow_if_nested( e);
} catch ( my_exception const& ex) {
std::cerr << "my_exception: " << ex.what() << std::endl;
}
return e.get_context< void >();
}
}
return std::move( ctx);
});
ctx = ctx();
ctx = ctx();
ctx = ctx( boost::context::exec_ontop_arg,[](){ throw my_exception{ "abc" }; });
output:
entered
entered
my_exception: abc
In this exception `my_exception` is throw from a function invoked ontop of
context `ctx` and catched inside the `for`-loop.
[heading stack unwinding]
On construction of __econtext__ a stack is allocated.
If the __context_fn__ returns the stack will be destructed.
If the __context_fn__ has not yet returned and the destructor of an valid
__econtext__ instance (e.g. ['execution_context::operator bool()] returns
`true`) is called, the stack will be destructed too.
[important Code executed by __context_fn__ must not prevent the propagation of the
__forced_unwind__ exception. Absorbing that exception will cause stack
unwinding to fail. Thus, any code that catches all exceptions must re-throw any
pending __forced_unwind__ exception.]
[#ecv2_prealloc]
[heading allocating control structures on top of stack]
Allocating control structures on top of the stack requires to allocated the
__stack_context__ and create the control structure with placement new before
__econtext__ is created.
[note The user is responsible for destructing the control structure at the top
of the stack.]
// stack-allocator used for (de-)allocating stack
fixedsize_stack salloc(4048);
// allocate stack space
stack_context sctx(salloc.allocate());
// reserve space for control structure on top of the stack
void * sp=static_cast<char*>(sctx.sp)-sizeof(my_control_structure);
std::size_t size=sctx.size-sizeof(my_control_structure);
// placement new creates control structure on reserved space
my_control_structure * cs=new(sp)my_control_structure(sp,size,sctx,salloc);
...
// destructing the control structure
cs->~my_control_structure();
...
struct my_control_structure {
// captured context
execution_context cctx;
template< typename StackAllocator >
my_control_structure(void * sp,std::size_t size,stack_context sctx,StackAllocator salloc) :
// create captured context
cctx(std::allocator_arg,preallocated(sp,size,sctx),salloc,entry_func) {
}
...
};
[heading inverting the control flow]
/*
* grammar:
* P ---> E '\0'
* E ---> T {('+'|'-') T}
* T ---> S {('*'|'/') S}
* S ---> digit | '(' E ')'
*/
class Parser{
// implementation omitted; see examples directory
};
std::istringstream is("1+1");
bool done=false;
std::exception_ptr except;
// execute parser in new execution context
boost::context::execution_context<char> source(
[&is,&done,&except](ctx::execution_context<char> && sink,char){
// create parser with callback function
Parser p( is,
[&sink](char ch){
// resume main execution context
auto result=sink(ch);
sink=std::move(std::get<0>(result));
});
try {
// start recursive parsing
p.run();
} catch (...) {
// store other exceptions in exception-pointer
except=std::current_exception();
}
// set termination flag
done=true;
// resume main execution context
return std::move(sink);
});
// user-code pulls parsed data from parser
// invert control flow
auto result=source('\0');
source=std::move(std::get<0>(result));
char c=std::get<1>(result);
if (except) {
std::rethrow_exception(except);
}
while(!done) {
printf("Parsed: %c\n",c);
std::tie(source,c)=source('\0');
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 __econtext__ 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 __econtext__.
If the code executed by __econtext__ emits an exception, the application is
terminated. ['std::exception_ptr] can be used to transfer exceptions between
different execution contexts.
Sometimes it is necessary to unwind the stack of an unfinished context to
destroy local stack variables so they can release allocated resources (RAII
pattern). The user is responsible for this task.
[heading Class `execution_context`]
struct exec_ontop_arg_t {};
const exec_ontop_arg_t exec_ontop_arg{};
class ontop_error {
public:
template< typename ... Args >
execution_context< Args ... > get_context() const noexcept;
}
template< typename ... Args >
class execution_context {
public:
template< typename Fn, typename ... Params >
execution_context( Fn && fn, Params && ... params);
template< typename StackAlloc, typename Fn, typename ... Params >
execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Params && ... params);
template< typename StackAlloc, typename Fn, typename ... Params >
execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Params && ... params);
template< typename Fn, typename ... Params >
execution_context( std::allocator_arg_t, segemented_stack, Fn && fn, Params && ... params) = delete;
template< typename Fn, typename ... Params >
execution_context( std::allocator_arg_t, preallocated palloc, segmented, Fn && fn, Params && ... params)= delete;
~execution_context();
execution_context( execution_context && other) noexcept;
execution_context & operator=( execution_context && other) noexcept;
execution_context( execution_context const& other) noexcept = delete;
execution_context & operator=( execution_context const& other) noexcept = delete;
explicit operator bool() const noexcept;
bool operator!() const noexcept;
std::tuple< execution_context, Args ... > operator()( Args ... args);
template< typename Fn >
std::tuple< execution_context, Args ... > operator()( exec_ontop_arg_t, Fn && fn, Args ... args);
bool operator==( execution_context const& other) const noexcept;
bool operator!=( execution_context const& other) const noexcept;
bool operator<( execution_context const& other) const noexcept;
bool operator>( execution_context const& other) const noexcept;
bool operator<=( execution_context const& other) const noexcept;
bool operator>=( execution_context const& other) const noexcept;
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other);
};
[constructor_heading ecv2..constructor]
template< typename Fn, typename ... Params >
execution_context( Fn && fn, Params && ... params);
template< typename StackAlloc, typename Fn, typename ... Params >
execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Params && ... params);
template< typename StackAlloc, typename Fn, typename ... Params >
execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Params && ... params);
[variablelist
[[Effects:] [Creates a new execution context and prepares the context to execute
`fn`. `fixedsize_stack` is used as default stack allocator
(stack size == fixedsize_stack::traits::default_size()).
The constructor with argument type `preallocated`, is used to create a user
defined data [link ecv2_prealloc (for instance additional control structures)] on
top of the stack.]]
]
]
[destructor_heading ecv2..destructor destructor]
~execution_context();
[variablelist
[[Effects:] [Destructs the associated stack if `*this` is a valid context,
e.g. ['execution_context::operator bool()] returns `true`.]]
[[Throws:] [Nothing.]]
]
[move_constructor_heading ecv2..move constructor]
execution_context( execution_context && other) noexcept;
[variablelist
[[Effects:] [Moves underlying capture record to `*this`.]]
[[Throws:] [Nothing.]]
]
[move_assignment_heading ecv2..move assignment]
execution_context & operator=( execution_context && other) noexcept;
[variablelist
[[Effects:] [Moves the state of `other` to `*this` using move semantics.]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv2..operator_bool..operator bool]
explicit operator bool() const noexcept;
[variablelist
[[Returns:] [`true` if `*this` points to a capture record.]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv2..operator_not..operator!]
bool operator!() const noexcept;
[variablelist
[[Returns:] [`true` if `*this` does not point to a capture record.]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv2..operator_call..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 >
[variablelist
[[Effects:] [Stores internally the current context data (stack pointer,
instruction pointer, and CPU registers) of the current active context and
restores the context data from `*this`, which implies jumping to `*this`'s
context.
The arguments, `... args`, are passed to the current context to be returned
by the most recent call to `execution_context::operator()` in the same thread.]]
[[Returns:] [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.]]
[[Note:] [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_heading ecv2..operator_call_ontop..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 >
[variablelist
[[Effects:] [Same as __ec_op__. Additionally, function `fn` is executed
in the context of `*this` (e.g. the stack frame of `fn` is allocated on
stack of `*this`).]]
[[Returns:] [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 .]]
[[Note:] [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.]]
[[Note:] [Function `fn` needs to return a tuple of arguments
([link ecv2_ontop see description]).]]
[[Note:] [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.]]
[[Note:] [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_heading ecv2..operator_equal..operator==]
bool operator==( execution_context const& other) const noexcept;
[variablelist
[[Returns:] [`true` if `*this` and `other` represent the same execution context,
`false` otherwise.]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv2..operator_notequal..operator!=]
bool operator!=( execution_context const& other) const noexcept;
[variablelist
[[Returns:] [[`! (other == * this)]]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv2..operator_less..operator<]
bool operator<( execution_context const& other) const noexcept;
[variablelist
[[Returns:] [`true` if `*this != other` is true and the
implementation-defined total order of `execution_context` values places `*this`
before `other`, false otherwise.]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv2..operator_greater..operator>]
bool operator>( execution_context const& other) const noexcept;
[variablelist
[[Returns:] [`other < * this`]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv2..operator_lesseq..operator<=]
bool operator<=( execution_context const& other) const noexcept;
[variablelist
[[Returns:] [`! (other < * this)`]]
[[Throws:] [Nothing.]]
]
[operator_heading ecv2..operator_greatereq..operator>=]
bool operator>=( execution_context const& other) const noexcept;
[variablelist
[[Returns:] [`! (* this < other)`]]
[[Throws:] [Nothing.]]
]
[hding ecv2_..Non-member function [`operator<<()]]
template< typename charT, class traitsT >
std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other);
[variablelist
[[Efects:] [Writes the representation of `other` to stream `os`.]]
[[Returns:] [`os`]]
]
[endsect]

View File

@@ -132,12 +132,11 @@ of `f1.resume()`, the variable `i` has the value of `i+1`.
[heading Exception handling]
If the function executed inside a __context_fn__ emits ans exception, the
If the function executed inside a __context_fn__ 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.]
[important Do not jump from inside a catch block.]
[#ff_ontop]
@@ -146,7 +145,7 @@ in another fiber.]
Sometimes it is useful to execute a new function on top of a resumed fiber. For
this purpose __resume_with__ has to be used.
The function passed as argument must accept a rvalue reference to __fib__ and
return `void`.
return __fib__.
namespace ctx=boost::context;
int data=0;
@@ -166,7 +165,7 @@ return `void`.
f1=std::move(f1).resume();
std::cout << "f1: returned second time: " << data << std::endl;
data+=1;
f1=f1.resume_with([&data](ctx::fiber&& f2){
f1=std::move(f1).resume_with([&data](ctx::fiber&& f2){
std::cout << "f2: entered: " << data << std::endl;
data=-1;
return std::move(f2);
@@ -372,7 +371,7 @@ of the stack.]
source=std::move(source).resume();
while(!done){
printf("Parsed: %c\n",c);
source=std::Move(source).resume();
source=std::move(source).resume();
}
output:

View File

@@ -232,6 +232,60 @@
</td>
</tr>
<tr>
<td>
<p>
riscv64
</p>
</td>
<td>
<p>
SYSV|ELF
</p>
</td>
<td>
<p>
-
</p>
</td>
<td>
<p>
SYSV
</p>
</td>
<td>
<p>
-
</p>
</td>
</tr>
<tr>
<td>
<p>
s390x
</p>
</td>
<td>
<p>
SYSV|ELF
</p>
</td>
<td>
<p>
-
</p>
</td>
<td>
<p>
-
</p>
</td>
<td>
<p>
-
</p>
</td>
</tr>
<tr>
<td>
<p>
sparc

View File

@@ -221,7 +221,7 @@
</h4>
<p>
If the function executed inside a <span class="emphasis"><em>context-function</em></span> emits
ans exception, the application is terminated by calling <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">terminate</span><span class="special">()</span></code>. <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception_ptr</span></code>
an exception, the application is terminated by calling <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">terminate</span><span class="special">()</span></code>. <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception_ptr</span></code>
can be used to transfer exceptions between different continuations.
</p>
<div class="important"><table border="0" summary="Important">

View File

@@ -7,7 +7,7 @@
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Context">
<link rel="up" href="../cc.html" title="Context switching with call/cc">
<link rel="prev" href="implementations__fcontext_t__ucontext_t_and_winfiber.html" title="Implementations: fcontext_t, ucontext_t and WinFiber">
<link rel="next" href="../ecv2.html" title="Class execution_context (version 2)">
<link rel="next" href="../stack.html" title="Stack allocation">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
@@ -20,7 +20,7 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="implementations__fcontext_t__ucontext_t_and_winfiber.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../cc.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../ecv2.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="implementations__fcontext_t__ucontext_t_and_winfiber.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../cc.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../stack.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
@@ -501,7 +501,7 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="implementations__fcontext_t__ucontext_t_and_winfiber.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../cc.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../ecv2.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="implementations__fcontext_t__ucontext_t_and_winfiber.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../cc.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../stack.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -280,7 +280,7 @@
</h4>
<p>
If the function executed inside a <span class="emphasis"><em>execution_context</em></span> emits
ans exception, the application is terminated by calling <span class="emphasis"><em>std::terminate()</em></span>.
an exception, the application is terminated by calling <span class="emphasis"><em>std::terminate()</em></span>.
<span class="emphasis"><em>std::exception_ptr</em></span> can be used to transfer exceptions
between different execution contexts.
</p>

View File

@@ -313,7 +313,7 @@
</h4>
<p>
If the function executed inside a <span class="emphasis"><em>execution_context</em></span> emits
ans exception, the application is terminated by calling <span class="emphasis"><em>std::terminate()</em></span>.
an exception, the application is terminated by calling <span class="emphasis"><em>std::terminate()</em></span>.
<span class="emphasis"><em>std::exception_ptr</em></span> can be used to transfer exceptions
between different execution contexts.
</p>

View File

@@ -209,7 +209,7 @@
</h4>
<p>
If the function executed inside a <span class="emphasis"><em>context-function</em></span> emits
ans exception, the application is terminated by calling <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">terminate</span><span class="special">()</span></code>. <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception_ptr</span></code>
an exception, the application is terminated by calling <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">terminate</span><span class="special">()</span></code>. <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception_ptr</span></code>
can be used to transfer exceptions between different fibers.
</p>
<div class="important"><table border="0" summary="Important">

View File

@@ -199,7 +199,7 @@
</h4>
<p>
If the function executed inside a <span class="emphasis"><em>context-function</em></span> emits
ans exception, the application is terminated by calling <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">terminate</span><span class="special">()</span></code>. <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception_ptr</span></code>
an exception, the application is terminated by calling <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">terminate</span><span class="special">()</span></code>. <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception_ptr</span></code>
can be used to transfer exceptions between different fibers.
</p>
<div class="important"><table border="0" summary="Important">

View File

@@ -55,16 +55,6 @@
requires only few CPU cycles because it does not involve system calls as it
is done within a single thread.
</p>
<p>
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:
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">context</span><span class="special">/</span><span class="identifier">all</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
</pre>
<p>
which includes all the other headers in turn.
</p>
<p>
All functions and classes are contained in the namespace <span class="emphasis"><em>boost::context</em></span>.
</p>
@@ -83,10 +73,10 @@
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
Windows: 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).
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).
</p></td></tr>
</table></div>
</div>

View File

@@ -71,8 +71,8 @@
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
Windows: for safe SEH the property 'asmflags=\safeseh' must be specified
at bjam command line.
Windows using fcontext_t: for safe SEH the property 'asmflags=\safeseh' must
be specified at bjam command line.
</p></td></tr>
</table></div>
<div class="important"><table border="0" summary="Important">
@@ -81,12 +81,20 @@
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
Windows: 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).
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).
</p></td></tr>
</table></div>
<p>
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.
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>

View File

@@ -6,7 +6,7 @@
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Context">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Context">
<link rel="prev" href="ecv1.html" title="Class execution_context (version 1)">
<link rel="prev" href="cc/class__continuation_.html" title="Class continuation">
<link rel="next" href="stack/protected_fixedsize.html" title="Class protected_fixedsize">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
@@ -20,7 +20,7 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="ecv1.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="stack/protected_fixedsize.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="cc/class__continuation_.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="stack/protected_fixedsize.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
@@ -35,6 +35,7 @@
<dt><span class="section"><a href="stack/stack_traits.html">Class <span class="emphasis"><em>stack_traits</em></span></a></span></dt>
<dt><span class="section"><a href="stack/stack_context.html">Class <span class="emphasis"><em>stack_context</em></span></a></span></dt>
<dt><span class="section"><a href="stack/valgrind.html">Support for valgrind</a></span></dt>
<dt><span class="section"><a href="stack/sanitizers.html">Support for sanitizers</a></span></dt>
</dl></div>
<p>
The memory used by the stack is allocated/deallocated via a <span class="emphasis"><em>StackAllocator</em></span>
@@ -154,15 +155,6 @@
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
The stack is not required to be aligned; alignment takes place inside <span class="emphasis"><em>execution_context</em></span>.
</p></td></tr>
</table></div>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
Depending on the architecture <code class="computeroutput"><span class="identifier">allocate</span><span class="special">()</span></code> stores an address from the top of the stack
(growing downwards) or the bottom of the stack (growing upwards).
@@ -179,7 +171,7 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="ecv1.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="stack/protected_fixedsize.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="cc/class__continuation_.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="stack/protected_fixedsize.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,49 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Support for sanitizers</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Context">
<link rel="up" href="../stack.html" title="Stack allocation">
<link rel="prev" href="valgrind.html" title="Support for valgrind">
<link rel="next" href="../struct__preallocated_.html" title="Struct preallocated">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="valgrind.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../struct__preallocated_.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="context.stack.sanitizers"></a><a class="link" href="sanitizers.html" title="Support for sanitizers">Support for sanitizers</a>
</h3></div></div></div>
<p>
Sanitizers (GCC/Clang) are confused by the stack switches. The library is
required to be compiled with property (b2 command-line) <code class="computeroutput"><span class="identifier">context</span><span class="special">-</span><span class="identifier">impl</span><span class="special">=</span><span class="identifier">ucontext</span></code> and compilers santizer options.
Users must define <code class="computeroutput"><span class="identifier">BOOST_USE_ASAN</span></code>
before including any Boost.Context headers when linking against Boost binaries.
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2014 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="valgrind.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../struct__preallocated_.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -59,7 +59,6 @@
<tr><td align="left" valign="top"><p>
Segmented stacks can only be used with <a class="link" href="../cc.html#cc"><span class="emphasis"><em>callcc()</em></span></a>
(using <a class="link" href="../ff/implementations__fcontext_t__ucontext_t_and_winfiber.html#implementation"><span class="emphasis"><em>ucontext_t</em></span></a>)
and <span class="emphasis"><em>execution_context</em></span> (v1)
</p></td></tr>
</table></div>
<p>

View File

@@ -7,7 +7,7 @@
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Context">
<link rel="up" href="../stack.html" title="Stack allocation">
<link rel="prev" href="stack_context.html" title="Class stack_context">
<link rel="next" href="../struct__preallocated_.html" title="Struct preallocated">
<link rel="next" href="sanitizers.html" title="Support for sanitizers">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
@@ -20,7 +20,7 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="stack_context.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../struct__preallocated_.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="stack_context.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="sanitizers.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
@@ -45,7 +45,7 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="stack_context.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../struct__preallocated_.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="stack_context.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stack.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="sanitizers.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -6,7 +6,7 @@
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Context">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Context">
<link rel="prev" href="stack/valgrind.html" title="Support for valgrind">
<link rel="prev" href="stack/sanitizers.html" title="Support for sanitizers">
<link rel="next" href="performance.html" title="Performance">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
@@ -20,7 +20,7 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="stack/valgrind.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="performance.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="stack/sanitizers.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="performance.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
@@ -60,7 +60,7 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="stack/valgrind.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="performance.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="stack/sanitizers.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="performance.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -7,8 +7,6 @@ context/ff/class__fiber_.html
context/cc.html
context/cc/implementations__fcontext_t__ucontext_t_and_winfiber.html
context/cc/class__continuation_.html
context/ecv2.html
context/ecv1.html
context/stack.html
context/stack/protected_fixedsize.html
context/stack/pooled_fixedsize.html
@@ -17,6 +15,7 @@ context/stack/segmented.html
context/stack/stack_traits.html
context/stack/stack_context.html
context/stack/valgrind.html
context/stack/sanitizers.html
context/struct__preallocated_.html
context/performance.html
context/architectures.html

View File

@@ -50,10 +50,6 @@
fcontext_t, ucontext_t and WinFiber</a></span></dt>
<dt><span class="section"><a href="context/cc/class__continuation_.html">Class <code class="computeroutput"><span class="identifier">continuation</span></code></a></span></dt>
</dl></dd>
<dt><span class="section"><a href="context/ecv2.html">Class execution_context
(version 2)</a></span></dt>
<dt><span class="section"><a href="context/ecv1.html">Class execution_context
(version 1)</a></span></dt>
<dt><span class="section"><a href="context/stack.html">Stack allocation</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="context/stack/protected_fixedsize.html">Class <span class="emphasis"><em>protected_fixedsize</em></span></a></span></dt>
@@ -64,6 +60,7 @@
<dt><span class="section"><a href="context/stack/stack_traits.html">Class <span class="emphasis"><em>stack_traits</em></span></a></span></dt>
<dt><span class="section"><a href="context/stack/stack_context.html">Class <span class="emphasis"><em>stack_context</em></span></a></span></dt>
<dt><span class="section"><a href="context/stack/valgrind.html">Support for valgrind</a></span></dt>
<dt><span class="section"><a href="context/stack/sanitizers.html">Support for sanitizers</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="context/struct__preallocated_.html">Struct <code class="computeroutput"><span class="identifier">preallocated</span></code></a></span></dt>
<dt><span class="section"><a href="context/performance.html">Performance</a></span></dt>
@@ -81,7 +78,7 @@
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"><p><small>Last revised: February 15, 2018 at 16:18:36 GMT</small></p></td>
<td align="left"><p><small>Last revised: October 02, 2019 at 06:15:46 GMT</small></p></td>
<td align="right"><div class="copyright-footer"></div></td>
</tr></table>
<hr>

View File

@@ -43,9 +43,6 @@ undefined behaviour.]
[important Calling `deallocate()` with a `stack_context` not set by `allocate()`
results in undefined behaviour.]
[note The stack is not required to be aligned; alignment takes place inside
__econtext__.]
[note Depending on the architecture `allocate()` stores an address from the
top of the stack (growing downwards) or the bottom of the stack (growing
upwards).]
@@ -216,7 +213,7 @@ property `segmented-stacks`, e.g. [*toolset=gcc segmented-stacks=on] and
applying `BOOST_USE_SEGMENTED_STACKS` at b2/bjam command line.]
[note Segmented stacks can only be used with __cc__ (using
[link implementation __ucontext__]) and __econtext__ (v1)].
[link implementation __ucontext__])].
#include <boost/context/segmented_stack.hpp>
@@ -356,4 +353,15 @@ compiled with `valgrind=on`.
[endsect]
[section:sanitizers Support for sanitizers]
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 santizer options.
Users must define `BOOST_USE_ASAN` before including any Boost.Context headers
when linking against Boost binaries.
[endsect]
[endsect]

View File

@@ -18,8 +18,8 @@ import architecture ;
project boost/context/example/callcc
: requirements
<library>/boost/context//boost_context
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<target-os>linux,<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<target-os>linux,<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>static

View File

@@ -1,44 +0,0 @@
// Copyright Oliver Kowalke 2016.
// 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)
#include <cstdlib>
#include <iostream>
#include <list>
#include <boost/context/fiber.hpp>
namespace ctx = boost::context;
int main() {
ctx::fiber f1, f2, f3;
f3 = ctx::fiber{[&](ctx::fiber && f)->ctx::fiber{
f2 = std::move( f);
for (;;) {
std::cout << "f3\n";
f2 = f1.resume();
}
return {};
}};
f2 = ctx::fiber{[&](ctx::fiber && f)->ctx::fiber{
f1 = std::move( f);
for (;;) {
std::cout << "f2\n";
f1 = f3.resume();
}
return {};
}};
f1 = ctx::fiber{[&](ctx::fiber && /*main*/)->ctx::fiber{
for (;;) {
std::cout << "f1\n";
f3 = f2.resume();
}
return {};
}};
f1.resume();
std::cout << "main: done" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -38,7 +38,7 @@ int main() {
c = c.resume_with(
[](ctx::continuation && c){
throw my_exception(std::move( c), "abc");
return std::move( c);
return {};
});
std::cout << "main: done" << std::endl;

View File

@@ -1,68 +0,0 @@
# Boost.Context Library Examples Jamfile
# Copyright Oliver Kowalke 2014.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
# For more information, see http://www.boost.org/
import common ;
import feature ;
import indirect ;
import modules ;
import os ;
import toolset ;
import architecture ;
project boost/context/example/execution_context_v2
: requirements
<library>/boost/context//boost_context
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>static
<threading>multi
;
exe jump_void
: jump_void.cpp
;
exe jump
: jump.cpp
;
exe fibonacci
: fibonacci.cpp
;
exe parser
: parser.cpp
;
exe parameter
: parameter.cpp
;
exe ontop_void
: ontop_void.cpp
;
exe ontop
: ontop.cpp
;
exe throw
: throw.cpp
;
exe echosse
: echosse.cpp
;
#exe backtrace
# : backtrace.cpp
# : <linkflags>"-lunwind"
# ;

View File

@@ -1,58 +0,0 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#define UNW_LOCAL_ONLY
#include <cstdlib>
#include <iostream>
#include <libunwind.h>
#include <boost/context/execution_context.hpp>
namespace ctx = boost::context;
void backtrace() {
unw_cursor_t cursor;
unw_context_t context;
unw_getcontext( & context);
unw_init_local( & cursor, & context);
while ( 0 < unw_step( & cursor) ) {
unw_word_t offset, pc;
unw_get_reg( & cursor, UNW_REG_IP, & pc);
if ( 0 == pc) {
break;
}
std::cout << "0x" << pc << ":";
char sym[256];
if ( 0 == unw_get_proc_name( & cursor, sym, sizeof( sym), & offset) ) {
std::cout << " (" << sym << "+0x" << offset << ")" << std::endl;
} else {
std::cout << " -- error: unable to obtain symbol name for this frame" << std::endl;
}
}
}
void bar() {
backtrace();
}
void foo() {
bar();
}
ctx::execution_context< void > f1( ctx::execution_context< void > && ctxm) {
foo();
return std::move( ctxm);
}
int main() {
ctx::execution_context< void > ctx1( f1);
ctx1 = ctx1();
std::cout << "main: done" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -1,45 +0,0 @@
// Copyright Oliver Kowalke 2009.
// 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)
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <emmintrin.h>
#include <boost/context/execution_context.hpp>
namespace ctx = boost::context;
void echoSSE( int i) {
__m128i xmm;
xmm = _mm_set_epi32( i, i + 1, i + 2, i + 3);
uint32_t v32[4];
memcpy( & v32, & xmm, 16);
std::cout << v32[0];
std::cout << v32[1];
std::cout << v32[2];
std::cout << v32[3];
}
ctx::execution_context< int > echo( ctx::execution_context< int > && ctx, int i) {
for (;;) {
std::cout << i;
echoSSE( i);
std::cout << " ";
std::tie( ctx, i) = ctx( 0);
}
return std::move( ctx);
}
int main( int argc, char * argv[]) {
ctx::execution_context< int > ctx( echo);
for ( int i = 0; i < 10; ++i) {
ctx = std::get< 0 >( ctx( i) );
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -1,38 +0,0 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <cstdlib>
#include <iostream>
#include <memory>
#include <boost/context/execution_context.hpp>
namespace ctx = boost::context;
int main() {
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)<<" ";
}
std::cout<<std::endl;
std::cout << "main: done" << std::endl;
}

View File

@@ -1,32 +0,0 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <cstdlib>
#include <iostream>
#include <boost/context/execution_context.hpp>
namespace ctx = boost::context;
ctx::execution_context< int > f1( ctx::execution_context< int > && ctxm, int data) {
std::cout << "f1: entered first time: " << data << std::endl;
std::tie( ctxm, data) = ctxm( data + 2);
std::cout << "f1: entered second time: " << data << std::endl;
return std::move( ctxm);
}
int main() {
int data = 1;
ctx::execution_context< int > ctx1( f1);
std::tie( ctx1, data) = ctx1( data + 2);
std::cout << "f1: returned first time: " << data << std::endl;
std::tie( ctx1, data) = ctx1( data + 2);
std::cout << "f1: returned second time: " << data << std::endl;
std::cout << "main: done" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -1,31 +0,0 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <cstdlib>
#include <iostream>
#include <boost/context/execution_context.hpp>
namespace ctx = boost::context;
ctx::execution_context< void > f1( ctx::execution_context< void > && ctxm) {
std::cout << "f1: entered first time" << std::endl;
ctxm = ctxm();
std::cout << "f1: entered second time" << std::endl;
return std::move( ctxm);
}
int main() {
ctx::execution_context< void > ctx1( f1);
ctx1 = ctx1();
std::cout << "f1: returned first time" << std::endl;
ctx1 = ctx1();
std::cout << "f1: returned second time" << std::endl;
std::cout << "main: done" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -1,42 +0,0 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <cstdlib>
#include <iostream>
#include <tuple>
#include <boost/context/execution_context.hpp>
namespace ctx = boost::context;
ctx::execution_context< int > f1( ctx::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 main() {
int data = 0;
ctx::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);
std::cout << "f1: returned third time" << std::endl;
std::cout << "main: done" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -1,40 +0,0 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <cstdlib>
#include <iostream>
#include <tuple>
#include <boost/context/execution_context.hpp>
namespace ctx = boost::context;
ctx::execution_context< void > f1( ctx::execution_context< void > && ctx) {
std::cout << "f1: entered first time" << std::endl;
ctx = ctx();
std::cout << "f1: entered second time" << std::endl;
ctx = ctx();
std::cout << "f1: entered third time" << std::endl;
return std::move( ctx);
}
void f2() {
std::cout << "f2: entered" << std::endl;
}
int main() {
ctx::execution_context< void > ctx( f1);
ctx = ctx();
std::cout << "f1: returned first time" << std::endl;
ctx = ctx();
std::cout << "f1: returned second time" << std::endl;
ctx = ctx( ctx::exec_ontop_arg, f2);
std::cout << "f1: returned third time" << std::endl;
std::cout << "main: done" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -1,62 +0,0 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <cstdlib>
#include <exception>
#include <iostream>
#include <memory>
#include <string>
#include <boost/variant.hpp>
#include <boost/context/execution_context.hpp>
#include <boost/lexical_cast.hpp>
typedef boost::variant<int,std::string> variant_t;
namespace ctx = boost::context;
class X{
private:
std::exception_ptr excptr_;
ctx::execution_context<variant_t> ctx_;
public:
X():
excptr_(),
ctx_(
[this](ctx::execution_context<variant_t> && ctx, variant_t 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){
variant_t 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);
}
};
int main() {
X x;
std::cout<<x(7)<<std::endl;
std::cout << "done" << std::endl;
}

View File

@@ -1,144 +0,0 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <cstdlib>
#include <exception>
#include <functional>
#include <iostream>
#include <memory>
#include <sstream>
#include <boost/context/execution_context.hpp>
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");
}
}
};
int main() {
try {
std::istringstream is("1+1");
bool done=false;
std::exception_ptr except;
// execute parser in new execution context
ctx::execution_context<char> source(
[&is,&done,&except](ctx::execution_context<char> && sink,char){
// create parser with callback function
Parser p( is,
[&sink](char ch){
// resume main execution context
auto result = sink(ch);
sink = std::move(std::get<0>(result));
});
try {
// start recursive parsing
p.run();
} catch (...) {
// store other exceptions in exception-pointer
except = std::current_exception();
}
// set termination flag
done=true;
// resume main execution context
return std::move( sink);
});
// user-code pulls parsed data from parser
// invert control flow
auto result = source('\0');
source = std::move(std::get<0>(result));
char c = std::get<1>(result);
if ( except) {
std::rethrow_exception(except);
}
while( ! done) {
printf("Parsed: %c\n",c);
std::tie(source,c) = source('\0');
if (except) {
std::rethrow_exception(except);
}
}
std::cout << "main: done" << std::endl;
return EXIT_SUCCESS;
} catch ( std::exception const& e) {
std::cerr << "exception: " << e.what() << std::endl;
}
return EXIT_FAILURE;
}

View File

@@ -1,47 +0,0 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <cstdlib>
#include <exception>
#include <iostream>
#include <stdexcept>
#include <string>
#include <boost/context/execution_context.hpp>
namespace ctx = boost::context;
struct my_exception : public std::runtime_error {
my_exception( std::string const& what) :
std::runtime_error{ what } {
}
};
int main() {
ctx::execution_context< void > ctx([](ctx::execution_context<void> && ctx) {
for (;;) {
try {
std::cout << "entered" << std::endl;
ctx = ctx();
} catch ( ctx::ontop_error const& e) {
try {
std::rethrow_if_nested( e);
} catch ( my_exception const& ex) {
std::cerr << "my_exception: " << ex.what() << std::endl;
}
return e.get_context< void >();
}
}
return std::move( ctx);
});
ctx = ctx();
ctx = ctx();
ctx = ctx( ctx::exec_ontop_arg, []() { throw my_exception("abc"); });
std::cout << "main: done" << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -18,8 +18,8 @@ import architecture ;
project boost/context/example/fiber
: requirements
<library>/boost/context//boost_context
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<target-os>linux,<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<target-os>linux,<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>static

View File

@@ -80,9 +80,6 @@ void context_entry( transfer_t t) noexcept {
t.fctx = rec->run( t.fctx);
} catch ( forced_unwind const& ex) {
t = { ex.fctx, nullptr };
#ifndef BOOST_ASSERT_IS_VOID
const_cast< forced_unwind & >( ex).caught = true;
#endif
}
BOOST_ASSERT( nullptr != t.fctx);
// destroy context-stack of `this`context on next context

View File

@@ -210,19 +210,10 @@ struct BOOST_CONTEXT_DECL activation_record_initializer {
struct forced_unwind {
activation_record * from{ nullptr };
#ifndef BOOST_ASSERT_IS_VOID
bool caught{ false };
#endif
forced_unwind( activation_record * from_) noexcept :
from{ from_ } {
}
#ifndef BOOST_ASSERT_IS_VOID
~forced_unwind() {
BOOST_ASSERT( caught);
}
#endif
};
template< typename Ctx, typename StackAlloc, typename Fn >
@@ -268,9 +259,6 @@ public:
#endif
} catch ( forced_unwind const& ex) {
c = Ctx{ ex.from };
#ifndef BOOST_ASSERT_IS_VOID
const_cast< forced_unwind & >( ex).caught = true;
#endif
}
// this context has finished its task
from = nullptr;
@@ -299,6 +287,8 @@ static activation_record * create_context1( StackAlloc && salloc, Fn && fn) {
reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) );
// create user-context
if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) {
record->~capture_t();
salloc.deallocate( sctx);
throw std::system_error(
std::error_code( errno, std::system_category() ),
"getcontext() failed");
@@ -332,6 +322,8 @@ static activation_record * create_context2( preallocated palloc, StackAlloc && s
reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) );
// create user-context
if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) {
record->~capture_t();
salloc.deallocate( palloc.sctx);
throw std::system_error(
std::error_code( errno, std::system_category() ),
"getcontext() failed");
@@ -461,6 +453,8 @@ public:
return ptr_ < other.ptr_;
}
#if !defined(BOOST_EMBTC)
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other) {
@@ -471,11 +465,33 @@ public:
}
}
#else
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other);
#endif
void swap( continuation & other) noexcept {
std::swap( ptr_, other.ptr_);
}
};
#if defined(BOOST_EMBTC)
template< typename charT, class traitsT >
inline std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other) {
if ( nullptr != other.ptr_) {
return os << other.ptr_;
} else {
return os << "{not-a-context}";
}
}
#endif
template<
typename Fn,
typename = detail::disable_overload< continuation, Fn >

View File

@@ -186,19 +186,10 @@ struct BOOST_CONTEXT_DECL activation_record_initializer {
struct forced_unwind {
activation_record * from{ nullptr };
#ifndef BOOST_ASSERT_IS_VOID
bool caught{ false };
#endif
explicit forced_unwind( activation_record * from_) :
from{ from_ } {
}
#ifndef BOOST_ASSERT_IS_VOID
~forced_unwind() {
BOOST_ASSERT( caught);
}
#endif
};
template< typename Ctx, typename StackAlloc, typename Fn >
@@ -239,9 +230,6 @@ public:
#endif
} catch ( forced_unwind const& ex) {
c = Ctx{ ex.from };
#ifndef BOOST_ASSERT_IS_VOID
const_cast< forced_unwind & >( ex).caught = true;
#endif
}
// this context has finished its task
from = nullptr;
@@ -399,7 +387,9 @@ public:
bool operator<( continuation const& other) const noexcept {
return ptr_ < other.ptr_;
}
#if !defined(BOOST_EMBTC)
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other) {
@@ -410,11 +400,33 @@ public:
}
}
#else
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other);
#endif
void swap( continuation & other) noexcept {
std::swap( ptr_, other.ptr_);
}
};
#if defined(BOOST_EMBTC)
template< typename charT, class traitsT >
inline std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other) {
if ( nullptr != other.ptr_) {
return os << other.ptr_;
} else {
return os << "{not-a-context}";
}
}
#endif
template<
typename Fn,
typename = detail::disable_overload< continuation, Fn >

View File

@@ -30,6 +30,10 @@
# define BOOST_CONTEXT_DECL
#endif
#if ! defined(BOOST_USE_UCONTEXT) && defined(__CYGWIN__)
# define BOOST_USE_UCONTEXT
#endif
#if ! defined(BOOST_CONTEXT_SOURCE) && ! defined(BOOST_ALL_NO_LIB) && ! defined(BOOST_CONTEXT_NO_LIB)
# define BOOST_LIB_NAME boost_context
# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTEXT_DYN_LINK)
@@ -115,4 +119,18 @@ static constexpr std::size_t cacheline_length{ 64 };
static constexpr std::size_t prefetch_stride{ 4 * cacheline_length };
#endif
#if defined(__GLIBCPP__) || defined(__GLIBCXX__)
// GNU libstdc++ 3
# define BOOST_CONTEXT_HAS_CXXABI_H
#endif
#if defined( BOOST_CONTEXT_HAS_CXXABI_H )
# include <cxxabi.h>
#endif
#if defined(__OpenBSD__)
// stacks need mmap(2) with MAP_STACK
# define BOOST_CONTEXT_USE_MAP_STACK
#endif
#endif // BOOST_CONTEXT_DETAIL_CONFIG_H

View File

@@ -22,21 +22,12 @@ namespace detail {
struct forced_unwind {
fcontext_t fctx{ nullptr };
#ifndef BOOST_ASSERT_IS_VOID
bool caught{ false };
#endif
forced_unwind() = default;
forced_unwind( fcontext_t fctx_) :
fctx( fctx_) {
}
#ifndef BOOST_ASSERT_IS_VOID
~forced_unwind() {
BOOST_ASSERT( caught);
}
#endif
};
}}}

View File

@@ -13,6 +13,10 @@
#include <boost/context/detail/config.hpp>
#if defined(BOOST_CONTEXT_NO_CXX14_INTEGER_SEQUENCE)
#include <boost/mp11/integer_sequence.hpp>
#endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
@@ -29,38 +33,12 @@ using make_index_sequence = std::make_index_sequence< I >;
template< typename ... T >
using index_sequence_for = std::index_sequence_for< T ... >;
#else
//http://stackoverflow.com/questions/17424477/implementation-c14-make-integer-sequence
template< std::size_t ... I >
struct index_sequence {
using type = index_sequence;
using value_type = std::size_t;
static constexpr std::size_t size() {
return sizeof ... (I);
}
};
template< typename Seq1, typename Seq2 >
struct concat_sequence;
template< std::size_t ... I1, std::size_t ... I2 >
struct concat_sequence< index_sequence< I1 ... >, index_sequence< I2 ... > > : public index_sequence< I1 ..., (sizeof ... (I1)+I2) ... > {
};
using index_sequence = mp11::index_sequence< I ... >;
template< std::size_t I >
struct make_index_sequence : public concat_sequence< typename make_index_sequence< I/2 >::type,
typename make_index_sequence< I-I/2 >::type > {
};
template<>
struct make_index_sequence< 0 > : public index_sequence<> {
};
template<>
struct make_index_sequence< 1 > : public index_sequence< 0 > {
};
using make_index_sequence = mp11::make_index_sequence< I >;
template< typename ... T >
using index_sequence_for = make_index_sequence< sizeof ... (T) >;
using index_sequence_for = mp11::index_sequence_for< T ... >;
#endif
}}}

View File

@@ -18,7 +18,7 @@
#include <immintrin.h>
#endif
#if BOOST_COMP_MSVC
#if BOOST_COMP_MSVC && !defined(_M_ARM) && !defined(_M_ARM64)
#include <mmintrin.h>
#endif
@@ -44,7 +44,7 @@ void prefetch( void * addr) {
// L1 cache : hint == _MM_HINT_T0
_mm_prefetch( (const char *)addr, _MM_HINT_T0);
}
#elif BOOST_COMP_MSVC
#elif BOOST_COMP_MSVC && !defined(_M_ARM) && !defined(_M_ARM64)
#define BOOST_HAS_PREFETCH 1
BOOST_FORCEINLINE
void prefetch( void * addr) {

View File

@@ -1,12 +0,0 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/context/detail/config.hpp>
#if !defined(BOOST_NO_CXX11_THREAD_LOCAL)
# include <boost/context/execution_context_v1.hpp>
#endif
#include <boost/context/execution_context_v2.hpp>

View File

@@ -1,473 +0,0 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_EXECUTION_CONTEXT_V1_H
#define BOOST_CONTEXT_EXECUTION_CONTEXT_V1_H
#include <boost/context/detail/config.hpp>
#include <algorithm>
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <functional>
#include <memory>
#include <ostream>
#include <tuple>
#include <utility>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/intrusive_ptr.hpp>
#if defined(BOOST_NO_CXX17_STD_APPLY)
#include <boost/context/detail/apply.hpp>
#endif
#include <boost/context/detail/disable_overload.hpp>
#include <boost/context/detail/externc.hpp>
#include <boost/context/detail/fcontext.hpp>
#include <boost/context/fixedsize_stack.hpp>
#include <boost/context/flags.hpp>
#include <boost/context/preallocated.hpp>
#include <boost/context/segmented_stack.hpp>
#include <boost/context/stack_context.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace context {
namespace detail {
template< typename Fn >
transfer_t ecv1_context_ontop( transfer_t);
struct ecv1_activation_record;
struct ecv1_data_t {
ecv1_activation_record * from;
void * data;
};
struct BOOST_CONTEXT_DECL ecv1_activation_record {
typedef boost::intrusive_ptr< ecv1_activation_record > ptr_t;
static ptr_t & current() noexcept;
std::atomic< std::size_t > use_count{ 0 };
fcontext_t fctx{ nullptr };
stack_context sctx{};
bool main_ctx{ true };
// used for toplevel-context
// (e.g. main context, thread-entry context)
ecv1_activation_record() = default;
ecv1_activation_record( fcontext_t fctx_, stack_context sctx_) noexcept :
fctx{ fctx_ },
sctx( sctx_ ), // sctx{ sctx_ } - clang-3.6: no viable conversion from 'boost::context::stack_context' to 'std::size_t'
main_ctx{ false } {
}
virtual ~ecv1_activation_record() = default;
bool is_main_context() const noexcept {
return main_ctx;
}
void * resume( void * vp) {
// store current activation record in local variable
auto from = current().get();
// store `this` in static, thread local pointer
// `this` will become the active (running) context
// returned by execution_context::current()
current() = this;
#if defined(BOOST_USE_SEGMENTED_STACKS)
// adjust segmented stack properties
__splitstack_getcontext( from->sctx.segments_ctx);
__splitstack_setcontext( sctx.segments_ctx);
#endif
ecv1_data_t d = { from, vp };
// context switch from parent context to `this`-context
transfer_t t = jump_fcontext( fctx, & d);
ecv1_data_t * dp = reinterpret_cast< ecv1_data_t * >( t.data);
dp->from->fctx = t.fctx;
// parent context resumed
return dp->data;
}
template< typename Fn >
void * resume_ontop( void * data, Fn && fn) {
// store current activation record in local variable
ecv1_activation_record * from = current().get();
// store `this` in static, thread local pointer
// `this` will become the active (running) context
// returned by execution_context::current()
current() = this;
#if defined(BOOST_USE_SEGMENTED_STACKS)
// adjust segmented stack properties
__splitstack_getcontext( from->sctx.segments_ctx);
__splitstack_setcontext( sctx.segments_ctx);
#endif
std::tuple< void *, Fn > p = std::forward_as_tuple( data, fn);
ecv1_data_t d = { from, & p };
// context switch from parent context to `this`-context
// execute Fn( Tpl) on top of `this`
transfer_t t = ontop_fcontext( fctx, & d, ecv1_context_ontop< Fn >);
ecv1_data_t * dp = reinterpret_cast< ecv1_data_t * >( t.data);
dp->from->fctx = t.fctx;
// parent context resumed
return dp->data;
}
virtual void deallocate() noexcept {
}
friend void intrusive_ptr_add_ref( ecv1_activation_record * ar) noexcept {
++ar->use_count;
}
friend void intrusive_ptr_release( ecv1_activation_record * ar) noexcept {
BOOST_ASSERT( nullptr != ar);
if ( 0 == --ar->use_count) {
ar->deallocate();
}
}
};
struct BOOST_CONTEXT_DECL ecv1_activation_record_initializer {
ecv1_activation_record_initializer() noexcept;
~ecv1_activation_record_initializer();
};
template< typename Fn >
transfer_t ecv1_context_ontop( transfer_t t) {
ecv1_data_t * dp = reinterpret_cast< ecv1_data_t * >( t.data);
dp->from->fctx = t.fctx;
auto tpl = reinterpret_cast< std::tuple< void *, Fn > * >( dp->data);
BOOST_ASSERT( nullptr != tpl);
auto data = std::get< 0 >( * tpl);
typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 1 >( * tpl) );
#if defined(BOOST_NO_CXX17_STD_APPLY)
dp->data = boost::context::detail::apply( fn, std::tie( data) );
#else
dp->data = std::apply( fn, std::tie( data) );
#endif
return { t.fctx, dp };
}
template< typename StackAlloc, typename Fn, typename ... Args >
class ecv1_capture_record : public ecv1_activation_record {
private:
typename std::decay< StackAlloc >::type salloc_;
typename std::decay< Fn >::type fn_;
std::tuple< typename std::decay< Args >::type ... > args_;
ecv1_activation_record * caller_;
static void destroy( ecv1_capture_record * p) noexcept {
typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
stack_context sctx = p->sctx;
// deallocate activation record
p->~ecv1_capture_record();
// destroy stack with stack allocator
salloc.deallocate( sctx);
}
public:
ecv1_capture_record( stack_context sctx, StackAlloc && salloc,
fcontext_t fctx,
ecv1_activation_record * caller,
Fn && fn, Args && ... args) noexcept :
ecv1_activation_record{ fctx, sctx },
salloc_{ std::forward< StackAlloc >( salloc) },
fn_( std::forward< Fn >( fn) ),
args_( std::forward< Args >( args) ... ),
caller_{ caller } {
}
void deallocate() noexcept override final {
destroy( this);
}
void run() {
auto data = caller_->resume( nullptr);
#if defined(BOOST_NO_CXX17_STD_APPLY)
boost::context::detail::apply( fn_, std::tuple_cat( args_, std::tie( data) ) );
#else
std::apply( fn_, std::tuple_cat( args_, std::tie( data) ) );
#endif
BOOST_ASSERT_MSG( ! main_ctx, "main-context does not execute activation-record::run()");
}
};
}
namespace v1 {
class BOOST_CONTEXT_DECL execution_context {
private:
// tampoline function
// entered if the execution context
// is resumed for the first time
template< typename AR >
static void entry_func( detail::transfer_t t) noexcept {
detail::ecv1_data_t * dp = reinterpret_cast< detail::ecv1_data_t * >( t.data);
AR * ar = static_cast< AR * >( dp->data);
BOOST_ASSERT( nullptr != ar);
dp->from->fctx = t.fctx;
// start execution of toplevel context-function
ar->run();
}
typedef boost::intrusive_ptr< detail::ecv1_activation_record > ptr_t;
ptr_t ptr_;
template< typename StackAlloc, typename Fn, typename ... Args >
static detail::ecv1_activation_record * create_context( StackAlloc && salloc,
Fn && fn, Args && ... args) {
typedef detail::ecv1_capture_record<
StackAlloc, Fn, Args ...
> capture_t;
auto sctx = salloc.allocate();
// reserve space for control structure
#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
const std::size_t size = sctx.size - sizeof( capture_t);
void * sp = static_cast< char * >( sctx.sp) - sizeof( capture_t);
#else
constexpr std::size_t func_alignment = 64; // alignof( capture_t);
constexpr std::size_t func_size = sizeof( capture_t);
// reserve space on stack
void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
// align sp pointer
std::size_t space = func_size + func_alignment;
sp = std::align( func_alignment, func_size, sp, space);
BOOST_ASSERT( nullptr != sp);
// calculate remaining size
const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
#endif
// create fast-context
const detail::fcontext_t fctx = detail::make_fcontext( sp, size, & execution_context::entry_func< capture_t >);
BOOST_ASSERT( nullptr != fctx);
// get current activation record
auto curr = execution_context::current().ptr_;
// placment new for control structure on fast-context stack
return ::new ( sp) capture_t{
sctx, std::forward< StackAlloc >( salloc), fctx, curr.get(), std::forward< Fn >( fn), std::forward< Args >( args) ... };
}
template< typename StackAlloc, typename Fn, typename ... Args >
static detail::ecv1_activation_record * create_context( preallocated palloc, StackAlloc && salloc,
Fn && fn, Args && ... args) {
typedef detail::ecv1_capture_record<
StackAlloc, Fn, Args ...
> capture_t;
// reserve space for control structure
#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
const std::size_t size = palloc.size - sizeof( capture_t);
void * sp = static_cast< char * >( palloc.sp) - sizeof( capture_t);
#else
constexpr std::size_t func_alignment = 64; // alignof( capture_t);
constexpr std::size_t func_size = sizeof( capture_t);
// reserve space on stack
void * sp = static_cast< char * >( palloc.sp) - func_size - func_alignment;
// align sp pointer
std::size_t space = func_size + func_alignment;
sp = std::align( func_alignment, func_size, sp, space);
BOOST_ASSERT( nullptr != sp);
// calculate remaining size
const std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) );
#endif
// create fast-context
const detail::fcontext_t fctx = detail::make_fcontext( sp, size, & execution_context::entry_func< capture_t >);
BOOST_ASSERT( nullptr != fctx);
// get current activation record
auto curr = execution_context::current().ptr_;
// placment new for control structure on fast-context stack
return ::new ( sp) capture_t{
palloc.sctx, std::forward< StackAlloc >( salloc), fctx, curr.get(), std::forward< Fn >( fn), std::forward< Args >( args) ... };
}
execution_context() noexcept :
// default constructed with current ecv1_activation_record
ptr_{ detail::ecv1_activation_record::current() } {
}
public:
static execution_context current() noexcept;
#if defined(BOOST_USE_SEGMENTED_STACKS)
template< typename Fn,
typename ... Args,
typename = detail::disable_overload< execution_context, Fn >
>
execution_context( Fn && fn, Args && ... args) :
// deferred execution of fn and its arguments
// arguments are stored in std::tuple<>
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
ptr_{ create_context( segmented_stack(),
std::forward< Fn >( fn),
std::forward< Args >( args) ...) } {
ptr_->resume( ptr_.get() );
}
template< typename Fn,
typename ... Args
>
execution_context( std::allocator_arg_t, segmented_stack salloc, Fn && fn, Args && ... args) :
// deferred execution of fn and its arguments
// arguments are stored in std::tuple<>
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
ptr_{ create_context( salloc,
std::forward< Fn >( fn),
std::forward< Args >( args) ...) } {
ptr_->resume( ptr_.get() );
}
template< typename Fn,
typename ... Args
>
execution_context( std::allocator_arg_t, preallocated palloc, segmented_stack salloc, Fn && fn, Args && ... args) :
// deferred execution of fn and its arguments
// arguments are stored in std::tuple<>
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
ptr_{ create_context( palloc, salloc,
std::forward< Fn >( fn),
std::forward< Args >( args) ...) } {
ptr_->resume( ptr_.get() );
}
#else
template< typename Fn,
typename ... Args,
typename = detail::disable_overload< execution_context, Fn >
>
execution_context( Fn && fn, Args && ... args) :
// deferred execution of fn and its arguments
// arguments are stored in std::tuple<>
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
ptr_{ create_context( fixedsize_stack(),
std::forward< Fn >( fn),
std::forward< Args >( args) ...) } {
ptr_->resume( ptr_.get() );
}
template< typename StackAlloc,
typename Fn,
typename ... Args
>
execution_context( std::allocator_arg_t, StackAlloc && salloc, Fn && fn, Args && ... args) :
// deferred execution of fn and its arguments
// arguments are stored in std::tuple<>
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
ptr_{ create_context( std::forward< StackAlloc >( salloc),
std::forward< Fn >( fn),
std::forward< Args >( args) ...) } {
ptr_->resume( ptr_.get() );
}
template< typename StackAlloc,
typename Fn,
typename ... Args
>
execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn, Args && ... args) :
// deferred execution of fn and its arguments
// arguments are stored in std::tuple<>
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
ptr_{ create_context( palloc, std::forward< StackAlloc >( salloc),
std::forward< Fn >( fn),
std::forward< Args >( args) ...) } {
ptr_->resume( ptr_.get() );
}
#endif
execution_context( execution_context const& other) noexcept :
ptr_{ other.ptr_ } {
}
execution_context( execution_context && other) noexcept :
ptr_{ other.ptr_ } {
other.ptr_.reset();
}
execution_context & operator=( execution_context const& other) noexcept {
// intrusive_ptr<> does not test for self-assignment
if ( this == & other) return * this;
ptr_ = other.ptr_;
return * this;
}
execution_context & operator=( execution_context && other) noexcept {
if ( this == & other) return * this;
execution_context tmp{ std::move( other) };
swap( tmp);
return * this;
}
void * operator()( void * vp = nullptr) {
return ptr_->resume( vp);
}
template< typename Fn >
void * operator()( exec_ontop_arg_t, Fn && fn, void * vp = nullptr) {
return ptr_->resume_ontop( vp,
std::forward< Fn >( fn) );
}
explicit operator bool() const noexcept {
return nullptr != ptr_.get();
}
bool operator!() const noexcept {
return nullptr == ptr_.get();
}
bool operator<( execution_context const& other) const noexcept {
return ptr_ < other.ptr_;
}
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other) {
if ( nullptr != other.ptr_) {
return os << other.ptr_;
} else {
return os << "{not-a-context}";
}
}
void swap( execution_context & other) noexcept {
ptr_.swap( other.ptr_);
}
};
inline
void swap( execution_context & l, execution_context & r) noexcept {
l.swap( r);
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_EXECUTION_CONTEXT_V1_H

View File

@@ -1,482 +0,0 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONTEXT_EXECUTION_CONTEXT_V2_H
#define BOOST_CONTEXT_EXECUTION_CONTEXT_V2_H
#include <boost/context/detail/config.hpp>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <exception>
#include <functional>
#include <memory>
#include <ostream>
#include <tuple>
#include <utility>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/intrusive_ptr.hpp>
#if defined(BOOST_NO_CXX17_STD_APPLY)
#include <boost/context/detail/apply.hpp>
#endif
#include <boost/context/detail/disable_overload.hpp>
#include <boost/context/detail/exception.hpp>
#include <boost/context/detail/exchange.hpp>
#include <boost/context/detail/fcontext.hpp>
#include <boost/context/detail/tuple.hpp>
#include <boost/context/fixedsize_stack.hpp>
#include <boost/context/flags.hpp>
#include <boost/context/preallocated.hpp>
#include <boost/context/segmented_stack.hpp>
#include <boost/context/stack_context.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable: 4702)
#endif
namespace boost {
namespace context {
namespace detail {
transfer_t ecv2_context_unwind( transfer_t);
template< typename Rec >
transfer_t ecv2_context_exit( transfer_t) noexcept;
template< typename Rec >
void ecv2_context_etry( transfer_t) noexcept;
template< typename Ctx, typename Fn, typename ... Args >
transfer_t ecv2_context_ontop( transfer_t);
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
fcontext_t ecv2_context_create( StackAlloc &&, Fn &&, Params && ...);
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
fcontext_t ecv2_context_create( preallocated, StackAlloc &&, Fn &&, Params && ...);
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
class ecv2_record {
private:
typename std::decay< StackAlloc >::type salloc_;
stack_context sctx_;
typename std::decay< Fn >::type fn_;
std::tuple< typename std::decay< Params >::type ... > params_;
static void destroy( ecv2_record * p) noexcept {
typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
stack_context sctx = p->sctx_;
// deallocate ecv2_record
p->~ecv2_record();
// destroy stack with stack allocator
salloc.deallocate( sctx);
}
public:
ecv2_record( stack_context sctx, StackAlloc && salloc,
Fn && fn, Params && ... params) noexcept :
salloc_( std::forward< StackAlloc >( salloc)),
sctx_( sctx),
fn_( std::forward< Fn >( fn) ),
params_( std::forward< Params >( params) ... ) {
}
ecv2_record( ecv2_record const&) = delete;
ecv2_record & operator=( ecv2_record const&) = delete;
void deallocate() noexcept {
destroy( this);
}
transfer_t run( transfer_t t) {
Ctx from{ t.fctx };
typename Ctx::args_tpl_t args = std::move( std::get<1>( * static_cast< std::tuple< std::exception_ptr, typename Ctx::args_tpl_t > * >( t.data) ) );
auto tpl = std::tuple_cat(
params_,
std::forward_as_tuple( std::move( from) ),
std::move( args) );
// invoke context-function
#if defined(BOOST_NO_CXX17_STD_APPLY)
Ctx cc = boost::context::detail::apply( std::move( fn_), std::move( tpl) );
#else
Ctx cc = std::apply( std::move( fn_), std::move( tpl) );
#endif
return { exchange( cc.fctx_, nullptr), nullptr };
}
};
}
inline namespace v2 {
template< typename ... Args >
class execution_context {
private:
friend class ontop_error;
typedef std::tuple< Args ... > args_tpl_t;
typedef std::tuple< execution_context, typename std::decay< Args >::type ... > ret_tpl_t;
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
friend class detail::ecv2_record;
template< typename Ctx, typename Fn, typename ... ArgsT >
friend detail::transfer_t detail::ecv2_context_ontop( detail::transfer_t);
detail::fcontext_t fctx_{ nullptr };
execution_context( detail::fcontext_t fctx) noexcept :
fctx_( fctx) {
}
public:
execution_context() noexcept = default;
#if defined(BOOST_USE_SEGMENTED_STACKS)
// segmented-stack requires to preserve the segments of the `current` context
// which is not possible (no global pointer to current context)
template< typename Fn, typename ... Params >
execution_context( std::allocator_arg_t, segmented_stack, Fn &&, Params && ...) = delete;
template< typename Fn, typename ... Params >
execution_context( std::allocator_arg_t, preallocated, segmented_stack, Fn &&, Params && ...) = delete;
#else
template< typename Fn,
typename ... Params,
typename = detail::disable_overload< execution_context, Fn >
>
execution_context( Fn && fn, Params && ... params) :
// deferred execution of fn and its arguments
// arguments are stored in std::tuple<>
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
fctx_( detail::ecv2_context_create< execution_context >(
fixedsize_stack(),
std::forward< Fn >( fn),
std::forward< Params >( params) ... ) ) {
}
template< typename StackAlloc,
typename Fn,
typename ... Params
>
execution_context( std::allocator_arg_t, StackAlloc && salloc, Fn && fn, Params && ... params) :
// deferred execution of fn and its arguments
// arguments are stored in std::tuple<>
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
fctx_( detail::ecv2_context_create< execution_context >(
std::forward< StackAlloc >( salloc),
std::forward< Fn >( fn),
std::forward< Params >( params) ... ) ) {
}
template< typename StackAlloc,
typename Fn,
typename ... Params
>
execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn, Params && ... params) :
// deferred execution of fn and its arguments
// arguments are stored in std::tuple<>
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
fctx_( detail::ecv2_context_create< execution_context >(
palloc, std::forward< StackAlloc >( salloc),
std::forward< Fn >( fn),
std::forward< Params >( params) ... ) ) {
}
#endif
~execution_context() {
if ( nullptr != fctx_) {
detail::ontop_fcontext( detail::exchange( fctx_, nullptr), nullptr, detail::ecv2_context_unwind);
}
}
execution_context( execution_context && other) noexcept :
fctx_( other.fctx_) {
other.fctx_ = nullptr;
}
execution_context & operator=( execution_context && other) noexcept {
if ( this != & other) {
execution_context tmp = std::move( other);
swap( tmp);
}
return * this;
}
execution_context( execution_context const& other) noexcept = delete;
execution_context & operator=( execution_context const& other) noexcept = delete;
ret_tpl_t operator()( Args ... args);
template< typename Fn >
ret_tpl_t operator()( exec_ontop_arg_t, Fn && fn, Args ... args);
explicit operator bool() const noexcept {
return nullptr != fctx_;
}
bool operator!() const noexcept {
return nullptr == fctx_;
}
bool operator<( execution_context const& other) const noexcept {
return fctx_ < other.fctx_;
}
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other) {
if ( nullptr != other.fctx_) {
return os << other.fctx_;
} else {
return os << "{not-a-context}";
}
}
void swap( execution_context & other) noexcept {
std::swap( fctx_, other.fctx_);
}
};
class ontop_error : public std::exception {
private:
detail::fcontext_t fctx_;
public:
ontop_error( detail::fcontext_t fctx) noexcept :
fctx_{ fctx } {
}
template< typename ... Args >
execution_context< Args ... > get_context() const noexcept {
return execution_context< Args ... >{ fctx_ };
}
};
template< typename ... Args >
typename execution_context< Args ... >::ret_tpl_t
execution_context< Args ... >::operator()( Args ... args) {
BOOST_ASSERT( nullptr != fctx_);
args_tpl_t data( std::forward< Args >( args) ... );
auto p = std::make_tuple( std::exception_ptr{}, std::move( data) );
detail::transfer_t t = detail::jump_fcontext( detail::exchange( fctx_, nullptr), & p);
if ( nullptr != t.data) {
auto p = static_cast< std::tuple< std::exception_ptr, args_tpl_t > * >( t.data);
std::exception_ptr eptr = std::get< 0 >( * p);
if ( eptr) {
try {
std::rethrow_exception( eptr);
} catch (...) {
std::throw_with_nested( ontop_error{ t.fctx } );
}
}
data = std::move( std::get< 1 >( * p) );
}
return std::tuple_cat( std::forward_as_tuple( execution_context( t.fctx) ), std::move( data) );
}
template< typename ... Args >
template< typename Fn >
typename execution_context< Args ... >::ret_tpl_t
execution_context< Args ... >::operator()( exec_ontop_arg_t, Fn && fn, Args ... args) {
BOOST_ASSERT( nullptr != fctx_);
args_tpl_t data{ std::forward< Args >( args) ... };
auto p = std::make_tuple( fn, std::make_tuple( std::exception_ptr{}, std::move( data) ) );
detail::transfer_t t = detail::ontop_fcontext(
detail::exchange( fctx_, nullptr),
& p,
detail::ecv2_context_ontop< execution_context, Fn, Args ... >);
if ( nullptr != t.data) {
auto p = static_cast< std::tuple< std::exception_ptr, args_tpl_t > * >( t.data);
std::exception_ptr eptr = std::get< 0 >( * p);
if ( eptr) {
try {
std::rethrow_exception( eptr);
} catch (...) {
std::throw_with_nested( ontop_error{ t.fctx } );
}
}
data = std::move( std::get< 1 >( * p) );
}
return std::tuple_cat( std::forward_as_tuple( execution_context( t.fctx) ), std::move( data) );
}
}
namespace detail {
template< int N >
struct helper {
template< typename T >
static T convert( T && t) noexcept {
return std::forward< T >( t);
}
};
template<>
struct helper< 1 > {
template< typename T >
static std::tuple< T > convert( T && t) noexcept {
return std::make_tuple( std::forward< T >( t) );
}
};
inline
transfer_t ecv2_context_unwind( transfer_t t) {
throw forced_unwind( t.fctx);
return { nullptr, nullptr };
}
template< typename Rec >
transfer_t ecv2_context_exit( transfer_t t) noexcept {
Rec * rec = static_cast< Rec * >( t.data);
// destroy context stack
rec->deallocate();
return { nullptr, nullptr };
}
template< typename Rec >
void ecv2_context_etry( transfer_t t_) noexcept {
// transfer control structure to the context-stack
Rec * rec = static_cast< Rec * >( t_.data);
BOOST_ASSERT( nullptr != rec);
transfer_t t = { nullptr, nullptr };
try {
// jump back to `ecv2_context_create()`
t = jump_fcontext( t_.fctx, nullptr);
// start executing
t = rec->run( t);
} catch ( forced_unwind const& ex) {
t = { ex.fctx, nullptr };
#ifndef BOOST_ASSERT_IS_VOID
const_cast< forced_unwind & >( ex).caught = true;
#endif
}
BOOST_ASSERT( nullptr != t.fctx);
// destroy context-stack of `this`context on next context
ontop_fcontext( t.fctx, rec, ecv2_context_exit< Rec >);
BOOST_ASSERT_MSG( false, "context already terminated");
}
template< typename Ctx, typename Fn, typename ... Args >
transfer_t ecv2_context_ontop( transfer_t t) {
auto p = static_cast< std::tuple< Fn, std::tuple< std::exception_ptr, std::tuple< Args ... > > > * >( t.data);
BOOST_ASSERT( nullptr != p);
typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * p) );
auto args = std::move( std::get< 1 >( std::get< 1 >( * p) ) );
try {
// execute function
#if defined(BOOST_NO_CXX17_STD_APPLY)
std::get< 1 >( std::get< 1 >( * p) ) = helper< sizeof ... (Args) >::convert( boost::context::detail::apply( fn, std::move( args) ) );
#else
std::get< 1 >( std::get< 1 >( * p) ) = helper< sizeof ... (Args) >::convert( std::apply( fn, std::move( args) ) );
#endif
} catch (...) {
std::get< 0 >( std::get< 1 >( * p) ) = std::current_exception();
}
// apply returned data
return { t.fctx, & std::get< 1 >( * p) };
}
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
fcontext_t ecv2_context_create( StackAlloc && salloc, Fn && fn, Params && ... params) {
typedef ecv2_record< Ctx, StackAlloc, Fn, Params ... > ecv2_record_t;
auto sctx = salloc.allocate();
// reserve space for control structure
#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
const std::size_t size = sctx.size - sizeof( ecv2_record_t);
void * sp = static_cast< char * >( sctx.sp) - sizeof( ecv2_record_t);
#else
constexpr std::size_t func_alignment = 64; // alignof( ecv2_record_t);
constexpr std::size_t func_size = sizeof( ecv2_record_t);
// reserve space on stack
void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
// align sp pointer
std::size_t space = func_size + func_alignment;
sp = std::align( func_alignment, func_size, sp, space);
BOOST_ASSERT( nullptr != sp);
// calculate remaining size
const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
#endif
// create fast-context
const fcontext_t fctx = make_fcontext( sp, size, & ecv2_context_etry< ecv2_record_t >);
BOOST_ASSERT( nullptr != fctx);
// placment new for control structure on context-stack
auto rec = ::new ( sp) ecv2_record_t{
sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn), std::forward< Params >( params) ... };
// transfer control structure to context-stack
return jump_fcontext( fctx, rec).fctx;
}
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
fcontext_t ecv2_context_create( preallocated palloc, StackAlloc && salloc, Fn && fn, Params && ... params) {
typedef ecv2_record< Ctx, StackAlloc, Fn, Params ... > ecv2_record_t;
// reserve space for control structure
#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
const std::size_t size = palloc.size - sizeof( ecv2_record_t);
void * sp = static_cast< char * >( palloc.sp) - sizeof( ecv2_record_t);
#else
constexpr std::size_t func_alignment = 64; // alignof( ecv2_record_t);
constexpr std::size_t func_size = sizeof( ecv2_record_t);
// reserve space on stack
void * sp = static_cast< char * >( palloc.sp) - func_size - func_alignment;
// align sp pointer
std::size_t space = func_size + func_alignment;
sp = std::align( func_alignment, func_size, sp, space);
BOOST_ASSERT( nullptr != sp);
// calculate remaining size
const std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) );
#endif
// create fast-context
const fcontext_t fctx = make_fcontext( sp, size, & ecv2_context_etry< ecv2_record_t >);
BOOST_ASSERT( nullptr != fctx);
// placment new for control structure on context-stack
auto rec = ::new ( sp) ecv2_record_t{
palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn), std::forward< Params >( params) ... };
// transfer control structure to context-stack
return jump_fcontext( fctx, rec).fctx;
}
}
#include <boost/context/execution_context_v2_void.ipp>
inline namespace v2 {
template< typename ... Args >
void swap( execution_context< Args ... > & l, execution_context< Args ... > & r) noexcept {
l.swap( r);
}
}}}
#if defined(BOOST_MSVC)
# pragma warning(pop)
#endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_CONTEXT_EXECUTION_CONTEXT_V2_H

View File

@@ -1,307 +0,0 @@
// Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
namespace detail {
template< typename Ctx, typename Fn >
transfer_t ecv2_context_ontop_void( transfer_t);
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
fcontext_t ecv2_context_create_void( StackAlloc &&, Fn &&, Params && ...);
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
fcontext_t ecv2_context_create_void( preallocated, StackAlloc &&, Fn &&, Params && ...);
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
class ecv2_record_void {
private:
typename std::decay< StackAlloc >::type salloc_;
stack_context sctx_;
typename std::decay< Fn >::type fn_;
std::tuple< typename std::decay< Params >::type ... > params_;
static void destroy( ecv2_record_void * p) noexcept {
typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
stack_context sctx = p->sctx_;
// deallocate record
p->~ecv2_record_void();
// destroy stack with stack allocator
salloc.deallocate( sctx);
}
public:
ecv2_record_void( stack_context sctx, StackAlloc && salloc,
Fn && fn, Params && ... params) noexcept :
salloc_( std::forward< StackAlloc >( salloc) ),
sctx_( sctx),
fn_( std::forward< Fn >( fn) ),
params_( std::forward< Params >( params) ... ) {
}
ecv2_record_void( ecv2_record_void const&) = delete;
ecv2_record_void & operator=( ecv2_record_void const&) = delete;
void deallocate() noexcept {
destroy( this);
}
transfer_t run( transfer_t t) {
Ctx from{ t.fctx };
// invoke context-function
#if defined(BOOST_NO_CXX17_STD_APPLY)
Ctx cc = boost::context::detail::apply( fn_, std::tuple_cat( params_, std::forward_as_tuple( std::move( from) ) ) );
#else
Ctx cc = std::apply( fn_, std::tuple_cat( params_, std::forward_as_tuple( std::move( from) ) ) );
#endif
return { exchange( cc.fctx_, nullptr), nullptr };
}
};
}
inline namespace v2 {
template<>
class execution_context< void > {
private:
friend class ontop_error;
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
friend class detail::ecv2_record_void;
template< typename Ctx, typename Fn >
friend detail::transfer_t detail::ecv2_context_ontop_void( detail::transfer_t);
detail::fcontext_t fctx_{ nullptr };
execution_context( detail::fcontext_t fctx) noexcept :
fctx_( fctx) {
}
public:
execution_context() noexcept = default;
#if defined(BOOST_USE_SEGMENTED_STACKS)
// segmented-stack requires to preserve the segments of the `current` context
// which is not possible (no global pointer to current context)
template< typename Fn, typename ... Params >
execution_context( std::allocator_arg_t, segmented_stack, Fn &&, Params && ...) = delete;
template< typename Fn, typename ... Params >
execution_context( std::allocator_arg_t, preallocated, segmented_stack, Fn &&, Params && ...) = delete;
#else
template< typename Fn,
typename ... Params,
typename = detail::disable_overload< execution_context, Fn >
>
execution_context( Fn && fn, Params && ... params) :
// deferred execution of fn and its arguments
// arguments are stored in std::tuple<>
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
fctx_( detail::ecv2_context_create_void< execution_context >(
fixedsize_stack(),
std::forward< Fn >( fn),
std::forward< Params >( params) ... ) ) {
}
template< typename StackAlloc,
typename Fn,
typename ... Params
>
execution_context( std::allocator_arg_t, StackAlloc && salloc, Fn && fn, Params && ... params) :
// deferred execution of fn and its arguments
// arguments are stored in std::tuple<>
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
fctx_( detail::ecv2_context_create_void< execution_context >(
std::forward< StackAlloc >( salloc),
std::forward< Fn >( fn),
std::forward< Params >( params) ... ) ) {
}
template< typename StackAlloc,
typename Fn,
typename ... Params
>
execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn, Params && ... params) :
// deferred execution of fn and its arguments
// arguments are stored in std::tuple<>
// non-type template parameter pack via std::index_sequence_for<>
// preserves the number of arguments
// used to extract the function arguments from std::tuple<>
fctx_( detail::ecv2_context_create_void< execution_context >(
palloc, std::forward< StackAlloc >( salloc),
std::forward< Fn >( fn),
std::forward< Params >( params) ... ) ) {
}
#endif
~execution_context() {
if ( nullptr != fctx_) {
detail::ontop_fcontext( detail::exchange( fctx_, nullptr), nullptr, detail::ecv2_context_unwind);
}
}
execution_context( execution_context && other) noexcept :
fctx_( other.fctx_) {
other.fctx_ = nullptr;
}
execution_context & operator=( execution_context && other) noexcept {
if ( this != & other) {
execution_context tmp = std::move( other);
swap( tmp);
}
return * this;
}
execution_context( execution_context const& other) noexcept = delete;
execution_context & operator=( execution_context const& other) noexcept = delete;
execution_context operator()() {
BOOST_ASSERT( nullptr != fctx_);
detail::transfer_t t = detail::jump_fcontext( detail::exchange( fctx_, nullptr), nullptr);
if ( nullptr != t.data) {
std::exception_ptr * eptr = static_cast< std::exception_ptr * >( t.data);
try {
std::rethrow_exception( * eptr);
} catch (...) {
std::throw_with_nested( ontop_error{ t.fctx } );
}
}
return execution_context( t.fctx);
}
template< typename Fn >
execution_context operator()( exec_ontop_arg_t, Fn && fn) {
BOOST_ASSERT( nullptr != fctx_);
auto p = std::make_tuple( fn, std::exception_ptr{} );
detail::transfer_t t = detail::ontop_fcontext(
detail::exchange( fctx_, nullptr),
& p,
detail::ecv2_context_ontop_void< execution_context, Fn >);
if ( nullptr != t.data) {
std::exception_ptr * eptr = static_cast< std::exception_ptr * >( t.data);
try {
std::rethrow_exception( * eptr);
} catch (...) {
std::throw_with_nested( ontop_error{ t.fctx } );
}
}
return execution_context( t.fctx);
}
explicit operator bool() const noexcept {
return nullptr != fctx_;
}
bool operator!() const noexcept {
return nullptr == fctx_;
}
bool operator<( execution_context const& other) const noexcept {
return fctx_ < other.fctx_;
}
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other) {
if ( nullptr != other.fctx_) {
return os << other.fctx_;
} else {
return os << "{not-a-context}";
}
}
void swap( execution_context & other) noexcept {
std::swap( fctx_, other.fctx_);
}
};
}
namespace detail {
template< typename Ctx, typename Fn >
transfer_t ecv2_context_ontop_void( transfer_t t) {
auto p = static_cast< std::tuple< Fn, std::exception_ptr > * >( t.data);
BOOST_ASSERT( nullptr != p);
typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * p) );
try {
// execute function
fn();
} catch (...) {
std::get< 1 >( * p) = std::current_exception();
return { t.fctx, & std::get< 1 >( * p ) };
}
return { exchange( t.fctx, nullptr), nullptr };
}
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
fcontext_t ecv2_context_create_void( StackAlloc && salloc, Fn && fn, Params && ... params) {
typedef ecv2_record_void< Ctx, StackAlloc, Fn, Params ... > record_t;
auto sctx = salloc.allocate();
// reserve space for control structure
#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
const std::size_t size = sctx.size - sizeof( record_t);
void * sp = static_cast< char * >( sctx.sp) - sizeof( record_t);
#else
constexpr std::size_t func_alignment = 64; // alignof( record_t);
constexpr std::size_t func_size = sizeof( record_t);
// reserve space on stack
void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
// align sp pointer
std::size_t space = func_size + func_alignment;
sp = std::align( func_alignment, func_size, sp, space);
BOOST_ASSERT( nullptr != sp);
// calculate remaining size
const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
#endif
// create fast-context
const fcontext_t fctx = make_fcontext( sp, size, & ecv2_context_etry< record_t >);
BOOST_ASSERT( nullptr != fctx);
// placment new for control structure on context-stack
auto rec = ::new ( sp) record_t{
sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn), std::forward< Params >( params) ... };
// transfer control structure to context-stack
return jump_fcontext( fctx, rec).fctx;
}
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
fcontext_t ecv2_context_create_void( preallocated palloc, StackAlloc && salloc, Fn && fn, Params && ... params) {
typedef ecv2_record_void< Ctx, StackAlloc, Fn, Params ... > record_t;
// reserve space for control structure
#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
const std::size_t size = palloc.size - sizeof( record_t);
void * sp = static_cast< char * >( palloc.sp) - sizeof( record_t);
#else
constexpr std::size_t func_alignment = 64; // alignof( record_t);
constexpr std::size_t func_size = sizeof( record_t);
// reserve space on stack
void * sp = static_cast< char * >( palloc.sp) - func_size - func_alignment;
// align sp pointer
std::size_t space = func_size + func_alignment;
sp = std::align( func_alignment, func_size, sp, space);
BOOST_ASSERT( nullptr != sp);
// calculate remaining size
const std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) );
#endif
// create fast-context
const fcontext_t fctx = make_fcontext( sp, size, & ecv2_context_etry< record_t >);
BOOST_ASSERT( nullptr != fctx);
// placment new for control structure on context-stack
auto rec = ::new ( sp) record_t{
palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn), std::forward< Params >( params) ... };
// transfer control structure to context-stack
return jump_fcontext( fctx, rec).fctx;
}
}

View File

@@ -80,9 +80,6 @@ void fiber_entry( transfer_t t) noexcept {
t.fctx = rec->run( t.fctx);
} catch ( forced_unwind const& ex) {
t = { ex.fctx, nullptr };
#ifndef BOOST_ASSERT_IS_VOID
const_cast< forced_unwind & >( ex).caught = true;
#endif
}
BOOST_ASSERT( nullptr != t.fctx);
// destroy context-stack of `this`context on next context
@@ -92,12 +89,11 @@ void fiber_entry( transfer_t t) noexcept {
template< typename Ctx, typename Fn >
transfer_t fiber_ontop( transfer_t t) {
auto p = static_cast< std::tuple< Fn > * >( t.data);
BOOST_ASSERT( nullptr != p);
typename std::decay< Fn >::type fn = std::get< 0 >( * p);
BOOST_ASSERT( nullptr != t.data);
auto p = *static_cast< Fn * >( t.data);
t.data = nullptr;
// execute function, pass fiber via reference
Ctx c = fn( Ctx{ t.fctx } );
Ctx c = p( Ctx{ t.fctx } );
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
return { exchange( c.fctx_, nullptr), nullptr };
#else
@@ -292,7 +288,7 @@ public:
template< typename Fn >
fiber resume_with( Fn && fn) && {
BOOST_ASSERT( nullptr != fctx_);
auto p = std::make_tuple( std::forward< Fn >( fn) );
auto p = std::forward< Fn >( fn);
return { detail::ontop_fcontext(
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
detail::exchange( fctx_, nullptr),
@@ -300,7 +296,7 @@ public:
std::exchange( fctx_, nullptr),
#endif
& p,
detail::fiber_ontop< fiber, Fn >).fctx };
detail::fiber_ontop< fiber, decltype(p) >).fctx };
}
explicit operator bool() const noexcept {
@@ -315,6 +311,8 @@ public:
return fctx_ < other.fctx_;
}
#if !defined(BOOST_EMBTC)
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) {
@@ -325,11 +323,33 @@ public:
}
}
#else
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other);
#endif
void swap( fiber & other) noexcept {
std::swap( fctx_, other.fctx_);
}
};
#if defined(BOOST_EMBTC)
template< typename charT, class traitsT >
inline std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) {
if ( nullptr != other.fctx_) {
return os << other.fctx_;
} else {
return os << "{not-a-context}";
}
}
#endif
inline
void swap( fiber & l, fiber & r) noexcept {
l.swap( r);

View File

@@ -32,6 +32,7 @@ extern "C" {
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/predef.h>
#include <boost/context/detail/disable_overload.hpp>
#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
@@ -53,6 +54,10 @@ extern "C" {
# include BOOST_ABI_PREFIX
#endif
#ifdef BOOST_USE_TSAN
#include <sanitizer/tsan_interface.h>
#endif
namespace boost {
namespace context {
namespace detail {
@@ -82,6 +87,11 @@ struct BOOST_CONTEXT_DECL fiber_activation_record {
std::size_t stack_size{ 0 };
#endif
#if defined(BOOST_USE_TSAN)
void * tsan_fiber{ nullptr };
bool destroy_tsan_fiber{ true };
#endif
static fiber_activation_record *& current() noexcept;
// used for toplevel-context
@@ -92,6 +102,11 @@ struct BOOST_CONTEXT_DECL fiber_activation_record {
std::error_code( errno, std::system_category() ),
"getcontext() failed");
}
#if defined(BOOST_USE_TSAN)
tsan_fiber = __tsan_get_current_fiber();
destroy_tsan_fiber = false;
#endif
}
fiber_activation_record( stack_context sctx_) noexcept :
@@ -100,6 +115,10 @@ struct BOOST_CONTEXT_DECL fiber_activation_record {
}
virtual ~fiber_activation_record() {
#if defined(BOOST_USE_TSAN)
if (destroy_tsan_fiber)
__tsan_destroy_fiber(tsan_fiber);
#endif
}
fiber_activation_record( fiber_activation_record const&) = delete;
@@ -125,6 +144,9 @@ struct BOOST_CONTEXT_DECL fiber_activation_record {
} else {
__sanitizer_start_switch_fiber( & from->fake_stack, stack_bottom, stack_size);
}
#endif
#if defined (BOOST_USE_TSAN)
__tsan_switch_to_fiber(tsan_fiber, 0);
#endif
// context switch from parent context to `this`-context
::swapcontext( & from->uctx, & uctx);
@@ -184,6 +206,9 @@ struct BOOST_CONTEXT_DECL fiber_activation_record {
#endif
#if defined(BOOST_USE_ASAN)
__sanitizer_start_switch_fiber( & from->fake_stack, stack_bottom, stack_size);
#endif
#if defined (BOOST_USE_TSAN)
__tsan_switch_to_fiber(tsan_fiber, 0);
#endif
// context switch from parent context to `this`-context
::swapcontext( & from->uctx, & uctx);
@@ -210,19 +235,10 @@ struct BOOST_CONTEXT_DECL fiber_activation_record_initializer {
struct forced_unwind {
fiber_activation_record * from{ nullptr };
#ifndef BOOST_ASSERT_IS_VOID
bool caught{ false };
#endif
forced_unwind( fiber_activation_record * from_) noexcept :
from{ from_ } {
}
#ifndef BOOST_ASSERT_IS_VOID
~forced_unwind() {
BOOST_ASSERT( caught);
}
#endif
};
template< typename Ctx, typename StackAlloc, typename Fn >
@@ -268,9 +284,6 @@ public:
#endif
} catch ( forced_unwind const& ex) {
c = Ctx{ ex.from };
#ifndef BOOST_ASSERT_IS_VOID
const_cast< forced_unwind & >( ex).caught = true;
#endif
}
// this context has finished its task
from = nullptr;
@@ -299,11 +312,18 @@ static fiber_activation_record * create_fiber1( StackAlloc && salloc, Fn && fn)
reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) );
// create user-context
if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) {
record->~capture_t();
salloc.deallocate( sctx);
throw std::system_error(
std::error_code( errno, std::system_category() ),
"getcontext() failed");
}
#if BOOST_OS_BSD_FREE
// because FreeBSD defines stack_t::ss_sp as char *
record->uctx.uc_stack.ss_sp = static_cast< char * >( stack_bottom);
#else
record->uctx.uc_stack.ss_sp = stack_bottom;
#endif
// 64byte gap between control structure and stack top
record->uctx.uc_stack.ss_size = reinterpret_cast< uintptr_t >( storage) -
reinterpret_cast< uintptr_t >( stack_bottom) - static_cast< uintptr_t >( 64);
@@ -312,6 +332,9 @@ static fiber_activation_record * create_fiber1( StackAlloc && salloc, Fn && fn)
#if defined(BOOST_USE_ASAN)
record->stack_bottom = record->uctx.uc_stack.ss_sp;
record->stack_size = record->uctx.uc_stack.ss_size;
#endif
#if defined (BOOST_USE_TSAN)
record->tsan_fiber = __tsan_create_fiber(0);
#endif
return record;
}
@@ -332,11 +355,18 @@ static fiber_activation_record * create_fiber2( preallocated palloc, StackAlloc
reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) );
// create user-context
if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) {
record->~capture_t();
salloc.deallocate( palloc.sctx);
throw std::system_error(
std::error_code( errno, std::system_category() ),
"getcontext() failed");
}
#if BOOST_OS_BSD_FREE
// because FreeBSD defines stack_t::ss_sp as char *
record->uctx.uc_stack.ss_sp = static_cast< char * >( stack_bottom);
#else
record->uctx.uc_stack.ss_sp = stack_bottom;
#endif
// 64byte gap between control structure and stack top
record->uctx.uc_stack.ss_size = reinterpret_cast< uintptr_t >( storage) -
reinterpret_cast< uintptr_t >( stack_bottom) - static_cast< uintptr_t >( 64);
@@ -345,6 +375,9 @@ static fiber_activation_record * create_fiber2( preallocated palloc, StackAlloc
#if defined(BOOST_USE_ASAN)
record->stack_bottom = record->uctx.uc_stack.ss_sp;
record->stack_size = record->uctx.uc_stack.ss_size;
#endif
#if defined (BOOST_USE_TSAN)
record->tsan_fiber = __tsan_create_fiber(0);
#endif
return record;
}
@@ -478,6 +511,8 @@ public:
return ptr_ < other.ptr_;
}
#if !defined(BOOST_EMBTC)
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) {
@@ -488,11 +523,33 @@ public:
}
}
#else
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other);
#endif
void swap( fiber & other) noexcept {
std::swap( ptr_, other.ptr_);
}
};
#if defined(BOOST_EMBTC)
template< typename charT, class traitsT >
inline std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) {
if ( nullptr != other.ptr_) {
return os << other.ptr_;
} else {
return os << "{not-a-context}";
}
}
#endif
inline
void swap( fiber & l, fiber & r) noexcept {
l.swap( r);

View File

@@ -185,19 +185,10 @@ struct BOOST_CONTEXT_DECL fiber_activation_record_initializer {
struct forced_unwind {
fiber_activation_record * from{ nullptr };
#ifndef BOOST_ASSERT_IS_VOID
bool caught{ false };
#endif
explicit forced_unwind( fiber_activation_record * from_) :
from{ from_ } {
}
#ifndef BOOST_ASSERT_IS_VOID
~forced_unwind() {
BOOST_ASSERT( caught);
}
#endif
};
template< typename Ctx, typename StackAlloc, typename Fn >
@@ -238,9 +229,6 @@ public:
#endif
} catch ( forced_unwind const& ex) {
c = Ctx{ ex.from };
#ifndef BOOST_ASSERT_IS_VOID
const_cast< forced_unwind & >( ex).caught = true;
#endif
}
// this context has finished its task
from = nullptr;
@@ -410,7 +398,9 @@ public:
bool operator<( fiber const& other) const noexcept {
return ptr_ < other.ptr_;
}
#if !defined(BOOST_EMBTC)
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) {
@@ -421,11 +411,33 @@ public:
}
}
#else
template< typename charT, class traitsT >
friend std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other);
#endif
void swap( fiber & other) noexcept {
std::swap( ptr_, other.ptr_);
}
};
#if defined(BOOST_EMBTC)
template< typename charT, class traitsT >
inline std::basic_ostream< charT, traitsT > &
operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) {
if ( nullptr != other.ptr_) {
return os << other.ptr_;
} else {
return os << "{not-a-context}";
}
}
#endif
inline
void swap( fiber & l, fiber & r) noexcept {
l.swap( r);

View File

@@ -18,6 +18,12 @@
#include <boost/context/stack_context.hpp>
#include <boost/context/stack_traits.hpp>
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
extern "C" {
#include <sys/mman.h>
}
#endif
#if defined(BOOST_USE_VALGRIND)
#include <valgrind/valgrind.h>
#endif
@@ -42,10 +48,17 @@ public:
}
stack_context allocate() {
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
void * vp = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
if ( vp == MAP_FAILED) {
throw std::bad_alloc();
}
#else
void * vp = std::malloc( size_);
if ( ! vp) {
throw std::bad_alloc();
}
#endif
stack_context sctx;
sctx.size = size_;
sctx.sp = static_cast< char * >( vp) + sctx.size;
@@ -62,7 +75,11 @@ public:
VALGRIND_STACK_DEREGISTER( sctx.valgrind_stack_id);
#endif
void * vp = static_cast< char * >( sctx.sp) - sctx.size;
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
::munmap( vp, sctx.size);
#else
std::free( vp);
#endif
}
};

View File

@@ -21,6 +21,13 @@
#include <boost/context/stack_context.hpp>
#include <boost/context/stack_traits.hpp>
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
extern "C" {
#include <sys/mman.h>
#include <stdlib.h>
}
#endif
#if defined(BOOST_USE_VALGRIND)
#include <valgrind/valgrind.h>
#endif
@@ -32,6 +39,31 @@
namespace boost {
namespace context {
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
namespace detail {
template< typename traitsT >
struct map_stack_allocator {
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
static char * malloc( const size_type bytes) {
void * block;
if ( ::posix_memalign( &block, traitsT::page_size(), bytes) != 0) {
return 0;
}
if ( mmap( block, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_STACK, -1, 0) == MAP_FAILED) {
std::free( block);
return 0;
}
return reinterpret_cast< char * >( block);
}
static void free( char * const block) {
std::free( block);
}
};
}
#endif
template< typename traitsT >
class basic_pooled_fixedsize_stack {
private:
@@ -39,7 +71,11 @@ private:
private:
std::atomic< std::size_t > use_count_;
std::size_t stack_size_;
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
boost::pool< detail::map_stack_allocator< traitsT > > storage_;
#else
boost::pool< boost::default_user_allocator_malloc_free > storage_;
#endif
public:
storage( std::size_t stack_size, std::size_t next_size, std::size_t max_size) :

View File

@@ -20,6 +20,7 @@ extern "C" {
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/context/detail/config.hpp>
#include <boost/context/stack_context.hpp>
@@ -50,15 +51,13 @@ public:
stack_context allocate() {
// calculate how many pages are required
const std::size_t pages(
static_cast< std::size_t >(
std::ceil(
static_cast< float >( size_) / traits_type::page_size() ) ) );
const std::size_t pages = (size_ + traits_type::page_size() - 1) / traits_type::page_size();
// add one page at bottom that will be used as guard-page
const std::size_t size__ = ( pages + 1) * traits_type::page_size();
// conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L)
#if defined(MAP_ANON)
#if defined(BOOST_CONTEXT_USE_MAP_STACK)
void * vp = ::mmap( 0, size__, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
#elif defined(MAP_ANON)
void * vp = ::mmap( 0, size__, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
#else
void * vp = ::mmap( 0, size__, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -66,12 +65,9 @@ public:
if ( MAP_FAILED == vp) throw std::bad_alloc();
// conforming to POSIX.1-2001
#if defined(BOOST_DISABLE_ASSERTS)
::mprotect( vp, traits_type::page_size(), PROT_NONE);
#else
const int result( ::mprotect( vp, traits_type::page_size(), PROT_NONE) );
boost::ignore_unused(result);
BOOST_ASSERT( 0 == result);
#endif
stack_context sctx;
sctx.size = size__;

View File

@@ -21,7 +21,7 @@ namespace boost {
namespace context {
#if ! defined(BOOST_CONTEXT_NO_CXX11)
struct stack_context {
struct BOOST_CONTEXT_DECL stack_context {
# if defined(BOOST_USE_SEGMENTED_STACKS)
typedef void * segments_context[BOOST_CONTEXT_SEGMENTS];
# endif
@@ -36,7 +36,7 @@ struct stack_context {
# endif
};
#else
struct stack_context {
struct BOOST_CONTEXT_DECL stack_context {
# if defined(BOOST_USE_SEGMENTED_STACKS)
typedef void * segments_context[BOOST_CONTEXT_SEGMENTS];
# endif

View File

@@ -16,6 +16,7 @@ extern "C" {
#include <new>
#include <boost/config.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/context/detail/config.hpp>
#include <boost/context/stack_context.hpp>
@@ -42,10 +43,7 @@ public:
stack_context allocate() {
// calculate how many pages are required
const std::size_t pages(
static_cast< std::size_t >(
std::ceil(
static_cast< float >( size_) / traits_type::page_size() ) ) );
const std::size_t pages = (size_ + traits_type::page_size() - 1) / traits_type::page_size();
// add one page at bottom that will be used as guard-page
const std::size_t size__ = ( pages + 1) * traits_type::page_size();
@@ -53,14 +51,10 @@ public:
if ( ! vp) throw std::bad_alloc();
DWORD old_options;
#if defined(BOOST_DISABLE_ASSERTS)
::VirtualProtect(
vp, traits_type::page_size(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options);
#else
const BOOL result = ::VirtualProtect(
vp, traits_type::page_size(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options);
boost::ignore_unused(result);
BOOST_ASSERT( FALSE != result);
#endif
stack_context sctx;
sctx.size = size__;

View File

@@ -11,5 +11,6 @@
],
"maintainers": [
"Oliver Kowalke <oliver.kowalke -at- gmail.com>"
]
],
"cxxstd": "11"
}

View File

@@ -18,8 +18,8 @@ project boost/context/performance/callcc
<library>/boost/chrono//boost_chrono
<library>/boost/context//boost_context
<library>/boost/program_options//boost_program_options
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<target-os>linux,<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<target-os>linux,<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>static

View File

@@ -1,34 +0,0 @@
# Copyright Oliver Kowalke 2009.
# 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)
# For more information, see http://www.boost.org/
import common ;
import feature ;
import indirect ;
import modules ;
import os ;
import toolset ;
project boost/context/performance/execution_context_v2
: requirements
<library>/boost/chrono//boost_chrono
<library>/boost/context//boost_context
<library>/boost/program_options//boost_program_options
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>static
<optimization>speed
<threading>multi
<variant>release
<cxxflags>-DBOOST_DISABLE_ASSERTS
;
exe performance
: performance.cpp
;

View File

@@ -1,100 +0,0 @@
// Copyright Oliver Kowalke 2009.
// 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)
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <boost/context/execution_context.hpp>
#include <boost/cstdint.hpp>
#include <boost/program_options.hpp>
#include "../clock.hpp"
#include "../cycle.hpp"
boost::uint64_t jobs = 1000000;
static boost::context::execution_context< void > foo( boost::context::execution_context< void > && ctx) {
while ( true) {
ctx = ctx();
}
return std::move( ctx);
}
duration_type measure_time() {
// cache warum-up
boost::context::execution_context< void > ctx( foo);
ctx = ctx();
time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) {
ctx = ctx();
}
duration_type total = clock_type::now() - start;
total -= overhead_clock(); // overhead of measurement
total /= jobs; // loops
total /= 2; // 2x jump_fcontext
return total;
}
#ifdef BOOST_CONTEXT_CYCLE
cycle_type measure_cycles() {
// cache warum-up
boost::context::fixedsize_stack alloc;
boost::context::execution_context< void > ctx( std::allocator_arg, alloc, foo);
ctx = ctx();
cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) {
ctx = ctx();
}
cycle_type total = cycles() - start;
total -= overhead_cycle(); // overhead of measurement
total /= jobs; // loops
total /= 2; // 2x jump_fcontext
return total;
}
#endif
int main( int argc, char * argv[]) {
try {
boost::program_options::options_description desc("allowed options");
desc.add_options()
("help", "help message")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm;
boost::program_options::store(
boost::program_options::parse_command_line(
argc,
argv,
desc),
vm);
boost::program_options::notify( vm);
if ( vm.count("help") ) {
std::cout << desc << std::endl;
return EXIT_SUCCESS;
}
boost::uint64_t res = measure_time().count();
std::cout << "execution_context: average of " << res << " nano seconds" << std::endl;
#ifdef BOOST_CONTEXT_CYCLE
res = measure_cycles();
std::cout << "execution_context: average of " << res << " cpu cycles" << std::endl;
#endif
return EXIT_SUCCESS;
} catch ( std::exception const& e) {
std::cerr << "exception: " << e.what() << std::endl;
} catch (...) {
std::cerr << "unhandled exception" << std::endl;
}
return EXIT_FAILURE;
}

View File

@@ -18,8 +18,8 @@ project boost/context/performance/fcontext
<library>/boost/chrono//boost_chrono
<library>/boost/context//boost_context
<library>/boost/program_options//boost_program_options
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<target-os>linux,<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<target-os>linux,<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>static

View File

@@ -18,8 +18,8 @@ project boost/context/performance/fiber
<library>/boost/chrono//boost_chrono
<library>/boost/context//boost_context
<library>/boost/program_options//boost_program_options
<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<target-os>linux,<toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
<target-os>linux,<toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
<toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
<link>static

View File

@@ -43,6 +43,7 @@
.globl jump_fcontext
.align 2
.type jump_fcontext,%function
.syntax unified
jump_fcontext:
@ save LR as PC
push {lr}

View File

@@ -15,6 +15,10 @@
#include "jump_ppc32_sysv_macho_gas.S"
#elif defined(__ppc64__)
#include "jump_ppc64_sysv_macho_gas.S"
#elif defined(__arm__)
#include "jump_arm_aapcs_macho_gas.S"
#elif defined(__arm64__)
#include "jump_arm64_aapcs_macho_gas.S"
#else
#error "No arch's"
#endif

View File

@@ -0,0 +1,123 @@
/*
Copyright Oliver Kowalke 2009.
Copyright Thomas Sailer 2013.
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)
*/
/*************************************************************************************
* --------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* --------------------------------------------------------------------------------- *
* | 0h | 04h | 08h | 0ch | 010h | 014h | 018h | 01ch | *
* --------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| fc_strg |fc_deallo| limit | base | fc_seh | EDI | *
* --------------------------------------------------------------------------------- *
* --------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* --------------------------------------------------------------------------------- *
* | 020h | 024h | 028h | 02ch | 030h | 034h | 038h | 03ch | *
* --------------------------------------------------------------------------------- *
* | ESI | EBX | EBP | EIP | to | data | EH NXT |SEH HNDLR| *
* --------------------------------------------------------------------------------- *
**************************************************************************************/
.file "jump_i386_ms_pe_clang_gas.S"
.text
.p2align 4,,15
/* mark as using no unregistered SEH handlers */
.globl @feat.00
.def @feat.00; .scl 3; .type 0; .endef
.set @feat.00, 1
.globl _jump_fcontext
.def _jump_fcontext; .scl 2; .type 32; .endef
_jump_fcontext:
/* prepare stack */
leal -0x2c(%esp), %esp
#if !defined(BOOST_USE_TSX)
/* save MMX control- and status-word */
stmxcsr (%esp)
/* save x87 control-word */
fnstcw 0x4(%esp)
#endif
/* load NT_TIB */
movl %fs:(0x18), %edx
/* load fiber local storage */
movl 0x10(%edx), %eax
movl %eax, 0x8(%esp)
/* load current dealloction stack */
movl 0xe0c(%edx), %eax
movl %eax, 0xc(%esp)
/* load current stack limit */
movl 0x8(%edx), %eax
movl %eax, 0x10(%esp)
/* load current stack base */
movl 0x4(%edx), %eax
movl %eax, 0x14(%esp)
/* load current SEH exception list */
movl (%edx), %eax
movl %eax, 0x18(%esp)
movl %edi, 0x1c(%esp) /* save EDI */
movl %esi, 0x20(%esp) /* save ESI */
movl %ebx, 0x24(%esp) /* save EBX */
movl %ebp, 0x28(%esp) /* save EBP */
/* store ESP (pointing to context-data) in EAX */
movl %esp, %eax
/* firstarg of jump_fcontext() == fcontext to jump to */
movl 0x30(%esp), %ecx
/* restore ESP (pointing to context-data) from ECX */
movl %ecx, %esp
#if !defined(BOOST_USE_TSX)
/* restore MMX control- and status-word */
ldmxcsr (%esp)
/* restore x87 control-word */
fldcw 0x4(%esp)
#endif
/* restore NT_TIB into EDX */
movl %fs:(0x18), %edx
/* restore fiber local storage */
movl 0x8(%esp), %ecx
movl %ecx, 0x10(%edx)
/* restore current deallocation stack */
movl 0xc(%esp), %ecx
movl %ecx, 0xe0c(%edx)
/* restore current stack limit */
movl 0x10(%esp), %ecx
movl %ecx, 0x8(%edx)
/* restore current stack base */
movl 0x14(%esp), %ecx
movl %ecx, 0x4(%edx)
/* restore current SEH exception list */
movl 0x18(%esp), %ecx
movl %ecx, (%edx)
movl 0x2c(%esp), %ecx /* restore EIP */
movl 0x1c(%esp), %edi /* restore EDI */
movl 0x20(%esp), %esi /* restore ESI */
movl 0x24(%esp), %ebx /* restore EBX */
movl 0x28(%esp), %ebp /* restore EBP */
/* prepare stack */
leal 0x30(%esp), %esp
/* return transfer_t */
/* FCTX == EAX, DATA == EDX */
movl 0x34(%eax), %edx
/* jump to context */
jmp *%ecx
.section .drectve
.ascii " -export:\"_jump_fcontext\""

View File

@@ -26,6 +26,12 @@
.file "jump_i386_ms_pe_gas.asm"
.text
.p2align 4,,15
/* mark as using no unregistered SEH handlers */
.globl @feat.00
.def @feat.00; .scl 3; .type 0; .endef
.set @feat.00, 1
.globl _jump_fcontext
.def _jump_fcontext; .scl 2; .type 32; .endef
_jump_fcontext:

View File

@@ -54,9 +54,8 @@ _jump_fcontext:
/* return parent fcontext_t */
movl %ecx, %eax
/* returned data is stored in EDX */
movl %edx, 0x4(%eax)
/* returned data is stored in EDX */
movl 0x18(%esp), %ecx /* restore EIP */
#if !defined(BOOST_USE_TSX)

View File

@@ -48,7 +48,7 @@
.file "jump_mips64_n64_elf_gas.S"
.text
.globl jump_fcontext
.align 2
.align 3
.type jump_fcontext,@function
.ent jump_fcontext
jump_fcontext:
@@ -67,7 +67,7 @@ jump_fcontext:
sd $ra, 144($sp) # save RA
sd $ra, 152($sp) # save RA as PC
#if defined(__mips_hard_float)
s.d $f24, 0($sp) # save F24
s.d $f25, 8($sp) # save F25
s.d $f26, 16($sp) # save F26
@@ -76,6 +76,7 @@ jump_fcontext:
s.d $f29, 40($sp) # save F29
s.d $f30, 48($sp) # save F30
s.d $f31, 56($sp) # save F31
#endif
# store SP (pointing to old context-data) in v0 as return
move $v0, $sp
@@ -83,6 +84,7 @@ jump_fcontext:
# get SP (pointing to new context-data) from a0 param
move $sp, $a0
#if defined(__mips_hard_float)
l.d $f24, 0($sp) # restore F24
l.d $f25, 8($sp) # restore F25
l.d $f26, 16($sp) # restore F26
@@ -91,6 +93,7 @@ jump_fcontext:
l.d $f29, 40($sp) # restore F29
l.d $f30, 48($sp) # restore F30
l.d $f31, 56($sp) # restore F31
#endif
ld $s0, 64($sp) # restore S0
ld $s1, 72($sp) # restore S1

View File

@@ -5,71 +5,48 @@
http://www.boost.org/LICENSE_1_0.txt)
*/
/******************************************************
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
* ------------------------------------------------- *
* |bchai|hiddn| fpscr | PC | CR | R14 | R15 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* ------------------------------------------------- *
* | R16 | R17 | R18 | R19 | R20 | R21 | R22 | R23 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* ------------------------------------------------- *
* | R24 | R25 | R26 | R27 | R28 | R29 | R30 | R31 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* ------------------------------------------------- *
* | F14 | F15 | F16 | F17 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
* | F18 | F19 | F20 | F21 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
* ------------------------------------------------- *
* | F22 | F23 | F24 | F25 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
* ------------------------------------------------- *
* | F26 | F27 | F28 | F29 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
* | F30 | F31 | fpscr | R13 | R14 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
* ------------------------------------------------- *
* | R15 | R16 | R17 | R18 | R19 | R20 | R21 | R22 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | *
* ------------------------------------------------- *
* | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
* ------------------------------------------------- *
* | R23 | R24 | R25 | R26 | R27 | R28 | R29 | R30 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | *
* ------------------------------------------------- *
* | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | *
* ------------------------------------------------- *
* | R31 |hiddn| CR | LR | PC |bchai|linkr| FCTX| *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 64 | | *
* ------------------------------------------------- *
* | 256 | | *
* ------------------------------------------------- *
* | DATA| | *
* ------------------------------------------------- *
* ------------------------|------------ *
* | 224 | 228 | 232 | 236 | 240 | 244 | *
* ------------------------|------------ *
* | F30 | F31 |bchai| LR | *
* ------------------------|------------ *
* *
*******************************************************/
@@ -79,125 +56,142 @@
.align 2
.type jump_fcontext,@function
jump_fcontext:
# reserve space on stack
subi %r1, %r1, 244
# Linux: jump_fcontext( hidden transfer_t * R3, R4, R5)
# Other: transfer_t R3:R4 = jump_fcontext( R3, R4)
stfd %f14, 0(%r1) # save F14
stfd %f15, 8(%r1) # save F15
stfd %f16, 16(%r1) # save F16
stfd %f17, 24(%r1) # save F17
stfd %f18, 32(%r1) # save F18
stfd %f19, 40(%r1) # save F19
stfd %f20, 48(%r1) # save F20
stfd %f21, 56(%r1) # save F21
stfd %f22, 64(%r1) # save F22
stfd %f23, 72(%r1) # save F23
stfd %f24, 80(%r1) # save F24
stfd %f25, 88(%r1) # save F25
stfd %f26, 96(%r1) # save F26
stfd %f27, 104(%r1) # save F27
stfd %f28, 112(%r1) # save F28
stfd %f29, 120(%r1) # save F29
stfd %f30, 128(%r1) # save F30
stfd %f31, 136(%r1) # save F31
mffs %f0 # load FPSCR
stfd %f0, 144(%r1) # save FPSCR
mflr %r0 # return address from LR
mffs %f0 # FPSCR
mfcr %r8 # condition register
stw %r13, 152(%r1) # save R13
stw %r14, 156(%r1) # save R14
stw %r15, 160(%r1) # save R15
stw %r16, 164(%r1) # save R16
stw %r17, 168(%r1) # save R17
stw %r18, 172(%r1) # save R18
stw %r19, 176(%r1) # save R19
stw %r20, 180(%r1) # save R20
stw %r21, 184(%r1) # save R21
stw %r22, 188(%r1) # save R22
stw %r23, 192(%r1) # save R23
stw %r24, 196(%r1) # save R24
stw %r25, 200(%r1) # save R25
stw %r26, 204(%r1) # save R26
stw %r27, 208(%r1) # save R27
stw %r28, 212(%r1) # save R28
stw %r29, 216(%r1) # save R29
stw %r30, 220(%r1) # save R30
stw %r31, 224(%r1) # save R31
stw %r3, 228(%r1) # save hidden
stwu %r1, -240(%r1) # allocate stack space, R1 % 16 == 0
stw %r0, 244(%r1) # save LR in caller's frame
# save CR
mfcr %r0
stw %r0, 232(%r1)
# save LR
mflr %r0
stw %r0, 236(%r1)
# save LR as PC
stw %r0, 240(%r1)
#ifdef __linux__
stw %r3, 4(%r1) # hidden pointer
#endif
# store RSP (pointing to context-data) in R6
mr %r6, %r1
stfd %f0, 8(%r1) # FPSCR
stw %r0, 16(%r1) # LR as PC
stw %r8, 20(%r1) # CR
# restore RSP (pointing to context-data) from R4
mr %r1, %r4
# Save registers R14 to R31.
# Don't change R2, the thread-local storage pointer.
# Don't change R13, the small data pointer.
stw %r14, 24(%r1)
stw %r15, 28(%r1)
stw %r16, 32(%r1)
stw %r17, 36(%r1)
stw %r18, 40(%r1)
stw %r19, 44(%r1)
stw %r20, 48(%r1)
stw %r21, 52(%r1)
stw %r22, 56(%r1)
stw %r23, 60(%r1)
stw %r24, 64(%r1)
stw %r25, 68(%r1)
stw %r26, 72(%r1)
stw %r27, 76(%r1)
stw %r28, 80(%r1)
stw %r29, 84(%r1)
stw %r30, 88(%r1)
stw %r31, 92(%r1)
lfd %f14, 0(%r1) # restore F14
lfd %f15, 8(%r1) # restore F15
lfd %f16, 16(%r1) # restore F16
lfd %f17, 24(%r1) # restore F17
lfd %f18, 32(%r1) # restore F18
lfd %f19, 40(%r1) # restore F19
lfd %f20, 48(%r1) # restore F20
lfd %f21, 56(%r1) # restore F21
lfd %f22, 64(%r1) # restore F22
lfd %f23, 72(%r1) # restore F23
lfd %f24, 80(%r1) # restore F24
lfd %f25, 88(%r1) # restore F25
lfd %f26, 96(%r1) # restore F26
lfd %f27, 104(%r1) # restore F27
lfd %f28, 112(%r1) # restore F28
lfd %f29, 120(%r1) # restore F29
lfd %f30, 128(%r1) # restore F30
lfd %f31, 136(%r1) # restore F31
lfd %f0, 144(%r1) # load FPSCR
mtfsf 0xff, %f0 # restore FPSCR
# Save registers F14 to F31 in slots with 8-byte alignment.
# 4-byte alignment may stall the pipeline of some processors.
# Less than 4 may cause alignment traps.
stfd %f14, 96(%r1)
stfd %f15, 104(%r1)
stfd %f16, 112(%r1)
stfd %f17, 120(%r1)
stfd %f18, 128(%r1)
stfd %f19, 136(%r1)
stfd %f20, 144(%r1)
stfd %f21, 152(%r1)
stfd %f22, 160(%r1)
stfd %f23, 168(%r1)
stfd %f24, 176(%r1)
stfd %f25, 184(%r1)
stfd %f26, 192(%r1)
stfd %f27, 200(%r1)
stfd %f28, 208(%r1)
stfd %f29, 216(%r1)
stfd %f30, 224(%r1)
stfd %f31, 232(%r1)
lwz %r13, 152(%r1) # restore R13
lwz %r14, 156(%r1) # restore R14
lwz %r15, 160(%r1) # restore R15
lwz %r16, 164(%r1) # restore R16
lwz %r17, 168(%r1) # restore R17
lwz %r18, 172(%r1) # restore R18
lwz %r19, 176(%r1) # restore R19
lwz %r20, 180(%r1) # restore R20
lwz %r21, 184(%r1) # restore R21
lwz %r22, 188(%r1) # restore R22
lwz %r23, 192(%r1) # restore R23
lwz %r24, 196(%r1) # restore R24
lwz %r25, 200(%r1) # restore R25
lwz %r26, 204(%r1) # restore R26
lwz %r27, 208(%r1) # restore R27
lwz %r28, 212(%r1) # restore R28
lwz %r29, 216(%r1) # restore R29
lwz %r30, 220(%r1) # restore R30
lwz %r31, 224(%r1) # restore R31
lwz %r3, 228(%r1) # restore hidden
# store RSP (pointing to context-data) in R7/R6
# restore RSP (pointing to context-data) from R4/R3
#ifdef __linux__
mr %r7, %r1
mr %r1, %r4
lwz %r3, 4(%r1) # hidden pointer
#else
mr %r6, %r1
mr %r1, %r3
#endif
# restore CR
lwz %r0, 232(%r1)
mtcr %r0
# restore LR
lwz %r0, 236(%r1)
lfd %f0, 8(%r1) # FPSCR
lwz %r0, 16(%r1) # PC
lwz %r8, 20(%r1) # CR
mtfsf 0xff, %f0 # restore FPSCR
mtctr %r0 # load CTR with PC
mtcr %r8 # restore CR
# restore R14 to R31
lwz %r14, 24(%r1)
lwz %r15, 28(%r1)
lwz %r16, 32(%r1)
lwz %r17, 36(%r1)
lwz %r18, 40(%r1)
lwz %r19, 44(%r1)
lwz %r20, 48(%r1)
lwz %r21, 52(%r1)
lwz %r22, 56(%r1)
lwz %r23, 60(%r1)
lwz %r24, 64(%r1)
lwz %r25, 68(%r1)
lwz %r26, 72(%r1)
lwz %r27, 76(%r1)
lwz %r28, 80(%r1)
lwz %r29, 84(%r1)
lwz %r30, 88(%r1)
lwz %r31, 92(%r1)
# restore F14 to F31
lfd %f14, 96(%r1)
lfd %f15, 104(%r1)
lfd %f16, 112(%r1)
lfd %f17, 120(%r1)
lfd %f18, 128(%r1)
lfd %f19, 136(%r1)
lfd %f20, 144(%r1)
lfd %f21, 152(%r1)
lfd %f22, 160(%r1)
lfd %f23, 168(%r1)
lfd %f24, 176(%r1)
lfd %f25, 184(%r1)
lfd %f26, 192(%r1)
lfd %f27, 200(%r1)
lfd %f28, 208(%r1)
lfd %f29, 216(%r1)
lfd %f30, 224(%r1)
lfd %f31, 232(%r1)
# restore LR from caller's frame
lwz %r0, 244(%r1)
mtlr %r0
# load PC
lwz %r0, 240(%r1)
# restore CTR
mtctr %r0
# adjust stack
addi %r1, %r1, 244
addi %r1, %r1, 240
# return transfer_t
stw %r6, 0(%r3)
# return transfer_t
#ifdef __linux__
stw %r7, 0(%r3)
stw %r5, 4(%r3)
#else
mr %r3, %r6
# %r4, %r4
#endif
# jump to context
bctr

View File

@@ -0,0 +1,150 @@
/*
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)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| *
* ------------------------------------------------- *
* | fs0 | fs1 | fs2 | fs3 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| *
* ------------------------------------------------- *
* | fs4 | fs5 | fs6 | fs7 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| *
* ------------------------------------------------- *
* | fs8 | fs9 | fs10 | fs11 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| *
* ------------------------------------------------- *
* | s0 | s1 | s2 | s3 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| *
* ------------------------------------------------- *
* | s4 | s5 | s6 | s7 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 0xa0| 0xa4| 0xa8| 0xac| 0xb0| 0xb4| 0xb8| 0xbc| *
* ------------------------------------------------- *
* | s8 | s9 | s10 | s11 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 48 | 49 | 50 | 51 | | | | | *
* ------------------------------------------------- *
* | 0xc0| 0xc4| 0xc8| 0xcc| | | | | *
* ------------------------------------------------- *
* | ra | pc | | | *
* ------------------------------------------------- *
* *
*******************************************************/
.file "jump_riscv64_sysv_elf_gas.S"
.text
.align 1
.global jump_fcontext
.type jump_fcontext, %function
jump_fcontext:
# prepare stack for GP + FPU
addi sp, sp, -0xd0
# save fs0 - fs11
fsd fs0, 0x00(sp)
fsd fs1, 0x08(sp)
fsd fs2, 0x10(sp)
fsd fs3, 0x18(sp)
fsd fs4, 0x20(sp)
fsd fs5, 0x28(sp)
fsd fs6, 0x30(sp)
fsd fs7, 0x38(sp)
fsd fs8, 0x40(sp)
fsd fs9, 0x48(sp)
fsd fs10, 0x50(sp)
fsd fs11, 0x58(sp)
# save s0-s11, ra
sd s0, 0x60(sp)
sd s1, 0x68(sp)
sd s2, 0x70(sp)
sd s3, 0x78(sp)
sd s4, 0x80(sp)
sd s5, 0x88(sp)
sd s6, 0x90(sp)
sd s7, 0x98(sp)
sd s8, 0xa0(sp)
sd s9, 0xa8(sp)
sd s10, 0xb0(sp)
sd s11, 0xb8(sp)
sd ra, 0xc0(sp)
# save RA as PC
sd ra, 0xc8(sp)
# store SP (pointing to context-data) in A2
mv a2, sp
# restore SP (pointing to context-data) from A0
mv sp, a0
# load fs0 - fs11
fld fs0, 0x00(sp)
fld fs1, 0x08(sp)
fld fs2, 0x10(sp)
fld fs3, 0x18(sp)
fld fs4, 0x20(sp)
fld fs5, 0x28(sp)
fld fs6, 0x30(sp)
fld fs7, 0x38(sp)
fld fs8, 0x40(sp)
fld fs9, 0x48(sp)
fld fs10, 0x50(sp)
fld fs11, 0x58(sp)
# load s0-s11,ra
ld s0, 0x60(sp)
ld s1, 0x68(sp)
ld s2, 0x70(sp)
ld s3, 0x78(sp)
ld s4, 0x80(sp)
ld s5, 0x88(sp)
ld s6, 0x90(sp)
ld s7, 0x98(sp)
ld s8, 0xa0(sp)
ld s9, 0xa8(sp)
ld s10, 0xb0(sp)
ld s11, 0xb8(sp)
ld ra, 0xc0(sp)
# return transfer_t from jump
# pass transfer_t as first arg in context function
# a0 == FCTX, a1 == DATA
mv a0, a2
# load pc
ld a2, 0xc8(sp)
# restore stack from GP + FPU
addi sp, sp, 0xd0
jr a2
.size jump_fcontext,.-jump_fcontext
# Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits

View File

@@ -0,0 +1,156 @@
/*******************************************************
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0 | 8 | 16 | 24 | *
* ------------------------------------------------- *
* | t.fctx | t.data | r2 | r6 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 40 | 48 | 56 | *
* ------------------------------------------------- *
* | r7 | r8 | r9 | r10 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 72 | 80 | 88 | *
* ------------------------------------------------- *
* | r11 | r12 | r13 | r14 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 104 | 112 | 120 | *
* ------------------------------------------------- *
* | f8 | f9 | f10 | f11 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 128 | 136 | 144 | 152 | *
* ------------------------------------------------- *
* | f12 | f13 | f14 | f15 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 160 | 168 | 176 | | *
* ------------------------------------------------- *
* | fpc | pc | | | *
* ------------------------------------------------- *
*******************************************************/
.text
.align 8
.global jump_fcontext
.type jump_fcontext, @function
#define ARG_OFFSET 0
#define GR_OFFSET 16
#define FP_OFFSET 96
#define FPC_OFFSET 160
#define PC_OFFSET 168
#define CONTEXT_SIZE 176
#define REG_SAVE_AREA_SIZE 160
/*
typedef void* fcontext_t;
struct transfer_t {
fcontext_t fctx;
void * data;
};
transfer_t jump_fcontext( fcontext_t const to,
void * data);
Incoming args
r2 - Hidden argument to the location where the return transfer_t needs to be returned
r3 - Context we want to switch to
r4 - Data pointer
*/
jump_fcontext:
.machine "z10"
/* Reserve stack space to store the current context. */
aghi %r15,-CONTEXT_SIZE
/* Save the argument register holding the location of the return value. */
stg %r2,GR_OFFSET(%r15)
/* Save the call-saved general purpose registers. */
stmg %r6,%r14,GR_OFFSET+8(%r15)
/* Save call-saved floating point registers. */
std %f8,FP_OFFSET(%r15)
std %f9,FP_OFFSET+8(%r15)
std %f10,FP_OFFSET+16(%r15)
std %f11,FP_OFFSET+24(%r15)
std %f12,FP_OFFSET+32(%r15)
std %f13,FP_OFFSET+40(%r15)
std %f14,FP_OFFSET+48(%r15)
std %f15,FP_OFFSET+56(%r15)
/* Save the return address as current pc. */
stg %r14,PC_OFFSET(%r15)
/* Save the floating point control register. */
stfpc FPC_OFFSET(%r15)
/* Backup the stack pointer pointing to the old context-data into r1. */
lgr %r1,%r15
/* Load the new context pointer as stack pointer. */
lgr %r15,%r3
/* Restore the call-saved GPRs from the new context. */
lmg %r6,%r14,GR_OFFSET+8(%r15)
/* Restore call-saved floating point registers. */
ld %f8,FP_OFFSET(%r15)
ld %f9,FP_OFFSET+8(%r15)
ld %f10,FP_OFFSET+16(%r15)
ld %f11,FP_OFFSET+24(%r15)
ld %f12,FP_OFFSET+32(%r15)
ld %f13,FP_OFFSET+40(%r15)
ld %f14,FP_OFFSET+48(%r15)
ld %f15,FP_OFFSET+56(%r15)
/* Load the floating point control register. */
lfpc FPC_OFFSET(%r15)
/* Restore PC - the location where we will jump to at the end. */
lg %r5,PC_OFFSET(%r15)
ltg %r2,GR_OFFSET(%r15)
jnz use_return_slot
/* We restore a make_fcontext context. Use the function
argument slot in the context we just saved and allocate the
register save area for the target function. */
la %r2,ARG_OFFSET(%r1)
aghi %r15,-REG_SAVE_AREA_SIZE
use_return_slot:
/* Save the two fields in transfer_t. When calling a
make_fcontext function this becomes the function argument of
the target function, otherwise it will be the return value of
jump_fcontext. */
stg %r1,0(%r2)
stg %r4,8(%r2)
/* Free the restored context. */
aghi %r15,CONTEXT_SIZE
/* Jump to the PC loaded from the new context. */
br %r5
.size jump_fcontext,.-jump_fcontext
.section .note.GNU-stack,"",%progbits

View File

@@ -0,0 +1,209 @@
/*
Copyright Oliver Kowalke 2009.
Copyright Thomas Sailer 2013.
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)
*/
/*************************************************************************************
* ---------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
* | SEE registers (XMM6-XMM15) | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | *
* ---------------------------------------------------------------------------------- *
* | SEE registers (XMM6-XMM15) | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ---------------------------------------------------------------------------------- *
* | 0xe40 | 0x44 | 0x48 | 0x4c | 0x50 | 0x54 | 0x58 | 0x5c | *
* ---------------------------------------------------------------------------------- *
* | SEE registers (XMM6-XMM15) | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ---------------------------------------------------------------------------------- *
* | 0x60 | 0x64 | 0x68 | 0x6c | 0x70 | 0x74 | 0x78 | 0x7c | *
* ---------------------------------------------------------------------------------- *
* | SEE registers (XMM6-XMM15) | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 32 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | *
* ---------------------------------------------------------------------------------- *
* | 0x80 | 0x84 | 0x88 | 0x8c | 0x90 | 0x94 | 0x98 | 0x9c | *
* ---------------------------------------------------------------------------------- *
* | SEE registers (XMM6-XMM15) | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | *
* ---------------------------------------------------------------------------------- *
* | 0xa0 | 0xa4 | 0xa8 | 0xac | 0xb0 | 0xb4 | 0xb8 | 0xbc | *
* ---------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| <alignment> | fbr_strg | fc_dealloc | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | *
* ---------------------------------------------------------------------------------- *
* | 0xc0 | 0xc4 | 0xc8 | 0xcc | 0xd0 | 0xd4 | 0xd8 | 0xdc | *
* ---------------------------------------------------------------------------------- *
* | limit | base | R12 | R13 | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | *
* ---------------------------------------------------------------------------------- *
* | 0xe0 | 0xe4 | 0xe8 | 0xec | 0xf0 | 0xf4 | 0xf8 | 0xfc | *
* ---------------------------------------------------------------------------------- *
* | R14 | R15 | RDI | RSI | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | *
* ---------------------------------------------------------------------------------- *
* | 0x100 | 0x104 | 0x108 | 0x10c | 0x110 | 0x114 | 0x118 | 0x11c | *
* ---------------------------------------------------------------------------------- *
* | RBX | RBP | hidden | RIP | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | *
* ---------------------------------------------------------------------------------- *
* | 0x120 | 0x124 | 0x128 | 0x12c | 0x130 | 0x134 | 0x138 | 0x13c | *
* ---------------------------------------------------------------------------------- *
* | parameter area | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | *
* ---------------------------------------------------------------------------------- *
* | 0x140 | 0x144 | 0x148 | 0x14c | 0x150 | 0x154 | 0x158 | 0x15c | *
* ---------------------------------------------------------------------------------- *
* | FCTX | DATA | | *
* ---------------------------------------------------------------------------------- *
**************************************************************************************/
.file "jump_x86_64_ms_pe_clang_gas.S"
.text
.p2align 4,,15
.globl jump_fcontext
.def jump_fcontext; .scl 2; .type 32; .endef
.seh_proc jump_fcontext
jump_fcontext:
.seh_endprologue
leaq -0x118(%rsp), %rsp /* prepare stack */
#if !defined(BOOST_USE_TSX)
/* save XMM storage */
movaps %xmm6, 0x0(%rsp)
movaps %xmm7, 0x10(%rsp)
movaps %xmm8, 0x20(%rsp)
movaps %xmm9, 0x30(%rsp)
movaps %xmm10, 0x40(%rsp)
movaps %xmm11, 0x50(%rsp)
movaps %xmm12, 0x60(%rsp)
movaps %xmm13, 0x70(%rsp)
movaps %xmm14, 0x80(%rsp)
movaps %xmm15, 0x90(%rsp)
stmxcsr 0xa0(%rsp) /* save MMX control- and status-word */
fnstcw 0xa4(%rsp) /* save x87 control-word */
#endif
/* load NT_TIB */
movq %gs:(0x30), %r10
/* save fiber local storage */
movq 0x20(%r10), %rax
movq %rax, 0xb0(%rsp)
/* save current deallocation stack */
movq 0x1478(%r10), %rax
movq %rax, 0xb8(%rsp)
/* save current stack limit */
movq 0x10(%r10), %rax
movq %rax, 0xc0(%rsp)
/* save current stack base */
movq 0x08(%r10), %rax
movq %rax, 0xc8(%rsp)
movq %r12, 0xd0(%rsp) /* save R12 */
movq %r13, 0xd8(%rsp) /* save R13 */
movq %r14, 0xe0(%rsp) /* save R14 */
movq %r15, 0xe8(%rsp) /* save R15 */
movq %rdi, 0xf0(%rsp) /* save RDI */
movq %rsi, 0xf8(%rsp) /* save RSI */
movq %rbx, 0x100(%rsp) /* save RBX */
movq %rbp, 0x108(%rsp) /* save RBP */
movq %rcx, 0x110(%rsp) /* save hidden address of transport_t */
/* preserve RSP (pointing to context-data) in R9 */
movq %rsp, %r9
/* restore RSP (pointing to context-data) from RDX */
movq %rdx, %rsp
#if !defined(BOOST_USE_TSX)
/* restore XMM storage */
movaps 0x0(%rsp), %xmm6
movaps 0x10(%rsp), %xmm7
movaps 0x20(%rsp), %xmm8
movaps 0x30(%rsp), %xmm9
movaps 0x40(%rsp), %xmm10
movaps 0x50(%rsp), %xmm11
movaps 0x60(%rsp), %xmm12
movaps 0x70(%rsp), %xmm13
movaps 0x80(%rsp), %xmm14
movaps 0x90(%rsp), %xmm15
ldmxcsr 0xa0(%rsp) /* restore MMX control- and status-word */
fldcw 0xa4(%rsp) /* restore x87 control-word */
#endif
/* load NT_TIB */
movq %gs:(0x30), %r10
/* restore fiber local storage */
movq 0xb0(%rsp), %rax
movq %rax, 0x20(%r10)
/* restore current deallocation stack */
movq 0xb8(%rsp), %rax
movq %rax, 0x1478(%r10)
/* restore current stack limit */
movq 0xc0(%rsp), %rax
movq %rax, 0x10(%r10)
/* restore current stack base */
movq 0xc8(%rsp), %rax
movq %rax, 0x08(%r10)
movq 0xd0(%rsp), %r12 /* restore R12 */
movq 0xd8(%rsp), %r13 /* restore R13 */
movq 0xe0(%rsp), %r14 /* restore R14 */
movq 0xe8(%rsp), %r15 /* restore R15 */
movq 0xf0(%rsp), %rdi /* restore RDI */
movq 0xf8(%rsp), %rsi /* restore RSI */
movq 0x100(%rsp), %rbx /* restore RBX */
movq 0x108(%rsp), %rbp /* restore RBP */
movq 0x110(%rsp), %rax /* restore hidden address of transport_t */
leaq 0x118(%rsp), %rsp /* prepare stack */
/* restore return-address */
popq %r10
/* transport_t returned in RAX */
/* return parent fcontext_t */
movq %r9, 0x0(%rax)
/* return data */
movq %r8, 0x8(%rax)
/* transport_t as 1.arg of context-function */
movq %rax, %rcx
/* indirect jump to context */
jmp *%r10
.seh_endproc
.section .drectve
.ascii " -export:\"jump_fcontext\""

View File

@@ -67,10 +67,20 @@ jump_fcontext:
leaq 0x40(%rsp), %rsp /* prepare stack */
/* return transfer_t from jump */
#if !defined(_ILP32)
/* RAX == fctx, RDX == data */
movq %rsi, %rdx
#else
/* RAX == data:fctx */
salq $32, %rsi
orq %rsi, %rax
#endif
/* pass transfer_t as first arg in context function */
#if !defined(_ILP32)
/* RDI == fctx, RSI == data */
#else
/* RDI == data:fctx */
#endif
movq %rax, %rdi
/* indirect jump to context */

View File

@@ -66,12 +66,7 @@ _make_fcontext:
; store address as a PC to jump in
str x2, [x0, #0xa0]
; compute abs address of label finish
; 0x0c = 3 instructions * size (4) before label 'finish'
; TODO: Numeric offset since llvm still does not support labels in ADR. Fix:
; http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20140407/212336.html
adr x1, 0x0c
adr x1, finish
; save address of finish as return-address for context-function
; will be entered after context-function returns (LR register)

View File

@@ -43,6 +43,7 @@
.globl make_fcontext
.align 2
.type make_fcontext,%function
.syntax unified
make_fcontext:
@ shift address in A1 to lower 16 byte boundary
bic a1, a1, #15

View File

@@ -15,6 +15,10 @@
#include "make_ppc32_sysv_macho_gas.S"
#elif defined(__ppc64__)
#include "make_ppc64_sysv_macho_gas.S"
#elif defined(__arm__)
#include "make_arm_aapcs_macho_gas.S"
#elif defined(__arm64__)
#include "make_arm64_aapcs_macho_gas.S"
#else
#error "No arch's"
#endif

View File

@@ -0,0 +1,153 @@
/*
Copyright Oliver Kowalke 2009.
Copyright Thomas Sailer 2013.
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)
*/
/*************************************************************************************
* --------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* --------------------------------------------------------------------------------- *
* | 0h | 04h | 08h | 0ch | 010h | 014h | 018h | 01ch | *
* --------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| fc_strg |fc_deallo| limit | base | fc_seh | EDI | *
* --------------------------------------------------------------------------------- *
* --------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* --------------------------------------------------------------------------------- *
* | 020h | 024h | 028h | 02ch | 030h | 034h | 038h | 03ch | *
* --------------------------------------------------------------------------------- *
* | ESI | EBX | EBP | EIP | to | data | EH NXT |SEH HNDLR| *
* --------------------------------------------------------------------------------- *
**************************************************************************************/
.file "make_i386_ms_pe_clang_gas.S"
.text
.p2align 4,,15
/* mark as using no unregistered SEH handlers */
.globl @feat.00
.def @feat.00; .scl 3; .type 0; .endef
.set @feat.00, 1
.globl _make_fcontext
.def _make_fcontext; .scl 2; .type 32; .endef
_make_fcontext:
/* first arg of make_fcontext() == top of context-stack */
movl 0x04(%esp), %eax
/* reserve space for first argument of context-function */
/* EAX might already point to a 16byte border */
leal -0x8(%eax), %eax
/* shift address in EAX to lower 16 byte boundary */
andl $-16, %eax
/* reserve space for context-data on context-stack */
/* size for fc_mxcsr .. EIP + return-address for context-function */
/* on context-function entry: (ESP -0x4) % 8 == 0 */
/* additional space is required for SEH */
leal -0x40(%eax), %eax
/* save MMX control- and status-word */
stmxcsr (%eax)
/* save x87 control-word */
fnstcw 0x4(%eax)
/* first arg of make_fcontext() == top of context-stack */
movl 0x4(%esp), %ecx
/* save top address of context stack as 'base' */
movl %ecx, 0x14(%eax)
/* second arg of make_fcontext() == size of context-stack */
movl 0x8(%esp), %edx
/* negate stack size for LEA instruction (== substraction) */
negl %edx
/* compute bottom address of context stack (limit) */
leal (%ecx,%edx), %ecx
/* save bottom address of context-stack as 'limit' */
movl %ecx, 0x10(%eax)
/* save bottom address of context-stack as 'dealloction stack' */
movl %ecx, 0xc(%eax)
/* set fiber-storage to zero */
xorl %ecx, %ecx
movl %ecx, 0x8(%eax)
/* third arg of make_fcontext() == address of context-function */
/* stored in EBX */
movl 0xc(%esp), %ecx
movl %ecx, 0x24(%eax)
/* compute abs address of label trampoline */
movl $trampoline, %ecx
/* save address of trampoline as return-address for context-function */
/* will be entered after calling jump_fcontext() first time */
movl %ecx, 0x2c(%eax)
/* compute abs address of label finish */
movl $finish, %ecx
/* save address of finish as return-address for context-function */
/* will be entered after context-function returns */
movl %ecx, 0x28(%eax)
/* traverse current seh chain to get the last exception handler installed by Windows */
/* note that on Windows Server 2008 and 2008 R2, SEHOP is activated by default */
/* the exception handler chain is tested for the presence of ntdll.dll!FinalExceptionHandler */
/* at its end by RaiseException all seh andlers are disregarded if not present and the */
/* program is aborted */
/* load NT_TIB into ECX */
movl %fs:(0x0), %ecx
walk:
/* load 'next' member of current SEH into EDX */
movl (%ecx), %edx
/* test if 'next' of current SEH is last (== 0xffffffff) */
incl %edx
jz found
decl %edx
/* exchange content; ECX contains address of next SEH */
xchgl %ecx, %edx
/* inspect next SEH */
jmp walk
found:
/* load 'handler' member of SEH == address of last SEH handler installed by Windows */
movl 0x04(%ecx), %ecx
/* save address in ECX as SEH handler for context */
movl %ecx, 0x3c(%eax)
/* set ECX to -1 */
movl $0xffffffff, %ecx
/* save ECX as next SEH item */
movl %ecx, 0x38(%eax)
/* load address of next SEH item */
leal 0x38(%eax), %ecx
/* save next SEH */
movl %ecx, 0x18(%eax)
/* return pointer to context-data */
ret
trampoline:
/* move transport_t for entering context-function */
/* FCTX == EAX, DATA == EDX */
movl %eax, (%esp)
movl %edx, 0x4(%esp)
/* label finish as return-address */
pushl %ebp
/* jump to context-function */
jmp *%ebx
finish:
/* ESP points to same address as ESP on entry of context function + 0x4 */
xorl %eax, %eax
/* exit code is zero */
movl %eax, (%esp)
/* exit application */
call __exit
hlt
.def __exit; .scl 2; .type 32; .endef /* standard C library function */
.section .drectve
.ascii " -export:\"_make_fcontext\""

View File

@@ -26,6 +26,12 @@
.file "make_i386_ms_pe_gas.asm"
.text
.p2align 4,,15
/* mark as using no unregistered SEH handlers */
.globl @feat.00
.def @feat.00; .scl 3; .type 0; .endef
.set @feat.00, 1
.globl _make_fcontext
.def _make_fcontext; .scl 2; .type 32; .endef
_make_fcontext:

View File

@@ -48,7 +48,7 @@
.file "make_mips64_n64_elf_gas.S"
.text
.globl make_fcontext
.align 2
.align 3
.type make_fcontext,@function
.ent make_fcontext
make_fcontext:

View File

@@ -5,71 +5,48 @@
http://www.boost.org/LICENSE_1_0.txt)
*/
/******************************************************
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
* ------------------------------------------------- *
* |bchai|hiddn| fpscr | PC | CR | R14 | R15 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* ------------------------------------------------- *
* | R16 | R17 | R18 | R19 | R20 | R21 | R22 | R23 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* ------------------------------------------------- *
* | R24 | R25 | R26 | R27 | R28 | R29 | R30 | R31 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* ------------------------------------------------- *
* | F14 | F15 | F16 | F17 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
* | F18 | F19 | F20 | F21 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
* ------------------------------------------------- *
* | F22 | F23 | F24 | F25 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
* ------------------------------------------------- *
* | F26 | F27 | F28 | F29 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
* | F30 | F31 | fpscr | R13 | R14 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
* ------------------------------------------------- *
* | R15 | R16 | R17 | R18 | R19 | R20 | R21 | R22 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | *
* ------------------------------------------------- *
* | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
* ------------------------------------------------- *
* | R23 | R24 | R25 | R26 | R27 | R28 | R29 | R30 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | *
* ------------------------------------------------- *
* | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | *
* ------------------------------------------------- *
* | R31 |hiddn| CR | LR | PC |bchai|linkr| FCTX| *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 64 | | *
* ------------------------------------------------- *
* | 256 | | *
* ------------------------------------------------- *
* | DATA| | *
* ------------------------------------------------- *
* ------------------------|------------ *
* | 224 | 228 | 232 | 236 | 240 | 244 | *
* ------------------------|------------ *
* | F30 | F31 |bchai| LR | *
* ------------------------|------------ *
* *
*******************************************************/
@@ -86,58 +63,84 @@ make_fcontext:
# shift address in R3 to lower 16 byte boundary
clrrwi %r3, %r3, 4
# reserve space for context-data on context-stack
# including 64 byte of linkage + parameter area (R1 % 16 == 0)
subi %r3, %r3, 336
# reserve space on context-stack, including 16 bytes of linkage
# and parameter area + 240 bytes of context-data (R1 % 16 == 0)
subi %r3, %r3, 16 + 240
# third arg of make_fcontext() == address of context-function
stw %r5, 240(%r3)
#ifdef __linux__
# save context-function as PC
stw %r5, 16(%r3)
#else
# save context-function for trampoline
stw %r5, 248(%r3)
#endif
# set back-chain to zero
li %r0, 0
stw %r0, 244(%r3)
stw %r0, 240(%r3)
mffs %f0 # load FPSCR
stfd %f0, 144(%r3) # save FPSCR
# copy FPSCR to new context
mffs %f0
stfd %f0, 8(%r3)
# compute address of returned transfer_t
addi %r0, %r3, 252
mr %r4, %r0
stw %r4, 228(%r3)
#ifdef __linux__
# set hidden pointer for returning transfer_t
la %r0, 248(%r3)
stw %r0, 4(%r3)
#endif
# load LR
mflr %r0
# jump to label 1
# load address of label 1 into R4
bl 1f
1:
# load LR into R4
mflr %r4
1: mflr %r4
#ifndef __linux__
# compute abs address of trampoline, use as PC
addi %r7, %r4, trampoline - 1b
stw %r7, 16(%r3)
#endif
# compute abs address of label finish
addi %r4, %r4, finish - 1b
# restore LR
mtlr %r0
# save address of finish as return-address for context-function
# will be entered after context-function returns
stw %r4, 236(%r3)
stw %r4, 244(%r3)
# restore return address from R6
mtlr %r6
blr # return pointer to context-data
finish:
# save return address into R0
mflr %r0
# save return address on stack, set up stack frame
stw %r0, 4(%r1)
# allocate stack space, R1 % 16 == 0
stwu %r1, -16(%r1)
#ifndef __linux__
trampoline:
# On systems other than Linux, jump_fcontext is returning the
# transfer_t in R3:R4, but we need to pass transfer_t * R3 to
# our context-function.
lwz %r0, 8(%r1) # address of context-function
mtctr %r0
stw %r3, 8(%r1)
stw %r4, 12(%r1)
la %r3, 8(%r1) # address of transfer_t
bctr
#endif
# exit code is zero
finish:
# Use the secure PLT for _exit(0). If we use the insecure BSS PLT
# here, then the linker may use the insecure BSS PLT even if the
# C++ compiler wanted the secure PLT.
# set R30 for secure PLT, large model
bl 2f
2: mflr %r30
addis %r30, %r30, .Ltoc - 2b@ha
addi %r30, %r30, .Ltoc - 2b@l
# call _exit(0) with special addend 0x8000 for large model
li %r3, 0
# exit application
bl _exit@plt
bl _exit + 0x8000@plt
.size make_fcontext, .-make_fcontext
/* Provide the GOT pointer for secure PLT, large model. */
.section .got2,"aw"
.Ltoc = . + 0x8000
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits

View File

@@ -0,0 +1,91 @@
/*
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)
*/
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| *
* ------------------------------------------------- *
* | fs0 | fs1 | fs2 | fs3 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| *
* ------------------------------------------------- *
* | fs4 | fs5 | fs6 | fs7 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| *
* ------------------------------------------------- *
* | fs8 | fs9 | fs10 | fs11 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| *
* ------------------------------------------------- *
* | s0 | s1 | s2 | s3 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| *
* ------------------------------------------------- *
* | s4 | s5 | s6 | s7 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 0xa0| 0xa4| 0xa8| 0xac| 0xb0| 0xb4| 0xb8| 0xbc| *
* ------------------------------------------------- *
* | s8 | s9 | s10 | s11 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 48 | 49 | 50 | 51 | | | | | *
* ------------------------------------------------- *
* | 0xc0| 0xc4| 0xc8| 0xcc| | | | | *
* ------------------------------------------------- *
* | ra | pc | | | *
* ------------------------------------------------- *
* *
*******************************************************/
.file "make_riscv64_sysv_elf_gas.S"
.text
.align 1
.global make_fcontext
.type make_fcontext, %function
make_fcontext:
# shift address in a0 (allocated stack) to lower 16 byte boundary
andi a0, a0, ~0xF
# reserve space for context-data on context-stack
addi a0, a0, -0xd0
# third arg of make_fcontext() == address of context-function
# store address as a PC to jump in
sd a2, 0xc8(a0)
# save address of finish as return-address for context-function
# will be entered after context-function returns (RA register)
lla a4, finish
sd a4, 0xc0(a0)
ret // return pointer to context-data (a0)
finish:
# exit code is zero
li a0, 0
# exit application
tail _exit@plt
.size make_fcontext,.-make_fcontext
# Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits

View File

@@ -0,0 +1,108 @@
/*******************************************************
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0 | 8 | 16 | 24 | *
* ------------------------------------------------- *
* | t.fctx | t.data | r2 | r6 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 40 | 48 | 56 | *
* ------------------------------------------------- *
* | r7 | r8 | r9 | r10 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 72 | 80 | 88 | *
* ------------------------------------------------- *
* | r11 | r12 | r13 | r14 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 104 | 112 | 120 | *
* ------------------------------------------------- *
* | f8 | f9 | f10 | f11 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 128 | 136 | 144 | 152 | *
* ------------------------------------------------- *
* | f12 | f13 | f14 | f15 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 160 | 168 | 176 | | *
* ------------------------------------------------- *
* | fpc | pc | | | *
* ------------------------------------------------- *
*******************************************************/
.text
.align 8
.global make_fcontext
.type make_fcontext, @function
#define ARG_OFFSET 0
#define GR_OFFSET 16
#define R14_OFFSET 88
#define FP_OFFSET 96
#define FPC_OFFSET 160
#define PC_OFFSET 168
#define CONTEXT_SIZE 176
/*
fcontext_t make_fcontext( void * sp, std::size_t size, void (* fn)( transfer_t) );
Create and return a context below SP to call FN.
Incoming args
r2 - The stack location where to create the context
r3 - The size of the context
r4 - The address of the context function
*/
make_fcontext:
.machine "z10"
/* Align the stack to an 8 byte boundary. */
nill %r2,0xfff0
/* Allocate stack space for the context. */
aghi %r2,-CONTEXT_SIZE
/* Set the r2 save slot to zero. This indicates jump_fcontext
that this is a special context. */
mvghi GR_OFFSET(%r2),0
/* Save the floating point control register. */
stfpc FPC_OFFSET(%r2)
/* Store the address of the target function as new pc. */
stg %r4,PC_OFFSET(%r2)
/* Store a pointer to the finish routine as r14. If a function
called via context routines just returns that value will be
loaded and used as return address. Hence the program will
just exit. */
larl %r1,finish
stg %r1,R14_OFFSET(%r2)
/* Return as usual with the new context returned in r2. */
br %r14
finish:
/* In finish tasks, you load the exit code and exit the
make_fcontext This is called when the context-function is
entirely executed. */
lghi %r2,0
brasl %r14,_exit@PLT
.size make_fcontext,.-make_fcontext
.section .note.GNU-stack,"",%progbits

View File

@@ -0,0 +1,174 @@
/*
Copyright Oliver Kowalke 2009.
Copyright Thomas Sailer 2013.
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)
*/
/*************************************************************************************
* ---------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
* | SEE registers (XMM6-XMM15) | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | *
* ---------------------------------------------------------------------------------- *
* | SEE registers (XMM6-XMM15) | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ---------------------------------------------------------------------------------- *
* | 0xe40 | 0x44 | 0x48 | 0x4c | 0x50 | 0x54 | 0x58 | 0x5c | *
* ---------------------------------------------------------------------------------- *
* | SEE registers (XMM6-XMM15) | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ---------------------------------------------------------------------------------- *
* | 0x60 | 0x64 | 0x68 | 0x6c | 0x70 | 0x74 | 0x78 | 0x7c | *
* ---------------------------------------------------------------------------------- *
* | SEE registers (XMM6-XMM15) | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 32 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | *
* ---------------------------------------------------------------------------------- *
* | 0x80 | 0x84 | 0x88 | 0x8c | 0x90 | 0x94 | 0x98 | 0x9c | *
* ---------------------------------------------------------------------------------- *
* | SEE registers (XMM6-XMM15) | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | *
* ---------------------------------------------------------------------------------- *
* | 0xa0 | 0xa4 | 0xa8 | 0xac | 0xb0 | 0xb4 | 0xb8 | 0xbc | *
* ---------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| <alignment> | fbr_strg | fc_dealloc | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | *
* ---------------------------------------------------------------------------------- *
* | 0xc0 | 0xc4 | 0xc8 | 0xcc | 0xd0 | 0xd4 | 0xd8 | 0xdc | *
* ---------------------------------------------------------------------------------- *
* | limit | base | R12 | R13 | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | *
* ---------------------------------------------------------------------------------- *
* | 0xe0 | 0xe4 | 0xe8 | 0xec | 0xf0 | 0xf4 | 0xf8 | 0xfc | *
* ---------------------------------------------------------------------------------- *
* | R14 | R15 | RDI | RSI | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | *
* ---------------------------------------------------------------------------------- *
* | 0x100 | 0x104 | 0x108 | 0x10c | 0x110 | 0x114 | 0x118 | 0x11c | *
* ---------------------------------------------------------------------------------- *
* | RBX | RBP | hidden | RIP | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | *
* ---------------------------------------------------------------------------------- *
* | 0x120 | 0x124 | 0x128 | 0x12c | 0x130 | 0x134 | 0x138 | 0x13c | *
* ---------------------------------------------------------------------------------- *
* | parameter area | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | *
* ---------------------------------------------------------------------------------- *
* | 0x140 | 0x144 | 0x148 | 0x14c | 0x150 | 0x154 | 0x158 | 0x15c | *
* ---------------------------------------------------------------------------------- *
* | FCTX | DATA | | *
* ---------------------------------------------------------------------------------- *
**************************************************************************************/
.file "make_x86_64_ms_pe_clang_gas.S"
.text
.p2align 4,,15
.globl make_fcontext
.def make_fcontext; .scl 2; .type 32; .endef
.seh_proc make_fcontext
make_fcontext:
.seh_endprologue
/* first arg of make_fcontext() == top of context-stack */
movq %rcx, %rax
/* shift address in RAX to lower 16 byte boundary */
/* == pointer to fcontext_t and address of context stack */
andq $-16, %rax
/* reserve space for context-data on context-stack */
/* on context-function entry: (RSP -0x8) % 16 == 0 */
leaq -0x150(%rax), %rax
/* third arg of make_fcontext() == address of context-function */
movq %r8, 0x100(%rax)
/* first arg of make_fcontext() == top of context-stack */
/* save top address of context stack as 'base' */
movq %rcx, 0xc8(%rax)
/* second arg of make_fcontext() == size of context-stack */
/* negate stack size for LEA instruction (== substraction) */
negq %rdx
/* compute bottom address of context stack (limit) */
leaq (%rcx,%rdx), %rcx
/* save bottom address of context stack as 'limit' */
movq %rcx, 0xc0(%rax)
/* save address of context stack limit as 'dealloction stack' */
movq %rcx, 0xb8(%rax)
/* set fiber-storage to zero */
xorq %rcx, %rcx
movq %rcx, 0xb0(%rax)
/* save MMX control- and status-word */
stmxcsr 0xa0(%rax)
/* save x87 control-word */
fnstcw 0xa4(%rax)
/* compute address of transport_t */
leaq 0x140(%rax), %rcx
/* store address of transport_t in hidden field */
movq %rcx, 0x110(%rax)
/* compute abs address of label trampoline */
leaq trampoline(%rip), %rcx
/* save address of finish as return-address for context-function */
/* will be entered after jump_fcontext() first time */
movq %rcx, 0x118(%rax)
/* compute abs address of label finish */
leaq finish(%rip), %rcx
/* save address of finish as return-address for context-function */
/* will be entered after context-function returns */
movq %rcx, 0x108(%rax)
ret /* return pointer to context-data */
trampoline:
/* store return address on stack */
/* fix stack alignment */
pushq %rbp
/* jump to context-function */
jmp *%rbx
finish:
/* 32byte shadow-space for _exit() */
andq $-32, %rsp
/* 32byte shadow-space for _exit() are */
/* already reserved by make_fcontext() */
/* exit code is zero */
xorq %rcx, %rcx
/* exit application */
call _exit
hlt
.seh_endproc
.def _exit; .scl 2; .type 32; .endef /* standard C library function */
.section .drectve
.ascii " -export:\"make_fcontext\""

View File

@@ -43,6 +43,7 @@
.globl ontop_fcontext
.align 2
.type ontop_fcontext,%function
.syntax unified
ontop_fcontext:
@ save LR as PC
push {lr}

View File

@@ -15,6 +15,10 @@
#include "ontop_ppc32_sysv_macho_gas.S"
#elif defined(__ppc64__)
#include "ontop_ppc64_sysv_macho_gas.S"
#elif defined(__arm__)
#include "ontop_arm_aapcs_macho_gas.S"
#elif defined(__arm64__)
#include "ontop_arm64_aapcs_macho_gas.S"
#else
#error "No arch's"
#endif

View File

@@ -0,0 +1,131 @@
/*
Copyright Oliver Kowalke 2009.
Copyright Thomas Sailer 2013.
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)
*/
/*************************************************************************************
* --------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* --------------------------------------------------------------------------------- *
* | 0h | 04h | 08h | 0ch | 010h | 014h | 018h | 01ch | *
* --------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| fc_strg |fc_deallo| limit | base | fc_seh | EDI | *
* --------------------------------------------------------------------------------- *
* --------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* --------------------------------------------------------------------------------- *
* | 020h | 024h | 028h | 02ch | 030h | 034h | 038h | 03ch | *
* --------------------------------------------------------------------------------- *
* | ESI | EBX | EBP | EIP | to | data | EH NXT |SEH HNDLR| *
* --------------------------------------------------------------------------------- *
**************************************************************************************/
.file "ontop_i386_ms_pe_clang_gas.S"
.text
.p2align 4,,15
/* mark as using no unregistered SEH handlers */
.globl @feat.00
.def @feat.00; .scl 3; .type 0; .endef
.set @feat.00, 1
.globl _ontop_fcontext
.def _ontop_fcontext; .scl 2; .type 32; .endef
_ontop_fcontext:
/* prepare stack */
leal -0x2c(%esp), %esp
#if !defined(BOOST_USE_TSX)
/* save MMX control- and status-word */
stmxcsr (%esp)
/* save x87 control-word */
fnstcw 0x4(%esp)
#endif
/* load NT_TIB */
movl %fs:(0x18), %edx
/* load fiber local storage */
movl 0x10(%edx), %eax
movl %eax, 0x8(%esp)
/* load current dealloction stack */
movl 0xe0c(%edx), %eax
movl %eax, 0xc(%esp)
/* load current stack limit */
movl 0x8(%edx), %eax
movl %eax, 0x10(%esp)
/* load current stack base */
movl 0x4(%edx), %eax
movl %eax, 0x14(%esp)
/* load current SEH exception list */
movl (%edx), %eax
movl %eax, 0x18(%esp)
movl %edi, 0x1c(%esp) /* save EDI */
movl %esi, 0x20(%esp) /* save ESI */
movl %ebx, 0x24(%esp) /* save EBX */
movl %ebp, 0x28(%esp) /* save EBP */
/* store ESP (pointing to context-data) in ECX */
movl %esp, %ecx
/* first arg of ontop_fcontext() == fcontext to jump to */
movl 0x30(%esp), %eax
/* pass parent fcontext_t */
movl %ecx, 0x30(%eax)
/* second arg of ontop_fcontext() == data to be transferred */
movl 0x34(%esp), %ecx
/* pass data */
movl %ecx, 0x34(%eax)
/* third arg of ontop_fcontext() == ontop-function */
movl 0x38(%esp), %ecx
/* restore ESP (pointing to context-data) from EDX */
movl %eax, %esp
#if !defined(BOOST_USE_TSX)
/* restore MMX control- and status-word */
ldmxcsr (%esp)
/* restore x87 control-word */
fldcw 0x4(%esp)
#endif
/* restore NT_TIB into EDX */
movl %fs:(0x18), %edx
/* restore fiber local storage */
movl 0x8(%esp), %eax
movl %eax, 0x10(%edx)
/* restore current deallocation stack */
movl 0xc(%esp), %eax
movl %eax, 0xe0c(%edx)
/* restore current stack limit */
movl 0x10(%esp), %eax
movl %eax, 0x08(%edx)
/* restore current stack base */
movl 0x14(%esp), %eax
movl %eax, 0x04(%edx)
/* restore current SEH exception list */
movl 0x18(%esp), %eax
movl %eax, (%edx)
movl 0x1c(%esp), %edi /* restore EDI */
movl 0x20(%esp), %esi /* restore ESI */
movl 0x24(%esp), %ebx /* restore EBX */
movl 0x28(%esp), %ebp /* restore EBP */
/* prepare stack */
leal 0x2c(%esp), %esp
/* keep return-address on stack */
/* jump to context */
jmp *%ecx
.section .drectve
.ascii " -export:\"_ontop_fcontext\""

View File

@@ -26,6 +26,12 @@
.file "ontop_i386_ms_pe_gas.asm"
.text
.p2align 4,,15
/* mark as using no unregistered SEH handlers */
.globl @feat.00
.def @feat.00; .scl 3; .type 0; .endef
.set @feat.00, 1
.globl _ontop_fcontext
.def _ontop_fcontext; .scl 2; .type 32; .endef
_ontop_fcontext:

View File

@@ -48,7 +48,7 @@
.file "ontop_mips64_n64_elf_gas.S"
.text
.globl ontop_fcontext
.align 2
.align 3
.type ontop_fcontext,@function
.ent ontop_fcontext
ontop_fcontext:
@@ -67,7 +67,7 @@ ontop_fcontext:
sd $ra, 144($sp) # save RA
sd $ra, 152($sp) # save RA as PC
#if defined(__mips_hard_float)
s.d $f24, 0($sp) # save F24
s.d $f25, 8($sp) # save F25
s.d $f26, 16($sp) # save F26
@@ -76,6 +76,7 @@ ontop_fcontext:
s.d $f29, 40($sp) # save F29
s.d $f30, 48($sp) # save F30
s.d $f31, 56($sp) # save F31
#endif
# store SP (pointing to context-data) in t0
move $t0, $sp
@@ -83,6 +84,7 @@ ontop_fcontext:
# restore SP (pointing to context-data) from a0
move $sp, $a0
#if defined(__mips_hard_float)
l.d $f24, 0($sp) # restore F24
l.d $f25, 8($sp) # restore F25
l.d $f26, 16($sp) # restore F26
@@ -91,6 +93,7 @@ ontop_fcontext:
l.d $f29, 40($sp) # restore F29
l.d $f30, 48($sp) # restore F30
l.d $f31, 56($sp) # restore F31
#endif
ld $s0, 64($sp) # restore S0
ld $s1, 72($sp) # restore S1

View File

@@ -5,71 +5,48 @@
http://www.boost.org/LICENSE_1_0.txt)
*/
/******************************************************
/*******************************************************
* *
* ------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ------------------------------------------------- *
* | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
* ------------------------------------------------- *
* |bchai|hiddn| fpscr | PC | CR | R14 | R15 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* ------------------------------------------------- *
* | R16 | R17 | R18 | R19 | R20 | R21 | R22 | R23 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* ------------------------------------------------- *
* | R24 | R25 | R26 | R27 | R28 | R29 | R30 | R31 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* ------------------------------------------------- *
* | F14 | F15 | F16 | F17 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
* | F18 | F19 | F20 | F21 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
* ------------------------------------------------- *
* | F22 | F23 | F24 | F25 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
* ------------------------------------------------- *
* | F26 | F27 | F28 | F29 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
* | F30 | F31 | fpscr | R13 | R14 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
* ------------------------------------------------- *
* | R15 | R16 | R17 | R18 | R19 | R20 | R21 | R22 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | *
* ------------------------------------------------- *
* | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
* ------------------------------------------------- *
* | R23 | R24 | R25 | R26 | R27 | R28 | R29 | R30 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | *
* ------------------------------------------------- *
* | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | *
* ------------------------------------------------- *
* | R31 |hiddn| CR | LR | PC |bchai|linkr| FCTX| *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 64 | | *
* ------------------------------------------------- *
* | 256 | | *
* ------------------------------------------------- *
* | DATA| | *
* ------------------------------------------------- *
* ------------------------|------------ *
* | 224 | 228 | 232 | 236 | 240 | 244 | *
* ------------------------|------------ *
* | F30 | F31 |bchai| LR | *
* ------------------------|------------ *
* *
*******************************************************/
@@ -79,128 +56,137 @@
.align 2
.type ontop_fcontext,@function
ontop_fcontext:
# reserve space on stack
subi %r1, %r1, 244
# Linux: ontop_fcontext( hidden transfer_t * R3, R4, R5, R6)
# Other: transfer_t R3:R4 = jump_fcontext( R3, R4, R5)
stfd %f14, 0(%r1) # save F14
stfd %f15, 8(%r1) # save F15
stfd %f16, 16(%r1) # save F16
stfd %f17, 24(%r1) # save F17
stfd %f18, 32(%r1) # save F18
stfd %f19, 40(%r1) # save F19
stfd %f20, 48(%r1) # save F20
stfd %f21, 56(%r1) # save F21
stfd %f22, 64(%r1) # save F22
stfd %f23, 72(%r1) # save F23
stfd %f24, 80(%r1) # save F24
stfd %f25, 88(%r1) # save F25
stfd %f26, 96(%r1) # save F26
stfd %f27, 104(%r1) # save F27
stfd %f28, 112(%r1) # save F28
stfd %f29, 120(%r1) # save F29
stfd %f30, 128(%r1) # save F30
stfd %f31, 136(%r1) # save F31
mffs %f0 # load FPSCR
stfd %f0, 144(%r1) # save FPSCR
mflr %r0 # return address from LR
mffs %f0 # FPSCR
mfcr %r8 # condition register
stw %r13, 152(%r1) # save R13
stw %r14, 156(%r1) # save R14
stw %r15, 160(%r1) # save R15
stw %r16, 164(%r1) # save R16
stw %r17, 168(%r1) # save R17
stw %r18, 172(%r1) # save R18
stw %r19, 176(%r1) # save R19
stw %r20, 180(%r1) # save R20
stw %r21, 184(%r1) # save R21
stw %r22, 188(%r1) # save R22
stw %r23, 192(%r1) # save R23
stw %r24, 196(%r1) # save R24
stw %r25, 200(%r1) # save R25
stw %r26, 204(%r1) # save R26
stw %r27, 208(%r1) # save R27
stw %r28, 212(%r1) # save R28
stw %r29, 216(%r1) # save R29
stw %r30, 220(%r1) # save R30
stw %r31, 224(%r1) # save R31
stw %r3, 228(%r1) # save hidden
stwu %r1, -240(%r1) # allocate stack space, R1 % 16 == 0
stw %r0, 244(%r1) # save LR in caller's frame
# save CR
mfcr %r0
stw %r0, 232(%r1)
# save LR
mflr %r0
stw %r0, 236(%r1)
# save LR as PC
stw %r0, 240(%r1)
#ifdef __linux__
stw %r3, 4(%r1) # hidden pointer
#endif
# store RSP (pointing to context-data) in R7
mr %r7, %r1
stfd %f0, 8(%r1) # FPSCR
stw %r0, 16(%r1) # LR as PC
stw %r8, 20(%r1) # CR
# restore RSP (pointing to context-data) from R4
mr %r1, %r4
# Save registers R14 to R31.
# Don't change R2, the thread-local storage pointer.
# Don't change R13, the small data pointer.
stw %r14, 24(%r1)
stw %r15, 28(%r1)
stw %r16, 32(%r1)
stw %r17, 36(%r1)
stw %r18, 40(%r1)
stw %r19, 44(%r1)
stw %r20, 48(%r1)
stw %r21, 52(%r1)
stw %r22, 56(%r1)
stw %r23, 60(%r1)
stw %r24, 64(%r1)
stw %r25, 68(%r1)
stw %r26, 72(%r1)
stw %r27, 76(%r1)
stw %r28, 80(%r1)
stw %r29, 84(%r1)
stw %r30, 88(%r1)
stw %r31, 92(%r1)
lfd %f14, 0(%r1) # restore F14
lfd %f15, 8(%r1) # restore F15
lfd %f16, 16(%r1) # restore F16
lfd %f17, 24(%r1) # restore F17
lfd %f18, 32(%r1) # restore F18
lfd %f19, 40(%r1) # restore F19
lfd %f20, 48(%r1) # restore F20
lfd %f21, 56(%r1) # restore F21
lfd %f22, 64(%r1) # restore F22
lfd %f23, 72(%r1) # restore F23
lfd %f24, 80(%r1) # restore F24
lfd %f25, 88(%r1) # restore F25
lfd %f26, 96(%r1) # restore F26
lfd %f27, 104(%r1) # restore F27
lfd %f28, 112(%r1) # restore F28
lfd %f29, 120(%r1) # restore F29
lfd %f30, 128(%r1) # restore F30
lfd %f31, 136(%r1) # restore F31
lfd %f0, 144(%r1) # load FPSCR
mtfsf 0xff, %f0 # restore FPSCR
# Save registers F14 to F31 in slots with 8-byte alignment.
# 4-byte alignment may stall the pipeline of some processors.
# Less than 4 may cause alignment traps.
stfd %f14, 96(%r1)
stfd %f15, 104(%r1)
stfd %f16, 112(%r1)
stfd %f17, 120(%r1)
stfd %f18, 128(%r1)
stfd %f19, 136(%r1)
stfd %f20, 144(%r1)
stfd %f21, 152(%r1)
stfd %f22, 160(%r1)
stfd %f23, 168(%r1)
stfd %f24, 176(%r1)
stfd %f25, 184(%r1)
stfd %f26, 192(%r1)
stfd %f27, 200(%r1)
stfd %f28, 208(%r1)
stfd %f29, 216(%r1)
stfd %f30, 224(%r1)
stfd %f31, 232(%r1)
lwz %r13, 152(%r1) # restore R13
lwz %r14, 156(%r1) # restore R14
lwz %r15, 160(%r1) # restore R15
lwz %r16, 164(%r1) # restore R16
lwz %r17, 168(%r1) # restore R17
lwz %r18, 172(%r1) # restore R18
lwz %r19, 176(%r1) # restore R19
lwz %r20, 180(%r1) # restore R20
lwz %r21, 184(%r1) # restore R21
lwz %r22, 188(%r1) # restore R22
lwz %r23, 192(%r1) # restore R23
lwz %r24, 196(%r1) # restore R24
lwz %r25, 200(%r1) # restore R25
lwz %r26, 204(%r1) # restore R26
lwz %r27, 208(%r1) # restore R27
lwz %r28, 212(%r1) # restore R28
lwz %r29, 216(%r1) # restore R29
lwz %r30, 220(%r1) # restore R30
lwz %r31, 224(%r1) # restore R31
lwz %r4, 228(%r1) # restore hidden
# store RSP (pointing to context-data) in R7/R6
# restore RSP (pointing to context-data) from R4/R3
#ifdef __linux__
mr %r7, %r1
mr %r1, %r4
lwz %r3, 4(%r1) # hidden pointer
#else
mr %r6, %r1
mr %r1, %r3
#endif
# restore CR
lwz %r0, 232(%r1)
mtcr %r0
# restore LR
lwz %r0, 236(%r1)
# ignore PC at 16(%r1)
lfd %f0, 8(%r1) # FPSCR
lwz %r8, 20(%r1) # CR
mtfsf 0xff, %f0 # restore FPSCR
mtcr %r8 # restore CR
# restore R14 to R31
lwz %r14, 24(%r1)
lwz %r15, 28(%r1)
lwz %r16, 32(%r1)
lwz %r17, 36(%r1)
lwz %r18, 40(%r1)
lwz %r19, 44(%r1)
lwz %r20, 48(%r1)
lwz %r21, 52(%r1)
lwz %r22, 56(%r1)
lwz %r23, 60(%r1)
lwz %r24, 64(%r1)
lwz %r25, 68(%r1)
lwz %r26, 72(%r1)
lwz %r27, 76(%r1)
lwz %r28, 80(%r1)
lwz %r29, 84(%r1)
lwz %r30, 88(%r1)
lwz %r31, 92(%r1)
# restore F14 to F31
lfd %f14, 96(%r1)
lfd %f15, 104(%r1)
lfd %f16, 112(%r1)
lfd %f17, 120(%r1)
lfd %f18, 128(%r1)
lfd %f19, 136(%r1)
lfd %f20, 144(%r1)
lfd %f21, 152(%r1)
lfd %f22, 160(%r1)
lfd %f23, 168(%r1)
lfd %f24, 176(%r1)
lfd %f25, 184(%r1)
lfd %f26, 192(%r1)
lfd %f27, 200(%r1)
lfd %f28, 208(%r1)
lfd %f29, 216(%r1)
lfd %f30, 224(%r1)
lfd %f31, 232(%r1)
# restore LR from caller's frame
lwz %r0, 244(%r1)
mtlr %r0
# ignore PC
# adjust stack
addi %r1, %r1, 244
addi %r1, %r1, 240
# return transfer_t
stw %r7, 0(%r4)
stw %r5, 4(%r4)
# restore CTR
mtctr %r6
# jump to ontop-function
bctr
# see tail_ppc32_sysv_elf_gas.cpp
# Linux: fcontext_ontop_tail( hidden transfer_t * R3, R4, R5, R6, R7)
# Other: transfer_t R3:R4 = fcontext_ontop_tail( R3, R4, R5, R6)
b ontop_fcontext_tail
.size ontop_fcontext, .-ontop_fcontext
/* Mark that we don't need executable stack. */

View File

@@ -174,6 +174,9 @@ ontop_fcontext:
# restore CTR
mtctr %r5
# store cb entrypoint in %r12, used for TOC calculation
mr %r12, %r5
# copy transfer_t into ontop_fn arg registers
mr %r3, %r7
# arg pointer already in %r4

Some files were not shown because too many files have changed in this diff Show More