From a67ae8a1051d7575670795b6a8ebf5fff39715bd Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Wed, 10 Apr 2019 09:06:24 +0200 Subject: [PATCH] P0876R7 --- build/Jamfile.v2 | 703 +----------------- example/{callcc => }/Jamfile.v2 | 22 +- example/backtrace.cpp | 91 +++ example/callcc/backtrace.cpp | 57 -- example/callcc/circle.cpp | 44 -- example/callcc/echosse.cpp | 46 -- example/callcc/endless_loop.cpp | 28 - example/callcc/jump.cpp | 35 - example/callcc/jump_mov.cpp | 59 -- example/callcc/jump_void.cpp | 28 - example/callcc/ontop.cpp | 40 - example/callcc/ontop_void.cpp | 40 - example/callcc/parser.cpp | 128 ---- example/callcc/throw.cpp | 47 -- example/{fiber => }/circle.cpp | 10 +- example/{fiber => }/echosse.cpp | 6 +- example/{fiber => }/endless_loop.cpp | 6 +- example/execution_context_v2/Jamfile.v2 | 68 -- example/execution_context_v2/backtrace.cpp | 58 -- example/execution_context_v2/echosse.cpp | 45 -- example/execution_context_v2/fibonacci.cpp | 38 - example/execution_context_v2/jump.cpp | 32 - example/execution_context_v2/jump_void.cpp | 31 - example/execution_context_v2/ontop.cpp | 42 -- example/execution_context_v2/ontop_void.cpp | 40 - example/execution_context_v2/parameter.cpp | 62 -- example/execution_context_v2/parser.cpp | 144 ---- example/execution_context_v2/throw.cpp | 47 -- example/fiber/Jamfile.v2 | 84 --- example/fiber/backtrace.cpp | 57 -- example/fiber/fibonacci.cpp | 50 -- example/fiber/hosting_thread.cpp | 31 - example/fiber/migrateable.cpp | 27 - example/fiber/stack.cpp | 25 - example/{callcc => }/fibonacci.cpp | 17 +- example/{fiber => }/jump.cpp | 6 +- example/{fiber => }/jump_mov.cpp | 5 +- example/{fiber => }/jump_void.cpp | 6 +- example/{fiber => }/ontop.cpp | 6 +- example/{fiber => }/ontop_void.cpp | 8 +- example/{fiber => }/parser.cpp | 4 +- example/{callcc => }/segmented.cpp | 10 +- example/{callcc => }/stack.cpp | 0 example/{fiber => }/throw.cpp | 10 +- example/unwind_fiber_context.cpp | 75 ++ example/unwind_main.cpp | 58 ++ example/unwind_multiple.cpp | 65 ++ example/unwind_ucontext.cpp | 76 ++ include/boost/context/all.hpp | 15 - include/boost/context/continuation.hpp | 13 - .../boost/context/continuation_fcontext.hpp | 370 --------- .../boost/context/continuation_ucontext.hpp | 510 ------------- include/boost/context/continuation_winfib.hpp | 449 ----------- include/boost/context/detail/exception.hpp | 38 - include/boost/context/execution_context.hpp | 12 - .../boost/context/execution_context_v1.hpp | 473 ------------ .../boost/context/execution_context_v2.hpp | 479 ------------ .../context/execution_context_v2_void.ipp | 307 -------- include/boost/context/fiber.hpp | 13 - .../{fiber_fcontext.hpp => fiber_context.hpp} | 197 ++--- include/boost/context/fiber_ucontext.hpp | 497 ------------- include/boost/context/fiber_winfib.hpp | 435 ----------- test/Jamfile.v2 | 69 +- test/test_callcc.cpp | 430 ----------- test/test_execution_context_v2.cpp | 582 --------------- test/test_fiber.cpp | 112 +-- 66 files changed, 608 insertions(+), 7010 deletions(-) rename example/{callcc => }/Jamfile.v2 (82%) create mode 100644 example/backtrace.cpp delete mode 100644 example/callcc/backtrace.cpp delete mode 100644 example/callcc/circle.cpp delete mode 100644 example/callcc/echosse.cpp delete mode 100644 example/callcc/endless_loop.cpp delete mode 100644 example/callcc/jump.cpp delete mode 100644 example/callcc/jump_mov.cpp delete mode 100644 example/callcc/jump_void.cpp delete mode 100644 example/callcc/ontop.cpp delete mode 100644 example/callcc/ontop_void.cpp delete mode 100644 example/callcc/parser.cpp delete mode 100644 example/callcc/throw.cpp rename example/{fiber => }/circle.cpp (73%) rename example/{fiber => }/echosse.cpp (90%) rename example/{fiber => }/endless_loop.cpp (82%) delete mode 100644 example/execution_context_v2/Jamfile.v2 delete mode 100644 example/execution_context_v2/backtrace.cpp delete mode 100644 example/execution_context_v2/echosse.cpp delete mode 100644 example/execution_context_v2/fibonacci.cpp delete mode 100644 example/execution_context_v2/jump.cpp delete mode 100644 example/execution_context_v2/jump_void.cpp delete mode 100644 example/execution_context_v2/ontop.cpp delete mode 100644 example/execution_context_v2/ontop_void.cpp delete mode 100644 example/execution_context_v2/parameter.cpp delete mode 100644 example/execution_context_v2/parser.cpp delete mode 100644 example/execution_context_v2/throw.cpp delete mode 100644 example/fiber/Jamfile.v2 delete mode 100644 example/fiber/backtrace.cpp delete mode 100644 example/fiber/fibonacci.cpp delete mode 100644 example/fiber/hosting_thread.cpp delete mode 100644 example/fiber/migrateable.cpp delete mode 100644 example/fiber/stack.cpp rename example/{callcc => }/fibonacci.cpp (67%) rename example/{fiber => }/jump.cpp (89%) rename example/{fiber => }/jump_mov.cpp (92%) rename example/{fiber => }/jump_void.cpp (85%) rename example/{fiber => }/ontop.cpp (88%) rename example/{fiber => }/ontop_void.cpp (85%) rename example/{fiber => }/parser.cpp (95%) rename example/{callcc => }/segmented.cpp (89%) rename example/{callcc => }/stack.cpp (100%) rename example/{fiber => }/throw.cpp (75%) create mode 100644 example/unwind_fiber_context.cpp create mode 100644 example/unwind_main.cpp create mode 100644 example/unwind_multiple.cpp create mode 100644 example/unwind_ucontext.cpp delete mode 100644 include/boost/context/all.hpp delete mode 100644 include/boost/context/continuation.hpp delete mode 100644 include/boost/context/continuation_fcontext.hpp delete mode 100644 include/boost/context/continuation_ucontext.hpp delete mode 100644 include/boost/context/continuation_winfib.hpp delete mode 100644 include/boost/context/detail/exception.hpp delete mode 100644 include/boost/context/execution_context.hpp delete mode 100644 include/boost/context/execution_context_v1.hpp delete mode 100644 include/boost/context/execution_context_v2.hpp delete mode 100644 include/boost/context/execution_context_v2_void.ipp delete mode 100644 include/boost/context/fiber.hpp rename include/boost/context/{fiber_fcontext.hpp => fiber_context.hpp} (70%) delete mode 100644 include/boost/context/fiber_ucontext.hpp delete mode 100644 include/boost/context/fiber_winfib.hpp delete mode 100644 test/test_callcc.cpp delete mode 100644 test/test_execution_context_v2.cpp diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 7953162..6bbde69 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -12,7 +12,7 @@ import indirect ; import modules ; import os ; import toolset ; -import ../../config/checks/config : requires ; + import ../../config/checks/config : requires ; feature.feature segmented-stacks : on : optional propagated composite ; feature.compose on : BOOST_USE_SEGMENTED_STACKS ; @@ -36,12 +36,15 @@ project boost/context intel,static:BOOST_CONTEXT_EXPORT= msvc,shared:BOOST_CONTEXT_EXPORT=EXPORT msvc,static:BOOST_CONTEXT_EXPORT= + clang-win,shared:BOOST_CONTEXT_EXPORT=EXPORT + clang-win,static:BOOST_CONTEXT_EXPORT= shared:BOOST_CONTEXT_DYN_LINK=1 "-lunwind" BOOST_CONTEXT_SOURCE multi : usage-requirements shared:BOOST_CONTEXT_DYN_LINK=1 + "-lunwind" speed:BOOST_DISABLE_ASSERTS release:BOOST_DISABLE_ASSERTS : source-location ../src @@ -51,18 +54,11 @@ project boost/context local rule default_binary_format ( ) { local tmp = elf ; - if [ os.name ] = "NT" { tmp = pe ; } - else if [ os.name ] = "CYGWIN" { tmp = pe ; } - else if [ os.name ] = "AIX" { tmp = xcoff ; } - else if [ os.name ] = "MACOSX" { tmp = mach-o ; } return $(tmp) ; } feature.feature binary-format : elf - mach-o - pe - xcoff : propagated ; feature.set-default binary-format : [ default_binary_format ] ; @@ -71,23 +67,11 @@ feature.set-default binary-format : [ default_binary_format ] ; local rule default_abi ( ) { local tmp = sysv ; - 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 ; } return $(tmp) ; } feature.feature abi - : aapcs - eabi - ms - n32 - n64 - o32 - o64 - sysv - x32 + : sysv : propagated ; feature.set-default abi : [ default_abi ] ; @@ -95,483 +79,14 @@ feature.set-default abi : [ default_abi ] ; feature.feature context-impl : fcontext - ucontext - winfib : propagated composite ; feature.set-default context-impl : fcontext ; -feature.compose ucontext : BOOST_USE_UCONTEXT ; -feature.compose winfib : BOOST_USE_WINFIB ; -actions gas32 -{ - cpp -x assembler-with-cpp "$(>)" | as --32 -o "$(<)" -} - -actions gas64 -{ - cpp -x assembler-with-cpp "$(>)" | as --64 -o "$(<)" -} - -actions gasx32 -{ - cpp -x assembler-with-cpp "$(>)" | as --x32 -o "$(<)" -} - -actions gas -{ - cpp -x assembler-with-cpp "$(>)" | as -o "$(<)" -} - -actions armasm -{ - armasm "$(>)" "$(<)" -} - -actions masm -{ - ml /c /Fo"$(<)" "$(>)" -} - -actions masm64 -{ - ml64 /c /Fo"$(<)" "$(>)" -} - - -rule configure ( properties * ) -{ - local result ; - -# if ( ! ( gcc in $(properties) -# || intel in $(properties) -# || msvc in $(properties) ) ) -# { -# result = no ; -# ECHO "toolset not supported" ; -# } - - return $(result) ; -} - -# ARM -# ARM/AAPCS/ELF -alias asm_sources - : asm/make_arm_aapcs_elf_gas.S - asm/jump_arm_aapcs_elf_gas.S - asm/ontop_arm_aapcs_elf_gas.S - : aapcs - 32 - arm - elf - clang - ; - -alias asm_sources - : asm/make_arm_aapcs_elf_gas.S - asm/jump_arm_aapcs_elf_gas.S - asm/ontop_arm_aapcs_elf_gas.S - : aapcs - 32 - arm - elf - gcc - ; - -alias asm_sources - : asm/make_arm_aapcs_elf_gas.S - asm/jump_arm_aapcs_elf_gas.S - asm/ontop_arm_aapcs_elf_gas.S - : aapcs - 32 - arm - elf - qcc - ; - -# ARM/AAPCS/MACH-O -alias asm_sources - : asm/make_arm_aapcs_macho_gas.S - asm/jump_arm_aapcs_macho_gas.S - asm/ontop_arm_aapcs_macho_gas.S - : aapcs - 32 - arm - mach-o - clang - ; - -alias asm_sources - : asm/make_arm_aapcs_macho_gas.S - asm/jump_arm_aapcs_macho_gas.S - asm/ontop_arm_aapcs_macho_gas.S - : aapcs - 32 - arm - mach-o - darwin - ; - -# ARM/AAPCS/PE -alias asm_sources - : asm/make_arm_aapcs_pe_armasm.asm - asm/jump_arm_aapcs_pe_armasm.asm - asm/ontop_arm_aapcs_pe_armasm.asm - untested.cpp - : aapcs - 32 - arm - pe - msvc - ; - -# ARM64 -# ARM64/AAPCS/ELF -alias asm_sources - : asm/make_arm64_aapcs_elf_gas.S - asm/jump_arm64_aapcs_elf_gas.S - asm/ontop_arm64_aapcs_elf_gas.S - : aapcs - 64 - arm - elf - clang - ; - -alias asm_sources - : asm/make_arm64_aapcs_elf_gas.S - asm/jump_arm64_aapcs_elf_gas.S - asm/ontop_arm64_aapcs_elf_gas.S - : aapcs - 64 - arm - elf - gcc - ; - -# ARM64/AAPCS/MACH-O -alias asm_sources - : asm/make_arm64_aapcs_macho_gas.S - asm/jump_arm64_aapcs_macho_gas.S - asm/ontop_arm64_aapcs_macho_gas.S - : aapcs - 64 - arm - mach-o - clang - ; - -alias asm_sources - : asm/make_arm64_aapcs_macho_gas.S - asm/jump_arm64_aapcs_macho_gas.S - asm/ontop_arm64_aapcs_macho_gas.S - : aapcs - 64 - arm - mach-o - darwin - ; - -# MIPS -# MIPS/O32/ELF -alias asm_sources - : asm/make_mips32_o32_elf_gas.S - asm/jump_mips32_o32_elf_gas.S - asm/ontop_mips32_o32_elf_gas.S - : o32 - 32 - mips1 - elf - clang - ; - -alias asm_sources - : asm/make_mips32_o32_elf_gas.S - asm/jump_mips32_o32_elf_gas.S - asm/ontop_mips32_o32_elf_gas.S - : o32 - 32 - mips1 - elf - gcc - ; - -# POWERPC_32 -# POWERPC_32/SYSV/ELF -alias asm_sources - : asm/make_ppc32_sysv_elf_gas.S - asm/jump_ppc32_sysv_elf_gas.S - asm/ontop_ppc32_sysv_elf_gas.S - : sysv - 32 - power - elf - clang - ; - -alias asm_sources - : asm/make_ppc32_sysv_elf_gas.S - asm/jump_ppc32_sysv_elf_gas.S - asm/ontop_ppc32_sysv_elf_gas.S - : sysv - 32 - power - elf - clang - ; - -alias asm_sources - : asm/make_ppc32_sysv_macho_gas.S - asm/jump_ppc32_sysv_macho_gas.S - asm/ontop_ppc32_sysv_macho_gas.S - : sysv - 32 - power - mach-o - darwin - ; - -#POWERPC_32/SYSV/XCOFF -alias asm_sources - : asm/make_ppc32_sysv_xcoff_gas.S - asm/jump_ppc32_sysv_xcoff_gas.S - asm/ontop_ppc32_sysv_xcoff_gas.S - : sysv - 32 - power - xcoff - clang - ; - -alias asm_sources - : asm/make_ppc32_sysv_xcoff_gas.S - asm/jump_ppc32_sysv_xcoff_gas.S - asm/ontop_ppc32_sysv_xcoff_gas.S - : sysv - 32 - power - xcoff - gcc - ; - -# POWERPC_64 -# POWERPC_64/SYSV/ELF -alias asm_sources - : asm/make_ppc64_sysv_elf_gas.S - asm/jump_ppc64_sysv_elf_gas.S - asm/ontop_ppc64_sysv_elf_gas.S - : sysv - 64 - power - elf - clang - ; - -alias asm_sources - : asm/make_ppc64_sysv_elf_gas.S - asm/jump_ppc64_sysv_elf_gas.S - asm/ontop_ppc64_sysv_elf_gas.S - : sysv - 64 - power - elf - gcc - ; - -# POWERPC_64/SYSV/MACH-O -alias asm_sources - : asm/make_ppc64_sysv_macho_gas.S - asm/jump_ppc64_sysv_macho_gas.S - asm/ontop_ppc64_sysv_macho_gas.S - untested.cpp - : sysv - 64 - power - mach-o - clang - ; - -alias asm_sources - : asm/make_ppc64_sysv_macho_gas.S - asm/jump_ppc64_sysv_macho_gas.S - asm/ontop_ppc64_sysv_macho_gas.S - untested.cpp - : sysv - 64 - power - mach-o - darwin - ; - -# POWERPC_64/SYSV/XCOFF -alias asm_sources - : asm/make_ppc64_sysv_xcoff_gas.S - asm/jump_ppc64_sysv_xcoff_gas.S - asm/ontop_ppc64_sysv_xcoff_gas.S - : sysv - 64 - power - xcoff - clang - ; - -alias asm_sources - : asm/make_ppc64_sysv_xcoff_gas.S - asm/jump_ppc64_sysv_xcoff_gas.S - asm/ontop_ppc64_sysv_xcoff_gas.S - : sysv - 64 - power - xcoff - gcc - ; - -# POWERPC universal -# POWERPC_32_64/SYSV/MACH-O -alias asm_sources - : asm/make_ppc32_ppc64_sysv_macho_gas.S - asm/jump_ppc32_ppc64_sysv_macho_gas.S - asm/ontop_ppc32_ppc64_sysv_macho_gas.S - : sysv - 32_64 - power - mach-o - ; - -# X86 -# X86/SYSV/ELF -alias asm_sources - : asm/make_i386_sysv_elf_gas.S - asm/jump_i386_sysv_elf_gas.S - asm/ontop_i386_sysv_elf_gas.S - : sysv - 32 - x86 - elf - clang - ; - -alias asm_sources - : asm/make_i386_sysv_elf_gas.S - asm/jump_i386_sysv_elf_gas.S - asm/ontop_i386_sysv_elf_gas.S - : sysv - 32 - x86 - elf - gcc - ; - -alias asm_sources - : asm/make_i386_sysv_elf_gas.S - asm/jump_i386_sysv_elf_gas.S - asm/ontop_i386_sysv_elf_gas.S - : sysv - 32 - x86 - elf - intel - ; - -# X86/SYSV/MACH-O -alias asm_sources - : asm/make_i386_sysv_macho_gas.S - asm/jump_i386_sysv_macho_gas.S - asm/ontop_i386_sysv_macho_gas.S - : sysv - 32 - x86 - mach-o - clang - ; - -alias asm_sources - : asm/make_i386_sysv_macho_gas.S - asm/jump_i386_sysv_macho_gas.S - asm/ontop_i386_sysv_macho_gas.S - : sysv - 32 - x86 - mach-o - darwin - ; - -# X86/MS/PE -alias asm_sources - : asm/make_i386_ms_pe_gas.asm - asm/jump_i386_ms_pe_gas.asm - asm/ontop_i386_ms_pe_gas.asm - dummy.cpp - : ms - 32 - x86 - pe - clang - ; - -alias asm_sources - : asm/make_i386_ms_pe_gas.asm - asm/jump_i386_ms_pe_gas.asm - asm/ontop_i386_ms_pe_gas.asm - dummy.cpp - : ms - 32 - x86 - pe - clang-win - ; - -alias asm_sources - : asm/make_i386_ms_pe_gas.asm - asm/jump_i386_ms_pe_gas.asm - asm/ontop_i386_ms_pe_gas.asm - dummy.cpp - : ms - 32 - x86 - pe - gcc - ; - -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 - : ms - 32 - x86 - pe - intel - ; - -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 - : ms - 32 - x86 - pe - msvc - ; - # X86_64 # X86_64/SYSV/ELF -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 - : sysv - 64 - x86 - elf - clang - ; - alias asm_sources : asm/make_x86_64_sysv_elf_gas.S asm/jump_x86_64_sysv_elf_gas.S @@ -583,167 +98,6 @@ alias asm_sources gcc ; -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 - : sysv - 64 - x86 - elf - intel - ; - -# X86_64/SYSV/MACH-O -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 - : sysv - 64 - x86 - mach-o - 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 - : sysv - 64 - x86 - mach-o - darwin - ; - -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 - : sysv - 64 - x86 - mach-o - intel - ; - -# X86_64/MS/PE -alias asm_sources - : asm/make_x86_64_ms_pe_gas.asm - asm/jump_x86_64_ms_pe_gas.asm - asm/ontop_x86_64_ms_pe_gas.asm - dummy.cpp - : ms - 64 - x86 - pe - clang - ; - -alias asm_sources - : asm/make_x86_64_ms_pe_gas.asm - asm/jump_x86_64_ms_pe_gas.asm - asm/ontop_x86_64_ms_pe_gas.asm - dummy.cpp - : ms - 64 - x86 - pe - clang-win - ; - -alias asm_sources - : asm/make_x86_64_ms_pe_gas.asm - asm/jump_x86_64_ms_pe_gas.asm - asm/ontop_x86_64_ms_pe_gas.asm - dummy.cpp - : ms - 64 - x86 - pe - gcc - ; - -alias asm_sources - : asm/make_x86_64_ms_pe_masm.asm - asm/jump_x86_64_ms_pe_masm.asm - asm/ontop_x86_64_ms_pe_masm.asm - dummy.cpp - : ms - 64 - x86 - pe - intel - ; - -alias asm_sources - : asm/make_x86_64_ms_pe_masm.asm - asm/jump_x86_64_ms_pe_masm.asm - asm/ontop_x86_64_ms_pe_masm.asm - dummy.cpp - : ms - 64 - x86 - pe - msvc - ; - -# X86_64/SYSV/X32 -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 - : x32 - 64 - x86 - elf - clang - ; - -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 - : x32 - 64 - x86 - elf - gcc - ; - -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 - : x32 - 64 - x86 - elf - intel - ; - -#X86 universal -alias asm_sources - : asm/make_i386_x86_64_sysv_macho_gas.S - asm/jump_i386_x86_64_sysv_macho_gas.S - asm/ontop_i386_x86_64_sysv_macho_gas.S - : sysv - 32_64 - x86 - mach-o - ; - -# COMBINED -alias asm_sources - : asm/make_combined_sysv_macho_gas.S - asm/jump_combined_sysv_macho_gas.S - asm/ontop_combined_sysv_macho_gas.S - : sysv - combined - mach-o - ; - explicit asm_sources ; @@ -753,46 +107,6 @@ alias impl_sources : fcontext ; -# ucontext_t -alias impl_sources - : continuation.cpp - fiber.cpp - : ucontext - [ requires cxx11_auto_declarations - cxx11_constexpr - cxx11_defaulted_functions - cxx11_final - cxx11_hdr_thread - cxx11_hdr_tuple - cxx11_lambdas - cxx11_noexcept - cxx11_nullptr - cxx11_rvalue_references - cxx11_template_aliases - cxx11_thread_local - cxx11_variadic_templates ] - ; - -# WinFiber -alias impl_sources - : continuation.cpp - fiber.cpp - : winfib - [ requires cxx11_auto_declarations - cxx11_constexpr - cxx11_defaulted_functions - cxx11_final - cxx11_hdr_thread - cxx11_hdr_tuple - cxx11_lambdas - cxx11_noexcept - cxx11_nullptr - cxx11_rvalue_references - cxx11_template_aliases - cxx11_thread_local - cxx11_variadic_templates ] - ; - explicit impl_sources ; obj cxx11_hdr_mutex_check : ../build/cxx11_hdr_mutex.cpp ; @@ -803,13 +117,6 @@ local cxx11_mutex = [ check-target-builds : /boost/thread//boost_thread ] ; -alias stack_traits_sources - : windows/stack_traits.cpp - : windows - : - : $(cxx11_mutex) - ; - alias stack_traits_sources : posix/stack_traits.cpp : diff --git a/example/callcc/Jamfile.v2 b/example/Jamfile.v2 similarity index 82% rename from example/callcc/Jamfile.v2 rename to example/Jamfile.v2 index f6bf504..7794597 100644 --- a/example/callcc/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -15,7 +15,7 @@ import os ; import toolset ; import architecture ; -project boost/context/example/callcc +project boost/context/example : requirements /boost/context//boost_context gcc,on:-fsplit-stack @@ -70,6 +70,26 @@ exe segmented : segmented.cpp ; +exe circle + : circle.cpp + ; + +exe unwind_ucontext + : unwind_ucontext.cpp + ; + +exe unwind_fiber_context + : unwind_fiber_context.cpp + ; + +exe unwind_multiple + : unwind_multiple.cpp + ; + +exe unwind_main + : unwind_main.cpp + ; + #exe backtrace # : backtrace.cpp # ; diff --git a/example/backtrace.cpp b/example/backtrace.cpp new file mode 100644 index 0000000..d1e1efc --- /dev/null +++ b/example/backtrace.cpp @@ -0,0 +1,91 @@ + +// 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) + +#define UNW_LOCAL_ONLY + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#define _U_VERSION 1 + +namespace ctx = boost::context; + +struct X { + int i; + X(int i_) : i{ i_ } { std::cout << "X(" << i << ")" << std::endl; } + ~X() { std::cout << "~X(" << i << ")" << std::endl; } +}; + +void print_data( unw_cursor_t * cursor) { + unw_proc_info_t pi; + if ( 0 > unw_get_proc_info( cursor, & pi) ) { + std::fprintf( stderr, "unw_get_proc_info failed\n"); + return; + } + char sym[256]; + unw_word_t offset; + if ( 0 > unw_get_proc_name( cursor, sym, sizeof( sym), & offset) ) { + std::fprintf( stderr, "unw_get_proc_name failed\n"); + return; + } + char * nameptr = sym; + int status; + char * demangled = abi::__cxa_demangle( sym, nullptr, nullptr, & status); + if ( 0 == status) { + nameptr = demangled; + } + std::printf("(%s\n", nameptr); + std::free( demangled); + std::printf("lsda=0x%lx, personality=0x%lx\n", pi.lsda, pi.handler); +} + +void backtrace( ctx::fiber_context && c) { + unw_cursor_t cursor; + unw_context_t context; + unw_getcontext( & context); + unw_init_local( & cursor, & context); + // print_data( & cursor); + while ( 0 < unw_step( & cursor) ) { + print_data( & cursor); + std::printf("\n"); + } + std::printf("unwinding done\n"); + std::move( c).resume(); +} + +void /* __attribute__((optimize("O0"))) */ bar( ctx::fiber_context && c) { + X x{ 3 }; + backtrace( std::move( c) ); + std::cout << "returned from unwind()" << std::endl; +} + +void /* __attribute__((optimize("O0"))) */ foo( ctx::fiber_context && c) { + X x{ 2 }; + bar( std::move( c) ); + std::cout << "returned from bar()" << std::endl; +} + +ctx::fiber_context /* __attribute__((optimize("O0"))) */ f( ctx::fiber_context && c) { + X x{ 1 }; + foo( std::move( c) ); + std::cout << "returned from foo()" << std::endl; + return std::move( c); +} + +int main() { + ctx::fiber_context{ f }.resume(); + std::cout << "main: done" << std::endl; + return EXIT_SUCCESS; +} diff --git a/example/callcc/backtrace.cpp b/example/callcc/backtrace.cpp deleted file mode 100644 index 43acc57..0000000 --- a/example/callcc/backtrace.cpp +++ /dev/null @@ -1,57 +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) - -#define UNW_LOCAL_ONLY - -#include -#include - -#include - -#include - -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::continuation f1( ctx::continuation && c) { - foo(); - return std::move( c); -} - -int main() { - ctx::callcc( f1); - std::cout << "main: done" << std::endl; - return EXIT_SUCCESS; -} diff --git a/example/callcc/circle.cpp b/example/callcc/circle.cpp deleted file mode 100644 index 4dd4036..0000000 --- a/example/callcc/circle.cpp +++ /dev/null @@ -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 -#include -#include - -#include - -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; -} diff --git a/example/callcc/echosse.cpp b/example/callcc/echosse.cpp deleted file mode 100644 index 4b76ffc..0000000 --- a/example/callcc/echosse.cpp +++ /dev/null @@ -1,46 +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 -#include -#include -#include -#include - -#include - -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]; -} - - -int main( int argc, char * argv[]) { - int i = 0; - ctx::continuation c = ctx::callcc( - [&i](ctx::continuation && c) { - for (;;) { - std::cout << i; - echoSSE( i); - std::cout << " "; - c = c.resume(); - } - return std::move( c); - }); - for (; i < 10; ++i) { - c = c.resume(); - } - std::cout << "\nmain: done" << std::endl; - return EXIT_SUCCESS; -} diff --git a/example/callcc/endless_loop.cpp b/example/callcc/endless_loop.cpp deleted file mode 100644 index 318bb88..0000000 --- a/example/callcc/endless_loop.cpp +++ /dev/null @@ -1,28 +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 -#include - -#include - -namespace ctx = boost::context; - -ctx::continuation foo( ctx::continuation && c) { - do { - std::cout << "foo\n"; - } while ( ( c = c.resume() ) ); - return std::move( c); -} - -int main() { - ctx::continuation c = ctx::callcc( foo); - do { - std::cout << "bar\n"; - } while ( ( c = c.resume() ) ); - std::cout << "main: done" << std::endl; - return EXIT_SUCCESS; -} diff --git a/example/callcc/jump.cpp b/example/callcc/jump.cpp deleted file mode 100644 index ab5d6b7..0000000 --- a/example/callcc/jump.cpp +++ /dev/null @@ -1,35 +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 -#include - -#include - -namespace ctx = boost::context; - -int main() { - ctx::continuation c; - int data = 1; - c = ctx::callcc( - [&data](ctx::continuation && c){ - std::cout << "entered first time: " << data << std::endl; - data += 2; - c = c.resume(); - std::cout << "entered second time: " << data << std::endl; - return std::move( c); - }); - std::cout << "returned first time: " << data << std::endl; - data += 2; - c = c.resume(); - if ( c) { - std::cout << "returned second time: " << data << std::endl; - } else { - std::cout << "returned second time: execution context terminated" << std::endl; - } - std::cout << "main: done" << std::endl; - return EXIT_SUCCESS; -} diff --git a/example/callcc/jump_mov.cpp b/example/callcc/jump_mov.cpp deleted file mode 100644 index 1f522ef..0000000 --- a/example/callcc/jump_mov.cpp +++ /dev/null @@ -1,59 +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 -#include - -#include - -namespace ctx = boost::context; - -class moveable { -public: - int value; - - moveable() : - value( -1) { - } - - moveable( int v) : - value( v) { - } - - moveable( moveable && other) { - std::swap( value, other.value); - } - - moveable & operator=( moveable && other) { - if ( this == & other) return * this; - value = other.value; - other.value = -1; - return * this; - } - - moveable( moveable const& other) = delete; - moveable & operator=( moveable const& other) = delete; -}; - -int main() { - ctx::continuation c; - moveable data{ 1 }; - c = ctx::callcc( std::allocator_arg, ctx::fixedsize_stack{}, - [&data](ctx::continuation && c){ - std::cout << "entered first time: " << data.value << std::endl; - data = std::move( moveable{ 3 }); - c = c.resume(); - std::cout << "entered second time: " << data.value << std::endl; - data = std::move( moveable{}); - return std::move( c); - }); - std::cout << "returned first time: " << data.value << std::endl; - data.value = 5; - c = c.resume(); - std::cout << "returned second time: " << data.value << std::endl; - std::cout << "main: done" << std::endl; - return EXIT_SUCCESS; -} diff --git a/example/callcc/jump_void.cpp b/example/callcc/jump_void.cpp deleted file mode 100644 index 7cb5d41..0000000 --- a/example/callcc/jump_void.cpp +++ /dev/null @@ -1,28 +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 -#include - -#include - -namespace ctx = boost::context; - -ctx::continuation f1( ctx::continuation && c) { - std::cout << "f1: entered first time" << std::endl; - c = c.resume(); - std::cout << "f1: entered second time" << std::endl; - return std::move( c); -} - -int main() { - ctx::continuation c = ctx::callcc( f1); - std::cout << "f1: returned first time" << std::endl; - c = c.resume(); - std::cout << "f1: returned second time" << std::endl; - std::cout << "main: done" << std::endl; - return EXIT_SUCCESS; -} diff --git a/example/callcc/ontop.cpp b/example/callcc/ontop.cpp deleted file mode 100644 index d59fde8..0000000 --- a/example/callcc/ontop.cpp +++ /dev/null @@ -1,40 +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 -#include -#include - -#include - -namespace ctx = boost::context; - -int main() { - int data = 0; - ctx::continuation c = ctx::callcc( [&data](ctx::continuation && c) { - std::cout << "f1: entered first time: " << data << std::endl; - data += 1; - c = c.resume(); - std::cout << "f1: entered second time: " << data << std::endl; - data += 1; - c = c.resume(); - std::cout << "f1: entered third time: " << data << std::endl; - return std::move( c); - }); - std::cout << "f1: returned first time: " << data << std::endl; - data += 1; - c = c.resume(); - std::cout << "f1: returned second time: " << data << std::endl; - data += 1; - c = c.resume_with( [&data](ctx::continuation && c){ - std::cout << "f2: entered: " << data << std::endl; - data = -1; - return std::move( c); - }); - std::cout << "f1: returned third time" << std::endl; - std::cout << "main: done" << std::endl; - return EXIT_SUCCESS; -} diff --git a/example/callcc/ontop_void.cpp b/example/callcc/ontop_void.cpp deleted file mode 100644 index fdc9827..0000000 --- a/example/callcc/ontop_void.cpp +++ /dev/null @@ -1,40 +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 -#include -#include - -#include - -namespace ctx = boost::context; - -ctx::continuation f1( ctx::continuation && c) { - std::cout << "f1: entered first time" << std::endl; - c = c.resume(); - std::cout << "f1: entered second time" << std::endl; - c = c.resume(); - std::cout << "f1: entered third time" << std::endl; - return std::move( c); -} - -ctx::continuation f2( ctx::continuation && c) { - std::cout << "f2: entered" << std::endl; - return std::move( c); -} - -int main() { - ctx::continuation c = ctx::callcc( f1); - std::cout << "f1: returned first time" << std::endl; - c = c.resume(); - std::cout << "f1: returned second time" << std::endl; - c = c.resume_with( f2); - std::cout << "f1: returned third time" << std::endl; - - std::cout << "main: done" << std::endl; - - return EXIT_SUCCESS; -} diff --git a/example/callcc/parser.cpp b/example/callcc/parser.cpp deleted file mode 100644 index b1744f0..0000000 --- a/example/callcc/parser.cpp +++ /dev/null @@ -1,128 +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 -#include -#include -#include -#include -#include -#include - -#include - -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 cb; - - char pull(){ - return std::char_traits::to_char_type(is.get()); - } - - void scan(){ - do{ - next=pull(); - } - while(isspace(next)); - } - -public: - Parser(std::istream& is_,std::function 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"); - // execute parser in new execution context - ctx::continuation source; - // user-code pulls parsed data from parser - // invert control flow - char c; - bool done = false; - source=ctx::callcc( - [&is,&c,&done](ctx::continuation && sink){ - // create parser with callback function - Parser p( is, - [&sink,&c](char c_){ - // resume main execution context - c = c_; - sink=sink.resume(); - }); - // start recursive parsing - p.run(); - // signal termination - done = true; - // resume main execution context - return std::move(sink); - }); - while(!done){ - printf("Parsed: %c\n",c); - source=source.resume(); - } - std::cout << "main: done" << std::endl; - return EXIT_SUCCESS; - } catch (std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } - return EXIT_FAILURE; -} diff --git a/example/callcc/throw.cpp b/example/callcc/throw.cpp deleted file mode 100644 index 723a956..0000000 --- a/example/callcc/throw.cpp +++ /dev/null @@ -1,47 +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 -#include -#include -#include -#include - -#include - -namespace ctx = boost::context; - -struct my_exception : public std::runtime_error { - ctx::continuation c; - my_exception( ctx::continuation && c_, std::string const& what) : - std::runtime_error{ what }, - c{ std::move( c_) } { - } -}; - -int main() { - ctx::continuation c = ctx::callcc([](ctx::continuation && c) { - for (;;) { - try { - std::cout << "entered" << std::endl; - c = c.resume(); - } catch ( my_exception & ex) { - std::cerr << "my_exception: " << ex.what() << std::endl; - return std::move( ex.c); - } - } - return std::move( c); - }); - c = c.resume_with( - [](ctx::continuation && c){ - throw my_exception(std::move( c), "abc"); - return std::move( c); - }); - - std::cout << "main: done" << std::endl; - - return EXIT_SUCCESS; -} diff --git a/example/fiber/circle.cpp b/example/circle.cpp similarity index 73% rename from example/fiber/circle.cpp rename to example/circle.cpp index 9631a17..c2dc5f9 100644 --- a/example/fiber/circle.cpp +++ b/example/circle.cpp @@ -8,13 +8,13 @@ #include #include -#include +#include namespace ctx = boost::context; int main() { - ctx::fiber_handle f1, f2, f3; - f3 = ctx::fiber_handle{[&](ctx::fiber_handle && f)->ctx::fiber_handle{ + ctx::fiber_context f1, f2, f3; + f3 = ctx::fiber_context{[&](ctx::fiber_context && f)->ctx::fiber_context{ f2 = std::move( f); for (;;) { std::cout << "f3\n"; @@ -22,7 +22,7 @@ int main() { } return {}; }}; - f2 = ctx::fiber_handle{[&](ctx::fiber_handle && f)->ctx::fiber_handle{ + f2 = ctx::fiber_context{[&](ctx::fiber_context && f)->ctx::fiber_context{ f1 = std::move( f); for (;;) { std::cout << "f2\n"; @@ -30,7 +30,7 @@ int main() { } return {}; }}; - f1 = ctx::fiber_handle{[&](ctx::fiber_handle && /*main*/)->ctx::fiber_handle{ + f1 = ctx::fiber_context{[&](ctx::fiber_context && /*main*/)->ctx::fiber_context{ for (;;) { std::cout << "f1\n"; f3 = std::move( f2).resume(); diff --git a/example/fiber/echosse.cpp b/example/echosse.cpp similarity index 90% rename from example/fiber/echosse.cpp rename to example/echosse.cpp index 3a8203c..f878e0c 100644 --- a/example/fiber/echosse.cpp +++ b/example/echosse.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include namespace ctx = boost::context; @@ -28,8 +28,8 @@ void echoSSE( int i) { int main( int argc, char * argv[]) { int i = 0; - ctx::fiber_handle f{ - [&i](ctx::fiber_handle && f) { + ctx::fiber_context f{ + [&i](ctx::fiber_context && f) { for (;;) { std::cout << i; echoSSE( i); diff --git a/example/fiber/endless_loop.cpp b/example/endless_loop.cpp similarity index 82% rename from example/fiber/endless_loop.cpp rename to example/endless_loop.cpp index 04e73af..984a909 100644 --- a/example/fiber/endless_loop.cpp +++ b/example/endless_loop.cpp @@ -7,11 +7,11 @@ #include #include -#include +#include namespace ctx = boost::context; -ctx::fiber_handle bar( ctx::fiber_handle && f) { +ctx::fiber_context bar( ctx::fiber_context && f) { do { std::cout << "bar\n"; f = std::move( f).resume(); @@ -20,7 +20,7 @@ ctx::fiber_handle bar( ctx::fiber_handle && f) { } int main() { - ctx::fiber_handle f{ bar }; + ctx::fiber_context f{ bar }; do { std::cout << "foo\n"; f = std::move( f).resume(); diff --git a/example/execution_context_v2/Jamfile.v2 b/example/execution_context_v2/Jamfile.v2 deleted file mode 100644 index d134d47..0000000 --- a/example/execution_context_v2/Jamfile.v2 +++ /dev/null @@ -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 - /boost/context//boost_context - gcc,on:-fsplit-stack - gcc,on:-DBOOST_USE_SEGMENTED_STACKS - clang,on:-fsplit-stack - clang,on:-DBOOST_USE_SEGMENTED_STACKS - static - 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 -# : "-lunwind" -# ; diff --git a/example/execution_context_v2/backtrace.cpp b/example/execution_context_v2/backtrace.cpp deleted file mode 100644 index dcf8220..0000000 --- a/example/execution_context_v2/backtrace.cpp +++ /dev/null @@ -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 -#include - -#include - -#include - -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; -} diff --git a/example/execution_context_v2/echosse.cpp b/example/execution_context_v2/echosse.cpp deleted file mode 100644 index 51ddcc6..0000000 --- a/example/execution_context_v2/echosse.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include - -#include - -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; -} diff --git a/example/execution_context_v2/fibonacci.cpp b/example/execution_context_v2/fibonacci.cpp deleted file mode 100644 index a3d78fe..0000000 --- a/example/execution_context_v2/fibonacci.cpp +++ /dev/null @@ -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 -#include -#include - -#include - -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<(result)<<" "; - } - std::cout< -#include - -#include - -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; -} diff --git a/example/execution_context_v2/jump_void.cpp b/example/execution_context_v2/jump_void.cpp deleted file mode 100644 index 2ce9090..0000000 --- a/example/execution_context_v2/jump_void.cpp +++ /dev/null @@ -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 -#include - -#include - -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; -} diff --git a/example/execution_context_v2/ontop.cpp b/example/execution_context_v2/ontop.cpp deleted file mode 100644 index 480012f..0000000 --- a/example/execution_context_v2/ontop.cpp +++ /dev/null @@ -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 -#include -#include - -#include - -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; -} diff --git a/example/execution_context_v2/ontop_void.cpp b/example/execution_context_v2/ontop_void.cpp deleted file mode 100644 index ef15498..0000000 --- a/example/execution_context_v2/ontop_void.cpp +++ /dev/null @@ -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 -#include -#include - -#include - -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; -} diff --git a/example/execution_context_v2/parameter.cpp b/example/execution_context_v2/parameter.cpp deleted file mode 100644 index 262f73e..0000000 --- a/example/execution_context_v2/parameter.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include - -#include -#include -#include - -typedef boost::variant variant_t; - -namespace ctx = boost::context; - -class X{ -private: - std::exception_ptr excptr_; - ctx::execution_context ctx_; - -public: - X(): - excptr_(), - ctx_( - [this](ctx::execution_context && ctx, variant_t data){ - try { - for (;;) { - int i = boost::get(data); - data = boost::lexical_cast(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(data); - } -}; - -int main() { - X x; - std::cout< -#include -#include -#include -#include -#include - -#include - -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 cb; - - char pull(){ - return std::char_traits::to_char_type(is.get()); - } - - void scan(){ - do{ - next=pull(); - } - while(isspace(next)); - } - -public: - Parser(std::istream& is_,std::function 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 source( - [&is,&done,&except](ctx::execution_context && 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; -} diff --git a/example/execution_context_v2/throw.cpp b/example/execution_context_v2/throw.cpp deleted file mode 100644 index 35e05c7..0000000 --- a/example/execution_context_v2/throw.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include - -#include - -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 && 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; -} diff --git a/example/fiber/Jamfile.v2 b/example/fiber/Jamfile.v2 deleted file mode 100644 index 98297af..0000000 --- a/example/fiber/Jamfile.v2 +++ /dev/null @@ -1,84 +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/fiber - : requirements - /boost/context//boost_context - static - "-lunwind" - multi - ; - -exe stack - : stack.cpp - ; - -exe jump_void - : jump_void.cpp - ; - -exe jump - : jump.cpp - ; - -exe jump_mov - : jump_mov.cpp - ; - -exe ontop_void - : ontop_void.cpp - ; - -exe throw - : throw.cpp - ; - -exe fibonacci - : fibonacci.cpp - ; - -exe parser - : parser.cpp - ; - -exe ontop - : ontop.cpp - ; - -exe endless_loop - : endless_loop.cpp - ; - -exe circle - : circle.cpp - ; - -exe migrateable - : migrateable.cpp - ; - -exe hosting_thread - : hosting_thread.cpp - ; - -#exe backtrace -# : backtrace.cpp -# ; - -#exe echosse -# : echosse.cpp -# ; diff --git a/example/fiber/backtrace.cpp b/example/fiber/backtrace.cpp deleted file mode 100644 index db6aad2..0000000 --- a/example/fiber/backtrace.cpp +++ /dev/null @@ -1,57 +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) - -#define UNW_LOCAL_ONLY - -#include -#include - -#include - -#include - -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::fiber_handle f1( ctx::fiber_handle && c) { - foo(); - return std::move( c); -} - -int main() { - ctx::fiber_handle{ f1 }.resume(); - std::cout << "main: done" << std::endl; - return EXIT_SUCCESS; -} diff --git a/example/fiber/fibonacci.cpp b/example/fiber/fibonacci.cpp deleted file mode 100644 index c5b5ab2..0000000 --- a/example/fiber/fibonacci.cpp +++ /dev/null @@ -1,50 +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 -#include -#include - -#include - -namespace ctx = boost::context; - -class F { -private: - int a; - ctx::fiber_handle f; - -public: - F() : - a{ 0 }, - f{ [this](ctx::fiber_handle && f){ - a=0; - int b=1; - for(;;){ - f = std::move( f).resume(); - int next=a+b; - a=b; - b=next; - } - return std::move( f); - }} { - } - - int call() { - f = std::move( f).resume(); - return a; - } -}; - -int main() { - F f; - for ( int j = 0; j < 10; ++j) { - std::cout << f.call() << " "; - } - std::cout << std::endl; - std::cout << "main: done" << std::endl; - return EXIT_SUCCESS; -} diff --git a/example/fiber/hosting_thread.cpp b/example/fiber/hosting_thread.cpp deleted file mode 100644 index 8680516..0000000 --- a/example/fiber/hosting_thread.cpp +++ /dev/null @@ -1,31 +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) - -#define UNW_LOCAL_ONLY - -#include -#include -#include - -#include - -namespace ctx = boost::context; - -int main() { - ctx::fiber_handle f{ - [](ctx::fiber_handle && m){ - std::cout << "m in main thread: " << std::boolalpha << m.can_resume() << std::endl; - ctx::fiber_handle * pm = & m; - std::thread{ [pm]{ std::cout << "m in other thread: " << std::boolalpha << pm->can_resume() << std::endl; }}.join(); - m = std::move( m).resume(); - return std::move( m); - }}; - std::cout << "f: before resumption: " << std::boolalpha << f.can_resume() << std::endl; - f = std::move( f).resume(); - std::cout << "f: after resumption: " << std::boolalpha << f.can_resume() << std::endl; - std::cout << "main: done" << std::endl; - return EXIT_SUCCESS; -} diff --git a/example/fiber/migrateable.cpp b/example/fiber/migrateable.cpp deleted file mode 100644 index f686b14..0000000 --- a/example/fiber/migrateable.cpp +++ /dev/null @@ -1,27 +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) - -#define UNW_LOCAL_ONLY - -#include -#include - -#include - -namespace ctx = boost::context; - -int main() { - ctx::fiber_handle f{ - [](ctx::fiber_handle && m){ - std::cout << "fiber `m`: " << std::boolalpha << m.can_resume_from_any_thread() << std::endl; - m = std::move( m).resume(); - return std::move( m); - }}; - std::cout << "fiber `f`: " << std::boolalpha << f.can_resume_from_any_thread() << std::endl; - f = std::move( f).resume(); - std::cout << "main: done" << std::endl; - return EXIT_SUCCESS; -} diff --git a/example/fiber/stack.cpp b/example/fiber/stack.cpp deleted file mode 100644 index 8879326..0000000 --- a/example/fiber/stack.cpp +++ /dev/null @@ -1,25 +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 -#include - -#include - -namespace ctx = boost::context; - -int main() { - std::cout << "minimum stack size: " << ctx::stack_traits::minimum_size() << " byte\n"; - std::cout << "default stack size: " << ctx::stack_traits::default_size() << " byte\n"; - std::cout << "maximum stack size: "; - if ( ctx::stack_traits::is_unbounded() ) { - std::cout << "unlimited\n"; - } else { - std::cout << ctx::stack_traits::maximum_size() << " byte\n"; - } - std::cout << "main: done" << std::endl; - return EXIT_SUCCESS; -} diff --git a/example/callcc/fibonacci.cpp b/example/fibonacci.cpp similarity index 67% rename from example/callcc/fibonacci.cpp rename to example/fibonacci.cpp index 170b9f2..30a191e 100644 --- a/example/callcc/fibonacci.cpp +++ b/example/fibonacci.cpp @@ -8,29 +8,32 @@ #include #include -#include +#include namespace ctx = boost::context; int main() { int a; - ctx::continuation c=ctx::callcc( - [&a](ctx::continuation && c){ + ctx::fiber_context f{ + [&a](ctx::fiber_context && f){ a=0; int b=1; for(;;){ - c=c.resume(); + f = std::move( f).resume(); int next=a+b; a=b; b=next; } - return std::move( c); - }); + return std::move( f); + }}; for ( int j = 0; j < 10; ++j) { + f = std::move( f).resume(); std::cout << a << " "; - c=c.resume(); } std::cout << std::endl; + if ( f) { + std::move( f).resume_with( ctx::unwind_fiber); + } std::cout << "main: done" << std::endl; return EXIT_SUCCESS; } diff --git a/example/fiber/jump.cpp b/example/jump.cpp similarity index 89% rename from example/fiber/jump.cpp rename to example/jump.cpp index d8149ba..671d065 100644 --- a/example/fiber/jump.cpp +++ b/example/jump.cpp @@ -7,14 +7,14 @@ #include #include -#include +#include namespace ctx = boost::context; int main() { int data = 1; - ctx::fiber_handle f{ - [&data](ctx::fiber_handle && f){ + ctx::fiber_context f{ + [&data](ctx::fiber_context && f){ std::cout << "entered first time: " << data << std::endl; data += 2; f = std::move( f).resume(); diff --git a/example/fiber/jump_mov.cpp b/example/jump_mov.cpp similarity index 92% rename from example/fiber/jump_mov.cpp rename to example/jump_mov.cpp index 6fa9f65..e64d8b5 100644 --- a/example/fiber/jump_mov.cpp +++ b/example/jump_mov.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include namespace ctx = boost::context; @@ -40,7 +40,8 @@ public: int main() { moveable data{ 1 }; - ctx::fiber_handle f{ [&data](ctx::fiber_handle && f){ + ctx::fiber_context f{ + [&data](ctx::fiber_context && f){ std::cout << "entered first time: " << data.value << std::endl; data = std::move( moveable{ 3 }); f = std::move( f).resume(); diff --git a/example/fiber/jump_void.cpp b/example/jump_void.cpp similarity index 85% rename from example/fiber/jump_void.cpp rename to example/jump_void.cpp index b391974..9a515e8 100644 --- a/example/fiber/jump_void.cpp +++ b/example/jump_void.cpp @@ -7,11 +7,11 @@ #include #include -#include +#include namespace ctx = boost::context; -ctx::fiber_handle f1( ctx::fiber_handle && f) { +ctx::fiber_context f1( ctx::fiber_context && f) { std::cout << "f1: entered first time" << std::endl; f = std::move( f).resume(); std::cout << "f1: entered second time" << std::endl; @@ -19,7 +19,7 @@ ctx::fiber_handle f1( ctx::fiber_handle && f) { } int main() { - ctx::fiber_handle f{ f1 }; + ctx::fiber_context f{ f1 }; f = std::move( f).resume(); std::cout << "f1: returned first time" << std::endl; f = std::move( f).resume(); diff --git a/example/fiber/ontop.cpp b/example/ontop.cpp similarity index 88% rename from example/fiber/ontop.cpp rename to example/ontop.cpp index 91836a2..0f98481 100644 --- a/example/fiber/ontop.cpp +++ b/example/ontop.cpp @@ -8,13 +8,13 @@ #include #include -#include +#include namespace ctx = boost::context; int main() { int data = 0; - ctx::fiber_handle f{ [&data](ctx::fiber_handle && f) { + ctx::fiber_context f{ [&data](ctx::fiber_context && f) { std::cout << "f1: entered first time: " << data << std::endl; data += 1; f = std::move( f).resume(); @@ -30,7 +30,7 @@ int main() { f = std::move( f).resume(); std::cout << "f1: returned second time: " << data << std::endl; data += 1; - f = std::move( f).resume_with([&data](ctx::fiber_handle && f){ + f = std::move( f).resume_with([&data](ctx::fiber_context && f){ std::cout << "f2: entered: " << data << std::endl; data = -1; return std::move( f); diff --git a/example/fiber/ontop_void.cpp b/example/ontop_void.cpp similarity index 85% rename from example/fiber/ontop_void.cpp rename to example/ontop_void.cpp index ebae39e..edca806 100644 --- a/example/fiber/ontop_void.cpp +++ b/example/ontop_void.cpp @@ -8,11 +8,11 @@ #include #include -#include +#include namespace ctx = boost::context; -ctx::fiber_handle f1( ctx::fiber_handle && f) { +ctx::fiber_context f1( ctx::fiber_context && f) { std::cout << "f1: entered first time" << std::endl; f = std::move( f).resume(); std::cout << "f1: entered second time" << std::endl; @@ -21,13 +21,13 @@ ctx::fiber_handle f1( ctx::fiber_handle && f) { return std::move( f); } -ctx::fiber_handle f2( ctx::fiber_handle && f) { +ctx::fiber_context f2( ctx::fiber_context && f) { std::cout << "f2: entered" << std::endl; return std::move( f); } int main() { - ctx::fiber_handle f{ f1 }; + ctx::fiber_context f{ f1 }; f = std::move( f).resume(); std::cout << "f1: returned first time" << std::endl; f = std::move( f).resume(); diff --git a/example/fiber/parser.cpp b/example/parser.cpp similarity index 95% rename from example/fiber/parser.cpp rename to example/parser.cpp index e506994..499c6bd 100644 --- a/example/fiber/parser.cpp +++ b/example/parser.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include namespace ctx = boost::context; @@ -98,7 +98,7 @@ int main() { char c; bool done = false; // execute parser in new execution context - ctx::fiber_handle source{[&is,&c,&done](ctx::fiber_handle && sink){ + ctx::fiber_context source{[&is,&c,&done](ctx::fiber_context && sink){ // create parser with callback function Parser p( is, [&sink,&c](char c_){ diff --git a/example/callcc/segmented.cpp b/example/segmented.cpp similarity index 89% rename from example/callcc/segmented.cpp rename to example/segmented.cpp index 9894e9d..b9f9e25 100644 --- a/example/callcc/segmented.cpp +++ b/example/segmented.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include namespace ctx = boost::context; @@ -41,11 +41,11 @@ int main() { std::cout << "initial stack size = " << ctx::fixedsize_stack::traits_type::default_size() / 1024 << "kB" << std::endl; std::cout << "application might fail" << std::endl; #endif - ctx::continuation c = ctx::callcc( - [count](ctx::continuation && c){ + ctx::fiber_context{ + [count](ctx::fiber_context && f){ bar( count); - return std::move( c); - }); + return std::move( f); + }}.resume(); std::cout << "main: done" << std::endl; return EXIT_SUCCESS; } diff --git a/example/callcc/stack.cpp b/example/stack.cpp similarity index 100% rename from example/callcc/stack.cpp rename to example/stack.cpp diff --git a/example/fiber/throw.cpp b/example/throw.cpp similarity index 75% rename from example/fiber/throw.cpp rename to example/throw.cpp index a1bbea2..157f414 100644 --- a/example/fiber/throw.cpp +++ b/example/throw.cpp @@ -10,20 +10,20 @@ #include #include -#include +#include namespace ctx = boost::context; struct my_exception : public std::runtime_error { - ctx::fiber_handle f; - my_exception( ctx::fiber_handle && f_, std::string const& what) : + ctx::fiber_context f; + my_exception( ctx::fiber_context && f_, std::string const& what) : std::runtime_error{ what }, f{ std::move( f_) } { } }; int main() { - ctx::fiber_handle f{[](ctx::fiber_handle && f) ->ctx::fiber_handle { + ctx::fiber_context f{[](ctx::fiber_context && f) ->ctx::fiber_context { std::cout << "entered" << std::endl; try { f = std::move( f).resume(); @@ -34,7 +34,7 @@ int main() { return {}; }}; f = std::move( f).resume(); - f = std::move( f).resume_with([](ctx::fiber_handle && f) ->ctx::fiber_handle { + f = std::move( f).resume_with([](ctx::fiber_context && f) ->ctx::fiber_context { throw my_exception(std::move( f), "abc"); return {}; }); diff --git a/example/unwind_fiber_context.cpp b/example/unwind_fiber_context.cpp new file mode 100644 index 0000000..e297147 --- /dev/null +++ b/example/unwind_fiber_context.cpp @@ -0,0 +1,75 @@ + +// Copyright Oliver Kowalke 2019. +// 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 +#include +#include + +#include + +#include + +namespace ctx = boost::context; + +void throw_int() { + try { + throw 1; + } catch (...) { + std::printf("int catched\n"); + } +} + +void throw_exception() { + try { + throw std::runtime_error("abc"); + } catch (...) { + std::printf("std::runtime_error() catched\n"); + } +} + +struct X { + int i; + X( int i_) : i{ i_ } { std::printf("X(%d)\n", i); } + ~X() { std::printf("~X(%d)\n", i); } + + X( X const&) = delete; + X& operator=( X const&) = delete; + + X( X &&) = delete; + X& operator=( X &&) = delete; +}; + +void bar( int i, ctx::fiber_context && fc) { + if ( 0 < i) { + X x{ i }; + bar( --i, std::move( fc) ); + } else { + try { + std::move( fc).resume(); + } catch (...) { + std::printf("catch-all: still needs re-throw\n"); + throw; + } + } + std::printf("bar returns\n"); +} + +ctx::fiber_context foo( ctx::fiber_context && fc) { + throw_int(); + throw_exception(); + bar( 5, std::move( fc) ); + std::printf("foo returns\n"); + return {}; +}; + +int main( int argc, char * argv[]) { + ctx::fiber_context f{ foo }; + f = std::move( f).resume(); + std::printf("unwind fiber\n"); + std::move( f).resume_with( ctx::unwind_fiber); + std::printf("main: done\n"); + return EXIT_SUCCESS; +} diff --git a/example/unwind_main.cpp b/example/unwind_main.cpp new file mode 100644 index 0000000..0752574 --- /dev/null +++ b/example/unwind_main.cpp @@ -0,0 +1,58 @@ + +// Copyright Oliver Kowalke 2019. +// 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 +#include +#include + +#include + +#include + +namespace ctx = boost::context; + +struct X { + int i; + X( int i_) : i{ i_ } { std::printf("X(%d)\n", i); } + ~X() { std::printf("~X(%d)\n", i); } + + X( X const&) = delete; + X& operator=( X const&) = delete; + + X( X &&) = delete; + X& operator=( X &&) = delete; +}; + +ctx::fiber_context bar( ctx::fiber_context && f_foo) { + std::printf("bar entered\n"); + X x2{ 2 }; + std::printf("bar resumes foo\n"); + f_foo = std::move( f_foo).resume(); + std::printf("bar returns\n"); + return std::move( f_foo); +} + +ctx::fiber_context foo( ctx::fiber_context && f_main) { + std::printf("foo entered\n"); + ctx::fiber_context f_bar{ bar }; + std::printf("foo resumes bar\n"); + f_bar = std::move( f_bar).resume(); + std::printf("foo destroys main\n"); + std::move( f_main).resume_with( ctx::unwind_fiber); + std::printf("foo resumes bar\n"); + std::move( f_bar).resume(); + std::printf("foo terminates application\n"); + std::exit( 0); + return {}; +}; + +int main( int argc, char * argv[]) { + X x1{ 1 }; + ctx::fiber_context f{ foo }; + std::printf("main resumes foo\n"); + f = std::move( f).resume(); + return EXIT_SUCCESS; +} diff --git a/example/unwind_multiple.cpp b/example/unwind_multiple.cpp new file mode 100644 index 0000000..ae9d18b --- /dev/null +++ b/example/unwind_multiple.cpp @@ -0,0 +1,65 @@ + +// 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 +#include + +#include + +namespace ctx = boost::context; + +int main() { + try { + std::cout << "f0: entered" << std::endl; + ctx::fiber_context f1{ + [](ctx::fiber_context && f0_){ + try { + std::cout << "f1: entered" << std::endl; + ctx::fiber_context f0 = std::move( f0_); + ctx::fiber_context f2{ + [](ctx::fiber_context && f1_){ + try { + std::cout << "f2: entered" << std::endl; + ctx::fiber_context f1 = std::move( f1_); + ctx::fiber_context f3{ + [](ctx::fiber_context && f2){ + std::cout << "f3: entered" << std::endl; + std::cout << "f3: unwinding f2" << std::endl; + std::move( f2).resume_with( ctx::unwind_fiber); + if ( ! f2) { + std::cout << "f3: no valid fiber_context so calling `std::exit(1)`" << std::endl; + std::exit( 1); + } + std::cout << "f3: done" << std::endl; + return std::move( f2); + }}; + std::cout << "f2: resume f3" << std::endl; + f3 = std::move( f3).resume(); + std::cout << "f2: done" << std::endl; + } catch (...) { + std::cout << "f2: catch unwind exception" << std::endl; + throw; + } + return std::move( f1_); + }}; + std::cout << "f1: resume f2" << std::endl; + f2 = std::move( f2).resume(); + std::cout << "f1: done" << std::endl; + } catch (...) { + std::cout << "f1: catch unwind exception" << std::endl; + throw; + } + return std::move( f0_); + }}; + std::cout << "f0: resume f1" << std::endl; + f1 = std::move( f1).resume(); + std::cout << "f0: done" << std::endl; + } catch (...) { + std::cout << "f0: catch unwind exception" << std::endl; + throw; + } + return EXIT_SUCCESS; +} diff --git a/example/unwind_ucontext.cpp b/example/unwind_ucontext.cpp new file mode 100644 index 0000000..f29bbc1 --- /dev/null +++ b/example/unwind_ucontext.cpp @@ -0,0 +1,76 @@ + +// Copyright Oliver Kowalke 2019. +// 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 +#include +#include +#include +#include +#include + +#include +#include + +struct context_t { + ucontext_t ucf; + ucontext_t ucm; +}; + +struct X { + int i; + X( int i_) : i{ i_ } { std::printf("X(%d)\n", i); } + ~X() { std::printf("~X(%d)\n", i); } +}; + +_Unwind_Reason_Code stop_fn( int version, + _Unwind_Action actions, + _Unwind_Exception_Class exc_class, + _Unwind_Exception *exc, + _Unwind_Context *context, + void * param) { + context_t * ctx = ( context_t *) param; + if ( actions & _UA_END_OF_STACK) { + std::printf("end of stack, jump back\n"); + _Unwind_DeleteException( exc); + if ( -1 == ::swapcontext( & ctx->ucf, & ctx->ucm) ) { + std::abort(); + } + } + return _URC_NO_REASON; +} + +void foo( int i, context_t * ctx) { + if ( 0 < i) { + X x{ i }; + foo( --i, ctx); + } else { + _Unwind_Exception * exc = ( _Unwind_Exception *) std::malloc( sizeof( _Unwind_Exception) ); + std::memset( exc, 0, sizeof( * exc) ); + _Unwind_ForcedUnwind( exc, stop_fn, ctx); + //ctx::detail::unwind( stop_fn, ctx); + } + std::printf("return from foo()\n"); +} + +int main( int argc, char * argv[]) { + context_t ctx; + std::vector< char > buffer(16384, '\0'); + void * fn_stack = & buffer[0]; + std::printf("buffer : %p\n", fn_stack); + fn_stack = ( char * )( ( ( ( ( uintptr_t) fn_stack) - 16) >> 4) << 4); + std::printf("aligned : %p\n", fn_stack); + if ( -1 == ::getcontext( & ctx.ucf) ) { + std::abort(); + } + ctx.ucf.uc_stack.ss_sp = fn_stack; + ctx.ucf.uc_stack.ss_size = buffer.size(); + ::makecontext( & ctx.ucf, (void(*)())( foo), 2, 5, & ctx); + if ( -1 == ::swapcontext( & ctx.ucm, & ctx.ucf) ) { + std::abort(); + } + std::printf("main: done\n"); + return EXIT_SUCCESS; +} diff --git a/include/boost/context/all.hpp b/include/boost/context/all.hpp deleted file mode 100644 index efee260..0000000 --- a/include/boost/context/all.hpp +++ /dev/null @@ -1,15 +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 -#include -#include -#include -#include -#include -#include -#include -#include diff --git a/include/boost/context/continuation.hpp b/include/boost/context/continuation.hpp deleted file mode 100644 index 8db62a9..0000000 --- a/include/boost/context/continuation.hpp +++ /dev/null @@ -1,13 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// 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) - -#if defined(BOOST_USE_UCONTEXT) -#include -#elif defined(BOOST_USE_WINFIB) -#include -#else -#include -#endif diff --git a/include/boost/context/continuation_fcontext.hpp b/include/boost/context/continuation_fcontext.hpp deleted file mode 100644 index 7e15dbe..0000000 --- a/include/boost/context/continuation_fcontext.hpp +++ /dev/null @@ -1,370 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// 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_CONTINUATION_H -#define BOOST_CONTEXT_CONTINUATION_H - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) -#include -#endif -#if defined(BOOST_NO_CXX17_STD_INVOKE) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 { - -inline -transfer_t context_unwind( transfer_t t) { - throw forced_unwind( t.fctx); - return { nullptr, nullptr }; -} - -template< typename Rec > -transfer_t 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 context_entry( transfer_t t) noexcept { - // transfer control structure to the context-stack - Rec * rec = static_cast< Rec * >( t.data); - BOOST_ASSERT( nullptr != t.fctx); - BOOST_ASSERT( nullptr != rec); - try { - // jump back to `create_context()` - t = jump_fcontext( t.fctx, nullptr); - // start executing - t.fctx = rec->run( t.fctx); - } catch ( forced_unwind const& e) { - t = { e.fctx, nullptr }; - } - BOOST_ASSERT( nullptr != t.fctx); - // destroy context-stack of `this`context on next context - ontop_fcontext( t.fctx, rec, context_exit< Rec >); - BOOST_ASSERT_MSG( false, "context already terminated"); -} - -template< typename Ctx, typename Fn > -transfer_t context_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); - t.data = nullptr; - Ctx c{ t.fctx }; - // execute function, pass continuation via reference - c = fn( std::move( c) ); -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return { exchange( c.fctx_, nullptr), nullptr }; -#else - return { std::exchange( c.fctx_, nullptr), nullptr }; -#endif -} - -template< typename Ctx, typename StackAlloc, typename Fn > -class record { -private: - stack_context sctx_; - typename std::decay< StackAlloc >::type salloc_; - typename std::decay< Fn >::type fn_; - - static void destroy( record * p) noexcept { - typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_); - stack_context sctx = p->sctx_; - // deallocate record - p->~record(); - // destroy stack with stack allocator - salloc.deallocate( sctx); - } - -public: - record( stack_context sctx, StackAlloc && salloc, - Fn && fn) noexcept : - sctx_( sctx), - salloc_( std::forward< StackAlloc >( salloc)), - fn_( std::forward< Fn >( fn) ) { - } - - record( record const&) = delete; - record & operator=( record const&) = delete; - - void deallocate() noexcept { - destroy( this); - } - - fcontext_t run( fcontext_t fctx) { - Ctx c{ fctx }; - // invoke context-function -#if defined(BOOST_NO_CXX17_STD_INVOKE) - c = invoke( fn_, std::move( c) ); -#else - c = std::invoke( fn_, std::move( c) ); -#endif -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.fctx_, nullptr); -#else - return std::exchange( c.fctx_, nullptr); -#endif - } -}; - -template< typename Record, typename StackAlloc, typename Fn > -fcontext_t create_context1( StackAlloc && salloc, Fn && fn) { - auto sctx = salloc.allocate(); - // reserve space for control structure - void * storage = reinterpret_cast< void * >( - ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( Record) ) ) - & ~static_cast< uintptr_t >( 0xff) ); - // placment new for control structure on context stack - Record * record = new ( storage) Record{ - sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; - // 64byte gab between control structure and stack top - // should be 16byte aligned - void * stack_top = reinterpret_cast< void * >( - reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) ); - void * stack_bottom = reinterpret_cast< void * >( - reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) ); - // create fast-context - const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom); - const fcontext_t fctx = make_fcontext( stack_top, size, & context_entry< Record >); - BOOST_ASSERT( nullptr != fctx); - // transfer control structure to context-stack - return jump_fcontext( fctx, record).fctx; -} - -template< typename Record, typename StackAlloc, typename Fn > -fcontext_t create_context2( preallocated palloc, StackAlloc && salloc, Fn && fn) { - // reserve space for control structure - void * storage = reinterpret_cast< void * >( - ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( Record) ) ) - & ~ static_cast< uintptr_t >( 0xff) ); - // placment new for control structure on context-stack - Record * record = new ( storage) Record{ - palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; - // 64byte gab between control structure and stack top - void * stack_top = reinterpret_cast< void * >( - reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) ); - void * stack_bottom = reinterpret_cast< void * >( - reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) ); - // create fast-context - const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom); - const fcontext_t fctx = make_fcontext( stack_top, size, & context_entry< Record >); - BOOST_ASSERT( nullptr != fctx); - // transfer control structure to context-stack - return jump_fcontext( fctx, record).fctx; -} - -} - -class continuation { -private: - template< typename Ctx, typename StackAlloc, typename Fn > - friend class detail::record; - - template< typename Ctx, typename Fn > - friend detail::transfer_t - detail::context_ontop( detail::transfer_t); - - template< typename StackAlloc, typename Fn > - friend continuation - callcc( std::allocator_arg_t, StackAlloc &&, Fn &&); - - template< typename StackAlloc, typename Fn > - friend continuation - callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&); - - detail::fcontext_t fctx_{ nullptr }; - - continuation( detail::fcontext_t fctx) noexcept : - fctx_{ fctx } { - } - -public: - continuation() noexcept = default; - - ~continuation() { - if ( BOOST_UNLIKELY( nullptr != fctx_) ) { - detail::ontop_fcontext( -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( fctx_, nullptr), -#else - std::exchange( fctx_, nullptr), -#endif - nullptr, - detail::context_unwind); - } - } - - continuation( continuation && other) noexcept { - swap( other); - } - - continuation & operator=( continuation && other) noexcept { - if ( BOOST_LIKELY( this != & other) ) { - continuation tmp = std::move( other); - swap( tmp); - } - return * this; - } - - continuation( continuation const& other) noexcept = delete; - continuation & operator=( continuation const& other) noexcept = delete; - - continuation resume() & { - return std::move( * this).resume(); - } - - continuation resume() && { - BOOST_ASSERT( nullptr != fctx_); - return { detail::jump_fcontext( -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( fctx_, nullptr), -#else - std::exchange( fctx_, nullptr), -#endif - nullptr).fctx }; - } - - template< typename Fn > - continuation resume_with( Fn && fn) & { - return std::move( * this).resume_with( std::forward< Fn >( fn) ); - } - - template< typename Fn > - continuation resume_with( Fn && fn) && { - BOOST_ASSERT( nullptr != fctx_); - auto p = std::make_tuple( std::forward< Fn >( fn) ); - return { detail::ontop_fcontext( -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( fctx_, nullptr), -#else - std::exchange( fctx_, nullptr), -#endif - & p, - detail::context_ontop< continuation, Fn >).fctx }; - } - - explicit operator bool() const noexcept { - return nullptr != fctx_; - } - - bool operator!() const noexcept { - return nullptr == fctx_; - } - - bool operator<( continuation 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, continuation const& other) { - if ( nullptr != other.fctx_) { - return os << other.fctx_; - } else { - return os << "{not-a-context}"; - } - } - - void swap( continuation & other) noexcept { - std::swap( fctx_, other.fctx_); - } -}; - -template< - typename Fn, - typename = detail::disable_overload< continuation, Fn > -> -continuation -callcc( Fn && fn) { - return callcc( - std::allocator_arg, fixedsize_stack(), - std::forward< Fn >( fn) ); -} - -template< typename StackAlloc, typename Fn > -continuation -callcc( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) { - using Record = detail::record< continuation, StackAlloc, Fn >; - return continuation{ - detail::create_context1< Record >( - std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume(); -} - -template< typename StackAlloc, typename Fn > -continuation -callcc( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) { - using Record = detail::record< continuation, StackAlloc, Fn >; - return continuation{ - detail::create_context2< Record >( - palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume(); -} - -#if defined(BOOST_USE_SEGMENTED_STACKS) -template< typename Fn > -continuation -callcc( std::allocator_arg_t, segmented_stack, Fn &&); - -template< typename StackAlloc, typename Fn > -continuation -callcc( std::allocator_arg_t, preallocated, segmented_stack, Fn &&); -#endif - -inline -void swap( continuation & l, continuation & 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_CONTINUATION_H diff --git a/include/boost/context/continuation_ucontext.hpp b/include/boost/context/continuation_ucontext.hpp deleted file mode 100644 index 5641f9c..0000000 --- a/include/boost/context/continuation_ucontext.hpp +++ /dev/null @@ -1,510 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// 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_CONTINUATION_H -#define BOOST_CONTEXT_CONTINUATION_H - -#include -#if BOOST_OS_MACOS -#define _XOPEN_SOURCE 600 -#endif - -extern "C" { -#include -} - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) -#include -#endif -#include -#if defined(BOOST_NO_CXX17_STD_INVOKE) -#include -#endif -#include -#include -#include -#if defined(BOOST_USE_SEGMENTED_STACKS) -#include -#endif -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { -namespace detail { - -// tampoline function -// entered if the execution context -// is resumed for the first time -template< typename Record > -static void entry_func( void * data) noexcept { - Record * record = static_cast< Record * >( data); - BOOST_ASSERT( nullptr != record); - // start execution of toplevel context-function - record->run(); -} - -struct BOOST_CONTEXT_DECL activation_record { - ucontext_t uctx{}; - stack_context sctx{}; - bool main_ctx{ true }; - activation_record * from{ nullptr }; - std::function< activation_record*(activation_record*&) > ontop{}; - bool terminated{ false }; - bool force_unwind{ false }; -#if defined(BOOST_USE_ASAN) - void * fake_stack{ nullptr }; - void * stack_bottom{ nullptr }; - std::size_t stack_size{ 0 }; -#endif - - static activation_record *& current() noexcept; - - // used for toplevel-context - // (e.g. main context, thread-entry context) - activation_record() { - if ( BOOST_UNLIKELY( 0 != ::getcontext( & uctx) ) ) { - throw std::system_error( - std::error_code( errno, std::system_category() ), - "getcontext() failed"); - } - } - - activation_record( stack_context sctx_) noexcept : - sctx( sctx_ ), - main_ctx( false ) { - } - - virtual ~activation_record() { - } - - activation_record( activation_record const&) = delete; - activation_record & operator=( activation_record const&) = delete; - - bool is_main_context() const noexcept { - return main_ctx; - } - - activation_record * resume() { - from = current(); - // store `this` in static, thread local pointer - // `this` will become the active (running) context - current() = this; -#if defined(BOOST_USE_SEGMENTED_STACKS) - // adjust segmented stack properties - __splitstack_getcontext( from->sctx.segments_ctx); - __splitstack_setcontext( sctx.segments_ctx); -#endif -#if defined(BOOST_USE_ASAN) - if ( terminated) { - __sanitizer_start_switch_fiber( nullptr, stack_bottom, stack_size); - } else { - __sanitizer_start_switch_fiber( & from->fake_stack, stack_bottom, stack_size); - } -#endif - // context switch from parent context to `this`-context - ::swapcontext( & from->uctx, & uctx); -#if defined(BOOST_USE_ASAN) - __sanitizer_finish_switch_fiber( current()->fake_stack, - (const void **) & current()->from->stack_bottom, - & current()->from->stack_size); -#endif -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( current()->from, nullptr); -#else - return std::exchange( current()->from, nullptr); -#endif - } - - template< typename Ctx, typename Fn > - activation_record * resume_with( Fn && fn) { - from = current(); - // store `this` in static, thread local pointer - // `this` will become the active (running) context - // returned by continuation::current() - current() = this; -#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) - current()->ontop = std::bind( - [](typename std::decay< Fn >::type & fn, activation_record *& ptr){ - Ctx c{ ptr }; - c = fn( std::move( c) ); - if ( ! c) { - ptr = nullptr; - } -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.ptr_, nullptr); -#else - return std::exchange( c.ptr_, nullptr); -#endif - }, - std::forward< Fn >( fn), - std::placeholders::_1); -#else - current()->ontop = [fn=std::forward(fn)](activation_record *& ptr){ - Ctx c{ ptr }; - c = fn( std::move( c) ); - if ( ! c) { - ptr = nullptr; - } -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.ptr_, nullptr); -#else - return std::exchange( c.ptr_, nullptr); -#endif - }; -#endif -#if defined(BOOST_USE_SEGMENTED_STACKS) - // adjust segmented stack properties - __splitstack_getcontext( from->sctx.segments_ctx); - __splitstack_setcontext( sctx.segments_ctx); -#endif -#if defined(BOOST_USE_ASAN) - __sanitizer_start_switch_fiber( & from->fake_stack, stack_bottom, stack_size); -#endif - // context switch from parent context to `this`-context - ::swapcontext( & from->uctx, & uctx); -#if defined(BOOST_USE_ASAN) - __sanitizer_finish_switch_fiber( current()->fake_stack, - (const void **) & current()->from->stack_bottom, - & current()->from->stack_size); -#endif -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( current()->from, nullptr); -#else - return std::exchange( current()->from, nullptr); -#endif - } - - virtual void deallocate() noexcept { - } -}; - -struct BOOST_CONTEXT_DECL activation_record_initializer { - activation_record_initializer() noexcept; - ~activation_record_initializer(); -}; - -struct forced_unwind { - activation_record * from{ nullptr }; - - forced_unwind( activation_record * from_) noexcept : - from{ from_ } { - } -}; - -template< typename Ctx, typename StackAlloc, typename Fn > -class capture_record : public activation_record { -private: - typename std::decay< StackAlloc >::type salloc_; - typename std::decay< Fn >::type fn_; - - static void destroy( capture_record * p) noexcept { - typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_); - stack_context sctx = p->sctx; - // deallocate activation record - p->~capture_record(); - // destroy stack with stack allocator - salloc.deallocate( sctx); - } - -public: - capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept : - activation_record{ sctx }, - salloc_{ std::forward< StackAlloc >( salloc) }, - fn_( std::forward< Fn >( fn) ) { - } - - void deallocate() noexcept override final { - BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) ); - destroy( this); - } - - void run() { -#if defined(BOOST_USE_ASAN) - __sanitizer_finish_switch_fiber( fake_stack, - (const void **) & from->stack_bottom, - & from->stack_size); -#endif - Ctx c{ from }; - try { - // invoke context-function -#if defined(BOOST_NO_CXX17_STD_INVOKE) - c = invoke( fn_, std::move( c) ); -#else - c = std::invoke( fn_, std::move( c) ); -#endif - } catch ( forced_unwind const& ex) { - c = Ctx{ ex.from }; - } - // this context has finished its task - from = nullptr; - ontop = nullptr; - terminated = true; - force_unwind = false; - c.resume(); - BOOST_ASSERT_MSG( false, "continuation already terminated"); - } -}; - -template< typename Ctx, typename StackAlloc, typename Fn > -static activation_record * create_context1( StackAlloc && salloc, Fn && fn) { - typedef capture_record< Ctx, StackAlloc, Fn > capture_t; - - auto sctx = salloc.allocate(); - // reserve space for control structure - void * storage = reinterpret_cast< void * >( - ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) - & ~ static_cast< uintptr_t >( 0xff) ); - // placment new for control structure on context stack - capture_t * record = new ( storage) capture_t{ - sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; - // stack bottom - void * stack_bottom = reinterpret_cast< void * >( - reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) ); - // create user-context - if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) { - throw std::system_error( - std::error_code( errno, std::system_category() ), - "getcontext() failed"); - } - record->uctx.uc_stack.ss_sp = stack_bottom; - // 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); - record->uctx.uc_link = nullptr; - ::makecontext( & record->uctx, ( void (*)() ) & entry_func< capture_t >, 1, record); -#if defined(BOOST_USE_ASAN) - record->stack_bottom = record->uctx.uc_stack.ss_sp; - record->stack_size = record->uctx.uc_stack.ss_size; -#endif - return record; -} - -template< typename Ctx, typename StackAlloc, typename Fn > -static activation_record * create_context2( preallocated palloc, StackAlloc && salloc, Fn && fn) { - typedef capture_record< Ctx, StackAlloc, Fn > capture_t; - - // reserve space for control structure - void * storage = reinterpret_cast< void * >( - ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) - & ~ static_cast< uintptr_t >( 0xff) ); - // placment new for control structure on context stack - capture_t * record = new ( storage) capture_t{ - palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; - // stack bottom - void * stack_bottom = reinterpret_cast< void * >( - reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) ); - // create user-context - if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) { - throw std::system_error( - std::error_code( errno, std::system_category() ), - "getcontext() failed"); - } - record->uctx.uc_stack.ss_sp = stack_bottom; - // 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); - record->uctx.uc_link = nullptr; - ::makecontext( & record->uctx, ( void (*)() ) & entry_func< capture_t >, 1, record); -#if defined(BOOST_USE_ASAN) - record->stack_bottom = record->uctx.uc_stack.ss_sp; - record->stack_size = record->uctx.uc_stack.ss_size; -#endif - return record; -} - -} - -class BOOST_CONTEXT_DECL continuation { -private: - friend struct detail::activation_record; - - template< typename Ctx, typename StackAlloc, typename Fn > - friend class detail::capture_record; - - template< typename Ctx, typename StackAlloc, typename Fn > - friend detail::activation_record * detail::create_context1( StackAlloc &&, Fn &&); - - template< typename Ctx, typename StackAlloc, typename Fn > - friend detail::activation_record * detail::create_context2( preallocated, StackAlloc &&, Fn &&); - - template< typename StackAlloc, typename Fn > - friend continuation - callcc( std::allocator_arg_t, StackAlloc &&, Fn &&); - - template< typename StackAlloc, typename Fn > - friend continuation - callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&); - - detail::activation_record * ptr_{ nullptr }; - - continuation( detail::activation_record * ptr) noexcept : - ptr_{ ptr } { - } - -public: - continuation() = default; - - ~continuation() { - if ( BOOST_UNLIKELY( nullptr != ptr_) && ! ptr_->main_ctx) { - if ( BOOST_LIKELY( ! ptr_->terminated) ) { - ptr_->force_unwind = true; - ptr_->resume(); - BOOST_ASSERT( ptr_->terminated); - } - ptr_->deallocate(); - } - } - - continuation( continuation const&) = delete; - continuation & operator=( continuation const&) = delete; - - continuation( continuation && other) noexcept { - swap( other); - } - - continuation & operator=( continuation && other) noexcept { - if ( BOOST_LIKELY( this != & other) ) { - continuation tmp = std::move( other); - swap( tmp); - } - return * this; - } - - continuation resume() & { - return std::move( * this).resume(); - } - - continuation resume() && { -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::activation_record * ptr = detail::exchange( ptr_, nullptr)->resume(); -#else - detail::activation_record * ptr = std::exchange( ptr_, nullptr)->resume(); -#endif - if ( BOOST_UNLIKELY( detail::activation_record::current()->force_unwind) ) { - throw detail::forced_unwind{ ptr}; - } else if ( BOOST_UNLIKELY( nullptr != detail::activation_record::current()->ontop) ) { - ptr = detail::activation_record::current()->ontop( ptr); - detail::activation_record::current()->ontop = nullptr; - } - return { ptr }; - } - - template< typename Fn > - continuation resume_with( Fn && fn) & { - return std::move( * this).resume_with( std::forward< Fn >( fn) ); - } - - template< typename Fn > - continuation resume_with( Fn && fn) && { -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::activation_record * ptr = - detail::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) ); -#else - detail::activation_record * ptr = - std::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) ); -#endif - if ( BOOST_UNLIKELY( detail::activation_record::current()->force_unwind) ) { - throw detail::forced_unwind{ ptr}; - } else if ( BOOST_UNLIKELY( nullptr != detail::activation_record::current()->ontop) ) { - ptr = detail::activation_record::current()->ontop( ptr); - detail::activation_record::current()->ontop = nullptr; - } - return { ptr }; - } - - explicit operator bool() const noexcept { - return nullptr != ptr_ && ! ptr_->terminated; - } - - bool operator!() const noexcept { - return nullptr == ptr_ || ptr_->terminated; - } - - bool operator<( continuation 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, continuation const& other) { - if ( nullptr != other.ptr_) { - return os << other.ptr_; - } else { - return os << "{not-a-context}"; - } - } - - void swap( continuation & other) noexcept { - std::swap( ptr_, other.ptr_); - } -}; - -template< - typename Fn, - typename = detail::disable_overload< continuation, Fn > -> -continuation -callcc( Fn && fn) { - return callcc( - std::allocator_arg, -#if defined(BOOST_USE_SEGMENTED_STACKS) - segmented_stack(), -#else - fixedsize_stack(), -#endif - std::forward< Fn >( fn) ); -} - -template< typename StackAlloc, typename Fn > -continuation -callcc( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) { - return continuation{ - detail::create_context1< continuation >( - std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume(); -} - -template< typename StackAlloc, typename Fn > -continuation -callcc( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) { - return continuation{ - detail::create_context2< continuation >( - palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume(); -} - -inline -void swap( continuation & l, continuation & r) noexcept { - l.swap( r); -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_CONTINUATION_H diff --git a/include/boost/context/continuation_winfib.hpp b/include/boost/context/continuation_winfib.hpp deleted file mode 100644 index a1c17cf..0000000 --- a/include/boost/context/continuation_winfib.hpp +++ /dev/null @@ -1,449 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// 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_CONTINUATION_H -#define BOOST_CONTEXT_CONTINUATION_H - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) -#include -#endif -#if defined(BOOST_NO_CXX17_STD_INVOKE) -#include -#endif -#include -#include -#include -#include - -#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 { - -// tampoline function -// entered if the execution context -// is resumed for the first time -template< typename Record > -static VOID WINAPI entry_func( LPVOID data) noexcept { - Record * record = static_cast< Record * >( data); - BOOST_ASSERT( nullptr != record); - // start execution of toplevel context-function - record->run(); -} - -struct BOOST_CONTEXT_DECL activation_record { - LPVOID fiber{ nullptr }; - stack_context sctx{}; - bool main_ctx{ true }; - activation_record * from{ nullptr }; - std::function< activation_record*(activation_record*&) > ontop{}; - bool terminated{ false }; - bool force_unwind{ false }; - - static activation_record *& current() noexcept; - - // used for toplevel-context - // (e.g. main context, thread-entry context) - activation_record() noexcept { -#if ( _WIN32_WINNT > 0x0600) - if ( ::IsThreadAFiber() ) { - fiber = ::GetCurrentFiber(); - } else { - fiber = ::ConvertThreadToFiber( nullptr); - } -#else - fiber = ::ConvertThreadToFiber( nullptr); - if ( BOOST_UNLIKELY( nullptr == fiber) ) { - DWORD err = ::GetLastError(); - BOOST_ASSERT( ERROR_ALREADY_FIBER == err); - fiber = ::GetCurrentFiber(); - BOOST_ASSERT( nullptr != fiber); - BOOST_ASSERT( reinterpret_cast< LPVOID >( 0x1E00) != fiber); - } -#endif - } - - activation_record( stack_context sctx_) noexcept : - sctx{ sctx_ }, - main_ctx{ false } { - } - - virtual ~activation_record() { - if ( BOOST_UNLIKELY( main_ctx) ) { - ::ConvertFiberToThread(); - } else { - ::DeleteFiber( fiber); - } - } - - activation_record( activation_record const&) = delete; - activation_record & operator=( activation_record const&) = delete; - - bool is_main_context() const noexcept { - return main_ctx; - } - - activation_record * resume() { - from = current(); - // store `this` in static, thread local pointer - // `this` will become the active (running) context - current() = this; - // context switch from parent context to `this`-context - // context switch - ::SwitchToFiber( fiber); -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return detail::exchange( current()->from, nullptr); -#else - return std::exchange( current()->from, nullptr); -#endif - } - - template< typename Ctx, typename Fn > - activation_record * resume_with( Fn && fn) { - from = current(); - // store `this` in static, thread local pointer - // `this` will become the active (running) context - // returned by continuation::current() - current() = this; -#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) - current()->ontop = std::bind( - [](typename std::decay< Fn >::type & fn, activation_record *& ptr){ - Ctx c{ ptr }; - c = fn( std::move( c) ); - if ( ! c) { - ptr = nullptr; - } -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.ptr_, nullptr); -#else - return std::exchange( c.ptr_, nullptr); -#endif - }, - std::forward< Fn >( fn), - std::placeholders::_1); -#else - current()->ontop = [fn=std::forward(fn)](activation_record *& ptr){ - Ctx c{ ptr }; - c = fn( std::move( c) ); - if ( ! c) { - ptr = nullptr; - } -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.ptr_, nullptr); -#else - return std::exchange( c.ptr_, nullptr); -#endif - }; -#endif - // context switch - ::SwitchToFiber( fiber); -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return detail::exchange( current()->from, nullptr); -#else - return std::exchange( current()->from, nullptr); -#endif - } - - virtual void deallocate() noexcept { - } -}; - -struct BOOST_CONTEXT_DECL activation_record_initializer { - activation_record_initializer() noexcept; - ~activation_record_initializer(); -}; - -struct forced_unwind { - activation_record * from{ nullptr }; - - explicit forced_unwind( activation_record * from_) : - from{ from_ } { - } -}; - -template< typename Ctx, typename StackAlloc, typename Fn > -class capture_record : public activation_record { -private: - typename std::decay< StackAlloc >::type salloc_; - typename std::decay< Fn >::type fn_; - - static void destroy( capture_record * p) noexcept { - typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_); - stack_context sctx = p->sctx; - // deallocate activation record - p->~capture_record(); - // destroy stack with stack allocator - salloc.deallocate( sctx); - } - -public: - capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept : - activation_record( sctx), - salloc_( std::forward< StackAlloc >( salloc)), - fn_( std::forward< Fn >( fn) ) { - } - - void deallocate() noexcept override final { - BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) ); - destroy( this); - } - - void run() { - Ctx c{ from }; - try { - // invoke context-function -#if defined(BOOST_NO_CXX17_STD_INVOKE) - c = invoke( fn_, std::move( c) ); -#else - c = std::invoke( fn_, std::move( c) ); -#endif - } catch ( forced_unwind const& ex) { - c = Ctx{ ex.from }; - } - // this context has finished its task - from = nullptr; - ontop = nullptr; - terminated = true; - force_unwind = false; - c.resume(); - BOOST_ASSERT_MSG( false, "continuation already terminated"); - } -}; - -template< typename Ctx, typename StackAlloc, typename Fn > -static activation_record * create_context1( StackAlloc && salloc, Fn && fn) { - typedef capture_record< Ctx, StackAlloc, Fn > capture_t; - - auto sctx = salloc.allocate(); - BOOST_ASSERT( ( sizeof( capture_t) ) < sctx.size); - // reserve space for control structure - void * storage = reinterpret_cast< void * >( - ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) - & ~ static_cast< uintptr_t >( 0xff) ); - // placment new for control structure on context stack - capture_t * record = new ( storage) capture_t{ - sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; - // create user-context - record->fiber = ::CreateFiber( sctx.size, & detail::entry_func< capture_t >, record); - return record; -} - -template< typename Ctx, typename StackAlloc, typename Fn > -static activation_record * create_context2( preallocated palloc, StackAlloc && salloc, Fn && fn) { - typedef capture_record< Ctx, StackAlloc, Fn > capture_t; - - BOOST_ASSERT( ( sizeof( capture_t) ) < palloc.size); - // reserve space for control structure - void * storage = reinterpret_cast< void * >( - ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) - & ~ static_cast< uintptr_t >( 0xff) ); - // placment new for control structure on context stack - capture_t * record = new ( storage) capture_t{ - palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; - // create user-context - record->fiber = ::CreateFiber( palloc.sctx.size, & detail::entry_func< capture_t >, record); - return record; -} - -} - -class BOOST_CONTEXT_DECL continuation { -private: - friend struct detail::activation_record; - - template< typename Ctx, typename StackAlloc, typename Fn > - friend class detail::capture_record; - - template< typename Ctx, typename StackAlloc, typename Fn > - friend detail::activation_record * detail::create_context1( StackAlloc &&, Fn &&); - - template< typename Ctx, typename StackAlloc, typename Fn > - friend detail::activation_record * detail::create_context2( preallocated, StackAlloc &&, Fn &&); - - template< typename StackAlloc, typename Fn > - friend continuation - callcc( std::allocator_arg_t, StackAlloc &&, Fn &&); - - template< typename StackAlloc, typename Fn > - friend continuation - callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&); - - detail::activation_record * ptr_{ nullptr }; - - continuation( detail::activation_record * ptr) noexcept : - ptr_{ ptr } { - } - -public: - continuation() = default; - - ~continuation() { - if ( BOOST_UNLIKELY( nullptr != ptr_) && ! ptr_->main_ctx) { - if ( BOOST_LIKELY( ! ptr_->terminated) ) { - ptr_->force_unwind = true; - ptr_->resume(); - BOOST_ASSERT( ptr_->terminated); - } - ptr_->deallocate(); - } - } - - continuation( continuation const&) = delete; - continuation & operator=( continuation const&) = delete; - - continuation( continuation && other) noexcept { - swap( other); - } - - continuation & operator=( continuation && other) noexcept { - if ( BOOST_LIKELY( this != & other) ) { - continuation tmp = std::move( other); - swap( tmp); - } - return * this; - } - - continuation resume() & { - return std::move( * this).resume(); - } - - continuation resume() && { -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::activation_record * ptr = detail::exchange( ptr_, nullptr)->resume(); -#else - detail::activation_record * ptr = std::exchange( ptr_, nullptr)->resume(); -#endif - if ( BOOST_UNLIKELY( detail::activation_record::current()->force_unwind) ) { - throw detail::forced_unwind{ ptr}; - } else if ( BOOST_UNLIKELY( nullptr != detail::activation_record::current()->ontop) ) { - ptr = detail::activation_record::current()->ontop( ptr); - detail::activation_record::current()->ontop = nullptr; - } - return { ptr }; - } - - template< typename Fn > - continuation resume_with( Fn && fn) & { - return std::move( * this).resume_with( std::forward< Fn >( fn) ); - } - - template< typename Fn > - continuation resume_with( Fn && fn) && { -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::activation_record * ptr = - detail::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) ); -#else - detail::activation_record * ptr = - std::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) ); -#endif - if ( BOOST_UNLIKELY( detail::activation_record::current()->force_unwind) ) { - throw detail::forced_unwind{ ptr}; - } else if ( BOOST_UNLIKELY( nullptr != detail::activation_record::current()->ontop) ) { - ptr = detail::activation_record::current()->ontop( ptr); - detail::activation_record::current()->ontop = nullptr; - } - return { ptr }; - } - - explicit operator bool() const noexcept { - return nullptr != ptr_ && ! ptr_->terminated; - } - - bool operator!() const noexcept { - return nullptr == ptr_ || ptr_->terminated; - } - - bool operator<( continuation 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, continuation const& other) { - if ( nullptr != other.ptr_) { - return os << other.ptr_; - } else { - return os << "{not-a-context}"; - } - } - - void swap( continuation & other) noexcept { - std::swap( ptr_, other.ptr_); - } -}; - -template< - typename Fn, - typename = detail::disable_overload< continuation, Fn > -> -continuation -callcc( Fn && fn) { - return callcc( - std::allocator_arg, - fixedsize_stack(), - std::forward< Fn >( fn) ); -} - -template< typename StackAlloc, typename Fn > -continuation -callcc( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) { - return continuation{ - detail::create_context1< continuation >( - std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume(); -} - -template< typename StackAlloc, typename Fn > -continuation -callcc( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) { - return continuation{ - detail::create_context2< continuation >( - palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume(); -} - -inline -void swap( continuation & l, continuation & 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_CONTINUATION_H diff --git a/include/boost/context/detail/exception.hpp b/include/boost/context/detail/exception.hpp deleted file mode 100644 index 14b4ab5..0000000 --- a/include/boost/context/detail/exception.hpp +++ /dev/null @@ -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) - -#ifndef BOOST_CONTEXT_DETAIL_EXCEPTION_H -#define BOOST_CONTEXT_DETAIL_EXCEPTION_H - -#include - -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { -namespace detail { - -struct forced_unwind { - fcontext_t fctx{ nullptr }; - - forced_unwind() = default; - - forced_unwind( fcontext_t fctx_) : - fctx( fctx_) { - } -}; - -}}} - -#ifdef BOOST_HAS_ABI_HEADERS -#include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_DETAIL_EXCEPTION_H diff --git a/include/boost/context/execution_context.hpp b/include/boost/context/execution_context.hpp deleted file mode 100644 index 5808e02..0000000 --- a/include/boost/context/execution_context.hpp +++ /dev/null @@ -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 - -#if !defined(BOOST_NO_CXX11_THREAD_LOCAL) -# include -#endif -#include diff --git a/include/boost/context/execution_context_v1.hpp b/include/boost/context/execution_context_v1.hpp deleted file mode 100644 index 721c4b9..0000000 --- a/include/boost/context/execution_context_v1.hpp +++ /dev/null @@ -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 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#if defined(BOOST_NO_CXX17_STD_APPLY) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#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( std::forward< StackAlloc >( 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, std::forward< StackAlloc >( 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 diff --git a/include/boost/context/execution_context_v2.hpp b/include/boost/context/execution_context_v2.hpp deleted file mode 100644 index 4311d1f..0000000 --- a/include/boost/context/execution_context_v2.hpp +++ /dev/null @@ -1,479 +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 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#if defined(BOOST_NO_CXX17_STD_APPLY) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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& e) { - t = { e.fctx, nullptr }; - } - 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 - -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 diff --git a/include/boost/context/execution_context_v2_void.ipp b/include/boost/context/execution_context_v2_void.ipp deleted file mode 100644 index eb291d2..0000000 --- a/include/boost/context/execution_context_v2_void.ipp +++ /dev/null @@ -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; -} - -} diff --git a/include/boost/context/fiber.hpp b/include/boost/context/fiber.hpp deleted file mode 100644 index ff1b79e..0000000 --- a/include/boost/context/fiber.hpp +++ /dev/null @@ -1,13 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// 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) - -#if defined(BOOST_USE_UCONTEXT) -#include -#elif defined(BOOST_USE_WINFIB) -#include -#else -#include -#endif diff --git a/include/boost/context/fiber_fcontext.hpp b/include/boost/context/fiber_context.hpp similarity index 70% rename from include/boost/context/fiber_fcontext.hpp rename to include/boost/context/fiber_context.hpp index a57f5ad..34a3c33 100644 --- a/include/boost/context/fiber_fcontext.hpp +++ b/include/boost/context/fiber_context.hpp @@ -4,8 +4,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_CONTEXT_FIBER_H -#define BOOST_CONTEXT_FIBER_H +#ifndef BOOST_CONTEXT_FIBER_CONTEXT_H +#define BOOST_CONTEXT_FIBER_CONTEXT_H #define UNW_LOCAL_ONLY @@ -25,18 +25,13 @@ #include #include +#include #include #include #include #include -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) -#include -#endif -#if defined(BOOST_NO_CXX17_STD_INVOKE) -#include -#endif #include #include #include @@ -56,10 +51,39 @@ # pragma warning(disable: 4702) #endif +constexpr _Unwind_Exception_Class __gxx_fiber_exception_class += ((((((((_Unwind_Exception_Class) 'G' + << 8 | (_Unwind_Exception_Class) 'N') + << 8 | (_Unwind_Exception_Class) 'U') + << 8 | (_Unwind_Exception_Class) 'F') + << 8 | (_Unwind_Exception_Class) 'I') + << 8 | (_Unwind_Exception_Class) 'B') + << 8 | (_Unwind_Exception_Class) 'E') + << 8 | (_Unwind_Exception_Class) 'R'); + +#define __GXX_INIT_FIBER_EXCEPTION_CLASS(c) c = __gxx_fiber_exception_class + namespace boost { namespace context { namespace detail { +class foreign_unwind_ex : public _Unwind_Exception { +private: + static void fiber_unwind_cleanup( _Unwind_Reason_Code code, _Unwind_Exception * exc) { + // We only want to be called through _Unwind_DeleteException. + if ( _URC_FOREIGN_EXCEPTION_CAUGHT != code) { + std::terminate(); + } + delete exc; + } + +public: + foreign_unwind_ex() noexcept { + __GXX_INIT_FIBER_EXCEPTION_CLASS( exception_class); + exception_cleanup = fiber_unwind_cleanup; + } +}; + struct data { enum flag_t { flag_side_stack = 0, @@ -87,9 +111,25 @@ bool fiber_uses_side_stack() { } inline -transfer_t fiber_unwind( transfer_t t) { - throw forced_unwind( t.fctx); - return { nullptr, nullptr }; +_Unwind_Reason_Code fiber_unwind_stop( + int version, + _Unwind_Action actions, + _Unwind_Exception_Class exc_class, + _Unwind_Exception * exc, + _Unwind_Context * context, + void * param) { + if ( actions & _UA_END_OF_STACK) { + _Unwind_DeleteException( exc); + // end of stack: switch back to calling fiber + static intptr_t stop_token = -1; + jump_fcontext( param, reinterpret_cast< void * >( stop_token) ); + __builtin_unreachable(); + } + // This is not the destination from. The unwind runtime will call frame's + // personality routine with the _UA_FORCE_UNWIND and _UA_CLEANUP_PHASE flag + // set in actions, and then unwind to the next frame and call the stop() + // function again. + return _URC_NO_REASON; } template< typename Rec > @@ -101,30 +141,26 @@ transfer_t fiber_exit( transfer_t t) noexcept { } template< typename Rec > -void fiber_entry( transfer_t t) noexcept { +void fiber_entry( transfer_t t) { // transfer control structure to the context-stack Rec * rec = static_cast< Rec * >( t.data); BOOST_ASSERT( nullptr != t.fctx); BOOST_ASSERT( nullptr != rec); - try { rep: - // jump back to `create_context()` - t = jump_fcontext( t.fctx, nullptr); - // test if stack walk was requested - if ( nullptr != t.data) { - data * d = static_cast< data * >( t.data); - if ( data::flag_side_stack == d->f) { - d->v = fiber_uses_side_stack(); - } else if ( data::flag_hosting_thread == d->f) { - d->v = std::thread::id{}; - } - goto rep; + // jump back to `create_context()` + t = jump_fcontext( t.fctx, nullptr); + // test if stack walk was requested + if ( nullptr != t.data) { + data * d = static_cast< data * >( t.data); + if ( data::flag_side_stack == d->f) { + d->v = fiber_uses_side_stack(); + } else if ( data::flag_hosting_thread == d->f) { + d->v = std::thread::id{}; } - // start executing - t.fctx = rec->run( t.fctx); - } catch ( forced_unwind const& e) { - t = { e.fctx, nullptr }; + goto rep; } + // start executing + t.fctx = rec->run( t.fctx); BOOST_ASSERT( nullptr != t.fctx); // destroy context-stack of `this`context on next context ontop_fcontext( t.fctx, rec, fiber_exit< Rec >); @@ -137,13 +173,9 @@ transfer_t fiber_ontop( transfer_t t) { BOOST_ASSERT( nullptr != p); typename std::decay< Fn >::type fn = std::get< 0 >( * p); t.data = nullptr; - // execute function, pass fiber_handle via reference + // execute function, pass fiber_context via reference Ctx c = fn( Ctx{ t.fctx } ); -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return { exchange( c.fctx_, nullptr), nullptr }; -#else return { std::exchange( c.fctx_, nullptr), nullptr }; -#endif } template< typename Ctx, typename StackAlloc, typename Fn > @@ -179,16 +211,8 @@ public: fcontext_t run( fcontext_t fctx) { // invoke context-function -#if defined(BOOST_NO_CXX17_STD_INVOKE) - Ctx c = invoke( fn_, Ctx{ fctx } ); -#else Ctx c = std::invoke( fn_, Ctx{ fctx } ); -#endif -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.fctx_, nullptr); -#else return std::exchange( c.fctx_, nullptr); -#endif } }; @@ -219,7 +243,10 @@ fcontext_t create_fiber( Fn && fn) { } -class fiber_handle { +class fiber_context; +fiber_context unwind_fiber( fiber_context &&); + +class fiber_context { private: template< typename Ctx, typename StackAlloc, typename Fn > friend class detail::fiber_record; @@ -228,67 +255,56 @@ private: friend detail::transfer_t detail::fiber_ontop( detail::transfer_t); + friend fiber_context unwind_fiber( fiber_context &&); + detail::fcontext_t fctx_{ nullptr }; - fiber_handle( detail::fcontext_t fctx) noexcept : + fiber_context( detail::fcontext_t fctx) noexcept : fctx_{ fctx } { } public: - fiber_handle() noexcept = default; + fiber_context() noexcept = default; - template< typename Fn, typename = detail::disable_overload< fiber_handle, Fn > > - fiber_handle( Fn && fn) : + template< typename Fn, typename = detail::disable_overload< fiber_context, Fn > > + fiber_context( Fn && fn) : fctx_{ - detail::create_fiber< detail::fiber_record< fiber_handle, fixedsize_stack, Fn > >( + detail::create_fiber< detail::fiber_record< fiber_context, fixedsize_stack, Fn > >( std::forward< Fn >( fn) ) } { } - ~fiber_handle() { - if ( BOOST_UNLIKELY( nullptr != fctx_) ) { - detail::ontop_fcontext( -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( fctx_, nullptr), -#else - std::exchange( fctx_, nullptr), -#endif - nullptr, - detail::fiber_unwind); - } + ~fiber_context() { + BOOST_ASSERT( nullptr == fctx_); } - fiber_handle( fiber_handle && other) noexcept { + fiber_context( fiber_context && other) noexcept { swap( other); } - fiber_handle & operator=( fiber_handle && other) noexcept { + fiber_context & operator=( fiber_context && other) noexcept { if ( BOOST_LIKELY( this != & other) ) { - fiber_handle tmp = std::move( other); + fiber_context tmp = std::move( other); swap( tmp); } return * this; } - fiber_handle( fiber_handle const& other) noexcept = delete; - fiber_handle & operator=( fiber_handle const& other) noexcept = delete; + fiber_context( fiber_context const& other) noexcept = delete; + fiber_context & operator=( fiber_context const& other) noexcept = delete; - fiber_handle resume() && { + fiber_context resume() && { if ( ! can_resume() ) { throw std::domain_error("fiber can not resume from any thread"); } return std::move( * this).resume_from_any_thread(); } - fiber_handle resume_from_any_thread() && { + fiber_context resume_from_any_thread() && { BOOST_ASSERT( nullptr != fctx_); auto tid = std::this_thread::get_id(); rep: auto t = detail::jump_fcontext( -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( fctx_, nullptr), -#else std::exchange( fctx_, nullptr), -#endif nullptr); if ( nullptr != t.data) { detail::data * d = static_cast< detail::data * >( t.data); @@ -304,7 +320,7 @@ rep: } template< typename Fn > - fiber_handle resume_with( Fn && fn) && { + fiber_context resume_with( Fn && fn) && { if ( ! can_resume() ) { throw std::domain_error("fiber can not resume from any thread"); } @@ -312,18 +328,17 @@ rep: } template< typename Fn > - fiber_handle resume_from_any_thread_with( Fn && fn) && { + fiber_context resume_from_any_thread_with( Fn && fn) && { BOOST_ASSERT( nullptr != fctx_); auto tid = std::this_thread::get_id(); auto p = std::make_tuple( std::forward< Fn >( fn) ); auto t = detail::ontop_fcontext( -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( fctx_, nullptr), -#else std::exchange( fctx_, nullptr), -#endif & p, - detail::fiber_ontop< fiber_handle, Fn >); + detail::fiber_ontop< fiber_context, Fn >); + if ( -1 == reinterpret_cast< intptr_t >( t.data) ) { + return {}; + } while ( nullptr != t.data) { detail::data * d = static_cast< detail::data * >( t.data); if ( detail::data::flag_side_stack == d->f) { @@ -333,11 +348,7 @@ rep: } fctx_ = t.fctx; t = detail::jump_fcontext( -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( fctx_, nullptr), -#else std::exchange( fctx_, nullptr), -#endif nullptr); } return { t.fctx }; @@ -347,11 +358,7 @@ rep: BOOST_ASSERT( * this); detail::data d = { detail::data::flag_side_stack }; auto t = detail::jump_fcontext( -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( fctx_, nullptr), -#else std::exchange( fctx_, nullptr), -#endif & d); fctx_ = t.fctx; return std::get< bool >( d.v); @@ -361,11 +368,7 @@ rep: BOOST_ASSERT( * this); detail::data d = { detail::data::flag_hosting_thread }; auto t = detail::jump_fcontext( -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( fctx_, nullptr), -#else std::exchange( fctx_, nullptr), -#endif & d); fctx_ = t.fctx; return (std::this_thread::get_id() == std::get< std::thread::id >( d.v)) || @@ -380,13 +383,13 @@ rep: return nullptr == fctx_; } - bool operator<( fiber_handle const& other) const noexcept { + bool operator<( fiber_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, fiber_handle const& other) { + operator<<( std::basic_ostream< charT, traitsT > & os, fiber_context const& other) { if ( nullptr != other.fctx_) { return os << other.fctx_; } else { @@ -394,13 +397,21 @@ rep: } } - void swap( fiber_handle & other) noexcept { + void swap( fiber_context & other) noexcept { std::swap( fctx_, other.fctx_); } }; +fiber_context unwind_fiber( fiber_context && other) { + _Unwind_ForcedUnwind( + new detail::foreign_unwind_ex{}, + detail::fiber_unwind_stop, + std::exchange( other.fctx_, nullptr) ); + __builtin_unreachable(); +} + inline -void swap( fiber_handle & l, fiber_handle & r) noexcept { +void swap( fiber_context & l, fiber_context & r) noexcept { l.swap( r); } @@ -414,4 +425,4 @@ void swap( fiber_handle & l, fiber_handle & r) noexcept { # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_CONTEXT_FIBER_H +#endif // BOOST_CONTEXT_FIBER_CONTEXT_H diff --git a/include/boost/context/fiber_ucontext.hpp b/include/boost/context/fiber_ucontext.hpp deleted file mode 100644 index dd40a52..0000000 --- a/include/boost/context/fiber_ucontext.hpp +++ /dev/null @@ -1,497 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// 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_FIBER_H -#define BOOST_CONTEXT_FIBER_H - -#include -#if BOOST_OS_MACOS -#define _XOPEN_SOURCE 600 -#endif - -extern "C" { -#include -} - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) -#include -#endif -#include -#if defined(BOOST_NO_CXX17_STD_INVOKE) -#include -#endif -#include -#include -#include -#if defined(BOOST_USE_SEGMENTED_STACKS) -#include -#endif -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace context { -namespace detail { - -// tampoline function -// entered if the execution context -// is resumed for the first time -template< typename Record > -static void fiber_entry_func( void * data) noexcept { - Record * record = static_cast< Record * >( data); - BOOST_ASSERT( nullptr != record); - // start execution of toplevel context-function - record->run(); -} - -struct BOOST_CONTEXT_DECL fiber_activation_record { - ucontext_t uctx{}; - stack_context sctx{}; - bool main_ctx{ true }; - fiber_activation_record * from{ nullptr }; - std::function< fiber_activation_record*(fiber_activation_record*&) > ontop{}; - bool terminated{ false }; - bool force_unwind{ false }; -#if defined(BOOST_USE_ASAN) - void * fake_stack{ nullptr }; - void * stack_bottom{ nullptr }; - std::size_t stack_size{ 0 }; -#endif - - static fiber_activation_record *& current() noexcept; - - // used for toplevel-context - // (e.g. main context, thread-entry context) - fiber_activation_record() { - if ( BOOST_UNLIKELY( 0 != ::getcontext( & uctx) ) ) { - throw std::system_error( - std::error_code( errno, std::system_category() ), - "getcontext() failed"); - } - } - - fiber_activation_record( stack_context sctx_) noexcept : - sctx( sctx_ ), - main_ctx( false ) { - } - - virtual ~fiber_activation_record() { - } - - fiber_activation_record( fiber_activation_record const&) = delete; - fiber_activation_record & operator=( fiber_activation_record const&) = delete; - - bool is_main_context() const noexcept { - return main_ctx; - } - - fiber_activation_record * resume() { - from = current(); - // store `this` in static, thread local pointer - // `this` will become the active (running) context - current() = this; -#if defined(BOOST_USE_SEGMENTED_STACKS) - // adjust segmented stack properties - __splitstack_getcontext( from->sctx.segments_ctx); - __splitstack_setcontext( sctx.segments_ctx); -#endif -#if defined(BOOST_USE_ASAN) - if ( terminated) { - __sanitizer_start_switch_fiber( nullptr, stack_bottom, stack_size); - } else { - __sanitizer_start_switch_fiber( & from->fake_stack, stack_bottom, stack_size); - } -#endif - // context switch from parent context to `this`-context - ::swapcontext( & from->uctx, & uctx); -#if defined(BOOST_USE_ASAN) - __sanitizer_finish_switch_fiber( current()->fake_stack, - (const void **) & current()->from->stack_bottom, - & current()->from->stack_size); -#endif -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( current()->from, nullptr); -#else - return std::exchange( current()->from, nullptr); -#endif - } - - template< typename Ctx, typename Fn > - fiber_activation_record * resume_with( Fn && fn) { - from = current(); - // store `this` in static, thread local pointer - // `this` will become the active (running) context - // returned by fiber::current() - current() = this; -#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) - current()->ontop = std::bind( - [](typename std::decay< Fn >::type & fn, fiber_activation_record *& ptr){ - Ctx c{ ptr }; - c = fn( std::move( c) ); - if ( ! c) { - ptr = nullptr; - } -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.ptr_, nullptr); -#else - return std::exchange( c.ptr_, nullptr); -#endif - }, - std::forward< Fn >( fn), - std::placeholders::_1); -#else - current()->ontop = [fn=std::forward(fn)](fiber_activation_record *& ptr){ - Ctx c{ ptr }; - c = fn( std::move( c) ); - if ( ! c) { - ptr = nullptr; - } -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.ptr_, nullptr); -#else - return std::exchange( c.ptr_, nullptr); -#endif - }; -#endif -#if defined(BOOST_USE_SEGMENTED_STACKS) - // adjust segmented stack properties - __splitstack_getcontext( from->sctx.segments_ctx); - __splitstack_setcontext( sctx.segments_ctx); -#endif -#if defined(BOOST_USE_ASAN) - __sanitizer_start_switch_fiber( & from->fake_stack, stack_bottom, stack_size); -#endif - // context switch from parent context to `this`-context - ::swapcontext( & from->uctx, & uctx); -#if defined(BOOST_USE_ASAN) - __sanitizer_finish_switch_fiber( current()->fake_stack, - (const void **) & current()->from->stack_bottom, - & current()->from->stack_size); -#endif -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( current()->from, nullptr); -#else - return std::exchange( current()->from, nullptr); -#endif - } - - virtual void deallocate() noexcept { - } -}; - -struct BOOST_CONTEXT_DECL fiber_activation_record_initializer { - fiber_activation_record_initializer() noexcept; - ~fiber_activation_record_initializer(); -}; - -struct forced_unwind { - fiber_activation_record * from{ nullptr }; - - forced_unwind( fiber_activation_record * from_) noexcept : - from{ from_ } { - } -}; - -template< typename Ctx, typename StackAlloc, typename Fn > -class fiber_capture_record : public fiber_activation_record { -private: - typename std::decay< StackAlloc >::type salloc_; - typename std::decay< Fn >::type fn_; - - static void destroy( fiber_capture_record * p) noexcept { - typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_); - stack_context sctx = p->sctx; - // deallocate activation record - p->~fiber_capture_record(); - // destroy stack with stack allocator - salloc.deallocate( sctx); - } - -public: - fiber_capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept : - fiber_activation_record{ sctx }, - salloc_{ std::forward< StackAlloc >( salloc) }, - fn_( std::forward< Fn >( fn) ) { - } - - void deallocate() noexcept override final { - BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) ); - destroy( this); - } - - void run() { -#if defined(BOOST_USE_ASAN) - __sanitizer_finish_switch_fiber( fake_stack, - (const void **) & from->stack_bottom, - & from->stack_size); -#endif - Ctx c{ from }; - try { - // invoke context-function -#if defined(BOOST_NO_CXX17_STD_INVOKE) - c = invoke( fn_, std::move( c) ); -#else - c = std::invoke( fn_, std::move( c) ); -#endif - } catch ( forced_unwind const& ex) { - c = Ctx{ ex.from }; - } - // this context has finished its task - from = nullptr; - ontop = nullptr; - terminated = true; - force_unwind = false; - std::move( c).resume(); - BOOST_ASSERT_MSG( false, "fiber already terminated"); - } -}; - -template< typename Ctx, typename StackAlloc, typename Fn > -static fiber_activation_record * create_fiber1( StackAlloc && salloc, Fn && fn) { - typedef fiber_capture_record< Ctx, StackAlloc, Fn > capture_t; - - auto sctx = salloc.allocate(); - // reserve space for control structure - void * storage = reinterpret_cast< void * >( - ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) - & ~ static_cast< uintptr_t >( 0xff) ); - // placment new for control structure on context stack - capture_t * record = new ( storage) capture_t{ - sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; - // stack bottom - void * stack_bottom = reinterpret_cast< void * >( - reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) ); - // create user-context - if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) { - throw std::system_error( - std::error_code( errno, std::system_category() ), - "getcontext() failed"); - } - record->uctx.uc_stack.ss_sp = stack_bottom; - // 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); - record->uctx.uc_link = nullptr; - ::makecontext( & record->uctx, ( void (*)() ) & fiber_entry_func< capture_t >, 1, record); -#if defined(BOOST_USE_ASAN) - record->stack_bottom = record->uctx.uc_stack.ss_sp; - record->stack_size = record->uctx.uc_stack.ss_size; -#endif - return record; -} - -template< typename Ctx, typename StackAlloc, typename Fn > -static fiber_activation_record * create_fiber2( preallocated palloc, StackAlloc && salloc, Fn && fn) { - typedef fiber_capture_record< Ctx, StackAlloc, Fn > capture_t; - - // reserve space for control structure - void * storage = reinterpret_cast< void * >( - ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) - & ~ static_cast< uintptr_t >( 0xff) ); - // placment new for control structure on context stack - capture_t * record = new ( storage) capture_t{ - palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; - // stack bottom - void * stack_bottom = reinterpret_cast< void * >( - reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) ); - // create user-context - if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) { - throw std::system_error( - std::error_code( errno, std::system_category() ), - "getcontext() failed"); - } - record->uctx.uc_stack.ss_sp = stack_bottom; - // 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); - record->uctx.uc_link = nullptr; - ::makecontext( & record->uctx, ( void (*)() ) & fiber_entry_func< capture_t >, 1, record); -#if defined(BOOST_USE_ASAN) - record->stack_bottom = record->uctx.uc_stack.ss_sp; - record->stack_size = record->uctx.uc_stack.ss_size; -#endif - return record; -} - -} - -class BOOST_CONTEXT_DECL fiber { -private: - friend struct detail::fiber_activation_record; - - template< typename Ctx, typename StackAlloc, typename Fn > - friend class detail::fiber_capture_record; - - template< typename Ctx, typename StackAlloc, typename Fn > - friend detail::fiber_activation_record * detail::create_fiber1( StackAlloc &&, Fn &&); - - template< typename Ctx, typename StackAlloc, typename Fn > - friend detail::fiber_activation_record * detail::create_fiber2( preallocated, StackAlloc &&, Fn &&); - - template< typename StackAlloc, typename Fn > - friend fiber - callcc( std::allocator_arg_t, StackAlloc &&, Fn &&); - - template< typename StackAlloc, typename Fn > - friend fiber - callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&); - - detail::fiber_activation_record * ptr_{ nullptr }; - - fiber( detail::fiber_activation_record * ptr) noexcept : - ptr_{ ptr } { - } - -public: - fiber() = default; - - template< typename Fn, typename = detail::disable_overload< fiber, Fn > > - fiber( Fn && fn) : - fiber{ - std::allocator_arg, -#if defined(BOOST_USE_SEGMENTED_STACKS) - segmented_stack(), -#else - fixedsize_stack(), -#endif - std::forward< Fn >( fn) } { - } - - template< typename StackAlloc, typename Fn > - fiber( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) : - ptr_{ detail::create_fiber1< fiber >( - std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } { - } - - template< typename StackAlloc, typename Fn > - fiber( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) : - ptr_{ detail::create_fiber2< fiber >( - palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } { - } - - ~fiber() { - if ( BOOST_UNLIKELY( nullptr != ptr_) && ! ptr_->main_ctx) { - if ( BOOST_LIKELY( ! ptr_->terminated) ) { - ptr_->force_unwind = true; - ptr_->resume(); - BOOST_ASSERT( ptr_->terminated); - } - ptr_->deallocate(); - } - } - - fiber( fiber const&) = delete; - fiber & operator=( fiber const&) = delete; - - fiber( fiber && other) noexcept { - swap( other); - } - - fiber & operator=( fiber && other) noexcept { - if ( BOOST_LIKELY( this != & other) ) { - fiber tmp = std::move( other); - swap( tmp); - } - return * this; - } - - fiber resume() && { - BOOST_ASSERT( nullptr != ptr_); -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::fiber_activation_record * ptr = detail::exchange( ptr_, nullptr)->resume(); -#else - detail::fiber_activation_record * ptr = std::exchange( ptr_, nullptr)->resume(); -#endif - if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) { - throw detail::forced_unwind{ ptr}; - } else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) { - ptr = detail::fiber_activation_record::current()->ontop( ptr); - detail::fiber_activation_record::current()->ontop = nullptr; - } - return { ptr }; - } - - template< typename Fn > - fiber resume_with( Fn && fn) && { - BOOST_ASSERT( nullptr != ptr_); -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::fiber_activation_record * ptr = - detail::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) ); -#else - detail::fiber_activation_record * ptr = - std::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) ); -#endif - if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) { - throw detail::forced_unwind{ ptr}; - } else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) { - ptr = detail::fiber_activation_record::current()->ontop( ptr); - detail::fiber_activation_record::current()->ontop = nullptr; - } - return { ptr }; - } - - explicit operator bool() const noexcept { - return nullptr != ptr_ && ! ptr_->terminated; - } - - bool operator!() const noexcept { - return nullptr == ptr_ || ptr_->terminated; - } - - bool operator<( fiber 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, fiber const& other) { - if ( nullptr != other.ptr_) { - return os << other.ptr_; - } else { - return os << "{not-a-context}"; - } - } - - void swap( fiber & other) noexcept { - std::swap( ptr_, other.ptr_); - } -}; - -inline -void swap( fiber & l, fiber & r) noexcept { - l.swap( r); -} - -typedef fiber fiber_context; - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_FIBER_H diff --git a/include/boost/context/fiber_winfib.hpp b/include/boost/context/fiber_winfib.hpp deleted file mode 100644 index d0a2c37..0000000 --- a/include/boost/context/fiber_winfib.hpp +++ /dev/null @@ -1,435 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// 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_FIBER_H -#define BOOST_CONTEXT_FIBER_H - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) -#include -#endif -#if defined(BOOST_NO_CXX17_STD_INVOKE) -#include -#endif -#include -#include -#include -#include - -#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 { - -// tampoline function -// entered if the execution context -// is resumed for the first time -template< typename Record > -static VOID WINAPI fiber_entry_func( LPVOID data) noexcept { - Record * record = static_cast< Record * >( data); - BOOST_ASSERT( nullptr != record); - // start execution of toplevel context-function - record->run(); -} - -struct BOOST_CONTEXT_DECL fiber_activation_record { - LPVOID fiber{ nullptr }; - stack_context sctx{}; - bool main_ctx{ true }; - fiber_activation_record * from{ nullptr }; - std::function< fiber_activation_record*(fiber_activation_record*&) > ontop{}; - bool terminated{ false }; - bool force_unwind{ false }; - - static fiber_activation_record *& current() noexcept; - - // used for toplevel-context - // (e.g. main context, thread-entry context) - fiber_activation_record() noexcept { -#if ( _WIN32_WINNT > 0x0600) - if ( ::IsThreadAFiber() ) { - fiber = ::GetCurrentFiber(); - } else { - fiber = ::ConvertThreadToFiber( nullptr); - } -#else - fiber = ::ConvertThreadToFiber( nullptr); - if ( BOOST_UNLIKELY( nullptr == fiber) ) { - DWORD err = ::GetLastError(); - BOOST_ASSERT( ERROR_ALREADY_FIBER == err); - fiber = ::GetCurrentFiber(); - BOOST_ASSERT( nullptr != fiber); - BOOST_ASSERT( reinterpret_cast< LPVOID >( 0x1E00) != fiber); - } -#endif - } - - fiber_activation_record( stack_context sctx_) noexcept : - sctx{ sctx_ }, - main_ctx{ false } { - } - - virtual ~fiber_activation_record() { - if ( BOOST_UNLIKELY( main_ctx) ) { - ::ConvertFiberToThread(); - } else { - ::DeleteFiber( fiber); - } - } - - fiber_activation_record( fiber_activation_record const&) = delete; - fiber_activation_record & operator=( fiber_activation_record const&) = delete; - - bool is_main_context() const noexcept { - return main_ctx; - } - - fiber_activation_record * resume() { - from = current(); - // store `this` in static, thread local pointer - // `this` will become the active (running) context - current() = this; - // context switch from parent context to `this`-context - // context switch - ::SwitchToFiber( fiber); -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return detail::exchange( current()->from, nullptr); -#else - return std::exchange( current()->from, nullptr); -#endif - } - - template< typename Ctx, typename Fn > - fiber_activation_record * resume_with( Fn && fn) { - from = current(); - // store `this` in static, thread local pointer - // `this` will become the active (running) context - // returned by fiber::current() - current() = this; -#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) - current()->ontop = std::bind( - [](typename std::decay< Fn >::type & fn, fiber_activation_record *& ptr){ - Ctx c{ ptr }; - c = fn( std::move( c) ); - if ( ! c) { - ptr = nullptr; - } -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.ptr_, nullptr); -#else - return std::exchange( c.ptr_, nullptr); -#endif - }, - std::forward< Fn >( fn), - std::placeholders::_1); -#else - current()->ontop = [fn=std::forward(fn)](fiber_activation_record *& ptr){ - Ctx c{ ptr }; - c = fn( std::move( c) ); - if ( ! c) { - ptr = nullptr; - } -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return exchange( c.ptr_, nullptr); -#else - return std::exchange( c.ptr_, nullptr); -#endif - }; -#endif - // context switch - ::SwitchToFiber( fiber); -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - return detail::exchange( current()->from, nullptr); -#else - return std::exchange( current()->from, nullptr); -#endif - } - - virtual void deallocate() noexcept { - } -}; - -struct BOOST_CONTEXT_DECL fiber_activation_record_initializer { - fiber_activation_record_initializer() noexcept; - ~fiber_activation_record_initializer(); -}; - -struct forced_unwind { - fiber_activation_record * from{ nullptr }; - - explicit forced_unwind( fiber_activation_record * from_) : - from{ from_ } { - } -}; - -template< typename Ctx, typename StackAlloc, typename Fn > -class fiber_capture_record : public fiber_activation_record { -private: - typename std::decay< StackAlloc >::type salloc_; - typename std::decay< Fn >::type fn_; - - static void destroy( fiber_capture_record * p) noexcept { - typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_); - stack_context sctx = p->sctx; - // deallocate activation record - p->~fiber_capture_record(); - // destroy stack with stack allocator - salloc.deallocate( sctx); - } - -public: - fiber_capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept : - fiber_activation_record( sctx), - salloc_( std::forward< StackAlloc >( salloc)), - fn_( std::forward< Fn >( fn) ) { - } - - void deallocate() noexcept override final { - BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) ); - destroy( this); - } - - void run() { - Ctx c{ from }; - try { - // invoke context-function -#if defined(BOOST_NO_CXX17_STD_INVOKE) - c = invoke( fn_, std::move( c) ); -#else - c = std::invoke( fn_, std::move( c) ); -#endif - } catch ( forced_unwind const& ex) { - c = Ctx{ ex.from }; - } - // this context has finished its task - from = nullptr; - ontop = nullptr; - terminated = true; - force_unwind = false; - std::move( c).resume(); - BOOST_ASSERT_MSG( false, "fiber already terminated"); - } -}; - -template< typename Ctx, typename StackAlloc, typename Fn > -static fiber_activation_record * create_fiber1( StackAlloc && salloc, Fn && fn) { - typedef fiber_capture_record< Ctx, StackAlloc, Fn > capture_t; - - auto sctx = salloc.allocate(); - BOOST_ASSERT( ( sizeof( capture_t) ) < sctx.size); - // reserve space for control structure - void * storage = reinterpret_cast< void * >( - ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) - & ~ static_cast< uintptr_t >( 0xff) ); - // placment new for control structure on context stack - capture_t * record = new ( storage) capture_t{ - sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; - // create user-context - record->fiber = ::CreateFiber( sctx.size, & detail::fiber_entry_func< capture_t >, record); - return record; -} - -template< typename Ctx, typename StackAlloc, typename Fn > -static fiber_activation_record * create_fiber2( preallocated palloc, StackAlloc && salloc, Fn && fn) { - typedef fiber_capture_record< Ctx, StackAlloc, Fn > capture_t; - - BOOST_ASSERT( ( sizeof( capture_t) ) < palloc.size); - // reserve space for control structure - void * storage = reinterpret_cast< void * >( - ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) - & ~ static_cast< uintptr_t >( 0xff) ); - // placment new for control structure on context stack - capture_t * record = new ( storage) capture_t{ - palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; - // create user-context - record->fiber = ::CreateFiber( palloc.sctx.size, & detail::fiber_entry_func< capture_t >, record); - return record; -} - -} - -class BOOST_CONTEXT_DECL fiber { -private: - friend struct detail::fiber_activation_record; - - template< typename Ctx, typename StackAlloc, typename Fn > - friend class detail::fiber_capture_record; - - template< typename Ctx, typename StackAlloc, typename Fn > - friend detail::fiber_activation_record * detail::create_fiber1( StackAlloc &&, Fn &&); - - template< typename Ctx, typename StackAlloc, typename Fn > - friend detail::fiber_activation_record * detail::create_fiber2( preallocated, StackAlloc &&, Fn &&); - - template< typename StackAlloc, typename Fn > - friend fiber - callcc( std::allocator_arg_t, StackAlloc &&, Fn &&); - - template< typename StackAlloc, typename Fn > - friend fiber - callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&); - - detail::fiber_activation_record * ptr_{ nullptr }; - - fiber( detail::fiber_activation_record * ptr) noexcept : - ptr_{ ptr } { - } - -public: - fiber() = default; - - template< typename Fn, typename = detail::disable_overload< fiber, Fn > > - fiber( Fn && fn) : - fiber{ std::allocator_arg, - fixedsize_stack(), - std::forward< Fn >( fn) } { - } - - template< typename StackAlloc, typename Fn > - fiber( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) : - ptr_{ detail::create_fiber1< fiber >( - std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } {; - } - - template< typename StackAlloc, typename Fn > - fiber( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) : - ptr_{ detail::create_fiber2< fiber >( - palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } { - } - - ~fiber() { - if ( BOOST_UNLIKELY( nullptr != ptr_) && ! ptr_->main_ctx) { - if ( BOOST_LIKELY( ! ptr_->terminated) ) { - ptr_->force_unwind = true; - ptr_->resume(); - BOOST_ASSERT( ptr_->terminated); - } - ptr_->deallocate(); - } - } - - fiber( fiber const&) = delete; - fiber & operator=( fiber const&) = delete; - - fiber( fiber && other) noexcept { - swap( other); - } - - fiber & operator=( fiber && other) noexcept { - if ( BOOST_LIKELY( this != & other) ) { - fiber tmp = std::move( other); - swap( tmp); - } - return * this; - } - - fiber resume() && { - BOOST_ASSERT( nullptr != ptr_); -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::fiber_activation_record * ptr = detail::exchange( ptr_, nullptr)->resume(); -#else - detail::fiber_activation_record * ptr = std::exchange( ptr_, nullptr)->resume(); -#endif - if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) { - throw detail::forced_unwind{ ptr}; - } else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) { - ptr = detail::fiber_activation_record::current()->ontop( ptr); - detail::fiber_activation_record::current()->ontop = nullptr; - } - return { ptr }; - } - - template< typename Fn > - fiber resume_with( Fn && fn) && { - BOOST_ASSERT( nullptr != ptr_); -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::fiber_activation_record * ptr = - detail::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) ); -#else - detail::fiber_activation_record * ptr = - std::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) ); -#endif - if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) { - throw detail::forced_unwind{ ptr}; - } else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) { - ptr = detail::fiber_activation_record::current()->ontop( ptr); - detail::fiber_activation_record::current()->ontop = nullptr; - } - return { ptr }; - } - - explicit operator bool() const noexcept { - return nullptr != ptr_ && ! ptr_->terminated; - } - - bool operator!() const noexcept { - return nullptr == ptr_ || ptr_->terminated; - } - - bool operator<( fiber 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, fiber const& other) { - if ( nullptr != other.ptr_) { - return os << other.ptr_; - } else { - return os << "{not-a-context}"; - } - } - - void swap( fiber & other) noexcept { - std::swap( ptr_, other.ptr_); - } -}; - -inline -void swap( fiber & l, fiber & r) noexcept { - l.swap( r); -} - -typedef fiber fiber_context; - -}} - -#if defined(BOOST_MSVC) -# pragma warning(pop) -#endif - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_FIBER_H diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c3928e6..0963176 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -24,24 +24,18 @@ project boost/context/test clang,on:-DBOOST_USE_SEGMENTED_STACKS static multi - "-lunwind" ; - -rule native-impl ( properties * ) +rule segmented-stack ( properties * ) { local result ; - if ( darwin in $(properties) || android in $(properties) ) + if ( gcc in $(properties) ) { - result = no ; - } - else if ( ! ( windows in $(properties) ) ) - { - result = ucontext ; + result = on ; } else { - result = winfib ; + result = no ; } return $(result) ; } @@ -80,59 +74,6 @@ test-suite minimal : cxx11_variadic_templates ] ] [ run test_fiber.cpp : - : : - fcontext - [ requires cxx11_auto_declarations - cxx11_constexpr - cxx11_defaulted_functions - cxx11_final - cxx11_hdr_thread - cxx11_hdr_tuple - cxx11_lambdas - cxx11_noexcept - cxx11_nullptr - cxx11_rvalue_references - cxx11_template_aliases - cxx11_thread_local - cxx11_variadic_templates ] ] - -[ run test_callcc.cpp : - : : - fcontext - [ requires cxx11_auto_declarations - cxx11_constexpr - cxx11_defaulted_functions - cxx11_final - cxx11_hdr_thread - cxx11_hdr_tuple - cxx11_lambdas - cxx11_noexcept - cxx11_nullptr - cxx11_rvalue_references - cxx11_template_aliases - cxx11_thread_local - cxx11_variadic_templates ] - : test_callcc_asm ] - -[ run test_callcc.cpp : - : : - @native-impl - [ requires cxx11_auto_declarations - cxx11_constexpr - cxx11_defaulted_functions - cxx11_final - cxx11_hdr_thread - cxx11_hdr_tuple - cxx11_lambdas - cxx11_noexcept - cxx11_nullptr - cxx11_rvalue_references - cxx11_template_aliases - cxx11_thread_local - cxx11_variadic_templates ] - : test_callcc_native ] - -[ run test_execution_context_v2.cpp : : : [ requires cxx11_auto_declarations cxx11_constexpr @@ -148,8 +89,6 @@ test-suite minimal : cxx11_thread_local cxx11_variadic_templates ] ] ; - - test-suite full : minimal ; diff --git a/test/test_callcc.cpp b/test/test_callcc.cpp deleted file mode 100644 index 7361947..0000000 --- a/test/test_callcc.cpp +++ /dev/null @@ -1,430 +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 -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef BOOST_WINDOWS -#include -#endif - -#if defined(BOOST_MSVC) -# pragma warning(push) -# pragma warning(disable: 4702 4723 4996) -#endif - -typedef boost::variant variant_t; - -namespace ctx = boost::context; - -int value1 = 0; -std::string value2; -double value3 = 0.; - -struct X { - ctx::continuation foo( ctx::continuation && c, int i) { - value1 = i; - return std::move( c); - } -}; - -struct Y { - Y() { - value1 = 3; - } - - Y( Y const&) = delete; - Y & operator=( Y const&) = delete; - - ~Y() { - value1 = 7; - } -}; - -class moveable { -public: - bool state; - int value; - - moveable() : - state( false), - value( -1) { - } - - moveable( int v) : - state( true), - value( v) { - } - - moveable( moveable && other) : - state( other.state), - value( other.value) { - other.state = false; - other.value = -1; - } - - moveable & operator=( moveable && other) { - if ( this == & other) return * this; - state = other.state; - value = other.value; - other.state = false; - other.value = -1; - return * this; - } - - moveable( moveable const& other) = delete; - moveable & operator=( moveable const& other) = delete; - - void operator()() { - value1 = value; - } -}; - -struct my_exception : public std::runtime_error { - ctx::continuation c; - my_exception( ctx::continuation && c_, char const* what) : - std::runtime_error( what), - c{ std::move( c_) } { - } -}; - -#ifdef BOOST_MSVC -// Optimizations can remove the integer-divide-by-zero here. -#pragma optimize("", off) -void seh( bool & catched) { - __try { - int i = 1; - i /= 0; - } __except( EXCEPTION_EXECUTE_HANDLER) { - catched = true; - } -} -#pragma optimize("", on) -#endif - -void test_move() { - value1 = 0; - int i = 1; - BOOST_CHECK_EQUAL( 0, value1); - ctx::continuation c1 = ctx::callcc( - [&i](ctx::continuation && c) { - value1 = i; - c = c.resume(); - value1 = i; - return std::move( c); - }); - BOOST_CHECK_EQUAL( 1, value1); - BOOST_CHECK( c1); - ctx::continuation c2; - BOOST_CHECK( ! c2); - c2 = std::move( c1); - BOOST_CHECK( ! c1); - BOOST_CHECK( c2); - i = 3; - c2.resume(); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK( ! c1); - BOOST_CHECK( ! c2); -} - -void test_bind() { - value1 = 0; - X x; - ctx::continuation c = ctx::callcc( std::bind( & X::foo, x, std::placeholders::_1, 7) ); - BOOST_CHECK_EQUAL( 7, value1); -} - -void test_exception() { - { - const char * what = "hello world"; - ctx::continuation c = ctx::callcc( - [&what](ctx::continuation && c) { - try { - throw std::runtime_error( what); - } catch ( std::runtime_error const& e) { - value2 = e.what(); - } - return std::move( c); - }); - BOOST_CHECK_EQUAL( std::string( what), value2); - BOOST_CHECK( ! c); - } -#ifdef BOOST_MSVC - { - bool catched = false; - std::thread([&catched](){ - ctx::continuation c = ctx::callcc([&catched](ctx::continuation && c){ - c = c.resume(); - seh( catched); - return std::move( c); - }); - BOOST_CHECK( c ); - c.resume(); - }).join(); - BOOST_CHECK( catched); - } -#endif -} - -void test_fp() { - value3 = 0.; - double d = 7.13; - ctx::continuation c = ctx::callcc( - [&d]( ctx::continuation && c) { - d += 3.45; - value3 = d; - return std::move( c); - }); - BOOST_CHECK_EQUAL( 10.58, value3); - BOOST_CHECK( ! c); -} - -void test_stacked() { - value1 = 0; - value3 = 0.; - ctx::continuation c = ctx::callcc( - [](ctx::continuation && c) { - ctx::continuation c1 = ctx::callcc( - [](ctx::continuation && c) { - value1 = 3; - return std::move( c); - }); - value3 = 3.14; - return std::move( c); - }); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK_EQUAL( 3.14, value3); - BOOST_CHECK( ! c ); -} - -void test_prealloc() { - value1 = 0; - ctx::default_stack alloc; - ctx::stack_context sctx( alloc.allocate() ); - void * sp = static_cast< char * >( sctx.sp) - 10; - std::size_t size = sctx.size - 10; - int i = 7; - ctx::continuation c = ctx::callcc( - std::allocator_arg, ctx::preallocated( sp, size, sctx), alloc, - [&i]( ctx::continuation && c) { - value1 = i; - return std::move( c); - }); - BOOST_CHECK_EQUAL( 7, value1); - BOOST_CHECK( ! c); -} - -void test_ontop() { - { - int i = 3; - ctx::continuation c = ctx::callcc([&i](ctx::continuation && c) { - for (;;) { - i *= 10; - c = c.resume(); - } - return std::move( c); - }); - c = c.resume_with( - [&i](ctx::continuation && c){ - i -= 10; - return std::move( c); - }); - BOOST_CHECK( c); - BOOST_CHECK_EQUAL( i, 200); - } - { - ctx::continuation c1; - ctx::continuation c = ctx::callcc([&c1](ctx::continuation && c) { - c = c.resume(); - BOOST_CHECK( ! c); - return std::move( c1); - }); - c = c.resume_with( - [&c1](ctx::continuation && c){ - c1 = std::move( c); - return std::move( c); - }); - } -} - -void test_ontop_exception() { - value1 = 0; - value2 = ""; - ctx::continuation c = ctx::callcc([](ctx::continuation && c){ - for (;;) { - value1 = 3; - try { - c = c.resume(); - } catch ( my_exception & ex) { - value2 = ex.what(); - return std::move( ex.c); - } - } - return std::move( c); - }); - c = c.resume(); - BOOST_CHECK_EQUAL( 3, value1); - const char * what = "hello world"; - c.resume_with( - [what](ctx::continuation && c){ - throw my_exception( std::move( c), what); - return std::move( c); - }); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK_EQUAL( std::string( what), value2); -} - -void test_termination() { - { - value1 = 0; - ctx::continuation c = ctx::callcc( - [](ctx::continuation && c){ - Y y; - return c.resume(); - }); - BOOST_CHECK_EQUAL( 3, value1); - } - BOOST_CHECK_EQUAL( 7, value1); - { - value1 = 0; - BOOST_CHECK_EQUAL( 0, value1); - ctx::continuation c = ctx::callcc( - [](ctx::continuation && c) { - value1 = 3; - return std::move( c); - }); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK( ! c ); - } - { - value1 = 0; - BOOST_CHECK_EQUAL( 0, value1); - int i = 3; - ctx::continuation c = ctx::callcc( - [&i](ctx::continuation && c){ - value1 = i; - c = c.resume(); - value1 = i; - return std::move( c); - }); - BOOST_CHECK( c); - BOOST_CHECK_EQUAL( i, value1); - BOOST_CHECK( c); - i = 7; - c = c.resume(); - BOOST_CHECK( ! c); - BOOST_CHECK_EQUAL( i, value1); - } -} - -void test_sscanf() { - ctx::continuation c = ctx::callcc( - []( ctx::continuation && c) { - { - double n1 = 0; - double n2 = 0; - sscanf("3.14 7.13", "%lf %lf", & n1, & n2); - BOOST_CHECK( n1 == 3.14); - BOOST_CHECK( n2 == 7.13); - } - { - int n1=0; - int n2=0; - sscanf("1 23", "%d %d", & n1, & n2); - BOOST_CHECK( n1 == 1); - BOOST_CHECK( n2 == 23); - } - { - int n1=0; - int n2=0; - sscanf("1 jjj 23", "%d %*[j] %d", & n1, & n2); - BOOST_CHECK( n1 == 1); - BOOST_CHECK( n2 == 23); - } - return std::move( c); - }); -} - -void test_snprintf() { - ctx::continuation c = ctx::callcc( - []( ctx::continuation && c) { - { - const char *fmt = "sqrt(2) = %f"; - char buf[19]; - snprintf( buf, sizeof( buf), fmt, std::sqrt( 2) ); - BOOST_CHECK( 0 < sizeof( buf) ); - BOOST_ASSERT( std::string("sqrt(2) = 1.41") == std::string( buf, 14) ); - } - { - std::uint64_t n = 0xbcdef1234567890; - const char *fmt = "0x%016llX"; - char buf[100]; - snprintf( buf, sizeof( buf), fmt, n); - BOOST_ASSERT( std::string("0x0BCDEF1234567890") == std::string( buf, 18) ); - } - return std::move( c); - }); -} - -#ifdef BOOST_WINDOWS -void test_bug12215() { - ctx::continuation c = ctx::callcc( - [](ctx::continuation && c) { - char buffer[MAX_PATH]; - GetModuleFileName( nullptr, buffer, MAX_PATH); - return std::move( c); - }); -} -#endif - -boost::unit_test::test_suite * init_unit_test_suite( int, char* []) -{ - boost::unit_test::test_suite * test = - BOOST_TEST_SUITE("Boost.Context: callcc test suite"); - - test->add( BOOST_TEST_CASE( & test_move) ); - test->add( BOOST_TEST_CASE( & test_bind) ); - test->add( BOOST_TEST_CASE( & test_exception) ); - test->add( BOOST_TEST_CASE( & test_fp) ); - test->add( BOOST_TEST_CASE( & test_stacked) ); - test->add( BOOST_TEST_CASE( & test_prealloc) ); - test->add( BOOST_TEST_CASE( & test_ontop) ); - test->add( BOOST_TEST_CASE( & test_ontop_exception) ); - test->add( BOOST_TEST_CASE( & test_termination) ); - test->add( BOOST_TEST_CASE( & test_sscanf) ); - test->add( BOOST_TEST_CASE( & test_snprintf) ); -#ifdef BOOST_WINDOWS - test->add( BOOST_TEST_CASE( & test_bug12215) ); -#endif - - return test; -} - -#if defined(BOOST_MSVC) -# pragma warning(pop) -#endif diff --git a/test/test_execution_context_v2.cpp b/test/test_execution_context_v2.cpp deleted file mode 100644 index 198a8a1..0000000 --- a/test/test_execution_context_v2.cpp +++ /dev/null @@ -1,582 +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 -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef BOOST_WINDOWS -#include -#endif - -#if defined(BOOST_MSVC) -# pragma warning(push) -# pragma warning(disable: 4723) -#endif - -typedef boost::variant variant_t; - -namespace ctx = boost::context; - -int value1 = 0; -std::string value2; -double value3 = 0.; - -struct X { - ctx::execution_context< void > foo( int i, ctx::execution_context< void > && ctx) { - value1 = i; - return std::move( ctx); - } -}; - -struct Y { - Y() { - value1 = 3; - } - - Y( Y const&) = delete; - Y & operator=( Y const&) = delete; - - ~Y() { - value1 = 7; - } -}; - -class moveable { -public: - bool state; - int value; - - moveable() : - state( false), - value( -1) { - } - - moveable( int v) : - state( true), - value( v) { - } - - moveable( moveable && other) : - state( other.state), - value( other.value) { - other.state = false; - other.value = -1; - } - - moveable & operator=( moveable && other) { - if ( this == & other) return * this; - state = other.state; - value = other.value; - other.state = false; - other.value = -1; - return * this; - } - - moveable( moveable const& other) = delete; - moveable & operator=( moveable const& other) = delete; - - void operator()() { - value1 = value; - } -}; - -struct my_exception : public std::runtime_error { - my_exception( char const* what) : - std::runtime_error( what) { - } -}; - -#ifdef BOOST_MSVC -// Optimizations can remove the integer-divide-by-zero here. -#pragma optimize("", off) -void seh( bool & catched) { - __try { - int i = 1; - i /= 0; - } __except( EXCEPTION_EXECUTE_HANDLER) { - catched = true; - } -} -#pragma optimize("", on) -#endif - -ctx::execution_context< void > fn1( int i, ctx::execution_context< void > && ctx) { - value1 = i; - return std::move( ctx); -} - -ctx::execution_context< void > fn2( const char * what, ctx::execution_context< void > && ctx) { - try { - throw std::runtime_error( what); - } catch ( std::runtime_error const& e) { - value2 = e.what(); - } - return std::move( ctx); -} - -ctx::execution_context< void > fn3( double d, ctx::execution_context< void > && ctx) { - d += 3.45; - value3 = d; - return std::move( ctx); -} - -ctx::execution_context< void > fn5( ctx::execution_context< void > && ctx) { - value1 = 3; - return std::move( ctx); -} - -ctx::execution_context< void > fn4( ctx::execution_context< void > && ctx) { - ctx::execution_context< void > ctx1( fn5); - ctx1(); - value3 = 3.14; - return std::move( ctx); -} - -ctx::execution_context< void > fn6( ctx::execution_context< void > && ctx) { - try { - value1 = 3; - ctx = ctx(); - value1 = 7; - ctx = ctx(); - } catch ( my_exception & e) { - value2 = e.what(); - } - return std::move( ctx); -} - -ctx::execution_context< void > fn7( ctx::execution_context< void > && ctx) { - Y y; - return ctx(); -} - -ctx::execution_context< int > fn8( ctx::execution_context< int > && ctx, int i) { - value1 = i; - return std::move( ctx); -} - -ctx::execution_context< int > fn9( ctx::execution_context< int > && ctx, int i) { - value1 = i; - std::tie( ctx, i) = ctx( i); - value1 = i; - return std::move( ctx); -} - -ctx::execution_context< int & > fn10( ctx::execution_context< int & > && ctx, int & i) { - std::tie( ctx, i) = ctx( i); - return std::move( ctx); -} - -ctx::execution_context< moveable > fn11( ctx::execution_context< moveable > && ctx, moveable m) { - std::tie( ctx, m) = ctx( std::move( m) ); - return std::move( ctx); -} - -ctx::execution_context< int, std::string > fn12( ctx::execution_context< int, std::string > && ctx, int i, std::string str) { - std::tie( ctx, i, str) = ctx( i, str); - return std::move( ctx); -} - -ctx::execution_context< int, moveable > fn13( ctx::execution_context< int, moveable > && ctx, int i, moveable m) { - std::tie( ctx, i, m) = ctx( i, std::move( m) ); - return std::move( ctx); -} - -ctx::execution_context< variant_t > fn14( ctx::execution_context< variant_t > && ctx, variant_t data) { - int i = boost::get< int >( data); - data = boost::lexical_cast< std::string >( i); - std::tie( ctx, data) = ctx( data); - return std::move( ctx); -} - -ctx::execution_context< Y * > fn15( ctx::execution_context< Y * > && ctx, Y * py) { - ctx( py); - return std::move( ctx); -} - -ctx::execution_context< int > fn16( ctx::execution_context< int > && ctx, int i) { - value1 = i; - std::tie( ctx, i) = ctx( i); - value1 = i; - return std::move( ctx); -} - -ctx::execution_context< int, int > fn17( ctx::execution_context< int, int > && ctx, int i, int j) { - for (;;) { - std::tie( ctx, i, j) = ctx( i, j); - } - return std::move( ctx); -} - - -void test_move() { - value1 = 0; - ctx::execution_context< void > ctx; - BOOST_CHECK( ! ctx); - ctx::execution_context< void > ctx1( fn1, 1); - ctx::execution_context< void > ctx2( fn1, 3); - BOOST_CHECK( ctx1); - BOOST_CHECK( ctx2); - ctx1 = std::move( ctx2); - BOOST_CHECK( ctx1); - BOOST_CHECK( ! ctx2); - BOOST_CHECK_EQUAL( 0, value1); - ctx1(); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK( ! ctx1); - BOOST_CHECK( ! ctx2); -} - -void test_memfn() { - value1 = 0; - X x; - ctx::execution_context< void > ctx( & X::foo, x, 7); - ctx(); - BOOST_CHECK_EQUAL( 7, value1); -} - -void test_exception() { - { - const char * what = "hello world"; - ctx::execution_context< void > ctx( fn2, what); - BOOST_CHECK( ctx); - ctx(); - BOOST_CHECK_EQUAL( std::string( what), value2); - BOOST_CHECK( ! ctx); - } -#ifdef BOOST_MSVC - { - bool catched = false; - std::thread([&catched](){ - ctx::execution_context< void > ctx([&catched](ctx::execution_context< void > && ctx){ - seh( catched); - return std::move( ctx); - }); - BOOST_CHECK( ctx); - ctx(); - }).join(); - BOOST_CHECK( catched); - } -#endif -} - -void test_fp() { - double d = 7.13; - ctx::execution_context< void > ctx( fn3, d); - BOOST_CHECK( ctx); - ctx(); - BOOST_CHECK_EQUAL( 10.58, value3); - BOOST_CHECK( ! ctx); -} - -void test_stacked() { - value1 = 0; - value3 = 0.; - ctx::execution_context< void > ctx( fn4); - BOOST_CHECK( ctx); - ctx(); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK_EQUAL( 3.14, value3); - BOOST_CHECK( ! ctx); -} - -void test_prealloc() { - value1 = 0; - ctx::default_stack alloc; - ctx::stack_context sctx( alloc.allocate() ); - void * sp = static_cast< char * >( sctx.sp) - 10; - std::size_t size = sctx.size - 10; - ctx::execution_context< void > ctx( std::allocator_arg, ctx::preallocated( sp, size, sctx), alloc, fn1, 7); - BOOST_CHECK( ctx); - ctx(); - BOOST_CHECK_EQUAL( 7, value1); - BOOST_CHECK( ! ctx); -} - -void test_ontop() { - { - int i = 3, j = 0; - ctx::execution_context< int > ctx([]( ctx::execution_context< int > && ctx, int x) { - for (;;) { - std::tie( ctx, x) = ctx( x*10); - } - return std::move( ctx); - }); - std::tie( ctx, j) = ctx( ctx::exec_ontop_arg, - []( int x){ - return x-10; - }, - i); - BOOST_CHECK( ctx); - BOOST_CHECK_EQUAL( j, -70); - } - { - int i = 3, j = 1; - ctx::execution_context< int, int > ctx( fn17); - std::tie( ctx, i, j) = ctx( i, j); - std::tie( ctx, i, j) = ctx( ctx::exec_ontop_arg, - []( int x, int y) { - return std::make_tuple( x - y, x + y); - }, - i, j); - BOOST_CHECK_EQUAL( i, 2); - BOOST_CHECK_EQUAL( j, 4); - } - { - moveable m1( 7), m2; - BOOST_CHECK( 7 == m1.value); - BOOST_CHECK( m1.state); - BOOST_CHECK( -1 == m2.value); - BOOST_CHECK( ! m2.state); - ctx::execution_context< moveable > ctx( fn11); - std::tie( ctx, m2) = ctx( ctx::exec_ontop_arg, - []( moveable&& m){ - return std::move( m); - }, - std::move( m1) ); - BOOST_CHECK( -1 == m1.value); - BOOST_CHECK( ! m1.state); - BOOST_CHECK( 7 == m2.value); - BOOST_CHECK( m2.state); - } -} - -void test_ontop_exception() { - { - value1 = 0; - value2 = ""; - ctx::execution_context< void > ctx([](ctx::execution_context< void > && ctx){ - for (;;) { - value1 = 3; - try { - ctx = ctx(); - } catch ( ctx::ontop_error const& e) { - try { - std::rethrow_if_nested( e); - } catch ( my_exception const& ex) { - value2 = ex.what(); - } - return e.get_context< void >(); - } - } - return std::move( ctx); - }); - ctx = ctx(); - BOOST_CHECK_EQUAL( 3, value1); - const char * what = "hello world"; - ctx( ctx::exec_ontop_arg, - [what](){ - throw my_exception( what); - }); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK_EQUAL( std::string( what), value2); - } - { - value2 = ""; - int i = 3, j = 1; - ctx::execution_context< int, int > ctx([]( ctx::execution_context< int, int > && ctx, int x, int y) { - for (;;) { - try { - std::tie( ctx, x, y) = ctx( x+y,x-y); - } catch ( ctx::ontop_error const& e) { - try { - std::rethrow_if_nested( e); - } catch ( my_exception const& ex) { - value2 = ex.what(); - } - return e.get_context< int, int >(); - } - } - return std::move( ctx); - }); - std::tie( ctx, i, j) = ctx( i, j); - BOOST_CHECK( ctx); - BOOST_CHECK_EQUAL( i, 4); - BOOST_CHECK_EQUAL( j, 2); - const char * what = "hello world"; - std::tie( ctx, i, j) = ctx( ctx::exec_ontop_arg, - [what](int x, int y) { - throw my_exception(what); - return std::make_tuple( x*y, x/y); - }, - i, j); - BOOST_CHECK_EQUAL( i, 4); - BOOST_CHECK_EQUAL( j, 2); - BOOST_CHECK_EQUAL( std::string( what), value2); - } -} - -void test_termination() { - { - value1 = 0; - ctx::execution_context< void > ctx( fn7); - BOOST_CHECK_EQUAL( 0, value1); - ctx = ctx(); - BOOST_CHECK_EQUAL( 3, value1); - } - BOOST_CHECK_EQUAL( 7, value1); - { - value1 = 0; - BOOST_CHECK_EQUAL( 0, value1); - ctx::execution_context< void > ctx( fn5); - BOOST_CHECK( ctx); - ctx(); - BOOST_CHECK_EQUAL( 3, value1); - BOOST_CHECK( ! ctx); - } - { - value1 = 0; - BOOST_CHECK_EQUAL( 0, value1); - int i = 3, j = 0; - ctx::execution_context< int > ctx( fn9); - BOOST_CHECK( ctx); - std::tie( ctx, j) = ctx( i); - BOOST_CHECK_EQUAL( i, value1); - BOOST_CHECK( ctx); - BOOST_CHECK_EQUAL( i, j); - i = 7; - std::tie( ctx, j) = ctx( i); - BOOST_CHECK_EQUAL( i, value1); - BOOST_CHECK( ! ctx); - BOOST_CHECK_EQUAL( i, j); - } -} - -void test_one_arg() { - { - value1 = 0; - ctx::execution_context< int > ctx( fn8); - ctx( 7); - BOOST_CHECK_EQUAL( 7, value1); - } - { - int i = 3, j = 0; - ctx::execution_context< int > ctx( fn9); - std::tie( ctx, j) = ctx( i); - BOOST_CHECK_EQUAL( i, j); - } - { - int i = 3, j = 0; - int & k = j; - BOOST_CHECK( & i != & k); - BOOST_CHECK( & j == & k); - ctx::execution_context< int & > ctx( fn10); - std::tie( ctx, k) = ctx( i); - BOOST_CHECK( & i != & k); - } - { - Y y; - Y * py = nullptr; - ctx::execution_context< Y * > ctx( fn15); - std::tie( ctx, py) = ctx( & y); - BOOST_CHECK( py == & y); - } - { - moveable m1( 7), m2; - BOOST_CHECK( 7 == m1.value); - BOOST_CHECK( m1.state); - BOOST_CHECK( -1 == m2.value); - BOOST_CHECK( ! m2.state); - ctx::execution_context< moveable > ctx( fn11); - std::tie( ctx, m2) = ctx( std::move( m1) ); - BOOST_CHECK( -1 == m1.value); - BOOST_CHECK( ! m1.state); - BOOST_CHECK( 7 == m2.value); - BOOST_CHECK( m2.state); - } -} - -void test_two_args() { - { - int i1 = 3, i2 = 0; - std::string str1("abc"), str2; - ctx::execution_context< int, std::string > ctx( fn12); - std::tie( ctx, i2, str2) = ctx( i1, str1); - BOOST_CHECK_EQUAL( i1, i2); - BOOST_CHECK_EQUAL( str1, str2); - } - { - int i1 = 3, i2 = 0; - moveable m1( 7), m2; - BOOST_CHECK( 7 == m1.value); - BOOST_CHECK( m1.state); - BOOST_CHECK( -1 == m2.value); - BOOST_CHECK( ! m2.state); - ctx::execution_context< int, moveable > ctx( fn13); - std::tie( ctx, i2, m2) = ctx( i1, std::move( m1) ); - BOOST_CHECK_EQUAL( i1, i2); - BOOST_CHECK( -1 == m1.value); - BOOST_CHECK( ! m1.state); - BOOST_CHECK( 7 == m2.value); - BOOST_CHECK( m2.state); - } -} - -void test_variant() { - { - int i = 7; - variant_t data1 = i, data2; - ctx::execution_context< variant_t > ctx( fn14); - std::tie( ctx, data2) = ctx( data1); - std::string str = boost::get< std::string >( data2); - BOOST_CHECK_EQUAL( std::string("7"), str); - } -} - -#ifdef BOOST_WINDOWS -void test_bug12215() { - ctx::execution_context< void > ctx( - [](ctx::execution_context< void > && ctx) { - char buffer[MAX_PATH]; - GetModuleFileName( nullptr, buffer, MAX_PATH); - return std::move( ctx); - }); - ctx(); - -} -#endif - -boost::unit_test::test_suite * init_unit_test_suite( int, char* []) -{ - boost::unit_test::test_suite * test = - BOOST_TEST_SUITE("Boost.Context: execution_context v2 test suite"); - - test->add( BOOST_TEST_CASE( & test_move) ); - test->add( BOOST_TEST_CASE( & test_memfn) ); - test->add( BOOST_TEST_CASE( & test_exception) ); - test->add( BOOST_TEST_CASE( & test_fp) ); - test->add( BOOST_TEST_CASE( & test_stacked) ); - test->add( BOOST_TEST_CASE( & test_prealloc) ); - test->add( BOOST_TEST_CASE( & test_ontop) ); - test->add( BOOST_TEST_CASE( & test_ontop_exception) ); - test->add( BOOST_TEST_CASE( & test_termination) ); - test->add( BOOST_TEST_CASE( & test_one_arg) ); - test->add( BOOST_TEST_CASE( & test_two_args) ); - test->add( BOOST_TEST_CASE( & test_variant) ); -#ifdef BOOST_WINDOWS - test->add( BOOST_TEST_CASE( & test_bug12215) ); -#endif - - return test; -} - -#if defined(BOOST_MSVC) -# pragma warning(pop) -#endif diff --git a/test/test_fiber.cpp b/test/test_fiber.cpp index dea79b0..e50014b 100644 --- a/test/test_fiber.cpp +++ b/test/test_fiber.cpp @@ -26,7 +26,7 @@ #include #include -#include +#include #include #ifdef BOOST_WINDOWS @@ -47,22 +47,24 @@ std::string value2; double value3 = 0.; struct X { - ctx::fiber_handle foo( ctx::fiber_handle && f, int i) { + ctx::fiber_context foo( ctx::fiber_context && f, int i) { value1 = i; return std::move( f); } }; struct Y { - Y() { - value1 = 3; + int & value; + Y( int & v) : + value{ v } { + value = 3; } Y( Y const&) = delete; Y & operator=( Y const&) = delete; ~Y() { - value1 = 7; + value = 7; } }; @@ -106,8 +108,8 @@ public: }; struct my_exception : public std::runtime_error { - ctx::fiber_handle f; - my_exception( ctx::fiber_handle && f_, char const* what) : + ctx::fiber_context f; + my_exception( ctx::fiber_context && f_, char const* what) : std::runtime_error( what), f{ std::move( f_) } { } @@ -131,8 +133,8 @@ void test_move() { value1 = 0; int i = 1; BOOST_CHECK_EQUAL( 0, value1); - ctx::fiber_handle f1{ - [&i](ctx::fiber_handle && f) { + ctx::fiber_context f1{ + [&i](ctx::fiber_context && f) { value1 = i; f = std::move( f).resume(); value1 = i; @@ -141,7 +143,7 @@ void test_move() { f1 = std::move( f1).resume(); BOOST_CHECK_EQUAL( 1, value1); BOOST_CHECK( f1); - ctx::fiber_handle f2; + ctx::fiber_context f2; BOOST_CHECK( ! f2); f2 = std::move( f1); BOOST_CHECK( ! f1); @@ -156,7 +158,7 @@ void test_move() { void test_bind() { value1 = 0; X x; - ctx::fiber_handle f{ std::bind( & X::foo, x, std::placeholders::_1, 7) }; + ctx::fiber_context f{ std::bind( & X::foo, x, std::placeholders::_1, 7) }; f = std::move( f).resume(); BOOST_CHECK_EQUAL( 7, value1); } @@ -164,8 +166,8 @@ void test_bind() { void test_exception() { { const char * what = "hello world"; - ctx::fiber_handle f{ - [&what](ctx::fiber_handle && f) { + ctx::fiber_context f{ + [&what](ctx::fiber_context && f) { try { throw std::runtime_error( what); } catch ( std::runtime_error const& e) { @@ -181,7 +183,7 @@ void test_exception() { { bool catched = false; std::thread([&catched](){ - ctx::fiber_handle f{ [&catched](ctx::fiber_handle && f){ + ctx::fiber_context f{ [&catched](ctx::fiber_context && f){ seh( catched); return std::move( f); }}; @@ -196,8 +198,8 @@ void test_exception() { void test_fp() { value3 = 0.; double d = 7.13; - ctx::fiber_handle f{ - [&d]( ctx::fiber_handle && f) { + ctx::fiber_context f{ + [&d]( ctx::fiber_context && f) { d += 3.45; value3 = d; return std::move( f); @@ -210,10 +212,10 @@ void test_fp() { void test_stacked() { value1 = 0; value3 = 0.; - ctx::fiber_handle f{ - [](ctx::fiber_handle && f) { - ctx::fiber_handle f1{ - [](ctx::fiber_handle && f) { + ctx::fiber_context f{ + [](ctx::fiber_context && f) { + ctx::fiber_context f1{ + [](ctx::fiber_context && f) { value1 = 3; return std::move( f); }}; @@ -230,7 +232,7 @@ void test_stacked() { void test_ontop() { { int i = 3; - ctx::fiber_handle f{ [&i](ctx::fiber_handle && f) { + ctx::fiber_context f{ [&i](ctx::fiber_context && f) { for (;;) { i *= 10; f = std::move( f).resume(); @@ -239,33 +241,36 @@ void test_ontop() { }}; f = std::move( f).resume(); f = std::move( f).resume_with( - [&i](ctx::fiber_handle && f){ + [&i](ctx::fiber_context && f){ i -= 10; return std::move( f); }); BOOST_CHECK( f); BOOST_CHECK_EQUAL( i, 200); + f = std::move( f).resume_with( ctx::unwind_fiber); + BOOST_CHECK( ! f); } { - ctx::fiber_handle f1; - ctx::fiber_handle f{ [&f1](ctx::fiber_handle && f) { + ctx::fiber_context f1; + ctx::fiber_context f{ [&f1](ctx::fiber_context && f) { f = std::move( f).resume(); BOOST_CHECK( ! f); return std::move( f1); }}; f = std::move( f).resume(); f = std::move( f).resume_with( - [&f1](ctx::fiber_handle && f){ + [&f1](ctx::fiber_context && f){ f1 = std::move( f); return std::move( f); }); + BOOST_CHECK( ! f); } } void test_ontop_exception() { value1 = 0; value2 = ""; - ctx::fiber_handle f{ [](ctx::fiber_handle && f){ + ctx::fiber_context f{ [](ctx::fiber_context && f){ for (;;) { value1 = 3; try { @@ -281,7 +286,7 @@ void test_ontop_exception() { BOOST_CHECK_EQUAL( 3, value1); const char * what = "hello world"; f = std::move( f).resume_with( - [what](ctx::fiber_handle && f){ + [what](ctx::fiber_context && f){ throw my_exception( std::move( f), what); return std::move( f); }); @@ -291,22 +296,24 @@ void test_ontop_exception() { void test_termination() { { - value1 = 0; - ctx::fiber_handle f{ - [](ctx::fiber_handle && f){ - Y y; + int value = 0; + ctx::fiber_context f{ + [&value](ctx::fiber_context && f){ + Y y{ value }; + BOOST_CHECK_EQUAL( 3, value); f = std::move( f).resume(); return std::move(f); }}; f = std::move( f).resume(); - BOOST_CHECK_EQUAL( 3, value1); + f = std::move( f).resume_with( ctx::unwind_fiber); + BOOST_CHECK( ! f); + BOOST_CHECK_EQUAL( 7, value); } - BOOST_CHECK_EQUAL( 7, value1); { value1 = 0; BOOST_CHECK_EQUAL( 0, value1); - ctx::fiber_handle f{ - [](ctx::fiber_handle && f) { + ctx::fiber_context f{ + [](ctx::fiber_context && f) { value1 = 3; return std::move( f); }}; @@ -318,8 +325,8 @@ void test_termination() { value1 = 0; BOOST_CHECK_EQUAL( 0, value1); int i = 3; - ctx::fiber_handle f{ - [&i](ctx::fiber_handle && f){ + ctx::fiber_context f{ + [&i](ctx::fiber_context && f){ value1 = i; f = std::move( f).resume(); value1 = i; @@ -337,8 +344,8 @@ void test_termination() { } void test_sscanf() { - ctx::fiber_handle{ - []( ctx::fiber_handle && f) { + ctx::fiber_context{ + []( ctx::fiber_context && f) { { double n1 = 0; double n2 = 0; @@ -365,8 +372,8 @@ void test_sscanf() { } void test_snprintf() { - ctx::fiber_handle{ - []( ctx::fiber_handle && f) { + ctx::fiber_context{ + []( ctx::fiber_context && f) { { const char *fmt = "sqrt(2) = %f"; char buf[19]; @@ -387,8 +394,8 @@ void test_snprintf() { void test_can_resume_from_any_thread() { { - ctx::fiber_handle f{ - []( ctx::fiber_handle && m) { + ctx::fiber_context f{ + []( ctx::fiber_context && m) { BOOST_CHECK( m); BOOST_CHECK( ! m.can_resume_from_any_thread() ); m = std::move( m).resume(); @@ -404,8 +411,8 @@ void test_can_resume_from_any_thread() { BOOST_CHECK( ! f); } { - ctx::fiber_handle f{ - []( ctx::fiber_handle && m) { + ctx::fiber_context f{ + []( ctx::fiber_context && m) { BOOST_CHECK( m); BOOST_CHECK( ! m.can_resume_from_any_thread() ); m = std::move( m).resume(); @@ -422,7 +429,7 @@ void test_can_resume_from_any_thread() { BOOST_CHECK( f); BOOST_CHECK( f.can_resume_from_any_thread() ); f = std::move( f).resume_with( - []( ctx::fiber_handle && m) { + []( ctx::fiber_context && m) { BOOST_CHECK( m); BOOST_CHECK( ! m.can_resume_from_any_thread() ); return std::move( m); @@ -435,10 +442,10 @@ void test_can_resume_from_any_thread() { } void test_hosting_thread() { - ctx::fiber_handle f{ - [](ctx::fiber_handle && m){ + ctx::fiber_context f{ + [](ctx::fiber_context && m){ BOOST_CHECK( m.can_resume() ); - ctx::fiber_handle * pm = & m; + ctx::fiber_context * pm = & m; std::thread{ [pm]{ BOOST_CHECK( ! pm->can_resume() ); }}.join(); m = std::move( m).resume(); return std::move( m); @@ -447,13 +454,14 @@ void test_hosting_thread() { BOOST_CHECK( f.can_resume() ); f = std::move( f).resume(); BOOST_CHECK( f.can_resume() ); - + f = std::move( f).resume_with( ctx::unwind_fiber); + BOOST_CHECK( ! f); } #ifdef BOOST_WINDOWS void test_bug12215() { - ctx::fiber_handle{ - [](ctx::fiber_handle && f) { + ctx::fiber_context{ + [](ctx::fiber_context && f) { char buffer[MAX_PATH]; GetModuleFileName( nullptr, buffer, MAX_PATH); return std::move( f);