├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── README.md ├── build.jam ├── build └── Jamfile.v2 ├── doc ├── Jamfile.v2 ├── acknowledgements.qbk ├── architectures.qbk ├── asymmetric.qbk ├── attributes.qbk ├── coro.qbk ├── coroutine.qbk ├── images │ ├── event_model.dia │ ├── event_model.png │ ├── foo_bar.png │ ├── foo_bar_seq.dia │ ├── foo_bar_seq.png │ ├── same_fringe.dia │ └── same_fringe.png ├── intro.qbk ├── motivation.qbk ├── overview.qbk ├── performance.qbk ├── stack.qbk └── symmetric.qbk ├── example ├── asymmetric │ ├── Jamfile.v2 │ ├── X.h │ ├── chaining.cpp │ ├── echo.cpp │ ├── exception.cpp │ ├── fibonacci.cpp │ ├── layout.cpp │ ├── parallel.cpp │ ├── power.cpp │ ├── same_fringe.cpp │ ├── segmented_stack.cpp │ ├── simple.cpp │ ├── test.cpp │ ├── tree.h │ └── unwind.cpp └── symmetric │ ├── Jamfile.v2 │ ├── dice_game.cpp │ ├── merge_arrays.cpp │ ├── segmented_stack.cpp │ ├── simple.cpp │ └── unwind.cpp ├── include └── boost │ └── coroutine │ ├── all.hpp │ ├── asymmetric_coroutine.hpp │ ├── attributes.hpp │ ├── coroutine.hpp │ ├── detail │ ├── config.hpp │ ├── coroutine_context.hpp │ ├── data.hpp │ ├── flags.hpp │ ├── parameters.hpp │ ├── preallocated.hpp │ ├── pull_coroutine_impl.hpp │ ├── pull_coroutine_object.hpp │ ├── pull_coroutine_synthesized.hpp │ ├── push_coroutine_impl.hpp │ ├── push_coroutine_object.hpp │ ├── push_coroutine_synthesized.hpp │ ├── setup.hpp │ ├── symmetric_coroutine_call.hpp │ ├── symmetric_coroutine_impl.hpp │ ├── symmetric_coroutine_object.hpp │ ├── symmetric_coroutine_yield.hpp │ ├── trampoline.hpp │ ├── trampoline_pull.hpp │ └── trampoline_push.hpp │ ├── exceptions.hpp │ ├── flags.hpp │ ├── posix │ ├── protected_stack_allocator.hpp │ └── segmented_stack_allocator.hpp │ ├── protected_stack_allocator.hpp │ ├── segmented_stack_allocator.hpp │ ├── stack_allocator.hpp │ ├── stack_context.hpp │ ├── stack_traits.hpp │ ├── standard_stack_allocator.hpp │ ├── symmetric_coroutine.hpp │ └── windows │ └── protected_stack_allocator.hpp ├── index.html ├── meta └── libraries.json ├── performance ├── asymmetric │ ├── Jamfile.v2 │ ├── performance_create_prealloc.cpp │ ├── performance_create_protected.cpp │ ├── performance_create_standard.cpp │ ├── performance_switch.cpp │ └── segmented │ │ ├── Jamfile.v2 │ │ └── performance_create_segmented.cpp ├── bind_processor.hpp ├── bind_processor_aix.cpp ├── bind_processor_freebsd.cpp ├── bind_processor_hpux.cpp ├── bind_processor_linux.cpp ├── bind_processor_solaris.cpp ├── bind_processor_windows.cpp ├── clock.hpp ├── cycle.hpp ├── cycle_i386.hpp ├── cycle_x86-64.hpp ├── preallocated_stack_allocator.hpp └── symmetric │ ├── Jamfile.v2 │ ├── performance_create_prealloc.cpp │ ├── performance_create_protected.cpp │ ├── performance_create_standard.cpp │ ├── performance_switch.cpp │ └── segmented │ ├── Jamfile.v2 │ └── performance_create_segmented.cpp ├── src ├── detail │ └── coroutine_context.cpp ├── exceptions.cpp ├── posix │ └── stack_traits.cpp └── windows │ └── stack_traits.cpp └── test ├── Jamfile.v2 ├── test_asymmetric_coroutine.cpp └── test_symmetric_coroutine.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto !eol svneol=native#text/plain 2 | *.gitattributes text svneol=native#text/plain 3 | 4 | # Scriptish formats 5 | *.bat text svneol=native#text/plain 6 | *.bsh text svneol=native#text/x-beanshell 7 | *.cgi text svneol=native#text/plain 8 | *.cmd text svneol=native#text/plain 9 | *.js text svneol=native#text/javascript 10 | *.php text svneol=native#text/x-php 11 | *.pl text svneol=native#text/x-perl 12 | *.pm text svneol=native#text/x-perl 13 | *.py text svneol=native#text/x-python 14 | *.sh eol=lf svneol=LF#text/x-sh 15 | configure eol=lf svneol=LF#text/x-sh 16 | 17 | # Image formats 18 | *.bmp binary svneol=unset#image/bmp 19 | *.gif binary svneol=unset#image/gif 20 | *.ico binary svneol=unset#image/ico 21 | *.jpeg binary svneol=unset#image/jpeg 22 | *.jpg binary svneol=unset#image/jpeg 23 | *.png binary svneol=unset#image/png 24 | *.tif binary svneol=unset#image/tiff 25 | *.tiff binary svneol=unset#image/tiff 26 | *.svg text svneol=native#image/svg%2Bxml 27 | 28 | # Data formats 29 | *.pdf binary svneol=unset#application/pdf 30 | *.avi binary svneol=unset#video/avi 31 | *.doc binary svneol=unset#application/msword 32 | *.dsp text svneol=crlf#text/plain 33 | *.dsw text svneol=crlf#text/plain 34 | *.eps binary svneol=unset#application/postscript 35 | *.gz binary svneol=unset#application/gzip 36 | *.mov binary svneol=unset#video/quicktime 37 | *.mp3 binary svneol=unset#audio/mpeg 38 | *.ppt binary svneol=unset#application/vnd.ms-powerpoint 39 | *.ps binary svneol=unset#application/postscript 40 | *.psd binary svneol=unset#application/photoshop 41 | *.rdf binary svneol=unset#text/rdf 42 | *.rss text svneol=unset#text/xml 43 | *.rtf binary svneol=unset#text/rtf 44 | *.sln text svneol=native#text/plain 45 | *.swf binary svneol=unset#application/x-shockwave-flash 46 | *.tgz binary svneol=unset#application/gzip 47 | *.vcproj text svneol=native#text/xml 48 | *.vcxproj text svneol=native#text/xml 49 | *.vsprops text svneol=native#text/xml 50 | *.wav binary svneol=unset#audio/wav 51 | *.xls binary svneol=unset#application/vnd.ms-excel 52 | *.zip binary svneol=unset#application/zip 53 | 54 | # Text formats 55 | .htaccess text svneol=native#text/plain 56 | *.bbk text svneol=native#text/xml 57 | *.cmake text svneol=native#text/plain 58 | *.css text svneol=native#text/css 59 | *.dtd text svneol=native#text/xml 60 | *.htm text svneol=native#text/html 61 | *.html text svneol=native#text/html 62 | *.ini text svneol=native#text/plain 63 | *.log text svneol=native#text/plain 64 | *.mak text svneol=native#text/plain 65 | *.qbk text svneol=native#text/plain 66 | *.rst text svneol=native#text/plain 67 | *.sql text svneol=native#text/x-sql 68 | *.txt text svneol=native#text/plain 69 | *.xhtml text svneol=native#text/xhtml%2Bxml 70 | *.xml text svneol=native#text/xml 71 | *.xsd text svneol=native#text/xml 72 | *.xsl text svneol=native#text/xml 73 | *.xslt text svneol=native#text/xml 74 | *.xul text svneol=native#text/xul 75 | *.yml text svneol=native#text/plain 76 | boost-no-inspect text svneol=native#text/plain 77 | CHANGES text svneol=native#text/plain 78 | COPYING text svneol=native#text/plain 79 | INSTALL text svneol=native#text/plain 80 | Jamfile text svneol=native#text/plain 81 | Jamroot text svneol=native#text/plain 82 | Jamfile.v2 text svneol=native#text/plain 83 | Jamrules text svneol=native#text/plain 84 | Makefile* text svneol=native#text/plain 85 | README text svneol=native#text/plain 86 | TODO text svneol=native#text/plain 87 | 88 | # Code formats 89 | *.c text svneol=native#text/plain 90 | *.cpp text svneol=native#text/plain 91 | *.h text svneol=native#text/plain 92 | *.hpp text svneol=native#text/plain 93 | *.ipp text svneol=native#text/plain 94 | *.tpp text svneol=native#text/plain 95 | *.jam text svneol=native#text/plain 96 | *.java text svneol=native#text/plain 97 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.sw* 3 | *.xml 4 | html 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2020, 2021 Peter Dimov 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # https://www.boost.org/LICENSE_1_0.txt 4 | 5 | cmake_minimum_required(VERSION 3.5...3.16) 6 | 7 | project(boost_coroutine VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) 8 | 9 | if(WIN32 AND NOT CMAKE_CXX_PLATFORM_ID MATCHES "Cygwin") 10 | set(STACK_TRAITS_SOURCES 11 | src/windows/stack_traits.cpp 12 | ) 13 | else() 14 | set(STACK_TRAITS_SOURCES 15 | src/posix/stack_traits.cpp 16 | ) 17 | endif() 18 | 19 | add_library(boost_coroutine 20 | src/detail/coroutine_context.cpp 21 | src/exceptions.cpp 22 | ${STACK_TRAITS_SOURCES} 23 | ) 24 | 25 | add_library(Boost::coroutine ALIAS boost_coroutine) 26 | 27 | target_include_directories(boost_coroutine PUBLIC include) 28 | 29 | target_link_libraries(boost_coroutine 30 | PUBLIC 31 | Boost::assert 32 | Boost::config 33 | Boost::context 34 | Boost::core 35 | Boost::exception 36 | Boost::move 37 | Boost::system 38 | Boost::throw_exception 39 | Boost::type_traits 40 | Boost::utility 41 | ) 42 | 43 | target_compile_definitions(boost_coroutine 44 | PUBLIC BOOST_COROUTINE_NO_LIB 45 | PRIVATE BOOST_COROUTINE_SOURCE BOOST_COROUTINES_SOURCE 46 | ) 47 | 48 | if(BUILD_SHARED_LIBS) 49 | target_compile_definitions(boost_coroutine PUBLIC BOOST_COROUTINE_DYN_LINK BOOST_COROUTINES_DYN_LINK) 50 | else() 51 | target_compile_definitions(boost_coroutine PUBLIC BOOST_COROUTINE_STATIC_LINK) 52 | endif() 53 | 54 | if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") 55 | 56 | add_subdirectory(test) 57 | 58 | endif() 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | boost.coroutine 2 | =============== 3 | 4 | boost.coroutine provides templates for generalized subroutines which allow multiple entry points for 5 | suspending and resuming execution at certain locations. It preserves the local state of execution and 6 | allows re-entering subroutines more than once (useful if state must be kept across function calls). 7 | 8 | Coroutines can be viewed as a language-level construct providing a special kind of control flow. 9 | 10 | In contrast to threads, which are pre-emptive, coroutines switches are cooperative (programmer controls 11 | when a switch will happen). The kernel is not involved in the coroutine switches. 12 | 13 | Note that boost.coroutine is deprecated - boost.coroutine2 is its successor. 14 | If you are forced to use a pre-C++11 compiler you should still use boost.coroutine. 15 | -------------------------------------------------------------------------------- /build.jam: -------------------------------------------------------------------------------- 1 | # Copyright René Ferdinand Rivera Morell 2023-2024 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | require-b2 5.2 ; 7 | 8 | constant boost_dependencies : 9 | /boost/assert//boost_assert 10 | /boost/config//boost_config 11 | /boost/context//boost_context 12 | /boost/core//boost_core 13 | /boost/exception//boost_exception 14 | /boost/move//boost_move 15 | /boost/system//boost_system 16 | /boost/throw_exception//boost_throw_exception 17 | /boost/type_traits//boost_type_traits 18 | /boost/utility//boost_utility ; 19 | 20 | project /boost/coroutine 21 | : common-requirements 22 | include 23 | ; 24 | 25 | explicit 26 | [ alias boost_coroutine : build//boost_coroutine ] 27 | [ alias all : boost_coroutine test ] 28 | ; 29 | 30 | call-if : boost-library coroutine 31 | : install boost_coroutine 32 | ; 33 | 34 | -------------------------------------------------------------------------------- /build/Jamfile.v2: -------------------------------------------------------------------------------- 1 | 2 | # Copyright Oliver Kowalke 2009. 3 | # Distributed under the Boost Software License, Version 1.0. 4 | # (See accompanying file LICENSE_1_0.txt or copy at 5 | # http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | import feature ; 8 | import modules ; 9 | import toolset ; 10 | import-search /boost/context ; 11 | import boost-context-features ; 12 | 13 | project 14 | : common-requirements $(boost_dependencies) 15 | : requirements 16 | /boost/context//boost_context 17 | linux,gcc,on:-fsplit-stack 18 | linux,gcc,on:-DBOOST_USE_SEGMENTED_STACKS 19 | clang,on:-fsplit-stack 20 | clang,on:-DBOOST_USE_SEGMENTED_STACKS 21 | shared:BOOST_COROUTINES_DYN_LINK=1 22 | BOOST_COROUTINES_SOURCE 23 | : usage-requirements 24 | shared:BOOST_COROUTINES_DYN_LINK=1 25 | BOOST_COROUTINES_NO_LIB=1 26 | : source-location ../src 27 | ; 28 | 29 | alias stack_traits_sources 30 | : windows/stack_traits.cpp 31 | : windows 32 | ; 33 | 34 | alias stack_traits_sources 35 | : posix/stack_traits.cpp 36 | ; 37 | 38 | explicit stack_traits_sources ; 39 | 40 | lib boost_coroutine 41 | : detail/coroutine_context.cpp 42 | exceptions.cpp 43 | stack_traits_sources 44 | : shared:/boost/context//boost_context 45 | ; 46 | -------------------------------------------------------------------------------- /doc/Jamfile.v2: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2008 Anthony Williams 2 | # 3 | # Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | project coroutine/doc ; 7 | 8 | import boostbook ; 9 | import quickbook ; 10 | import modules ; 11 | 12 | path-constant here : . ; 13 | 14 | boostbook coro 15 | : 16 | coro.qbk 17 | : 18 | # Path for links to Boost: 19 | boost.root=../../../.. 20 | # HTML options first: 21 | # How far down we chunk nested sections, basically all of them: 22 | chunk.section.depth=3 23 | # Don't put the first section on the same page as the TOC: 24 | chunk.first.sections=1 25 | # How far down sections get TOC's 26 | toc.section.depth=10 27 | # Max depth in each TOC: 28 | toc.max.depth=3 29 | # How far down we go with TOC's 30 | generate.section.toc.level=10 31 | # Absolute path for images: 32 | pdf:img.src.path=$(here)/html/ 33 | ; 34 | 35 | ############################################################################### 36 | alias boostdoc ; 37 | explicit boostdoc ; 38 | alias boostrelease : coro ; 39 | explicit boostrelease ; 40 | -------------------------------------------------------------------------------- /doc/acknowledgements.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright Oliver Kowalke 2009. 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE_1_0.txt or copy at 5 | http://www.boost.org/LICENSE_1_0.txt 6 | ] 7 | 8 | [section:acknowledgements Acknowledgments] 9 | 10 | I'd like to thank Alex Hagen-Zanker, Christopher Kormanyos, Conrad Poelman, 11 | Eugene Yakubovich, Giovanni Piero Deretta, Hartmut Kaiser, Jeffrey Lee Hellrung, 12 | [*Nat Goodspeed], Robert Stewart, Vicente J. Botet Escriba and Yuriy Krasnoschek. 13 | 14 | Especially Eugene Yakubovich, Giovanni Piero Deretta and Vicente J. Botet 15 | Escriba contributed many good ideas during the review. 16 | 17 | [endsect] 18 | -------------------------------------------------------------------------------- /doc/architectures.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright Oliver Kowalke 2009. 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE_1_0.txt or copy at 5 | http://www.boost.org/LICENSE_1_0.txt 6 | ] 7 | 8 | [section:architectures Architectures] 9 | 10 | __boost_coroutine__ depends on __boost_context__ which supports these 11 | [@boost:/libs/context/doc/html/context/architectures.html architectures]. 12 | 13 | [endsect] 14 | -------------------------------------------------------------------------------- /doc/attributes.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright Oliver Kowalke 2009. 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE_1_0.txt or copy at 5 | http://www.boost.org/LICENSE_1_0.txt 6 | ] 7 | 8 | [section:attributes Attributes] 9 | 10 | Class `attributes` is used to specify parameters required to setup a 11 | coroutine's context. 12 | 13 | enum flag_unwind_t 14 | { 15 | stack_unwind, 16 | no_stack_unwind 17 | }; 18 | 19 | struct attributes 20 | { 21 | std::size_t size; 22 | flag_unwind_t do_unwind; 23 | 24 | attributes() noexcept; 25 | 26 | explicit attributes( std::size_t size_) noexcept; 27 | 28 | explicit attributes( flag_unwind_t do_unwind_) noexcept; 29 | 30 | explicit attributes( std::size_t size_, flag_unwind_t do_unwind_) noexcept; 31 | }; 32 | 33 | [heading `attributes()`] 34 | [variablelist 35 | [[Effects:] [Default constructor using `boost::context::default_stacksize()`, does unwind 36 | the stack after coroutine/generator is complete.]] 37 | [[Throws:] [Nothing.]] 38 | ] 39 | 40 | [heading `attributes( std::size_t size)`] 41 | [variablelist 42 | [[Effects:] [Argument `size` defines stack size of the new coroutine. 43 | Stack unwinding after termination.]] 44 | [[Throws:] [Nothing.]] 45 | ] 46 | 47 | [heading `attributes( flag_unwind_t do_unwind)`] 48 | [variablelist 49 | [[Effects:] [Argument `do_unwind` determines if stack will be unwound after 50 | termination or not. The default stacksize is used for the new coroutine.]] 51 | [[Throws:] [Nothing.]] 52 | ] 53 | 54 | [heading `attributes( std::size_t size, flag_unwind_t do_unwind)`] 55 | [variablelist 56 | [[Effects:] [Arguments `size` and `do_unwind` are given by the user.]] 57 | [[Throws:] [Nothing.]] 58 | ] 59 | 60 | [endsect] 61 | -------------------------------------------------------------------------------- /doc/coro.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright Oliver Kowalke 2009. 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE_1_0.txt or copy at 5 | http://www.boost.org/LICENSE_1_0.txt 6 | ] 7 | 8 | [library Coroutine 9 | [quickbook 1.5] 10 | [authors [Kowalke, Oliver]] 11 | [copyright 2009 Oliver Kowalke] 12 | [purpose C++ Library providing coroutine facility] 13 | [id coroutine] 14 | [category text] 15 | [license 16 | Distributed under the Boost Software License, Version 1.0. 17 | (See accompanying file LICENSE_1_0.txt or copy at 18 | [@http://www.boost.org/LICENSE_1_0.txt]) 19 | ] 20 | ] 21 | 22 | 23 | [def __boost_asio__ [*Boost.Asio]] 24 | [def __boost_build__ [*Boost.Build]] 25 | [def __boost_context__ [*Boost.Context]] 26 | [def __boost_coroutine__ [*Boost.Coroutine]] 27 | [def __boost_exception__ [*Boost.Exception]] 28 | [def __boost_function_types__ [*Boost.FunctionTypes]] 29 | [def __boost_move__ [*Boost.Move]] 30 | [def __boost_mpl__ [*Boost.MPL]] 31 | [def __boost_optional__ [*Boost.Optional]] 32 | [def __boost_preprocessor__ [*Boost.Preprocessor]] 33 | [def __boost_range__ [*Boost.Range]] 34 | [def __boost_result_of__ [*Boost.ResultOf]] 35 | [def __boost_smart_ptr__ [*Boost.SmartPtr]] 36 | [def __boost_static_assert__ [*Boost.StaticAssert]] 37 | [def __boost_tuple__ [*Boost.Tuple]] 38 | [def __boost_type_traits__ [*Boost.TypeTraits]] 39 | [def __boost_utility__ [*Boost.Utility]] 40 | [def __boost_version__ [*Boost-1.52.0]] 41 | 42 | [def __coro__ ['coroutine]] 43 | [def __coro_fn__ ['coroutine-function]] 44 | [def __coros__ ['coroutines]] 45 | [def __ctx__ ['context]] 46 | [def __not_a_coro__ ['not-a-coroutine]] 47 | [def __segmented_stack__ ['segmented-stack]] 48 | [def __signature__ ['Signature]] 49 | [def __stack_allocator_concept__ ['stack-allocator concept]] 50 | [def __stack_allocator__ ['stack-allocator]] 51 | [def __stack_traits__ ['stack-traits]] 52 | [def __stack__ ['stack]] 53 | [def __tls__ ['thread-local-storage]] 54 | 55 | [def __acoro__ ['asymmetric_coroutine<>]] 56 | [def __attrs__ ['attributes]] 57 | [def __begin__ ['std::begin()]] 58 | [def __bind__ ['boost::bind()]] 59 | [def __call_coro_bool__ ['symmetric_coroutine<>::call_type::operator bool]] 60 | [def __call_coro_op__ ['symmetric_coroutine<>::call_type::operator()]] 61 | [def __call_coro__ ['symmetric_coroutine<>::call_type]] 62 | [def __coro_allocator__ ['stack_allocator]] 63 | [def __coro_ns__ ['boost::coroutines]] 64 | [def __end__ ['std::end()]] 65 | [def __fcontext__ ['boost::contexts::fcontext_t]] 66 | [def __fetch__ ['inbuf::fetch()]] 67 | [def __forced_unwind__ ['detail::forced_unwind]] 68 | [def __getline__ ['std::getline()]] 69 | [def __handle_read__ ['session::handle_read()]] 70 | [def __io_service__ ['boost::asio::io_sevice]] 71 | [def __protected_allocator__ ['protected_stack_allocator]] 72 | [def __pull_coro__ ['asymmetric_coroutine<>::pull_type]] 73 | [def __pull_coro_bool__ ['asymmetric_coroutine<>::pull_type::operator bool]] 74 | [def __pull_coro_get__ ['asymmetric_coroutine<>::pull_type::get()]] 75 | [def __pull_coro_it__ ['asymmetric_coroutine<>::pull_type::iterator]] 76 | [def __pull_coro_op__ ['asymmetric_coroutine<>::pull_type::operator()]] 77 | [def __push_coro__ ['asymmetric_coroutine<>::push_type]] 78 | [def __push_coro_bool__ ['asymmetric_coroutine<>::push_type::operator bool]] 79 | [def __push_coro_it__ ['asymmetric_coroutine<>::push_type::iterator]] 80 | [def __push_coro_op__ ['asymmetric_coroutine<>::push_type::operator()]] 81 | [def __scoro__ ['symmetric_coroutine<>]] 82 | [def __segmented_allocator__ ['segmented_stack_allocator]] 83 | [def __server__ ['server]] 84 | [def __session__ ['session]] 85 | [def __stack_context__ ['stack_context]] 86 | [def __segmented_allocator__ ['segmented_stack_allocator]] 87 | [def __standard_allocator__ ['standard_stack_allocator]] 88 | [def __start__ ['session::start()]] 89 | [def __terminate__ ['std::terminate()]] 90 | [def __thread__ ['boost::thread]] 91 | [def __tie__ ['boost::tie]] 92 | [def __tuple__ ['boost::tuple<>]] 93 | [def __underflow__ ['stream_buf::underflow()]] 94 | [def __yield_context__ ['boost::asio::yield_context]] 95 | [def __yield_coro_bool__ ['symmetric_coroutine<>::yield_type::operator bool]] 96 | [def __yield_coro_get__ ['symmetric_coroutine<>::yield_type::get()]] 97 | [def __yield_coro_op__ ['symmetric_coroutine<>::yield_type::operator()]] 98 | [def __yield_coro__ ['symmetric_coroutine<>::yield_type]] 99 | 100 | [include overview.qbk] 101 | [include intro.qbk] 102 | [include motivation.qbk] 103 | [include coroutine.qbk] 104 | [include attributes.qbk] 105 | [include stack.qbk] 106 | [include performance.qbk] 107 | [include architectures.qbk] 108 | [include acknowledgements.qbk] 109 | -------------------------------------------------------------------------------- /doc/coroutine.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright Oliver Kowalke 2009. 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE_1_0.txt or copy at 5 | http://www.boost.org/LICENSE_1_0.txt 6 | ] 7 | 8 | [section:coroutine Coroutine] 9 | 10 | __boost_coroutine__ provides two implementations - asymmetric and symmetric 11 | coroutines. 12 | 13 | Symmetric coroutines occur usually in the context of concurrent programming 14 | in order to represent independent units of execution. 15 | Implementations that produce sequences of values typically use asymmetric 16 | coroutines. 17 | [footnote Moura, Ana Lucia De and Ierusalimschy, Roberto. 18 | "Revisiting coroutines". ACM Trans. Program. Lang. Syst., Volume 31 Issue 2, 19 | February 2009, Article No. 6] 20 | 21 | 22 | [heading stackful] 23 | Each instance of a coroutine has its own stack. 24 | 25 | In contrast to stackless coroutines, stackful coroutines allow invoking the 26 | suspend operation out of arbitrary sub-stackframes, enabling escape-and-reenter 27 | recursive operations. 28 | 29 | 30 | [heading move-only] 31 | A coroutine is moveable-only. 32 | 33 | If it were copyable, then its stack with all the objects allocated on it 34 | would be copied too. That would force undefined behaviour if some of these 35 | objects were RAII-classes (manage a resource via RAII pattern). When the first 36 | of the coroutine copies terminates (unwinds its stack), the RAII class 37 | destructors will release their managed resources. When the second copy 38 | terminates, the same destructors will try to doubly-release the same resources, 39 | leading to undefined behaviour. 40 | 41 | 42 | [heading clean-up] 43 | On coroutine destruction the associated stack will be unwound. 44 | 45 | The constructor of coroutine allows you to pass a customized ['stack-allocator]. 46 | ['stack-allocator] is free to deallocate the stack or cache it for future usage 47 | (for coroutines created later). 48 | 49 | 50 | [heading segmented stack] 51 | __call_coro__, __push_coro__ and __pull_coro__ support segmented stacks 52 | (growing on demand). 53 | 54 | It is not always possible to accurately estimate the required stack size - in 55 | most cases too much memory is allocated (waste of virtual address-space). 56 | 57 | At construction a coroutine starts with a default (minimal) stack size. This 58 | minimal stack size is the maximum of page size and the canonical size for signal 59 | stack (macro SIGSTKSZ on POSIX). 60 | 61 | At this time of writing only GCC (4.7) 62 | [footnote [@http://gcc.gnu.org/wiki/SplitStacks Ian Lance Taylor, Split Stacks in GCC]] 63 | is known to support segmented stacks. With version 1.54 __boost_coroutine__ 64 | provides support for segmented stacks. 65 | 66 | The destructor releases the associated stack. The implementer is free to 67 | deallocate the stack or to cache it for later usage. 68 | 69 | 70 | [heading context switch] 71 | A coroutine saves and restores registers according to the underlying ABI on 72 | each context switch (using __boost_context__). 73 | 74 | Some applications do not use floating-point registers and can disable preserving 75 | FPU registers for performance reasons. 76 | 77 | [note According to the calling convention the FPU registers are preserved by 78 | default.] 79 | 80 | On POSIX systems, the coroutine context switch does not preserve signal masks 81 | for performance reasons. 82 | 83 | A context switch is done via __call_coro_op__, __push_coro_op__ and 84 | __pull_coro_op__. 85 | 86 | [warning Calling __call_coro_op__, __push_coro_op__ and __pull_coro_op__ from 87 | inside the [_same] coroutine results in undefined behaviour.] 88 | 89 | As an example, the code below will result in undefined behaviour: 90 | 91 | boost::coroutines::symmetric_coroutine::call_type coro( 92 | [&](boost::coroutines::symmetric_coroutine::yield_type& yield){ 93 | yield(coro); // yield to same symmetric_coroutine 94 | }); 95 | coro(); 96 | 97 | 98 | [include asymmetric.qbk] 99 | [include symmetric.qbk] 100 | 101 | [endsect] 102 | -------------------------------------------------------------------------------- /doc/images/event_model.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostorg/coroutine/8b09bf7d0e8a13d1ef59aaff02a84d42acb034f3/doc/images/event_model.dia -------------------------------------------------------------------------------- /doc/images/event_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostorg/coroutine/8b09bf7d0e8a13d1ef59aaff02a84d42acb034f3/doc/images/event_model.png -------------------------------------------------------------------------------- /doc/images/foo_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostorg/coroutine/8b09bf7d0e8a13d1ef59aaff02a84d42acb034f3/doc/images/foo_bar.png -------------------------------------------------------------------------------- /doc/images/foo_bar_seq.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostorg/coroutine/8b09bf7d0e8a13d1ef59aaff02a84d42acb034f3/doc/images/foo_bar_seq.dia -------------------------------------------------------------------------------- /doc/images/foo_bar_seq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostorg/coroutine/8b09bf7d0e8a13d1ef59aaff02a84d42acb034f3/doc/images/foo_bar_seq.png -------------------------------------------------------------------------------- /doc/images/same_fringe.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostorg/coroutine/8b09bf7d0e8a13d1ef59aaff02a84d42acb034f3/doc/images/same_fringe.dia -------------------------------------------------------------------------------- /doc/images/same_fringe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostorg/coroutine/8b09bf7d0e8a13d1ef59aaff02a84d42acb034f3/doc/images/same_fringe.png -------------------------------------------------------------------------------- /doc/intro.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright Oliver Kowalke 2009. 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE_1_0.txt or copy at 5 | http://www.boost.org/LICENSE_1_0.txt 6 | ] 7 | 8 | [section:intro Introduction] 9 | 10 | [heading Definition] 11 | 12 | In computer science routines are defined as a sequence of operations. The 13 | execution of routines forms a parent-child relationship and the child terminates 14 | always before the parent. Coroutines (the term was introduced by Melvin 15 | Conway [footnote Conway, Melvin E.. "Design of a Separable Transition-Diagram Compiler". 16 | Commun. ACM, Volume 6 Issue 7, July 1963, Article No. 7]), 17 | are a generalization of routines (Donald Knuth [footnote Knuth, Donald Ervin (1997). 18 | "Fundamental Algorithms. The Art of Computer Programming 1", (3rd ed.)]. 19 | The principal difference between coroutines and routines 20 | is that a coroutine enables explicit suspend and resume of its progress via 21 | additional operations by preserving execution state and thus provides an 22 | [*enhanced control flow] (maintaining the execution context). 23 | 24 | 25 | [heading How it works] 26 | 27 | Functions foo() and bar() are supposed to alternate their execution (leave and 28 | enter function body). 29 | 30 | [$../../../../libs/coroutine/doc/images/foo_bar.png [align center]] 31 | 32 | If coroutines were called exactly like routines, the stack would grow with 33 | every call and would never be popped. A jump into the middle of a coroutine 34 | would not be possible, because the return address would be on top of 35 | stack entries. 36 | 37 | The solution is that each coroutine has its own stack and control-block 38 | (__fcontext__ from __boost_context__). 39 | Before the coroutine gets suspended, the non-volatile registers (including stack 40 | and instruction/program pointer) of the currently active coroutine are stored in 41 | the coroutine's control-block. 42 | The registers of the newly activated coroutine must be restored from its 43 | associated control-block before it is resumed. 44 | 45 | The context switch requires no system privileges and provides cooperative 46 | multitasking convenient to C++. Coroutines provide quasi parallelism. 47 | When a program is supposed to do several things at the same time, coroutines 48 | help to do this much more simply and elegantly than with only a single flow of 49 | control. 50 | The advantages can be seen particularly clearly with the use of a recursive 51 | function, such as traversal of binary trees (see example 'same fringe'). 52 | 53 | 54 | [heading characteristics] 55 | Characteristics [footnote Moura, Ana Lucia De and Ierusalimschy, Roberto. 56 | "Revisiting coroutines". ACM Trans. Program. Lang. Syst., Volume 31 Issue 2, 57 | February 2009, Article No. 6] of a coroutine are: 58 | 59 | * values of local data persist between successive calls (context switches) 60 | * execution is suspended as control leaves coroutine and is resumed at certain time later 61 | * symmetric or asymmetric control-transfer mechanism; see below 62 | * first-class object (can be passed as argument, returned by procedures, 63 | stored in a data structure to be used later or freely manipulated by 64 | the developer) 65 | * stackful or stackless 66 | 67 | Coroutines are useful in simulation, artificial intelligence, concurrent 68 | programming, text processing and data manipulation, supporting 69 | the implementation of components such as cooperative tasks (fibers), iterators, 70 | generators, infinite lists, pipes etc. 71 | 72 | 73 | [heading execution-transfer mechanism] 74 | Two categories of coroutines exist: symmetric and asymmetric coroutines. 75 | 76 | An asymmetric coroutine knows its invoker, using a special operation to 77 | implicitly yield control specifically to its invoker. By contrast, all symmetric 78 | coroutines are equivalent; one symmetric coroutine may pass control to any 79 | other symmetric coroutine. Because of this, a symmetric coroutine ['must] 80 | specify the coroutine to which it intends to yield control. 81 | 82 | [$../../../../libs/coroutine/doc/images/foo_bar_seq.png [align center]] 83 | 84 | Both concepts are equivalent and a fully-general coroutine library can provide 85 | either symmetric or asymmetric coroutines. For convenience, Boost.Coroutine 86 | provides both. 87 | 88 | 89 | [heading stackfulness] 90 | In contrast to a stackless coroutine a stackful coroutine can be suspended 91 | from within a nested stackframe. Execution resumes at exactly the same point 92 | in the code where it was suspended before. 93 | With a stackless coroutine, only the top-level routine may be suspended. Any 94 | routine called by that top-level routine may not itself suspend. This prohibits 95 | providing suspend/resume operations in routines within a general-purpose library. 96 | 97 | [heading first-class continuation] 98 | A first-class continuation can be passed as an argument, returned by a 99 | function and stored in a data structure to be used later. 100 | In some implementations (for instance C# ['yield]) the continuation can 101 | not be directly accessed or directly manipulated. 102 | 103 | Without stackfulness and first-class semantics, some useful execution control 104 | flows cannot be supported (for instance cooperative multitasking or 105 | checkpointing). 106 | 107 | [endsect] 108 | -------------------------------------------------------------------------------- /doc/overview.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright Oliver Kowalke 2009. 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE_1_0.txt or copy at 5 | http://www.boost.org/LICENSE_1_0.txt 6 | ] 7 | 8 | [section:overview Overview] 9 | 10 | __boost_coroutine__ provides templates for generalized subroutines which allow 11 | suspending and resuming execution at certain locations. 12 | It preserves the local state of execution and allows re-entering subroutines more 13 | than once (useful if state must be kept across function calls). 14 | 15 | Coroutines can be viewed as a language-level construct providing a special kind 16 | of control flow. 17 | 18 | In contrast to threads, which are pre-emptive, __coro__ switches are 19 | cooperative (programmer controls when a switch will happen). The kernel is not 20 | involved in the coroutine switches. 21 | 22 | The implementation uses __boost_context__ for context switching. 23 | 24 | In order to use the classes and functions described here, you can either include 25 | the specific headers specified by the descriptions of each class or function, or 26 | include the master library header: 27 | 28 | #include 29 | 30 | which includes all the other headers in turn. 31 | 32 | All functions and classes are contained in the namespace __coro_ns__. 33 | 34 | [warning BoostCoroutine is now deprecated. Please use 35 | [@http://www.boost.org/doc/libs/release/libs/coroutine2/index.html Boost.Coroutine2].] 36 | 37 | [endsect] 38 | -------------------------------------------------------------------------------- /doc/performance.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright Oliver Kowalke 2009. 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE_1_0.txt or copy at 5 | http://www.boost.org/LICENSE_1_0.txt 6 | ] 7 | 8 | [section:performance Performance] 9 | 10 | Performance of __boost_coroutine__ was measured on the platforms shown in the 11 | following table. Performance measurements were taken using `rdtsc` and 12 | `boost::chrono::high_resolution_clock`, with overhead corrections, on x86 13 | platforms. In each case, cache warm-up was accounted for, and the one 14 | running thread was pinned to a single CPU. 15 | 16 | [table Performance of asymmetric coroutines 17 | [ 18 | [Platform] 19 | [switch] 20 | [construction (protected stack-allocator)] 21 | [construction (preallocated stack-allocator)] 22 | [construction (standard stack-allocator)] 23 | ] 24 | [ 25 | [i386 (AMD Athlon 64 DualCore 4400+, Linux 32bit)] 26 | [49 ns / 50 cycles] 27 | [51 \u00b5s / 51407 cycles] 28 | [14 \u00b5s / 15231 cycles] 29 | [14 \u00b5s / 15216 cycles] 30 | ] 31 | [ 32 | [x86_64 (Intel Core2 Q6700, Linux 64bit)] 33 | [12 ns / 39 cycles] 34 | [16 \u00b5s / 41802 cycles] 35 | [6 \u00b5s / 10350 cycles] 36 | [6 \u00b5s / 18817 cycles] 37 | ] 38 | ] 39 | 40 | [table Performance of symmetric coroutines 41 | [ 42 | [Platform] 43 | [switch] 44 | [construction (protected stack-allocator)] 45 | [construction (preallocated stack-allocator)] 46 | [construction (standard stack-allocator)] 47 | ] 48 | [ 49 | [i386 (AMD Athlon 64 DualCore 4400+, Linux 32bit)] 50 | [47 ns / 49 cycles] 51 | [27 \u00b5s / 28002 cycles] 52 | [98 ns / 116 cycles] 53 | [319 ns / 328 cycles] 54 | ] 55 | [ 56 | [x86_64 (Intel Core2 Q6700, Linux 64bit)] 57 | [10 ns / 33 cycles] 58 | [10 \u00b5s / 22828 cycles] 59 | [42 ns / 710 cycles] 60 | [135 ns / 362 cycles] 61 | ] 62 | ] 63 | 64 | 65 | [endsect] 66 | -------------------------------------------------------------------------------- /example/asymmetric/Jamfile.v2: -------------------------------------------------------------------------------- 1 | # Boost.Coroutine Library Examples Jamfile 2 | 3 | # Copyright Oliver Kowalke 2009. 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # (See accompanying file LICENSE_1_0.txt or copy at 6 | # http://www.boost.org/LICENSE_1_0.txt) 7 | 8 | # For more information, see http://www.boost.org/ 9 | 10 | import common ; 11 | import feature ; 12 | import indirect ; 13 | import modules ; 14 | import os ; 15 | import toolset ; 16 | 17 | project 18 | : requirements 19 | /boost/context//boost_context 20 | /boost/coroutine//boost_coroutine 21 | /boost/program_options//boost_program_options 22 | linux,gcc,on:-fsplit-stack 23 | linux,gcc,on:-DBOOST_USE_SEGMENTED_STACKS 24 | clang,on:-fsplit-stack 25 | clang,on:-DBOOST_USE_SEGMENTED_STACKS 26 | shared 27 | multi 28 | ; 29 | 30 | exe chaining 31 | : chaining.cpp 32 | ; 33 | exe echo 34 | : echo.cpp 35 | ; 36 | exe exception 37 | : exception.cpp 38 | ; 39 | exe fibonacci 40 | : fibonacci.cpp 41 | ; 42 | exe layout 43 | : layout.cpp 44 | ; 45 | exe parallel 46 | : parallel.cpp 47 | ; 48 | exe power 49 | : power.cpp 50 | ; 51 | exe same_fringe 52 | : same_fringe.cpp 53 | ; 54 | exe segmented_stack 55 | : segmented_stack.cpp 56 | ; 57 | exe simple 58 | : simple.cpp 59 | test.cpp 60 | ; 61 | exe unwind 62 | : unwind.cpp 63 | ; 64 | -------------------------------------------------------------------------------- /example/asymmetric/X.h: -------------------------------------------------------------------------------- 1 | #ifndef X_H 2 | #define X_H 3 | 4 | struct X 5 | { 6 | int i; 7 | 8 | X( int i_) : 9 | i( i_) 10 | {} 11 | }; 12 | 13 | #endif // X_H 14 | -------------------------------------------------------------------------------- /example/asymmetric/chaining.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Nat Goodspeed 2013. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | typedef boost::coroutines::asymmetric_coroutine coro_t; 19 | 20 | // deliver each line of input stream to sink as a separate string 21 | void readlines(coro_t::push_type& sink, std::istream& in) 22 | { 23 | std::string line; 24 | while (std::getline(in, line)) 25 | sink(line); 26 | } 27 | 28 | void tokenize(coro_t::push_type& sink, coro_t::pull_type& source) 29 | { 30 | // This tokenizer doesn't happen to be stateful: you could reasonably 31 | // implement it with a single call to push each new token downstream. But 32 | // I've worked with stateful tokenizers, in which the meaning of input 33 | // characters depends in part on their position within the input line. At 34 | // the time, I wished for a way to resume at the suspend point! 35 | BOOST_FOREACH(std::string line, source) 36 | { 37 | std::string::size_type pos = 0; 38 | while (pos < line.length()) 39 | { 40 | if (line[pos] == '"') 41 | { 42 | std::string token; 43 | ++pos; // skip open quote 44 | while (pos < line.length() && line[pos] != '"') 45 | token += line[pos++]; 46 | ++pos; // skip close quote 47 | sink(token); // pass token downstream 48 | } 49 | else if (std::isspace(line[pos])) 50 | { 51 | ++pos; // outside quotes, ignore whitespace 52 | } 53 | else if (std::isalpha(line[pos])) 54 | { 55 | std::string token; 56 | while (pos < line.length() && std::isalpha(line[pos])) 57 | token += line[pos++]; 58 | sink(token); // pass token downstream 59 | } 60 | else // punctuation 61 | { 62 | sink(std::string(1, line[pos++])); 63 | } 64 | } 65 | } 66 | } 67 | 68 | void only_words(coro_t::push_type& sink, coro_t::pull_type& source) 69 | { 70 | BOOST_FOREACH(std::string token, source) 71 | { 72 | if (! token.empty() && std::isalpha(token[0])) 73 | sink(token); 74 | } 75 | } 76 | 77 | void trace(coro_t::push_type& sink, coro_t::pull_type& source) 78 | { 79 | BOOST_FOREACH(std::string token, source) 80 | { 81 | std::cout << "trace: '" << token << "'\n"; 82 | sink(token); 83 | } 84 | } 85 | 86 | struct FinalEOL 87 | { 88 | ~FinalEOL() { std::cout << std::endl; } 89 | }; 90 | 91 | void layout(coro_t::pull_type& source, int num, int width) 92 | { 93 | // Finish the last line when we leave by whatever means 94 | FinalEOL eol; 95 | 96 | // Pull values from upstream, lay them out 'num' to a line 97 | for (;;) 98 | { 99 | for (int i = 0; i < num; ++i) 100 | { 101 | // when we exhaust the input, stop 102 | if (! source) 103 | return; 104 | 105 | std::cout << std::setw(width) << source.get(); 106 | // now that we've handled this item, advance to next 107 | source(); 108 | } 109 | // after 'num' items, line break 110 | std::cout << std::endl; 111 | } 112 | } 113 | 114 | int main(int argc, char *argv[]) 115 | { 116 | // For example purposes, instead of having a separate text file in the 117 | // local filesystem, construct an istringstream to read. 118 | std::string data( 119 | "This is the first line.\n" 120 | "This, the second.\n" 121 | "The third has \"a phrase\"!\n" 122 | ); 123 | 124 | { 125 | std::cout << "\nreadlines:\n"; 126 | std::istringstream infile(data); 127 | // Each coroutine-function has a small, specific job to do. Instead of 128 | // adding conditional logic to a large, complex input function, the 129 | // caller composes smaller functions into the desired processing 130 | // chain. 131 | coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile))); 132 | coro_t::pull_type tracer(boost::bind(trace, _1, boost::ref(reader))); 133 | BOOST_FOREACH(std::string line, tracer) 134 | { 135 | std::cout << "got: " << line << "\n"; 136 | } 137 | } 138 | 139 | { 140 | std::cout << "\ncompose a chain:\n"; 141 | std::istringstream infile(data); 142 | coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile))); 143 | coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader))); 144 | coro_t::pull_type tracer(boost::bind(trace, _1, boost::ref(tokenizer))); 145 | BOOST_FOREACH(std::string token, tracer) 146 | { 147 | // just iterate, we're already pulling through tracer 148 | } 149 | } 150 | 151 | { 152 | std::cout << "\nfilter:\n"; 153 | std::istringstream infile(data); 154 | coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile))); 155 | coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader))); 156 | coro_t::pull_type filter(boost::bind(only_words, _1, boost::ref(tokenizer))); 157 | coro_t::pull_type tracer(boost::bind(trace, _1, boost::ref(filter))); 158 | BOOST_FOREACH(std::string token, tracer) 159 | { 160 | // just iterate, we're already pulling through tracer 161 | } 162 | } 163 | 164 | { 165 | std::cout << "\nlayout() as coroutine::push_type:\n"; 166 | std::istringstream infile(data); 167 | coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile))); 168 | coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader))); 169 | coro_t::pull_type filter(boost::bind(only_words, _1, boost::ref(tokenizer))); 170 | coro_t::push_type writer(boost::bind(layout, _1, 5, 15)); 171 | BOOST_FOREACH(std::string token, filter) 172 | { 173 | writer(token); 174 | } 175 | } 176 | 177 | { 178 | std::cout << "\ncalling layout() directly:\n"; 179 | std::istringstream infile(data); 180 | coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile))); 181 | coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader))); 182 | coro_t::pull_type filter(boost::bind(only_words, _1, boost::ref(tokenizer))); 183 | // Because of the symmetry of the API, we can directly call layout() 184 | // instead of using it as a coroutine-function. 185 | layout(filter, 5, 15); 186 | } 187 | 188 | { 189 | std::cout << "\nfiltering output:\n"; 190 | std::istringstream infile(data); 191 | coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile))); 192 | coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader))); 193 | coro_t::push_type writer(boost::bind(layout, _1, 5, 15)); 194 | // Because of the symmetry of the API, we can use any of these 195 | // chaining functions in a push_type coroutine chain as well. 196 | coro_t::push_type filter(boost::bind(only_words, boost::ref(writer), _1)); 197 | BOOST_FOREACH(std::string token, tokenizer) 198 | { 199 | filter(token); 200 | } 201 | } 202 | 203 | std::cout << "\nDone" << std::endl; 204 | 205 | return EXIT_SUCCESS; 206 | } 207 | -------------------------------------------------------------------------------- /example/asymmetric/echo.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | typedef boost::coroutines::asymmetric_coroutine< void >::pull_type pull_coro_t; 15 | typedef boost::coroutines::asymmetric_coroutine< void >::push_type push_coro_t; 16 | 17 | void echo( pull_coro_t & source, int i) 18 | { 19 | std::cout << i; 20 | source(); 21 | } 22 | 23 | void runit( push_coro_t & sink1) 24 | { 25 | std::cout << "started! "; 26 | for ( int i = 0; i < 10; ++i) 27 | { 28 | push_coro_t sink2( boost::bind( echo, _1, i) ); 29 | while ( sink2) 30 | sink2(); 31 | sink1(); 32 | } 33 | } 34 | 35 | int main( int argc, char * argv[]) 36 | { 37 | { 38 | pull_coro_t source( runit); 39 | while ( source) { 40 | std::cout << "-"; 41 | source(); 42 | } 43 | } 44 | 45 | std::cout << "\nDone" << std::endl; 46 | 47 | return EXIT_SUCCESS; 48 | } 49 | -------------------------------------------------------------------------------- /example/asymmetric/exception.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | typedef boost::coroutines::asymmetric_coroutine< int >::pull_type pull_coro_t; 18 | typedef boost::coroutines::asymmetric_coroutine< int >::push_type push_coro_t; 19 | 20 | struct my_exception : public std::runtime_error 21 | { 22 | my_exception( std::string const& str) : 23 | std::runtime_error( str) 24 | {} 25 | }; 26 | 27 | void echo( push_coro_t & sink, int j) 28 | { 29 | for ( int i = 0; i < j; ++i) 30 | { 31 | if ( i == 5) boost::throw_exception( my_exception("abc") ); 32 | sink( i); 33 | } 34 | } 35 | 36 | int main( int argc, char * argv[]) 37 | { 38 | pull_coro_t source( boost::bind( echo, _1, 10) ); 39 | try 40 | { 41 | while ( source) 42 | { 43 | std::cout << source.get() << std::endl; 44 | source(); 45 | } 46 | } 47 | catch ( my_exception const& ex) 48 | { std::cout << "exception: " << ex.what() << std::endl; } 49 | 50 | std::cout << "\nDone" << std::endl; 51 | 52 | return EXIT_SUCCESS; 53 | } 54 | -------------------------------------------------------------------------------- /example/asymmetric/fibonacci.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | void fibonacci( boost::coroutines::asymmetric_coroutine< int >::push_type & sink) 15 | { 16 | int first = 1, second = 1; 17 | sink( first); 18 | sink( second); 19 | while ( true) 20 | { 21 | int third = first + second; 22 | first = second; 23 | second = third; 24 | sink( third); 25 | } 26 | } 27 | 28 | int main() 29 | { 30 | boost::coroutines::asymmetric_coroutine< int >::pull_type source( fibonacci); 31 | boost::range_iterator< 32 | boost::coroutines::asymmetric_coroutine< int >::pull_type 33 | >::type it( boost::begin( source) ); 34 | for ( int i = 0; i < 10; ++i) 35 | { 36 | std::cout << * it << " "; 37 | ++it; 38 | } 39 | 40 | std::cout << "\nDone" << std::endl; 41 | 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /example/asymmetric/layout.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Nat Goodspeed 2013. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | struct FinalEOL 20 | { 21 | ~FinalEOL() { std::cout << std::endl; } 22 | }; 23 | 24 | void layout(boost::coroutines::asymmetric_coroutine::pull_type& in, int num, int width) 25 | { 26 | // Finish the last line when we leave by whatever means 27 | FinalEOL eol; 28 | 29 | // Pull values from upstream, lay them out 'num' to a line 30 | for (;;) 31 | { 32 | for (int i = 0; i < num; ++i) 33 | { 34 | // when we exhaust the input, stop 35 | if (! in) 36 | return; 37 | 38 | std::cout << std::setw(width) << in.get(); 39 | // now that we've handled this item, advance to next 40 | in(); 41 | } 42 | // after 'num' items, line break 43 | std::cout << std::endl; 44 | } 45 | } 46 | 47 | int main(int argc, char *argv[]) 48 | { 49 | std::vector words = boost::assign::list_of 50 | ("peas") 51 | ("porridge") 52 | ("hot") 53 | ("peas") 54 | ("porridge") 55 | ("cold") 56 | ("peas") 57 | ("porridge") 58 | ("in") 59 | ("the") 60 | ("pot") 61 | ("nine") 62 | ("days") 63 | ("old") 64 | ; 65 | 66 | boost::coroutines::asymmetric_coroutine::push_type writer( 67 | boost::bind(layout, _1, 5, 15)); 68 | 69 | std::copy(boost::begin(words), boost::end(words), boost::begin(writer)); 70 | 71 | std::cout << "\nDone" << std::endl; 72 | 73 | return EXIT_SUCCESS; 74 | } 75 | -------------------------------------------------------------------------------- /example/asymmetric/parallel.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | void first( boost::coroutines::asymmetric_coroutine< void >::push_type & sink) 15 | { 16 | std::cout << "started first! "; 17 | for ( int i = 0; i < 10; ++i) 18 | { 19 | sink(); 20 | std::cout << "a" << i; 21 | } 22 | } 23 | 24 | void second( boost::coroutines::asymmetric_coroutine< void >::push_type & sink) 25 | { 26 | std::cout << "started second! "; 27 | for ( int i = 0; i < 10; ++i) 28 | { 29 | sink(); 30 | std::cout << "b" << i; 31 | } 32 | } 33 | 34 | int main( int argc, char * argv[]) 35 | { 36 | { 37 | boost::coroutines::asymmetric_coroutine< void >::pull_type source1( boost::bind( first, _1) ); 38 | boost::coroutines::asymmetric_coroutine< void >::pull_type source2( boost::bind( second, _1) ); 39 | while ( source1 && source2) { 40 | source1(); 41 | std::cout << " "; 42 | source2(); 43 | std::cout << " "; 44 | } 45 | } 46 | 47 | std::cout << "\nDone" << std::endl; 48 | 49 | return EXIT_SUCCESS; 50 | } 51 | -------------------------------------------------------------------------------- /example/asymmetric/power.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | void power( boost::coroutines::asymmetric_coroutine< int >::push_type & sink, int number, int exponent) 17 | { 18 | int counter = 0; 19 | int result = 1; 20 | while ( counter++ < exponent) 21 | { 22 | result = result * number; 23 | sink( result); 24 | } 25 | } 26 | 27 | int main() 28 | { 29 | { 30 | std::cout << "using range functions" << std::endl; 31 | boost::coroutines::asymmetric_coroutine< int >::pull_type source( boost::bind( power, _1, 2, 8) ); 32 | boost::coroutines::asymmetric_coroutine< int >::pull_type::iterator e( boost::end( source) ); 33 | for ( boost::coroutines::asymmetric_coroutine< int >::pull_type::iterator i( boost::begin( source) ); 34 | i != e; ++i) 35 | std::cout << * i << " "; 36 | } 37 | 38 | { 39 | std::cout << "\nusing BOOST_FOREACH" << std::endl; 40 | boost::coroutines::asymmetric_coroutine< int >::pull_type source( boost::bind( power, _1, 2, 8) ); 41 | BOOST_FOREACH( int i, source) 42 | { std::cout << i << " "; } 43 | } 44 | 45 | std::cout << "\nDone" << std::endl; 46 | 47 | return EXIT_SUCCESS; 48 | } 49 | -------------------------------------------------------------------------------- /example/asymmetric/same_fringe.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Nat Goodspeed 2013. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | struct node 21 | { 22 | typedef boost::shared_ptr< node > ptr_t; 23 | 24 | // Each tree node has an optional left subtree, an optional right subtree 25 | // and a value of its own. The value is considered to be between the left 26 | // subtree and the right. 27 | ptr_t left, right; 28 | std::string value; 29 | 30 | // construct leaf 31 | node(const std::string& v): 32 | left(), right(), value(v) 33 | {} 34 | // construct nonleaf 35 | node(ptr_t l, const std::string& v, ptr_t r): 36 | left(l), right(r), value(v) 37 | {} 38 | 39 | static ptr_t create(const std::string& v) 40 | { 41 | return ptr_t(new node(v)); 42 | } 43 | 44 | static ptr_t create(ptr_t l, const std::string& v, ptr_t r) 45 | { 46 | return ptr_t(new node(l, v, r)); 47 | } 48 | }; 49 | 50 | node::ptr_t create_left_tree_from(const std::string& root) 51 | { 52 | /* -------- 53 | root 54 | / \ 55 | b e 56 | / \ 57 | a c 58 | -------- */ 59 | return node::create( 60 | node::create( 61 | node::create("a"), 62 | "b", 63 | node::create("c")), 64 | root, 65 | node::create("e")); 66 | } 67 | 68 | node::ptr_t create_right_tree_from(const std::string& root) 69 | { 70 | /* -------- 71 | root 72 | / \ 73 | a d 74 | / \ 75 | c e 76 | -------- */ 77 | return node::create( 78 | node::create("a"), 79 | root, 80 | node::create( 81 | node::create("c"), 82 | "d", 83 | node::create("e"))); 84 | } 85 | 86 | // recursively walk the tree, delivering values in order 87 | void traverse(node::ptr_t n,boost::coroutines::asymmetric_coroutine::push_type& out) 88 | { 89 | if (n->left) traverse(n->left,out); 90 | out(n->value); 91 | if (n->right) traverse(n->right,out); 92 | } 93 | 94 | int main() 95 | { 96 | { 97 | node::ptr_t left_d(create_left_tree_from("d")); 98 | boost::coroutines::asymmetric_coroutine::pull_type left_d_reader( 99 | boost::bind(traverse, left_d, _1)); 100 | std::cout << "left tree from d:\n"; 101 | std::copy(boost::begin(left_d_reader), 102 | boost::end(left_d_reader), 103 | std::ostream_iterator(std::cout, " ")); 104 | std::cout << std::endl; 105 | 106 | node::ptr_t right_b(create_right_tree_from("b")); 107 | boost::coroutines::asymmetric_coroutine::pull_type right_b_reader( 108 | boost::bind(traverse, right_b, _1)); 109 | std::cout << "right tree from b:\n"; 110 | std::copy(boost::begin(right_b_reader), 111 | boost::end(right_b_reader), 112 | std::ostream_iterator(std::cout, " ")); 113 | std::cout << std::endl; 114 | 115 | node::ptr_t right_x(create_right_tree_from("x")); 116 | boost::coroutines::asymmetric_coroutine::pull_type right_x_reader( 117 | boost::bind(traverse, right_x, _1)); 118 | std::cout << "right tree from x:\n"; 119 | std::copy(boost::begin(right_x_reader), 120 | boost::end(right_x_reader), 121 | std::ostream_iterator(std::cout, " ")); 122 | std::cout << std::endl; 123 | } 124 | 125 | { 126 | node::ptr_t left_d(create_left_tree_from("d")); 127 | boost::coroutines::asymmetric_coroutine::pull_type left_d_reader( 128 | boost::bind(traverse, left_d, _1)); 129 | 130 | node::ptr_t right_b(create_right_tree_from("b")); 131 | boost::coroutines::asymmetric_coroutine::pull_type right_b_reader( 132 | boost::bind(traverse, right_b, _1)); 133 | 134 | std::cout << "left tree from d == right tree from b? " 135 | << std::boolalpha 136 | << std::equal(boost::begin(left_d_reader), 137 | boost::end(left_d_reader), 138 | boost::begin(right_b_reader)) 139 | << std::endl; 140 | } 141 | 142 | { 143 | node::ptr_t left_d(create_left_tree_from("d")); 144 | boost::coroutines::asymmetric_coroutine::pull_type left_d_reader( 145 | boost::bind(traverse, left_d, _1)); 146 | 147 | node::ptr_t right_x(create_right_tree_from("x")); 148 | boost::coroutines::asymmetric_coroutine::pull_type right_x_reader( 149 | boost::bind(traverse, right_x, _1)); 150 | 151 | std::cout << "left tree from d == right tree from x? " 152 | << std::boolalpha 153 | << std::equal(boost::begin(left_d_reader), 154 | boost::end(left_d_reader), 155 | boost::begin(right_x_reader)) 156 | << std::endl; 157 | } 158 | 159 | std::cout << "Done" << std::endl; 160 | 161 | return EXIT_SUCCESS; 162 | } 163 | -------------------------------------------------------------------------------- /example/asymmetric/segmented_stack.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | int count = 384; 15 | 16 | #ifdef BOOST_MSVC //MS VisualStudio 17 | __declspec(noinline) void access( char *buf); 18 | #else // GCC 19 | void access( char *buf) __attribute__ ((noinline)); 20 | #endif 21 | void access( char *buf) 22 | { 23 | buf[0] = '\0'; 24 | } 25 | 26 | void bar( int i) 27 | { 28 | char buf[4 * 1024]; 29 | 30 | if ( i > 0) 31 | { 32 | access( buf); 33 | std::cout << i << ". iteration" << std::endl; 34 | bar( i - 1); 35 | } 36 | } 37 | 38 | void foo( boost::coroutines::asymmetric_coroutine< void >::pull_type & source) 39 | { 40 | bar( count); 41 | source(); 42 | } 43 | 44 | 45 | int main( int argc, char * argv[]) 46 | { 47 | #if defined(BOOST_USE_SEGMENTED_STACKS) 48 | std::cout << "using segmented stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, "; 49 | std::cout << "initial stack size = " << boost::coroutines::stack_allocator::traits_type::default_size() / 1024 << "kB" << std::endl; 50 | std::cout << "application should not fail" << std::endl; 51 | #else 52 | std::cout << "using standard stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, "; 53 | std::cout << "initial stack size = " << boost::coroutines::stack_allocator::traits_type::default_size() / 1024 << "kB" << std::endl; 54 | std::cout << "application might fail" << std::endl; 55 | #endif 56 | 57 | boost::coroutines::asymmetric_coroutine< void >::push_type sink( foo); 58 | sink(); 59 | 60 | std::cout << "Done" << std::endl; 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /example/asymmetric/simple.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "X.h" 9 | 10 | typedef boost::coroutines::asymmetric_coroutine< X& >::pull_type pull_coro_t; 11 | typedef boost::coroutines::asymmetric_coroutine< X& >::push_type push_coro_t; 12 | 13 | void fn1( push_coro_t & sink) 14 | { 15 | for ( int i = 0; i < 10; ++i) 16 | { 17 | X x( i); 18 | sink( x); 19 | } 20 | } 21 | 22 | void fn2( pull_coro_t & source) 23 | { 24 | while ( source) { 25 | X & x = source.get(); 26 | std::cout << "i = " << x.i << std::endl; 27 | source(); 28 | } 29 | } 30 | 31 | int main( int argc, char * argv[]) 32 | { 33 | { 34 | pull_coro_t source( fn1); 35 | while ( source) { 36 | X & x = source.get(); 37 | std::cout << "i = " << x.i << std::endl; 38 | source(); 39 | } 40 | } 41 | { 42 | push_coro_t sink( fn2); 43 | for ( int i = 0; i < 10; ++i) 44 | { 45 | X x( i); 46 | sink( x); 47 | } 48 | } 49 | std::cout << "Done" << std::endl; 50 | 51 | return EXIT_SUCCESS; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /example/asymmetric/test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "X.h" 6 | 7 | typedef boost::coroutines::asymmetric_coroutine< X& >::pull_type pull_coro_t; 8 | typedef boost::coroutines::asymmetric_coroutine< X& >::push_type push_coro_t; 9 | 10 | void foo1( push_coro_t & sink) 11 | { 12 | for ( int i = 0; i < 10; ++i) 13 | { 14 | X x( i); 15 | sink( x); 16 | } 17 | } 18 | 19 | void foo2( pull_coro_t & source) 20 | { 21 | while ( source) { 22 | X & x = source.get(); 23 | source(); 24 | } 25 | } 26 | 27 | void bar() 28 | { 29 | { 30 | pull_coro_t source( foo1); 31 | while ( source) { 32 | X & x = source.get(); 33 | source(); 34 | } 35 | } 36 | { 37 | push_coro_t sink( foo2); 38 | for ( int i = 0; i < 10; ++i) 39 | { 40 | X x( i); 41 | sink( x); 42 | } 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /example/asymmetric/tree.h: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef TREE_H 8 | #define TREE_H 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #if defined(_MSC_VER) 20 | # pragma warning(push) 21 | # pragma warning(disable:4355) 22 | #endif 23 | 24 | struct branch; 25 | struct leaf; 26 | 27 | struct visitor 28 | { 29 | virtual ~visitor() {}; 30 | 31 | virtual void visit( branch & b) = 0; 32 | virtual void visit( leaf & l) = 0; 33 | }; 34 | 35 | struct node 36 | { 37 | typedef boost::intrusive_ptr< node > ptr_t; 38 | 39 | std::size_t use_count; 40 | 41 | node() : 42 | use_count( 0) 43 | {} 44 | 45 | virtual ~node() {} 46 | 47 | virtual void accept( visitor & v) = 0; 48 | 49 | friend inline void intrusive_ptr_add_ref( node * p) 50 | { ++p->use_count; } 51 | 52 | friend inline void intrusive_ptr_release( node * p) 53 | { if ( 0 == --p->use_count) delete p; } 54 | }; 55 | 56 | struct branch : public node 57 | { 58 | node::ptr_t left; 59 | node::ptr_t right; 60 | 61 | static ptr_t create( node::ptr_t left_, node::ptr_t right_) 62 | { return ptr_t( new branch( left_, right_) ); } 63 | 64 | branch( node::ptr_t left_, node::ptr_t right_) : 65 | left( left_), right( right_) 66 | {} 67 | 68 | void accept( visitor & v) 69 | { v.visit( * this); } 70 | }; 71 | 72 | struct leaf : public node 73 | { 74 | std::string value; 75 | 76 | static ptr_t create( std::string const& value_) 77 | { return ptr_t( new leaf( value_) ); } 78 | 79 | leaf( std::string const& value_) : 80 | value( value_) 81 | {} 82 | 83 | void accept( visitor & v) 84 | { v.visit( * this); } 85 | }; 86 | 87 | inline 88 | bool operator==( leaf const& l, leaf const& r) 89 | { return l.value == r.value; } 90 | 91 | inline 92 | bool operator!=( leaf const& l, leaf const& r) 93 | { return l.value != r.value; } 94 | 95 | class tree_visitor : public visitor 96 | { 97 | private: 98 | boost::coroutines::asymmetric_coroutine< leaf & >::push_type & c_; 99 | 100 | public: 101 | tree_visitor( boost::coroutines::asymmetric_coroutine< leaf & >::push_type & c) : 102 | c_( c) 103 | {} 104 | 105 | void visit( branch & b) 106 | { 107 | if ( b.left) b.left->accept( * this); 108 | if ( b.right) b.right->accept( * this); 109 | } 110 | 111 | void visit( leaf & l) 112 | { c_( l); } 113 | }; 114 | 115 | void enumerate_leafs( boost::coroutines::asymmetric_coroutine< leaf & >::push_type & c, node::ptr_t root) 116 | { 117 | tree_visitor v( c); 118 | root->accept( v); 119 | } 120 | 121 | #if defined(_MSC_VER) 122 | # pragma warning(pop) 123 | #endif 124 | 125 | #endif // TREE_H 126 | -------------------------------------------------------------------------------- /example/asymmetric/unwind.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | struct X : private boost::noncopyable 15 | { 16 | X() { std::cout << "X()" << std::endl; } 17 | ~X() { std::cout << "~X()" << std::endl; } 18 | }; 19 | 20 | void fn( boost::coroutines::asymmetric_coroutine< void >::push_type & sink) 21 | { 22 | X x; 23 | int i = 0; 24 | while ( true) 25 | { 26 | std::cout << "fn() : " << ++i << std::endl; 27 | sink(); 28 | } 29 | } 30 | 31 | int main( int argc, char * argv[]) 32 | { 33 | { 34 | boost::coroutines::asymmetric_coroutine< void >::pull_type source( fn); 35 | for ( int k = 0; k < 3; ++k) 36 | { 37 | source(); 38 | } 39 | std::cout << "destroying coroutine and unwinding stack" << std::endl; 40 | } 41 | 42 | std::cout << "\nDone" << std::endl; 43 | 44 | return EXIT_SUCCESS; 45 | } 46 | -------------------------------------------------------------------------------- /example/symmetric/Jamfile.v2: -------------------------------------------------------------------------------- 1 | # Boost.Coroutine Library Examples Jamfile 2 | 3 | # Copyright Oliver Kowalke 2009. 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # (See accompanying file LICENSE_1_0.txt or copy at 6 | # http://www.boost.org/LICENSE_1_0.txt) 7 | 8 | # For more information, see http://www.boost.org/ 9 | 10 | import common ; 11 | import feature ; 12 | import indirect ; 13 | import modules ; 14 | import os ; 15 | import toolset ; 16 | 17 | project 18 | : requirements 19 | /boost/context//boost_context 20 | /boost/coroutine//boost_coroutine 21 | /boost/program_options//boost_program_options 22 | /boost/random//boost_random 23 | linux,gcc,on:-fsplit-stack 24 | linux,gcc,on:-DBOOST_USE_SEGMENTED_STACKS 25 | clang,on:-fsplit-stack 26 | clang,on:-DBOOST_USE_SEGMENTED_STACKS 27 | static 28 | multi 29 | ; 30 | 31 | exe simple 32 | : simple.cpp 33 | ; 34 | 35 | exe dice_game 36 | : dice_game.cpp 37 | ; 38 | 39 | exe merge_arrays 40 | : merge_arrays.cpp 41 | ; 42 | 43 | exe unwind 44 | : unwind.cpp 45 | ; 46 | 47 | exe segmented_stack 48 | : segmented_stack.cpp 49 | ; 50 | -------------------------------------------------------------------------------- /example/symmetric/dice_game.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Keld Helsgaun 2000, Oliver Kowalke 2014. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | typedef boost::coroutines::symmetric_coroutine< void > coro_t; 18 | 19 | class player 20 | { 21 | private: 22 | int die() 23 | { 24 | boost::random::uniform_int_distribution<> dist( 1, 6); 25 | return dist( gen); 26 | } 27 | 28 | void run_( coro_t::yield_type & yield) 29 | { 30 | int sum = 0; 31 | while ( ( sum += die() ) < 100) 32 | yield( nxt->coro); 33 | std::cout << "player " << id << " winns" << std::endl; 34 | } 35 | 36 | player( player const&); 37 | player & operator=( player const&); 38 | 39 | public: 40 | int id; 41 | player * nxt; 42 | coro_t::call_type coro; 43 | boost::random::random_device gen; 44 | 45 | player( int id_) : 46 | id( id_), nxt( 0), 47 | coro( boost::bind( & player::run_, this, _1) ), 48 | gen() 49 | {} 50 | 51 | void run() 52 | { coro(); } 53 | }; 54 | 55 | int main( int argc, char * argv[]) 56 | { 57 | player * first = new player( 1); 58 | player * p = first; 59 | for ( int i = 2; i <= 4; ++i) 60 | { 61 | p->nxt = new player( i); 62 | p = p->nxt; 63 | } 64 | p->nxt = first; 65 | first->run(); 66 | 67 | std::cout << "Done" << std::endl; 68 | 69 | return EXIT_SUCCESS; 70 | } 71 | -------------------------------------------------------------------------------- /example/symmetric/merge_arrays.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Keld Helsgaun 2000, Oliver Kowalke 2014. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | typedef boost::coroutines::symmetric_coroutine< void > coro_t; 18 | 19 | class merger 20 | { 21 | private: 22 | std::size_t max_; 23 | std::vector< int > & to_; 24 | 25 | void run_( coro_t::yield_type & yield) 26 | { 27 | while ( idx < from.size() ) 28 | { 29 | if ( other->from[other->idx] < from[idx]) 30 | yield( other->coro); 31 | to_.push_back(from[idx++]); 32 | } 33 | while ( to_.size() < max_) 34 | to_.push_back( other->from[other->idx++]); 35 | } 36 | 37 | merger( merger const&); 38 | merger & operator=( merger const&); 39 | 40 | public: 41 | std::vector< int > const& from; 42 | std::size_t idx; 43 | merger * other; 44 | coro_t::call_type coro; 45 | 46 | merger( std::vector< int > const& from_, std::vector< int > & to, std::size_t max) : 47 | max_( max), 48 | to_( to), 49 | from( from_), 50 | idx( 0), 51 | other( 0), 52 | coro( boost::bind( & merger::run_, this, _1) ) 53 | {} 54 | 55 | void run() 56 | { coro(); } 57 | }; 58 | 59 | std::vector< int > merge( std::vector< int > const& a, std::vector< int > const& b) 60 | { 61 | std::vector< int > c; 62 | merger ma( a, c, a.size() + b. size() ); 63 | merger mb( b, c, a.size() + b. size() ); 64 | 65 | ma.other = & mb; 66 | mb.other = & ma; 67 | 68 | ma.run(); 69 | 70 | return c; 71 | } 72 | 73 | void print( std::string const& name, std::vector< int > const& v) 74 | { 75 | std::cout << name << " : "; 76 | BOOST_FOREACH( int itm, v) 77 | { std::cout << itm << " "; } 78 | std::cout << "\n"; 79 | } 80 | 81 | int main( int argc, char * argv[]) 82 | { 83 | std::vector< int > a; 84 | a.push_back( 1); 85 | a.push_back( 5); 86 | a.push_back( 6); 87 | a.push_back( 10); 88 | print( "a", a); 89 | 90 | std::vector< int > b; 91 | b.push_back( 2); 92 | b.push_back( 4); 93 | b.push_back( 7); 94 | b.push_back( 8); 95 | b.push_back( 9); 96 | b.push_back( 13); 97 | print( "b", b); 98 | 99 | std::vector< int > c = merge( a, b); 100 | print( "c", c); 101 | 102 | std::cout << "Done" << std::endl; 103 | 104 | return EXIT_SUCCESS; 105 | } 106 | -------------------------------------------------------------------------------- /example/symmetric/segmented_stack.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | int count = 384; 16 | 17 | #ifdef BOOST_MSVC //MS VisualStudio 18 | __declspec(noinline) void access( char *buf); 19 | #else // GCC 20 | void access( char *buf) __attribute__ ((noinline)); 21 | #endif 22 | void access( char *buf) 23 | { 24 | buf[0] = '\0'; 25 | } 26 | 27 | void bar( int i) 28 | { 29 | char buf[4 * 1024]; 30 | 31 | if ( i > 0) 32 | { 33 | access( buf); 34 | std::cout << i << ". iteration" << std::endl; 35 | bar( i - 1); 36 | } 37 | } 38 | 39 | void foo( boost::coroutines::symmetric_coroutine< void >::yield_type &) 40 | { 41 | bar( count); 42 | } 43 | 44 | void thread_fn() 45 | { 46 | { 47 | boost::coroutines::symmetric_coroutine< void >::call_type coro( foo); 48 | coro(); 49 | } 50 | } 51 | 52 | int main( int argc, char * argv[]) 53 | { 54 | #if defined(BOOST_USE_SEGMENTED_STACKS) 55 | std::cout << "using segmented stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, "; 56 | std::cout << "initial stack size = " << boost::coroutines::stack_allocator::traits_type::default_size() / 1024 << "kB" << std::endl; 57 | std::cout << "application should not fail" << std::endl; 58 | #else 59 | std::cout << "using standard stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, "; 60 | std::cout << "initial stack size = " << boost::coroutines::stack_allocator::traits_type::default_size() / 1024 << "kB" << std::endl; 61 | std::cout << "application might fail" << std::endl; 62 | #endif 63 | 64 | boost::thread( thread_fn).join(); 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /example/symmetric/simple.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | typedef boost::coroutines::symmetric_coroutine< void > coro_t; 15 | 16 | coro_t::call_type * c1 = 0; 17 | coro_t::call_type * c2 = 0; 18 | 19 | void foo( coro_t::yield_type & yield) 20 | { 21 | std::cout << "foo1" << std::endl; 22 | yield( * c2); 23 | std::cout << "foo2" << std::endl; 24 | yield( * c2); 25 | std::cout << "foo3" << std::endl; 26 | } 27 | 28 | void bar( coro_t::yield_type & yield) 29 | { 30 | std::cout << "bar1" << std::endl; 31 | yield( * c1); 32 | std::cout << "bar2" << std::endl; 33 | yield( * c1); 34 | std::cout << "bar3" << std::endl; 35 | } 36 | 37 | int main( int argc, char * argv[]) 38 | { 39 | coro_t::call_type coro1( foo); 40 | coro_t::call_type coro2( bar); 41 | c1 = & coro1; 42 | c2 = & coro2; 43 | coro1(); 44 | std::cout << "Done" << std::endl; 45 | 46 | return EXIT_SUCCESS; 47 | } 48 | -------------------------------------------------------------------------------- /example/symmetric/unwind.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | struct X : private boost::noncopyable 15 | { 16 | X() { std::cout << "X()" << std::endl; } 17 | ~X() { std::cout << "~X()" << std::endl; } 18 | }; 19 | 20 | typedef boost::coroutines::symmetric_coroutine< void > coro_t; 21 | 22 | coro_t::call_type * c1 = 0; 23 | coro_t::call_type * c2 = 0; 24 | 25 | void foo( coro_t::yield_type & yield) 26 | { 27 | X x; 28 | std::cout << "foo() entered" << std::endl; 29 | yield( * c2); 30 | yield( * c2); 31 | std::cout << "foo() finished" << std::endl; 32 | } 33 | 34 | void bar( coro_t::yield_type & yield) 35 | { 36 | std::cout << "bar() entered" << std::endl; 37 | yield( * c1); 38 | std::cout << "bar() finished" << std::endl; 39 | } 40 | 41 | int main( int argc, char * argv[]) 42 | { 43 | coro_t::call_type coro1( foo); 44 | coro_t::call_type coro2( bar); 45 | c1 = & coro1; 46 | c2 = & coro2; 47 | coro1(); 48 | std::cout << "Done" << std::endl; 49 | 50 | return EXIT_SUCCESS; 51 | } 52 | -------------------------------------------------------------------------------- /include/boost/coroutine/all.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_ALL_H 8 | #define BOOST_COROUTINES_ALL_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #endif // BOOST_COROUTINES_ALL_H 22 | -------------------------------------------------------------------------------- /include/boost/coroutine/attributes.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_ATTRIBUTES_H 8 | #define BOOST_COROUTINES_ATTRIBUTES_H 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #ifdef BOOST_HAS_ABI_HEADERS 18 | # include BOOST_ABI_PREFIX 19 | #endif 20 | 21 | namespace boost { 22 | namespace coroutines { 23 | 24 | struct attributes 25 | { 26 | std::size_t size; 27 | flag_unwind_t do_unwind; 28 | 29 | attributes() BOOST_NOEXCEPT : 30 | size( stack_allocator::traits_type::default_size() ), 31 | do_unwind( stack_unwind) 32 | {} 33 | 34 | explicit attributes( std::size_t size_) BOOST_NOEXCEPT : 35 | size( size_), 36 | do_unwind( stack_unwind) 37 | {} 38 | 39 | explicit attributes( flag_unwind_t do_unwind_) BOOST_NOEXCEPT : 40 | size( stack_allocator::traits_type::default_size() ), 41 | do_unwind( do_unwind_) 42 | {} 43 | 44 | explicit attributes( 45 | std::size_t size_, 46 | flag_unwind_t do_unwind_) BOOST_NOEXCEPT : 47 | size( size_), 48 | do_unwind( do_unwind_) 49 | {} 50 | }; 51 | 52 | }} 53 | 54 | #ifdef BOOST_HAS_ABI_HEADERS 55 | # include BOOST_ABI_SUFFIX 56 | #endif 57 | 58 | #endif // BOOST_COROUTINES_ATTRIBUTES_H 59 | -------------------------------------------------------------------------------- /include/boost/coroutine/coroutine.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_COROUTINE_H 8 | #define BOOST_COROUTINES_COROUTINE_H 9 | 10 | #include 11 | #include 12 | 13 | #endif // BOOST_COROUTINES_COROUTINE_H 14 | -------------------------------------------------------------------------------- /include/boost/coroutine/detail/config.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_DETAIL_CONFIG_H 8 | #define BOOST_COROUTINES_DETAIL_CONFIG_H 9 | 10 | #include 11 | #include 12 | 13 | #ifdef BOOST_COROUTINES_DECL 14 | # undef BOOST_COROUTINES_DECL 15 | #endif 16 | 17 | #if (defined(BOOST_ALL_DYN_LINK) || defined(BOOST_COROUTINES_DYN_LINK) ) && ! defined(BOOST_COROUTINES_STATIC_LINK) 18 | # if defined(BOOST_COROUTINES_SOURCE) 19 | # define BOOST_COROUTINES_DECL BOOST_SYMBOL_EXPORT 20 | # define BOOST_COROUTINES_BUILD_DLL 21 | # else 22 | # define BOOST_COROUTINES_DECL BOOST_SYMBOL_IMPORT 23 | # endif 24 | #endif 25 | 26 | #if ! defined(BOOST_COROUTINES_DECL) 27 | # define BOOST_COROUTINES_DECL 28 | #endif 29 | 30 | #if ! defined(BOOST_COROUTINES_SOURCE) && ! defined(BOOST_ALL_NO_LIB) && ! defined(BOOST_COROUTINES_NO_LIB) 31 | # define BOOST_LIB_NAME boost_coroutine 32 | # if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_COROUTINES_DYN_LINK) 33 | # define BOOST_DYN_LINK 34 | # endif 35 | # include 36 | #endif 37 | 38 | #define BOOST_COROUTINES_UNIDIRECT 39 | #define BOOST_COROUTINES_SYMMETRIC 40 | 41 | #if defined(__OpenBSD__) 42 | // stacks need mmap(2) with MAP_STACK 43 | # define BOOST_COROUTINES_USE_MAP_STACK 44 | #endif 45 | 46 | #endif // BOOST_COROUTINES_DETAIL_CONFIG_H 47 | -------------------------------------------------------------------------------- /include/boost/coroutine/detail/coroutine_context.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_DETAIL_COROUTINE_CONTEXT_H 8 | #define BOOST_COROUTINES_DETAIL_COROUTINE_CONTEXT_H 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #ifdef BOOST_HAS_ABI_HEADERS 21 | # include BOOST_ABI_PREFIX 22 | #endif 23 | 24 | namespace boost { 25 | namespace coroutines { 26 | namespace detail { 27 | 28 | // class hold stack-context and coroutines execution-context 29 | class BOOST_COROUTINES_DECL coroutine_context 30 | { 31 | private: 32 | template< typename Coro > 33 | friend void trampoline( context::detail::transfer_t); 34 | template< typename Coro > 35 | friend void trampoline_void( context::detail::transfer_t); 36 | template< typename Coro > 37 | friend void trampoline_pull( context::detail::transfer_t); 38 | template< typename Coro > 39 | friend void trampoline_push( context::detail::transfer_t); 40 | template< typename Coro > 41 | friend void trampoline_push_void( context::detail::transfer_t); 42 | 43 | preallocated palloc_; 44 | context::detail::fcontext_t ctx_; 45 | 46 | public: 47 | typedef void( * ctx_fn)( context::detail::transfer_t); 48 | 49 | // default ctor represents the current execution-context 50 | coroutine_context(); 51 | 52 | // ctor creates a new execution-context running coroutine-fn `fn` 53 | // `ctx_` will be allocated on top of the stack managed by parameter 54 | // `stack_ctx` 55 | coroutine_context( ctx_fn fn, preallocated const& palloc); 56 | 57 | coroutine_context( coroutine_context const&); 58 | 59 | coroutine_context& operator=( coroutine_context const&); 60 | 61 | void * jump( coroutine_context &, void * = 0); 62 | 63 | stack_context & stack_ctx() 64 | { return palloc_.sctx; } 65 | }; 66 | 67 | }}} 68 | 69 | #ifdef BOOST_HAS_ABI_HEADERS 70 | # include BOOST_ABI_SUFFIX 71 | #endif 72 | 73 | #endif // BOOST_COROUTINES_DETAIL_COROUTINE_CONTEXT_H 74 | -------------------------------------------------------------------------------- /include/boost/coroutine/detail/data.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_DETAIL_DATA_H 8 | #define BOOST_COROUTINES_DETAIL_DATA_H 9 | 10 | #include 11 | 12 | #include 13 | 14 | #ifdef BOOST_HAS_ABI_HEADERS 15 | # include BOOST_ABI_PREFIX 16 | #endif 17 | 18 | namespace boost { 19 | namespace coroutines { 20 | namespace detail { 21 | 22 | struct data_t 23 | { 24 | coroutine_context * from; 25 | void * data; 26 | }; 27 | 28 | }}} 29 | 30 | #ifdef BOOST_HAS_ABI_HEADERS 31 | # include BOOST_ABI_SUFFIX 32 | #endif 33 | 34 | #endif // BOOST_COROUTINES_DETAIL_DATA_H 35 | -------------------------------------------------------------------------------- /include/boost/coroutine/detail/flags.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_DETAIL_FLAGS_H 8 | #define BOOST_COROUTINES_DETAIL_FLAGS_H 9 | 10 | #include 11 | 12 | #ifdef BOOST_HAS_ABI_HEADERS 13 | # include BOOST_ABI_PREFIX 14 | #endif 15 | 16 | namespace boost { 17 | namespace coroutines { 18 | namespace detail { 19 | 20 | enum flag_t 21 | { 22 | flag_started = 1 << 1, 23 | flag_running = 1 << 2, 24 | flag_complete = 1 << 3, 25 | flag_unwind_stack = 1 << 4, 26 | flag_force_unwind = 1 << 5 27 | }; 28 | 29 | struct unwind_t 30 | { 31 | enum flag_t 32 | { force_unwind = 1 }; 33 | }; 34 | 35 | struct synthesized_t 36 | { 37 | enum flag_t 38 | { syntesized = 1 }; 39 | }; 40 | 41 | }}} 42 | 43 | #ifdef BOOST_HAS_ABI_HEADERS 44 | # include BOOST_ABI_SUFFIX 45 | #endif 46 | 47 | #endif // BOOST_COROUTINES_DETAIL_FLAGS_H 48 | -------------------------------------------------------------------------------- /include/boost/coroutine/detail/parameters.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_DETAIL_PARAMETERS_H 8 | #define BOOST_COROUTINES_DETAIL_PARAMETERS_H 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #ifdef BOOST_HAS_ABI_HEADERS 16 | # include BOOST_ABI_PREFIX 17 | #endif 18 | 19 | namespace boost { 20 | namespace coroutines { 21 | namespace detail { 22 | 23 | template< typename Data > 24 | struct parameters 25 | { 26 | Data * data; 27 | bool do_unwind; 28 | void * coro; 29 | 30 | parameters() : 31 | data( 0), do_unwind( false), coro( 0) 32 | {} 33 | 34 | explicit parameters( void * coro_) : 35 | data( 0), do_unwind( false), coro( coro_) 36 | { BOOST_ASSERT( 0 != coro); } 37 | 38 | explicit parameters( Data * data_, void * coro_) : 39 | data( data_), do_unwind( false), coro( coro_) 40 | { 41 | BOOST_ASSERT( 0 != data); 42 | BOOST_ASSERT( 0 != coro); 43 | } 44 | 45 | explicit parameters( unwind_t::flag_t) : 46 | data( 0), do_unwind( true) 47 | {} 48 | }; 49 | 50 | template< typename Data > 51 | struct parameters< Data & > 52 | { 53 | Data * data; 54 | bool do_unwind; 55 | void * coro; 56 | 57 | parameters() : 58 | data( 0), do_unwind( false), coro( 0) 59 | {} 60 | 61 | explicit parameters( void * coro_) : 62 | data( 0), do_unwind( false), coro( coro_) 63 | { BOOST_ASSERT( 0 != coro); } 64 | 65 | explicit parameters( Data * data_, void * coro_) : 66 | data( data_), do_unwind( false), coro( coro_) 67 | { 68 | BOOST_ASSERT( 0 != data); 69 | BOOST_ASSERT( 0 != coro); 70 | } 71 | 72 | explicit parameters( unwind_t::flag_t) : 73 | data( 0), do_unwind( true), coro( 0) 74 | {} 75 | }; 76 | 77 | template<> 78 | struct parameters< void > 79 | { 80 | bool do_unwind; 81 | void * coro; 82 | 83 | parameters() : 84 | do_unwind( false), coro(0) 85 | {} 86 | 87 | parameters( void * coro_) : 88 | do_unwind( false), coro( coro_) 89 | { BOOST_ASSERT( 0 != coro); } 90 | 91 | explicit parameters( unwind_t::flag_t) : 92 | do_unwind( true), coro( 0) 93 | {} 94 | }; 95 | 96 | }}} 97 | 98 | #ifdef BOOST_HAS_ABI_HEADERS 99 | # include BOOST_ABI_SUFFIX 100 | #endif 101 | 102 | #endif // BOOST_COROUTINES_DETAIL_PARAMETERS_H 103 | -------------------------------------------------------------------------------- /include/boost/coroutine/detail/preallocated.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2015. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_DETAIL_PREALLOCATED_H 8 | #define BOOST_COROUTINES_DETAIL_PREALLOCATED_H 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #ifdef BOOST_HAS_ABI_HEADERS 18 | # include BOOST_ABI_PREFIX 19 | #endif 20 | 21 | namespace boost { 22 | namespace coroutines { 23 | namespace detail { 24 | 25 | struct BOOST_COROUTINES_DECL preallocated { 26 | void * sp; 27 | std::size_t size; 28 | stack_context sctx; 29 | 30 | preallocated() BOOST_NOEXCEPT : 31 | sp( 0), size( 0), sctx() { 32 | } 33 | 34 | preallocated( void * sp_, std::size_t size_, stack_context sctx_) BOOST_NOEXCEPT : 35 | sp( sp_), size( size_), sctx( sctx_) { 36 | } 37 | }; 38 | 39 | }}} 40 | 41 | #ifdef BOOST_HAS_ABI_HEADERS 42 | # include BOOST_ABI_SUFFIX 43 | #endif 44 | 45 | #endif // BOOST_COROUTINES_DETAIL_PREALLOCATED_H 46 | -------------------------------------------------------------------------------- /include/boost/coroutine/detail/pull_coroutine_synthesized.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_DETAIL_PULL_COROUTINE_SYNTHESIZED_H 8 | #define BOOST_COROUTINES_DETAIL_PULL_COROUTINE_SYNTHESIZED_H 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #ifdef BOOST_HAS_ABI_HEADERS 17 | # include BOOST_ABI_PREFIX 18 | #endif 19 | 20 | namespace boost { 21 | namespace coroutines { 22 | namespace detail { 23 | 24 | template< typename R > 25 | class pull_coroutine_synthesized : public pull_coroutine_impl< R > 26 | { 27 | private: 28 | typedef pull_coroutine_impl< R > impl_t; 29 | 30 | public: 31 | pull_coroutine_synthesized( coroutine_context * caller, 32 | coroutine_context * callee, 33 | bool unwind, 34 | R * result) : 35 | impl_t( caller, callee, unwind, result) 36 | {} 37 | 38 | void destroy() {} 39 | }; 40 | 41 | template< typename R > 42 | class pull_coroutine_synthesized< R & > : public pull_coroutine_impl< R & > 43 | { 44 | private: 45 | typedef pull_coroutine_impl< R & > impl_t; 46 | 47 | public: 48 | pull_coroutine_synthesized( coroutine_context * caller, 49 | coroutine_context * callee, 50 | bool unwind, 51 | R * result) : 52 | impl_t( caller, callee, unwind, result) 53 | {} 54 | 55 | void destroy() {} 56 | }; 57 | 58 | template<> 59 | class pull_coroutine_synthesized< void > : public pull_coroutine_impl< void > 60 | { 61 | private: 62 | typedef pull_coroutine_impl< void > impl_t; 63 | 64 | public: 65 | pull_coroutine_synthesized( coroutine_context * caller, 66 | coroutine_context * callee, 67 | bool unwind) : 68 | impl_t( caller, callee, unwind) 69 | {} 70 | 71 | inline void destroy() {} 72 | }; 73 | 74 | }}} 75 | 76 | #ifdef BOOST_HAS_ABI_HEADERS 77 | # include BOOST_ABI_SUFFIX 78 | #endif 79 | 80 | #endif // BOOST_COROUTINES_DETAIL_PULL_COROUTINE_SYNTHESIZED_H 81 | -------------------------------------------------------------------------------- /include/boost/coroutine/detail/push_coroutine_impl.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H 8 | #define BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #ifdef BOOST_HAS_ABI_HEADERS 24 | # include BOOST_ABI_PREFIX 25 | #endif 26 | 27 | namespace boost { 28 | namespace coroutines { 29 | 30 | struct stack_context; 31 | 32 | namespace detail { 33 | 34 | template< typename Arg > 35 | class push_coroutine_impl : private noncopyable 36 | { 37 | protected: 38 | int flags_; 39 | exception_ptr except_; 40 | coroutine_context * caller_; 41 | coroutine_context * callee_; 42 | 43 | public: 44 | typedef parameters< Arg > param_type; 45 | 46 | push_coroutine_impl( coroutine_context * caller, 47 | coroutine_context * callee, 48 | bool unwind) : 49 | flags_( 0), 50 | except_(), 51 | caller_( caller), 52 | callee_( callee) 53 | { 54 | if ( unwind) flags_ |= flag_force_unwind; 55 | } 56 | 57 | virtual ~push_coroutine_impl() {} 58 | 59 | bool force_unwind() const BOOST_NOEXCEPT 60 | { return 0 != ( flags_ & flag_force_unwind); } 61 | 62 | bool unwind_requested() const BOOST_NOEXCEPT 63 | { return 0 != ( flags_ & flag_unwind_stack); } 64 | 65 | bool is_started() const BOOST_NOEXCEPT 66 | { return 0 != ( flags_ & flag_started); } 67 | 68 | bool is_running() const BOOST_NOEXCEPT 69 | { return 0 != ( flags_ & flag_running); } 70 | 71 | bool is_complete() const BOOST_NOEXCEPT 72 | { return 0 != ( flags_ & flag_complete); } 73 | 74 | void unwind_stack() BOOST_NOEXCEPT 75 | { 76 | if ( is_started() && ! is_complete() && force_unwind() ) 77 | { 78 | flags_ |= flag_unwind_stack; 79 | param_type to( unwind_t::force_unwind); 80 | caller_->jump( 81 | * callee_, 82 | & to); 83 | flags_ &= ~flag_unwind_stack; 84 | 85 | BOOST_ASSERT( is_complete() ); 86 | } 87 | } 88 | 89 | void push( Arg const& arg) 90 | { 91 | BOOST_ASSERT( ! is_running() ); 92 | BOOST_ASSERT( ! is_complete() ); 93 | 94 | flags_ |= flag_running; 95 | param_type to( const_cast< Arg * >( & arg), this); 96 | param_type * from( 97 | static_cast< param_type * >( 98 | caller_->jump( 99 | * callee_, 100 | & to) ) ); 101 | flags_ &= ~flag_running; 102 | if ( from->do_unwind) throw forced_unwind(); 103 | if ( except_) rethrow_exception( except_); 104 | } 105 | 106 | void push( BOOST_RV_REF( Arg) arg) 107 | { 108 | BOOST_ASSERT( ! is_running() ); 109 | BOOST_ASSERT( ! is_complete() ); 110 | 111 | flags_ |= flag_running; 112 | param_type to( const_cast< Arg * >( & arg), this); 113 | param_type * from( 114 | static_cast< param_type * >( 115 | caller_->jump( 116 | * callee_, 117 | & to) ) ); 118 | flags_ &= ~flag_running; 119 | if ( from->do_unwind) throw forced_unwind(); 120 | if ( except_) rethrow_exception( except_); 121 | } 122 | 123 | virtual void destroy() = 0; 124 | }; 125 | 126 | template< typename Arg > 127 | class push_coroutine_impl< Arg & > : private noncopyable 128 | { 129 | protected: 130 | int flags_; 131 | exception_ptr except_; 132 | coroutine_context * caller_; 133 | coroutine_context * callee_; 134 | 135 | public: 136 | typedef parameters< Arg & > param_type; 137 | 138 | push_coroutine_impl( coroutine_context * caller, 139 | coroutine_context * callee, 140 | bool unwind) : 141 | flags_( 0), 142 | except_(), 143 | caller_( caller), 144 | callee_( callee) 145 | { 146 | if ( unwind) flags_ |= flag_force_unwind; 147 | } 148 | 149 | virtual ~push_coroutine_impl() {} 150 | 151 | bool force_unwind() const BOOST_NOEXCEPT 152 | { return 0 != ( flags_ & flag_force_unwind); } 153 | 154 | bool unwind_requested() const BOOST_NOEXCEPT 155 | { return 0 != ( flags_ & flag_unwind_stack); } 156 | 157 | bool is_started() const BOOST_NOEXCEPT 158 | { return 0 != ( flags_ & flag_started); } 159 | 160 | bool is_running() const BOOST_NOEXCEPT 161 | { return 0 != ( flags_ & flag_running); } 162 | 163 | bool is_complete() const BOOST_NOEXCEPT 164 | { return 0 != ( flags_ & flag_complete); } 165 | 166 | void unwind_stack() BOOST_NOEXCEPT 167 | { 168 | if ( is_started() && ! is_complete() && force_unwind() ) 169 | { 170 | flags_ |= flag_unwind_stack; 171 | param_type to( unwind_t::force_unwind); 172 | caller_->jump( 173 | * callee_, 174 | & to); 175 | flags_ &= ~flag_unwind_stack; 176 | 177 | BOOST_ASSERT( is_complete() ); 178 | } 179 | } 180 | 181 | void push( Arg & arg) 182 | { 183 | BOOST_ASSERT( ! is_running() ); 184 | BOOST_ASSERT( ! is_complete() ); 185 | 186 | flags_ |= flag_running; 187 | param_type to( & arg, this); 188 | param_type * from( 189 | static_cast< param_type * >( 190 | caller_->jump( 191 | * callee_, 192 | & to) ) ); 193 | flags_ &= ~flag_running; 194 | if ( from->do_unwind) throw forced_unwind(); 195 | if ( except_) rethrow_exception( except_); 196 | } 197 | 198 | virtual void destroy() = 0; 199 | }; 200 | 201 | template<> 202 | class push_coroutine_impl< void > : private noncopyable 203 | { 204 | protected: 205 | int flags_; 206 | exception_ptr except_; 207 | coroutine_context * caller_; 208 | coroutine_context * callee_; 209 | 210 | public: 211 | typedef parameters< void > param_type; 212 | 213 | push_coroutine_impl( coroutine_context * caller, 214 | coroutine_context * callee, 215 | bool unwind) : 216 | flags_( 0), 217 | except_(), 218 | caller_( caller), 219 | callee_( callee) 220 | { 221 | if ( unwind) flags_ |= flag_force_unwind; 222 | } 223 | 224 | virtual ~push_coroutine_impl() {} 225 | 226 | inline bool force_unwind() const BOOST_NOEXCEPT 227 | { return 0 != ( flags_ & flag_force_unwind); } 228 | 229 | inline bool unwind_requested() const BOOST_NOEXCEPT 230 | { return 0 != ( flags_ & flag_unwind_stack); } 231 | 232 | inline bool is_started() const BOOST_NOEXCEPT 233 | { return 0 != ( flags_ & flag_started); } 234 | 235 | inline bool is_running() const BOOST_NOEXCEPT 236 | { return 0 != ( flags_ & flag_running); } 237 | 238 | inline bool is_complete() const BOOST_NOEXCEPT 239 | { return 0 != ( flags_ & flag_complete); } 240 | 241 | inline void unwind_stack() BOOST_NOEXCEPT 242 | { 243 | if ( is_started() && ! is_complete() && force_unwind() ) 244 | { 245 | flags_ |= flag_unwind_stack; 246 | param_type to( unwind_t::force_unwind); 247 | caller_->jump( 248 | * callee_, 249 | & to); 250 | flags_ &= ~flag_unwind_stack; 251 | 252 | BOOST_ASSERT( is_complete() ); 253 | } 254 | } 255 | 256 | inline void push() 257 | { 258 | BOOST_ASSERT( ! is_running() ); 259 | BOOST_ASSERT( ! is_complete() ); 260 | 261 | flags_ |= flag_running; 262 | param_type to( this); 263 | param_type * from( 264 | static_cast< param_type * >( 265 | caller_->jump( 266 | * callee_, 267 | & to) ) ); 268 | flags_ &= ~flag_running; 269 | if ( from->do_unwind) throw forced_unwind(); 270 | if ( except_) rethrow_exception( except_); 271 | } 272 | 273 | virtual void destroy() = 0; 274 | }; 275 | 276 | }}} 277 | 278 | #ifdef BOOST_HAS_ABI_HEADERS 279 | # include BOOST_ABI_SUFFIX 280 | #endif 281 | 282 | #endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H 283 | -------------------------------------------------------------------------------- /include/boost/coroutine/detail/push_coroutine_synthesized.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_SYNTHESIZED_H 8 | #define BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_SYNTHESIZED_H 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #ifdef BOOST_HAS_ABI_HEADERS 17 | # include BOOST_ABI_PREFIX 18 | #endif 19 | 20 | namespace boost { 21 | namespace coroutines { 22 | namespace detail { 23 | 24 | template< typename R > 25 | class push_coroutine_synthesized : public push_coroutine_impl< R > 26 | { 27 | private: 28 | typedef push_coroutine_impl< R > impl_t; 29 | 30 | public: 31 | push_coroutine_synthesized( coroutine_context * caller, 32 | coroutine_context * callee, 33 | bool unwind) : 34 | impl_t( caller, callee, unwind) 35 | {} 36 | 37 | void destroy() {} 38 | }; 39 | 40 | template< typename R > 41 | class push_coroutine_synthesized< R & > : public push_coroutine_impl< R & > 42 | { 43 | private: 44 | typedef push_coroutine_impl< R & > impl_t; 45 | 46 | public: 47 | push_coroutine_synthesized( coroutine_context * caller, 48 | coroutine_context * callee, 49 | bool unwind) : 50 | impl_t( caller, callee, unwind) 51 | {} 52 | 53 | void destroy() {} 54 | }; 55 | 56 | template<> 57 | class push_coroutine_synthesized< void > : public push_coroutine_impl< void > 58 | { 59 | private: 60 | typedef push_coroutine_impl< void > impl_t; 61 | 62 | public: 63 | push_coroutine_synthesized( coroutine_context * caller, 64 | coroutine_context * callee, 65 | bool unwind) : 66 | impl_t( caller, callee, unwind) 67 | {} 68 | 69 | inline void destroy() {} 70 | }; 71 | 72 | }}} 73 | 74 | #ifdef BOOST_HAS_ABI_HEADERS 75 | # include BOOST_ABI_SUFFIX 76 | #endif 77 | 78 | #endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_SYNTHESIZED_H 79 | -------------------------------------------------------------------------------- /include/boost/coroutine/detail/setup.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_DETAIL_SETUP_H 8 | #define BOOST_COROUTINES_DETAIL_SETUP_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #ifdef BOOST_HAS_ABI_HEADERS 22 | # include BOOST_ABI_PREFIX 23 | #endif 24 | 25 | namespace boost { 26 | namespace coroutines { 27 | namespace detail { 28 | 29 | template< typename Fn > 30 | struct setup 31 | { 32 | struct dummy {}; 33 | 34 | Fn fn; 35 | coroutine_context * caller; 36 | coroutine_context * callee; 37 | attributes attr; 38 | 39 | #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES 40 | setup( Fn fn_, 41 | coroutine_context * caller_, 42 | coroutine_context * callee_, 43 | attributes const& attr_) : 44 | fn( boost::forward< Fn >( fn_) ), 45 | caller( caller_), 46 | callee( callee_), 47 | attr( attr_) 48 | {} 49 | #endif 50 | setup( BOOST_RV_REF( Fn) fn_, 51 | coroutine_context * caller_, 52 | coroutine_context * callee_, 53 | attributes const& attr_, 54 | typename disable_if< 55 | is_same< typename decay< Fn >::type, setup >, 56 | dummy* 57 | >::type = 0) : 58 | #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES 59 | fn( fn_), 60 | #else 61 | fn( boost::forward< Fn >( fn_) ), 62 | #endif 63 | caller( caller_), 64 | callee( callee_), 65 | attr( attr_) 66 | {} 67 | }; 68 | 69 | }}} 70 | 71 | #ifdef BOOST_HAS_ABI_HEADERS 72 | # include BOOST_ABI_SUFFIX 73 | #endif 74 | 75 | #endif // BOOST_COROUTINES_DETAIL_SETUP_H 76 | -------------------------------------------------------------------------------- /include/boost/coroutine/detail/trampoline.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_DETAIL_TRAMPOLINE_H 8 | #define BOOST_COROUTINES_DETAIL_TRAMPOLINE_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #ifdef BOOST_HAS_ABI_HEADERS 19 | # include BOOST_ABI_PREFIX 20 | #endif 21 | 22 | namespace boost { 23 | namespace coroutines { 24 | namespace detail { 25 | 26 | template< typename Coro > 27 | void trampoline( context::detail::transfer_t t) 28 | { 29 | typedef typename Coro::param_type param_type; 30 | 31 | data_t * data = static_cast< data_t * >( t.data); 32 | data->from->ctx_ = t.fctx; 33 | param_type * param( 34 | static_cast< param_type * >( data->data) ); 35 | BOOST_ASSERT( 0 != param); 36 | BOOST_ASSERT( 0 != param->data); 37 | 38 | Coro * coro( 39 | static_cast< Coro * >( param->coro) ); 40 | BOOST_ASSERT( 0 != coro); 41 | 42 | coro->run( param->data); 43 | } 44 | 45 | template< typename Coro > 46 | void trampoline_void( context::detail::transfer_t t) 47 | { 48 | typedef typename Coro::param_type param_type; 49 | 50 | data_t * data = static_cast< data_t * >( t.data); 51 | data->from->ctx_ = t.fctx; 52 | param_type * param( 53 | static_cast< param_type * >( data->data) ); 54 | BOOST_ASSERT( 0 != param); 55 | 56 | Coro * coro( 57 | static_cast< Coro * >( param->coro) ); 58 | BOOST_ASSERT( 0 != coro); 59 | 60 | coro->run(); 61 | } 62 | 63 | }}} 64 | 65 | #ifdef BOOST_HAS_ABI_HEADERS 66 | # include BOOST_ABI_SUFFIX 67 | #endif 68 | 69 | #endif // BOOST_COROUTINES_DETAIL_TRAMPOLINE_H 70 | -------------------------------------------------------------------------------- /include/boost/coroutine/detail/trampoline_pull.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_DETAIL_TRAMPOLINE_PULL_H 8 | #define BOOST_COROUTINES_DETAIL_TRAMPOLINE_PULL_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #ifdef BOOST_HAS_ABI_HEADERS 19 | # include BOOST_ABI_PREFIX 20 | #endif 21 | 22 | namespace boost { 23 | namespace coroutines { 24 | namespace detail { 25 | 26 | template< typename Coro > 27 | void trampoline_pull( context::detail::transfer_t t) 28 | { 29 | typedef typename Coro::param_type param_type; 30 | 31 | data_t * data = static_cast< data_t * >( t.data); 32 | data->from->ctx_ = t.fctx; 33 | param_type * param( 34 | static_cast< param_type * >( data->data) ); 35 | BOOST_ASSERT( 0 != param); 36 | 37 | Coro * coro( 38 | static_cast< Coro * >( param->coro) ); 39 | BOOST_ASSERT( 0 != coro); 40 | 41 | coro->run(); 42 | } 43 | 44 | }}} 45 | 46 | #ifdef BOOST_HAS_ABI_HEADERS 47 | # include BOOST_ABI_SUFFIX 48 | #endif 49 | 50 | #endif // BOOST_COROUTINES_DETAIL_TRAMPOLINE_PULL_H 51 | -------------------------------------------------------------------------------- /include/boost/coroutine/detail/trampoline_push.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_DETAIL_TRAMPOLINE_PUSH_H 8 | #define BOOST_COROUTINES_DETAIL_TRAMPOLINE_PUSH_H 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef BOOST_HAS_ABI_HEADERS 29 | # include BOOST_ABI_PREFIX 30 | #endif 31 | 32 | namespace boost { 33 | namespace coroutines { 34 | namespace detail { 35 | 36 | template< typename Coro > 37 | void trampoline_push( context::detail::transfer_t t) 38 | { 39 | typedef typename Coro::param_type param_type; 40 | 41 | data_t * data = static_cast< data_t * >( t.data); 42 | data->from->ctx_ = t.fctx; 43 | param_type * param( 44 | static_cast< param_type * >( data->data) ); 45 | BOOST_ASSERT( 0 != param); 46 | BOOST_ASSERT( 0 != param->data); 47 | 48 | Coro * coro( 49 | static_cast< Coro * >( param->coro) ); 50 | BOOST_ASSERT( 0 != coro); 51 | 52 | coro->run( param->data); 53 | } 54 | 55 | template< typename Coro > 56 | void trampoline_push_void( context::detail::transfer_t t) 57 | { 58 | typedef typename Coro::param_type param_type; 59 | 60 | data_t * data = static_cast< data_t * >( t.data); 61 | data->from->ctx_ = t.fctx; 62 | param_type * param( 63 | static_cast< param_type * >( data->data) ); 64 | BOOST_ASSERT( 0 != param); 65 | 66 | Coro * coro( 67 | static_cast< Coro * >( param->coro) ); 68 | BOOST_ASSERT( 0 != coro); 69 | 70 | coro->run(); 71 | } 72 | 73 | }}} 74 | 75 | #ifdef BOOST_HAS_ABI_HEADERS 76 | # include BOOST_ABI_SUFFIX 77 | #endif 78 | 79 | #endif // BOOST_COROUTINES_DETAIL_TRAMPOLINE_PUSH_H 80 | -------------------------------------------------------------------------------- /include/boost/coroutine/exceptions.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_EXCEPTIONS_H 8 | #define BOOST_COROUTINES_EXCEPTIONS_H 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | #ifdef BOOST_HAS_ABI_HEADERS 22 | # include BOOST_ABI_PREFIX 23 | #endif 24 | 25 | namespace boost { 26 | namespace coroutines { 27 | namespace detail { 28 | 29 | struct forced_unwind {}; 30 | 31 | } 32 | 33 | BOOST_SCOPED_ENUM_DECLARE_BEGIN(coroutine_errc) 34 | { 35 | no_data = 1 36 | } 37 | BOOST_SCOPED_ENUM_DECLARE_END(coroutine_errc) 38 | 39 | BOOST_COROUTINES_DECL 40 | system::error_category const& coroutine_category() BOOST_NOEXCEPT; 41 | 42 | } 43 | 44 | namespace system { 45 | 46 | template<> 47 | struct is_error_code_enum< coroutines::coroutine_errc > : public true_type 48 | {}; 49 | 50 | #ifdef BOOST_NO_CXX11_SCOPED_ENUMS 51 | template<> 52 | struct is_error_code_enum< coroutines::coroutine_errc::enum_type > : public true_type 53 | {}; 54 | #endif 55 | 56 | inline 57 | error_code make_error_code( coroutines::coroutine_errc e) //BOOST_NOEXCEPT 58 | { 59 | return error_code( underlying_cast< int >( e), coroutines::coroutine_category() ); 60 | } 61 | 62 | inline 63 | error_condition make_error_condition( coroutines::coroutine_errc e) //BOOST_NOEXCEPT 64 | { 65 | return error_condition( underlying_cast< int >( e), coroutines::coroutine_category() ); 66 | } 67 | 68 | } 69 | 70 | namespace coroutines { 71 | 72 | class coroutine_error : public std::logic_error 73 | { 74 | private: 75 | system::error_code ec_; 76 | 77 | public: 78 | coroutine_error( system::error_code ec) : 79 | logic_error( ec.message() ), 80 | ec_( ec) 81 | {} 82 | 83 | system::error_code const& code() const BOOST_NOEXCEPT 84 | { return ec_; } 85 | }; 86 | 87 | class invalid_result : public coroutine_error 88 | { 89 | public: 90 | invalid_result() : 91 | coroutine_error( 92 | system::make_error_code( 93 | coroutine_errc::no_data) ) 94 | {} 95 | }; 96 | 97 | }} 98 | 99 | #ifdef BOOST_HAS_ABI_HEADERS 100 | # include BOOST_ABI_SUFFIX 101 | #endif 102 | 103 | #endif // BOOST_COROUTINES_EXCEPTIONS_H 104 | -------------------------------------------------------------------------------- /include/boost/coroutine/flags.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_FLAGS_H 8 | #define BOOST_COROUTINES_FLAGS_H 9 | 10 | namespace boost { 11 | namespace coroutines { 12 | 13 | enum flag_unwind_t 14 | { 15 | stack_unwind = 0, 16 | no_stack_unwind 17 | }; 18 | 19 | }} 20 | 21 | #endif // BOOST_COROUTINES_FLAGS_H 22 | -------------------------------------------------------------------------------- /include/boost/coroutine/posix/protected_stack_allocator.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H 8 | #define BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H 9 | 10 | extern "C" { 11 | #include 12 | #include 13 | #include 14 | #include 15 | } 16 | 17 | #if defined(BOOST_USE_VALGRIND) 18 | #include 19 | #endif 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #ifdef BOOST_HAS_ABI_HEADERS 33 | # include BOOST_ABI_PREFIX 34 | #endif 35 | 36 | namespace boost { 37 | namespace coroutines { 38 | 39 | template< typename traitsT > 40 | struct basic_protected_stack_allocator 41 | { 42 | typedef traitsT traits_type; 43 | 44 | void allocate( stack_context & ctx, std::size_t size = traits_type::minimum_size() ) 45 | { 46 | BOOST_ASSERT( traits_type::minimum_size() <= size); 47 | BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size) ); 48 | 49 | // page at bottom will be used as guard-page 50 | const std::size_t pages( 51 | static_cast< std::size_t >( 52 | std::floor( 53 | static_cast< float >( size) / traits_type::page_size() ) ) ); 54 | BOOST_ASSERT_MSG( 2 <= pages, "at least two pages must fit into stack (one page is guard-page)"); 55 | const std::size_t size_( pages * traits_type::page_size() ); 56 | BOOST_ASSERT( 0 != size && 0 != size_); 57 | BOOST_ASSERT( size_ <= size); 58 | 59 | // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) 60 | #if defined(MAP_ANON) 61 | void * limit = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 62 | #else 63 | void * limit = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 64 | #endif 65 | if ( MAP_FAILED == limit) throw std::bad_alloc(); 66 | 67 | // conforming to POSIX.1-2001 68 | BOOST_VERIFY( 0 == ::mprotect( limit, traits_type::page_size(), PROT_NONE)); 69 | 70 | ctx.size = size_; 71 | ctx.sp = static_cast< char * >( limit) + ctx.size; 72 | #if defined(BOOST_USE_VALGRIND) 73 | ctx.valgrind_stack_id = VALGRIND_STACK_REGISTER( ctx.sp, limit); 74 | #endif 75 | } 76 | 77 | void deallocate( stack_context & ctx) 78 | { 79 | BOOST_ASSERT( ctx.sp); 80 | BOOST_ASSERT( traits_type::minimum_size() <= ctx.size); 81 | BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= ctx.size) ); 82 | 83 | #if defined(BOOST_USE_VALGRIND) 84 | VALGRIND_STACK_DEREGISTER( ctx.valgrind_stack_id); 85 | #endif 86 | void * limit = static_cast< char * >( ctx.sp) - ctx.size; 87 | // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) 88 | ::munmap( limit, ctx.size); 89 | } 90 | }; 91 | 92 | typedef basic_protected_stack_allocator< stack_traits > protected_stack_allocator; 93 | 94 | }} 95 | 96 | #ifdef BOOST_HAS_ABI_HEADERS 97 | # include BOOST_ABI_SUFFIX 98 | #endif 99 | 100 | #endif // BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H 101 | -------------------------------------------------------------------------------- /include/boost/coroutine/posix/segmented_stack_allocator.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_SEGMENTED_STACK_ALLOCATOR_H 8 | #define BOOST_COROUTINES_SEGMENTED_STACK_ALLOCATOR_H 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #ifdef BOOST_HAS_ABI_HEADERS 20 | # include BOOST_ABI_PREFIX 21 | #endif 22 | 23 | // forward declaration for splitstack-functions defined in libgcc 24 | extern "C" { 25 | void *__splitstack_makecontext( std::size_t, 26 | void * [BOOST_CONTEXT_SEGMENTS], 27 | std::size_t *); 28 | 29 | void __splitstack_releasecontext( void * [BOOST_CONTEXT_SEGMENTS]); 30 | 31 | void __splitstack_resetcontext( void * [BOOST_CONTEXT_SEGMENTS]); 32 | 33 | void __splitstack_block_signals_context( void * [BOOST_CONTEXT_SEGMENTS], 34 | int * new_value, int * old_value); 35 | } 36 | 37 | namespace boost { 38 | namespace coroutines { 39 | 40 | template< typename traitsT > 41 | struct basic_segmented_stack_allocator 42 | { 43 | typedef traitsT traits_type; 44 | 45 | void allocate( stack_context & ctx, std::size_t size = traits_type::minimum_size() ) 46 | { 47 | void * limit = __splitstack_makecontext( size, ctx.segments_ctx, & ctx.size); 48 | if ( ! limit) throw std::bad_alloc(); 49 | 50 | // ctx.size is already filled by __splitstack_makecontext 51 | ctx.sp = static_cast< char * >( limit) + ctx.size; 52 | 53 | int off = 0; 54 | __splitstack_block_signals_context( ctx.segments_ctx, & off, 0); 55 | } 56 | 57 | void deallocate( stack_context & ctx) 58 | { __splitstack_releasecontext( ctx.segments_ctx); } 59 | }; 60 | 61 | typedef basic_segmented_stack_allocator< stack_traits > segmented_stack_allocator; 62 | 63 | }} 64 | 65 | #ifdef BOOST_HAS_ABI_HEADERS 66 | # include BOOST_ABI_SUFFIX 67 | #endif 68 | 69 | #endif // BOOST_COROUTINES_SEGMENTED_STACK_ALLOCATOR_H 70 | -------------------------------------------------------------------------------- /include/boost/coroutine/protected_stack_allocator.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #if defined(BOOST_WINDOWS) 10 | # include 11 | #else 12 | # include 13 | #endif 14 | -------------------------------------------------------------------------------- /include/boost/coroutine/segmented_stack_allocator.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | #if defined(BOOST_USE_SEGMENTED_STACKS) 10 | # if defined(BOOST_WINDOWS) 11 | # error "segmented stacks are not supported by Windows" 12 | # else 13 | # include 14 | # endif 15 | #endif 16 | -------------------------------------------------------------------------------- /include/boost/coroutine/stack_allocator.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_STACK_ALLOCATOR_H 8 | #define BOOST_COROUTINES_STACK_ALLOCATOR_H 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #ifdef BOOST_HAS_ABI_HEADERS 19 | # include BOOST_ABI_PREFIX 20 | #endif 21 | 22 | namespace boost { 23 | namespace coroutines { 24 | 25 | #if defined(BOOST_USE_SEGMENTED_STACKS) 26 | typedef segmented_stack_allocator stack_allocator; 27 | #else 28 | typedef standard_stack_allocator stack_allocator; 29 | #endif 30 | 31 | }} 32 | 33 | #ifdef BOOST_HAS_ABI_HEADERS 34 | # include BOOST_ABI_SUFFIX 35 | #endif 36 | 37 | #endif // BOOST_COROUTINES_STACK_ALLOCATOR_H 38 | -------------------------------------------------------------------------------- /include/boost/coroutine/stack_context.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_STACK_CONTEXT_H 8 | #define BOOST_COROUTINES_STACK_CONTEXT_H 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #ifdef BOOST_HAS_ABI_HEADERS 17 | # include BOOST_ABI_PREFIX 18 | #endif 19 | 20 | namespace boost { 21 | namespace coroutines { 22 | 23 | #if defined(BOOST_USE_SEGMENTED_STACKS) 24 | struct BOOST_COROUTINES_DECL stack_context 25 | { 26 | typedef void * segments_context[BOOST_CONTEXT_SEGMENTS]; 27 | 28 | std::size_t size; 29 | void * sp; 30 | segments_context segments_ctx; 31 | #if defined(BOOST_USE_VALGRIND) 32 | unsigned valgrind_stack_id; 33 | #endif 34 | 35 | stack_context() : 36 | size( 0), sp( 0), segments_ctx() 37 | #if defined(BOOST_USE_VALGRIND) 38 | , valgrind_stack_id( 0) 39 | #endif 40 | {} 41 | }; 42 | #else 43 | struct BOOST_COROUTINES_DECL stack_context 44 | { 45 | std::size_t size; 46 | void * sp; 47 | #if defined(BOOST_USE_VALGRIND) 48 | unsigned valgrind_stack_id; 49 | #endif 50 | 51 | stack_context() : 52 | size( 0), sp( 0) 53 | #if defined(BOOST_USE_VALGRIND) 54 | , valgrind_stack_id( 0) 55 | #endif 56 | {} 57 | }; 58 | #endif 59 | 60 | }} 61 | 62 | #ifdef BOOST_HAS_ABI_HEADERS 63 | # include BOOST_ABI_SUFFIX 64 | #endif 65 | 66 | #endif // BOOST_COROUTINES_STACK_CONTEXT_H 67 | -------------------------------------------------------------------------------- /include/boost/coroutine/stack_traits.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_STACK_TRAITS_H 8 | #define BOOST_COROUTINES_STACK_TRAITS_H 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #ifdef BOOST_HAS_ABI_HEADERS 17 | # include BOOST_ABI_PREFIX 18 | #endif 19 | 20 | namespace boost { 21 | namespace coroutines { 22 | 23 | struct BOOST_COROUTINES_DECL stack_traits 24 | { 25 | static bool is_unbounded() BOOST_NOEXCEPT; 26 | 27 | static std::size_t page_size() BOOST_NOEXCEPT; 28 | 29 | static std::size_t default_size() BOOST_NOEXCEPT; 30 | 31 | static std::size_t minimum_size() BOOST_NOEXCEPT; 32 | 33 | static std::size_t maximum_size() BOOST_NOEXCEPT; 34 | }; 35 | 36 | }} 37 | 38 | #ifdef BOOST_HAS_ABI_HEADERS 39 | # include BOOST_ABI_SUFFIX 40 | #endif 41 | 42 | #endif // BOOST_COROUTINES_STACK_TRAITS_H 43 | -------------------------------------------------------------------------------- /include/boost/coroutine/standard_stack_allocator.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_STANDARD_STACK_ALLOCATOR_H 8 | #define BOOST_COROUTINES_STANDARD_STACK_ALLOCATOR_H 9 | 10 | #if defined(BOOST_USE_VALGRIND) 11 | #include 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #if defined(BOOST_COROUTINES_USE_MAP_STACK) 26 | extern "C" { 27 | #include 28 | } 29 | #endif 30 | 31 | #ifdef BOOST_HAS_ABI_HEADERS 32 | # include BOOST_ABI_PREFIX 33 | #endif 34 | 35 | namespace boost { 36 | namespace coroutines { 37 | 38 | template< typename traitsT > 39 | struct basic_standard_stack_allocator 40 | { 41 | typedef traitsT traits_type; 42 | 43 | void allocate( stack_context & ctx, std::size_t size = traits_type::minimum_size() ) 44 | { 45 | BOOST_ASSERT( traits_type::minimum_size() <= size); 46 | BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size) ); 47 | 48 | #if defined(BOOST_COROUTINES_USE_MAP_STACK) 49 | void * limit = ::mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0); 50 | if ( limit == MAP_FAILED ) throw std::bad_alloc(); 51 | #else 52 | void * limit = std::malloc( size); 53 | if ( ! limit) throw std::bad_alloc(); 54 | #endif 55 | 56 | ctx.size = size; 57 | ctx.sp = static_cast< char * >( limit) + ctx.size; 58 | #if defined(BOOST_USE_VALGRIND) 59 | ctx.valgrind_stack_id = VALGRIND_STACK_REGISTER( ctx.sp, limit); 60 | #endif 61 | } 62 | 63 | void deallocate( stack_context & ctx) 64 | { 65 | BOOST_ASSERT( ctx.sp); 66 | BOOST_ASSERT( traits_type::minimum_size() <= ctx.size); 67 | BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= ctx.size) ); 68 | 69 | #if defined(BOOST_USE_VALGRIND) 70 | VALGRIND_STACK_DEREGISTER( ctx.valgrind_stack_id); 71 | #endif 72 | 73 | void * limit = static_cast< char * >( ctx.sp) - ctx.size; 74 | #if defined(BOOST_COROUTINES_USE_MAP_STACK) 75 | munmap(limit, ctx.size); 76 | #else 77 | std::free( limit); 78 | #endif 79 | } 80 | }; 81 | 82 | typedef basic_standard_stack_allocator< stack_traits > standard_stack_allocator; 83 | 84 | }} 85 | 86 | #ifdef BOOST_HAS_ABI_HEADERS 87 | # include BOOST_ABI_SUFFIX 88 | #endif 89 | 90 | #endif // BOOST_COROUTINES_STANDARD_STACK_ALLOCATOR_H 91 | -------------------------------------------------------------------------------- /include/boost/coroutine/symmetric_coroutine.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_SYMMETRIC_COROUTINE_H 8 | #define BOOST_COROUTINES_SYMMETRIC_COROUTINE_H 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #ifdef BOOST_HAS_ABI_HEADERS 16 | # include BOOST_ABI_PREFIX 17 | #endif 18 | 19 | namespace boost { 20 | namespace coroutines { 21 | 22 | template< typename T > 23 | struct symmetric_coroutine 24 | { 25 | typedef detail::symmetric_coroutine_call< T > call_type; 26 | typedef detail::symmetric_coroutine_yield< T > yield_type; 27 | }; 28 | 29 | }} 30 | 31 | #ifdef BOOST_HAS_ABI_HEADERS 32 | # include BOOST_ABI_SUFFIX 33 | #endif 34 | 35 | #endif // BOOST_COROUTINES_SYMMETRIC_COROUTINE_H 36 | -------------------------------------------------------------------------------- /include/boost/coroutine/windows/protected_stack_allocator.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H 8 | #define BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H 9 | 10 | extern "C" { 11 | #include 12 | } 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | #ifdef BOOST_HAS_ABI_HEADERS 24 | # include BOOST_ABI_PREFIX 25 | #endif 26 | 27 | namespace boost { 28 | namespace coroutines { 29 | 30 | struct stack_context; 31 | 32 | template< typename traitsT > 33 | struct basic_protected_stack_allocator 34 | { 35 | typedef traitsT traits_type; 36 | 37 | void allocate( stack_context & ctx, std::size_t size) 38 | { 39 | BOOST_ASSERT( traits_type::minimum_size() <= size); 40 | BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size) ); 41 | 42 | // page at bottom will be used as guard-page 43 | const std::size_t pages( 44 | static_cast< std::size_t >( 45 | std::floor( 46 | static_cast< float >( size) / traits_type::page_size() ) ) ); 47 | BOOST_ASSERT_MSG( 2 <= pages, "at least two pages must fit into stack (one page is guard-page)"); 48 | const std::size_t size_ = pages * traits_type::page_size(); 49 | BOOST_ASSERT( 0 != size && 0 != size_); 50 | 51 | void * limit = ::VirtualAlloc( 0, size_, MEM_COMMIT, PAGE_READWRITE); 52 | if ( ! limit) throw std::bad_alloc(); 53 | 54 | DWORD old_options; 55 | BOOST_VERIFY( FALSE != ::VirtualProtect( 56 | limit, traits_type::page_size(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options)); 57 | 58 | ctx.size = size_; 59 | ctx.sp = static_cast< char * >( limit) + ctx.size; 60 | } 61 | 62 | void deallocate( stack_context & ctx) 63 | { 64 | BOOST_ASSERT( ctx.sp); 65 | BOOST_ASSERT( traits_type::minimum_size() <= ctx.size); 66 | BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= ctx.size) ); 67 | 68 | void * limit = static_cast< char * >( ctx.sp) - ctx.size; 69 | ::VirtualFree( limit, 0, MEM_RELEASE); 70 | } 71 | }; 72 | 73 | typedef basic_protected_stack_allocator< stack_traits > protected_stack_allocator; 74 | 75 | }} 76 | 77 | #ifdef BOOST_HAS_ABI_HEADERS 78 | # include BOOST_ABI_SUFFIX 79 | #endif 80 | 81 | #endif // BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H 82 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Automatic redirection failed, please go to 7 | doc/html/index.html 8 |
9 |

© Copyright Beman Dawes, 2001

10 |

Distributed under the Boost Software 11 | License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 12 | www.boost.org/LICENSE_1_0.txt)

13 | 14 | 15 | -------------------------------------------------------------------------------- /meta/libraries.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "coroutine", 3 | "status": "deprecated", 4 | "name": "Coroutine", 5 | "authors": [ 6 | "Oliver Kowalke" 7 | ], 8 | "description": "Coroutine library.", 9 | "category": [ 10 | "Concurrent" 11 | ], 12 | "maintainers": [ 13 | "Oliver Kowalke " 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /performance/asymmetric/Jamfile.v2: -------------------------------------------------------------------------------- 1 | 2 | # Copyright Oliver Kowalke 2009. 3 | # Distributed under the Boost Software License, Version 1.0. 4 | # (See accompanying file LICENSE_1_0.txt or copy at 5 | # http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | # For more information, see http://www.boost.org/ 8 | 9 | import common ; 10 | import feature ; 11 | import indirect ; 12 | import modules ; 13 | import os ; 14 | import toolset ; 15 | 16 | project 17 | : requirements 18 | /boost/chrono//boost_chrono 19 | /boost/context//boost_context 20 | /boost/coroutine//boost_coroutine 21 | /boost/program_options//boost_program_options 22 | linux,gcc,on:-fsplit-stack 23 | linux,gcc,on:-DBOOST_USE_SEGMENTED_STACKS 24 | clang,on:-fsplit-stack 25 | clang,on:-DBOOST_USE_SEGMENTED_STACKS 26 | static 27 | multi 28 | -DBOOST_DISABLE_ASSERTS 29 | speed 30 | release 31 | ; 32 | 33 | alias sources 34 | : ../bind_processor_aix.cpp 35 | : aix 36 | ; 37 | 38 | alias sources 39 | : ../bind_processor_freebsd.cpp 40 | : freebsd 41 | ; 42 | 43 | alias sources 44 | : ../bind_processor_hpux.cpp 45 | : hpux 46 | ; 47 | 48 | alias sources 49 | : ../bind_processor_linux.cpp 50 | : linux 51 | ; 52 | 53 | alias sources 54 | : ../bind_processor_solaris.cpp 55 | : solaris 56 | ; 57 | 58 | alias sources 59 | : ../bind_processor_windows.cpp 60 | : windows 61 | ; 62 | 63 | explicit sources ; 64 | 65 | exe performance_create_protected 66 | : sources 67 | performance_create_protected.cpp 68 | ; 69 | 70 | exe performance_create_standard 71 | : sources 72 | performance_create_standard.cpp 73 | ; 74 | 75 | exe performance_create_prealloc 76 | : sources 77 | performance_create_prealloc.cpp 78 | ; 79 | 80 | exe performance_switch 81 | : sources 82 | performance_switch.cpp 83 | ; 84 | -------------------------------------------------------------------------------- /performance/asymmetric/performance_create_prealloc.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../bind_processor.hpp" 17 | #include "../clock.hpp" 18 | #include "../cycle.hpp" 19 | #include "../preallocated_stack_allocator.hpp" 20 | 21 | typedef preallocated_stack_allocator stack_allocator; 22 | typedef boost::coroutines::asymmetric_coroutine< void > coro_type; 23 | 24 | boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; 25 | boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind; 26 | boost::uint64_t jobs = 1000; 27 | 28 | void fn( coro_type::push_type & c) 29 | { while ( true) c(); } 30 | 31 | duration_type measure_time( duration_type overhead) 32 | { 33 | stack_allocator stack_alloc; 34 | 35 | time_point_type start( clock_type::now() ); 36 | for ( std::size_t i = 0; i < jobs; ++i) { 37 | coro_type::pull_type c( fn, 38 | boost::coroutines::attributes( unwind_stack, preserve_fpu), 39 | stack_alloc); 40 | } 41 | duration_type total = clock_type::now() - start; 42 | total -= overhead_clock(); // overhead of measurement 43 | total /= jobs; // loops 44 | 45 | return total; 46 | } 47 | 48 | # ifdef BOOST_CONTEXT_CYCLE 49 | cycle_type measure_cycles( cycle_type overhead) 50 | { 51 | stack_allocator stack_alloc; 52 | 53 | cycle_type start( cycles() ); 54 | for ( std::size_t i = 0; i < jobs; ++i) { 55 | coro_type::pull_type c( fn, 56 | boost::coroutines::attributes( unwind_stack, preserve_fpu), 57 | stack_alloc); 58 | } 59 | cycle_type total = cycles() - start; 60 | total -= overhead; // overhead of measurement 61 | total /= jobs; // loops 62 | 63 | return total; 64 | } 65 | # endif 66 | 67 | int main( int argc, char * argv[]) 68 | { 69 | try 70 | { 71 | bool preserve = false, unwind = true, bind = false; 72 | boost::program_options::options_description desc("allowed options"); 73 | desc.add_options() 74 | ("help", "help message") 75 | ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") 76 | ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") 77 | ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack") 78 | ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); 79 | 80 | boost::program_options::variables_map vm; 81 | boost::program_options::store( 82 | boost::program_options::parse_command_line( 83 | argc, 84 | argv, 85 | desc), 86 | vm); 87 | boost::program_options::notify( vm); 88 | 89 | if ( vm.count("help") ) { 90 | std::cout << desc << std::endl; 91 | return EXIT_SUCCESS; 92 | } 93 | 94 | if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; 95 | if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind; 96 | if ( bind) bind_to_processor( 0); 97 | 98 | duration_type overhead_c = overhead_clock(); 99 | std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl; 100 | boost::uint64_t res = measure_time( overhead_c).count(); 101 | std::cout << "average of " << res << " nano seconds" << std::endl; 102 | #ifdef BOOST_CONTEXT_CYCLE 103 | cycle_type overhead_y = overhead_cycle(); 104 | std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl; 105 | res = measure_cycles( overhead_y); 106 | std::cout << "average of " << res << " cpu cycles" << std::endl; 107 | #endif 108 | 109 | return EXIT_SUCCESS; 110 | } 111 | catch ( std::exception const& e) 112 | { std::cerr << "exception: " << e.what() << std::endl; } 113 | catch (...) 114 | { std::cerr << "unhandled exception" << std::endl; } 115 | return EXIT_FAILURE; 116 | } 117 | -------------------------------------------------------------------------------- /performance/asymmetric/performance_create_protected.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../bind_processor.hpp" 17 | #include "../clock.hpp" 18 | #include "../cycle.hpp" 19 | 20 | typedef boost::coroutines::protected_stack_allocator stack_allocator; 21 | typedef boost::coroutines::asymmetric_coroutine< void > coro_type; 22 | 23 | boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; 24 | boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind; 25 | boost::uint64_t jobs = 1000; 26 | 27 | void fn( coro_type::push_type & c) 28 | { while ( true) c(); } 29 | 30 | duration_type measure_time( duration_type overhead) 31 | { 32 | stack_allocator stack_alloc; 33 | 34 | time_point_type start( clock_type::now() ); 35 | for ( std::size_t i = 0; i < jobs; ++i) { 36 | coro_type::pull_type c( fn, 37 | boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc); 38 | } 39 | duration_type total = clock_type::now() - start; 40 | total -= overhead_clock(); // overhead of measurement 41 | total /= jobs; // loops 42 | 43 | return total; 44 | } 45 | 46 | # ifdef BOOST_CONTEXT_CYCLE 47 | cycle_type measure_cycles( cycle_type overhead) 48 | { 49 | stack_allocator stack_alloc; 50 | 51 | cycle_type start( cycles() ); 52 | for ( std::size_t i = 0; i < jobs; ++i) { 53 | coro_type::pull_type c( fn, 54 | boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc); 55 | } 56 | cycle_type total = cycles() - start; 57 | total -= overhead; // overhead of measurement 58 | total /= jobs; // loops 59 | 60 | return total; 61 | } 62 | # endif 63 | 64 | int main( int argc, char * argv[]) 65 | { 66 | try 67 | { 68 | bool preserve = false, unwind = true, bind = false; 69 | boost::program_options::options_description desc("allowed options"); 70 | desc.add_options() 71 | ("help", "help message") 72 | ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") 73 | ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") 74 | ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack") 75 | ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); 76 | 77 | boost::program_options::variables_map vm; 78 | boost::program_options::store( 79 | boost::program_options::parse_command_line( 80 | argc, 81 | argv, 82 | desc), 83 | vm); 84 | boost::program_options::notify( vm); 85 | 86 | if ( vm.count("help") ) { 87 | std::cout << desc << std::endl; 88 | return EXIT_SUCCESS; 89 | } 90 | 91 | if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; 92 | if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind; 93 | if ( bind) bind_to_processor( 0); 94 | 95 | duration_type overhead_c = overhead_clock(); 96 | std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl; 97 | boost::uint64_t res = measure_time( overhead_c).count(); 98 | std::cout << "average of " << res << " nano seconds" << std::endl; 99 | #ifdef BOOST_CONTEXT_CYCLE 100 | cycle_type overhead_y = overhead_cycle(); 101 | std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl; 102 | res = measure_cycles( overhead_y); 103 | std::cout << "average of " << res << " cpu cycles" << std::endl; 104 | #endif 105 | 106 | return EXIT_SUCCESS; 107 | } 108 | catch ( std::exception const& e) 109 | { std::cerr << "exception: " << e.what() << std::endl; } 110 | catch (...) 111 | { std::cerr << "unhandled exception" << std::endl; } 112 | return EXIT_FAILURE; 113 | } 114 | -------------------------------------------------------------------------------- /performance/asymmetric/performance_create_standard.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../bind_processor.hpp" 17 | #include "../clock.hpp" 18 | #include "../cycle.hpp" 19 | 20 | typedef boost::coroutines::standard_stack_allocator stack_allocator; 21 | typedef boost::coroutines::asymmetric_coroutine< void > coro_type; 22 | 23 | boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; 24 | boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind; 25 | boost::uint64_t jobs = 1000; 26 | 27 | void fn( coro_type::push_type & c) 28 | { while ( true) c(); } 29 | 30 | duration_type measure_time( duration_type overhead) 31 | { 32 | stack_allocator stack_alloc; 33 | 34 | time_point_type start( clock_type::now() ); 35 | for ( std::size_t i = 0; i < jobs; ++i) { 36 | coro_type::pull_type c( fn, 37 | boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc); 38 | } 39 | duration_type total = clock_type::now() - start; 40 | total -= overhead_clock(); // overhead of measurement 41 | total /= jobs; // loops 42 | 43 | return total; 44 | } 45 | 46 | # ifdef BOOST_CONTEXT_CYCLE 47 | cycle_type measure_cycles( cycle_type overhead) 48 | { 49 | stack_allocator stack_alloc; 50 | 51 | cycle_type start( cycles() ); 52 | for ( std::size_t i = 0; i < jobs; ++i) { 53 | coro_type::pull_type c( fn, 54 | boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc); 55 | } 56 | cycle_type total = cycles() - start; 57 | total -= overhead; // overhead of measurement 58 | total /= jobs; // loops 59 | 60 | return total; 61 | } 62 | # endif 63 | 64 | int main( int argc, char * argv[]) 65 | { 66 | try 67 | { 68 | bool preserve = false, unwind = true, bind = false; 69 | boost::program_options::options_description desc("allowed options"); 70 | desc.add_options() 71 | ("help", "help message") 72 | ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") 73 | ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") 74 | ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack") 75 | ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); 76 | 77 | boost::program_options::variables_map vm; 78 | boost::program_options::store( 79 | boost::program_options::parse_command_line( 80 | argc, 81 | argv, 82 | desc), 83 | vm); 84 | boost::program_options::notify( vm); 85 | 86 | if ( vm.count("help") ) { 87 | std::cout << desc << std::endl; 88 | return EXIT_SUCCESS; 89 | } 90 | 91 | if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; 92 | if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind; 93 | if ( bind) bind_to_processor( 0); 94 | 95 | duration_type overhead_c = overhead_clock(); 96 | std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl; 97 | boost::uint64_t res = measure_time( overhead_c).count(); 98 | std::cout << "average of " << res << " nano seconds" << std::endl; 99 | #ifdef BOOST_CONTEXT_CYCLE 100 | cycle_type overhead_y = overhead_cycle(); 101 | std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl; 102 | res = measure_cycles( overhead_y); 103 | std::cout << "average of " << res << " cpu cycles" << std::endl; 104 | #endif 105 | 106 | return EXIT_SUCCESS; 107 | } 108 | catch ( std::exception const& e) 109 | { std::cerr << "exception: " << e.what() << std::endl; } 110 | catch (...) 111 | { std::cerr << "unhandled exception" << std::endl; } 112 | return EXIT_FAILURE; 113 | } 114 | -------------------------------------------------------------------------------- /performance/asymmetric/performance_switch.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "../bind_processor.hpp" 18 | #include "../clock.hpp" 19 | #include "../cycle.hpp" 20 | 21 | boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; 22 | boost::uint64_t jobs = 1000; 23 | 24 | struct X 25 | { 26 | std::string str; 27 | 28 | X( std::string const& str_) : 29 | str( str_) 30 | {} 31 | }; 32 | 33 | const X x("abc"); 34 | 35 | void fn_void( boost::coroutines::asymmetric_coroutine< void >::push_type & c) 36 | { while ( true) c(); } 37 | 38 | void fn_int( boost::coroutines::asymmetric_coroutine< int >::push_type & c) 39 | { while ( true) c( 7); } 40 | 41 | void fn_x( boost::coroutines::asymmetric_coroutine< X >::push_type & c) 42 | { 43 | while ( true) c( x); 44 | } 45 | 46 | duration_type measure_time_void( duration_type overhead) 47 | { 48 | boost::coroutines::asymmetric_coroutine< void >::pull_type c( fn_void, 49 | boost::coroutines::attributes( preserve_fpu) ); 50 | 51 | time_point_type start( clock_type::now() ); 52 | for ( std::size_t i = 0; i < jobs; ++i) { 53 | c(); 54 | } 55 | duration_type total = clock_type::now() - start; 56 | total -= overhead_clock(); // overhead of measurement 57 | total /= jobs; // loops 58 | total /= 2; // 2x jump_fcontext 59 | 60 | return total; 61 | } 62 | 63 | duration_type measure_time_int( duration_type overhead) 64 | { 65 | boost::coroutines::asymmetric_coroutine< int >::pull_type c( fn_int, 66 | boost::coroutines::attributes( preserve_fpu) ); 67 | 68 | time_point_type start( clock_type::now() ); 69 | for ( std::size_t i = 0; i < jobs; ++i) { 70 | c(); 71 | } 72 | duration_type total = clock_type::now() - start; 73 | total -= overhead_clock(); // overhead of measurement 74 | total /= jobs; // loops 75 | total /= 2; // 2x jump_fcontext 76 | 77 | return total; 78 | } 79 | 80 | duration_type measure_time_x( duration_type overhead) 81 | { 82 | boost::coroutines::asymmetric_coroutine< X >::pull_type c( fn_x, 83 | boost::coroutines::attributes( preserve_fpu) ); 84 | 85 | time_point_type start( clock_type::now() ); 86 | for ( std::size_t i = 0; i < jobs; ++i) { 87 | c(); 88 | } 89 | duration_type total = clock_type::now() - start; 90 | total -= overhead_clock(); // overhead of measurement 91 | total /= jobs; // loops 92 | total /= 2; // 2x jump_fcontext 93 | 94 | return total; 95 | } 96 | 97 | # ifdef BOOST_CONTEXT_CYCLE 98 | cycle_type measure_cycles_void( cycle_type overhead) 99 | { 100 | boost::coroutines::asymmetric_coroutine< void >::pull_type c( fn_void, 101 | boost::coroutines::attributes( preserve_fpu) ); 102 | 103 | cycle_type start( cycles() ); 104 | for ( std::size_t i = 0; i < jobs; ++i) { 105 | c(); 106 | } 107 | cycle_type total = cycles() - start; 108 | total -= overhead; // overhead of measurement 109 | total /= jobs; // loops 110 | total /= 2; // 2x jump_fcontext 111 | 112 | return total; 113 | } 114 | 115 | cycle_type measure_cycles_int( cycle_type overhead) 116 | { 117 | boost::coroutines::asymmetric_coroutine< int >::pull_type c( fn_int, 118 | boost::coroutines::attributes( preserve_fpu) ); 119 | 120 | cycle_type start( cycles() ); 121 | for ( std::size_t i = 0; i < jobs; ++i) { 122 | c(); 123 | } 124 | cycle_type total = cycles() - start; 125 | total -= overhead; // overhead of measurement 126 | total /= jobs; // loops 127 | total /= 2; // 2x jump_fcontext 128 | 129 | return total; 130 | } 131 | 132 | cycle_type measure_cycles_x( cycle_type overhead) 133 | { 134 | boost::coroutines::asymmetric_coroutine< X >::pull_type c( fn_x, 135 | boost::coroutines::attributes( preserve_fpu) ); 136 | 137 | cycle_type start( cycles() ); 138 | for ( std::size_t i = 0; i < jobs; ++i) { 139 | c(); 140 | } 141 | cycle_type total = cycles() - start; 142 | total -= overhead; // overhead of measurement 143 | total /= jobs; // loops 144 | total /= 2; // 2x jump_fcontext 145 | 146 | return total; 147 | } 148 | # endif 149 | 150 | int main( int argc, char * argv[]) 151 | { 152 | try 153 | { 154 | bool preserve = false, bind = false; 155 | boost::program_options::options_description desc("allowed options"); 156 | desc.add_options() 157 | ("help", "help message") 158 | ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") 159 | ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") 160 | ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); 161 | 162 | boost::program_options::variables_map vm; 163 | boost::program_options::store( 164 | boost::program_options::parse_command_line( 165 | argc, 166 | argv, 167 | desc), 168 | vm); 169 | boost::program_options::notify( vm); 170 | 171 | if ( vm.count("help") ) { 172 | std::cout << desc << std::endl; 173 | return EXIT_SUCCESS; 174 | } 175 | 176 | if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; 177 | if ( bind) bind_to_processor( 0); 178 | 179 | duration_type overhead_c = overhead_clock(); 180 | std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl; 181 | boost::uint64_t res = measure_time_void( overhead_c).count(); 182 | std::cout << "void: average of " << res << " nano seconds" << std::endl; 183 | res = measure_time_int( overhead_c).count(); 184 | std::cout << "int: average of " << res << " nano seconds" << std::endl; 185 | res = measure_time_x( overhead_c).count(); 186 | std::cout << "X: average of " << res << " nano seconds" << std::endl; 187 | #ifdef BOOST_CONTEXT_CYCLE 188 | cycle_type overhead_y = overhead_cycle(); 189 | std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl; 190 | res = measure_cycles_void( overhead_y); 191 | std::cout << "void: average of " << res << " cpu cycles" << std::endl; 192 | res = measure_cycles_int( overhead_y); 193 | std::cout << "int: average of " << res << " cpu cycles" << std::endl; 194 | res = measure_cycles_x( overhead_y); 195 | std::cout << "X: average of " << res << " cpu cycles" << std::endl; 196 | #endif 197 | 198 | return EXIT_SUCCESS; 199 | } 200 | catch ( std::exception const& e) 201 | { std::cerr << "exception: " << e.what() << std::endl; } 202 | catch (...) 203 | { std::cerr << "unhandled exception" << std::endl; } 204 | return EXIT_FAILURE; 205 | } 206 | -------------------------------------------------------------------------------- /performance/asymmetric/segmented/Jamfile.v2: -------------------------------------------------------------------------------- 1 | 2 | # Copyright Oliver Kowalke 2009. 3 | # Distributed under the Boost Software License, Version 1.0. 4 | # (See accompanying file LICENSE_1_0.txt or copy at 5 | # http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | # For more information, see http://www.boost.org/ 8 | 9 | import common ; 10 | import feature ; 11 | import indirect ; 12 | import modules ; 13 | import os ; 14 | import toolset ; 15 | 16 | project 17 | : requirements 18 | /boost/chrono//boost_chrono 19 | /boost/context//boost_context 20 | /boost/coroutine//boost_coroutine 21 | /boost/program_options//boost_program_options 22 | gcc,on:-fsplit-stack 23 | gcc,on:-DBOOST_USE_SEGMENTED_STACKS 24 | clang,on:-fsplit-stack 25 | clang,on:-DBOOST_USE_SEGMENTED_STACKS 26 | static 27 | multi 28 | -DBOOST_DISABLE_ASSERTS 29 | speed 30 | release 31 | ; 32 | 33 | alias sources 34 | : ../../bind_processor_aix.cpp 35 | : aix 36 | ; 37 | 38 | alias sources 39 | : ../../bind_processor_freebsd.cpp 40 | : freebsd 41 | ; 42 | 43 | alias sources 44 | : ../../bind_processor_hpux.cpp 45 | : hpux 46 | ; 47 | 48 | alias sources 49 | : ../../bind_processor_linux.cpp 50 | : linux 51 | ; 52 | 53 | alias sources 54 | : ../../bind_processor_solaris.cpp 55 | : solaris 56 | ; 57 | 58 | alias sources 59 | : ../../bind_processor_windows.cpp 60 | : windows 61 | ; 62 | 63 | explicit sources ; 64 | 65 | exe performance_create_segmented 66 | : sources 67 | performance_create_segmented.cpp 68 | ; 69 | -------------------------------------------------------------------------------- /performance/asymmetric/segmented/performance_create_segmented.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../../bind_processor.hpp" 17 | #include "../../clock.hpp" 18 | #include "../../cycle.hpp" 19 | 20 | boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; 21 | boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind; 22 | boost::uint64_t jobs = 1000; 23 | 24 | void fn( boost::coroutines::asymmetric_coroutine< void >::push_type & c) 25 | { while ( true) c(); } 26 | 27 | duration_type measure_time( duration_type overhead) 28 | { 29 | time_point_type start( clock_type::now() ); 30 | for ( std::size_t i = 0; i < jobs; ++i) { 31 | boost::coroutines::asymmetric_coroutine< void >::pull_type c( fn, 32 | boost::coroutines::attributes( unwind_stack, preserve_fpu) ); 33 | } 34 | duration_type total = clock_type::now() - start; 35 | total -= overhead_clock(); // overhead of measurement 36 | total /= jobs; // loops 37 | 38 | return total; 39 | } 40 | 41 | # ifdef BOOST_CONTEXT_CYCLE 42 | cycle_type measure_cycles( cycle_type overhead) 43 | { 44 | cycle_type start( cycles() ); 45 | for ( std::size_t i = 0; i < jobs; ++i) { 46 | boost::coroutines::asymmetric_coroutine< void >::pull_type c( fn, 47 | boost::coroutines::attributes( unwind_stack, preserve_fpu) ); 48 | } 49 | cycle_type total = cycles() - start; 50 | total -= overhead; // overhead of measurement 51 | total /= jobs; // loops 52 | 53 | return total; 54 | } 55 | # endif 56 | 57 | int main( int argc, char * argv[]) 58 | { 59 | try 60 | { 61 | bool preserve = false, unwind = true, bind = false; 62 | boost::program_options::options_description desc("allowed options"); 63 | desc.add_options() 64 | ("help", "help message") 65 | ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") 66 | ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") 67 | ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack") 68 | ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); 69 | 70 | boost::program_options::variables_map vm; 71 | boost::program_options::store( 72 | boost::program_options::parse_command_line( 73 | argc, 74 | argv, 75 | desc), 76 | vm); 77 | boost::program_options::notify( vm); 78 | 79 | if ( vm.count("help") ) { 80 | std::cout << desc << std::endl; 81 | return EXIT_SUCCESS; 82 | } 83 | 84 | if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; 85 | if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind; 86 | if ( bind) bind_to_processor( 0); 87 | 88 | duration_type overhead_c = overhead_clock(); 89 | std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl; 90 | boost::uint64_t res = measure_time( overhead_c).count(); 91 | std::cout << "average of " << res << " nano seconds" << std::endl; 92 | #ifdef BOOST_CONTEXT_CYCLE 93 | cycle_type overhead_y = overhead_cycle(); 94 | std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl; 95 | res = measure_cycles( overhead_y); 96 | std::cout << "average of " << res << " cpu cycles" << std::endl; 97 | #endif 98 | 99 | return EXIT_SUCCESS; 100 | } 101 | catch ( std::exception const& e) 102 | { std::cerr << "exception: " << e.what() << std::endl; } 103 | catch (...) 104 | { std::cerr << "unhandled exception" << std::endl; } 105 | return EXIT_FAILURE; 106 | } 107 | -------------------------------------------------------------------------------- /performance/bind_processor.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BIND_TO_PROCESSOR_H 8 | #define BIND_TO_PROCESSOR_H 9 | 10 | void bind_to_processor( unsigned int n); 11 | 12 | #endif // BIND_TO_PROCESSOR_H 13 | -------------------------------------------------------------------------------- /performance/bind_processor_aix.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include "bind_processor.hpp" 8 | 9 | extern "C" 10 | { 11 | #include 12 | #include 13 | } 14 | 15 | #include 16 | 17 | #include 18 | 19 | void bind_to_processor( unsigned int n) 20 | { 21 | if ( ::bindprocessor( BINDTHREAD, ::thread_yield(), static_cast< cpu_t >( n) ) == -1) 22 | throw std::runtime_error("::bindprocessor() failed"); 23 | } 24 | 25 | #include 26 | -------------------------------------------------------------------------------- /performance/bind_processor_freebsd.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include "bind_processor.hpp" 8 | 9 | extern "C" 10 | { 11 | #include 12 | #include 13 | } 14 | 15 | #include 16 | 17 | #include 18 | 19 | void bind_to_processor( unsigned int n) 20 | { 21 | cpuset_t cpuset; 22 | CPU_ZERO( & cpuset); 23 | CPU_SET( n, & cpuset); 24 | 25 | if ( ::cpuset_setaffinity( CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof( cpuset), & cpuset) == -1) 26 | throw std::runtime_error("::cpuset_setaffinity() failed"); 27 | } 28 | 29 | #include 30 | -------------------------------------------------------------------------------- /performance/bind_processor_hpux.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include "bind_processor.hpp" 8 | 9 | extern "C" 10 | { 11 | #include 12 | } 13 | 14 | #include 15 | 16 | #include 17 | 18 | void bind_to_processor( unsigned int n) 19 | { 20 | ::pthread_spu_t spu; 21 | int errno_( 22 | ::pthread_processor_bind_np( 23 | PTHREAD_BIND_FORCED_NP, 24 | & spu, 25 | static_cast< pthread_spu_t >( n), 26 | PTHREAD_SELFTID_NP) ); 27 | if ( errno_ != 0) 28 | throw std::runtime_error("::pthread_processor_bind_np() failed"); 29 | } 30 | 31 | #include 32 | -------------------------------------------------------------------------------- /performance/bind_processor_linux.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include "bind_processor.hpp" 8 | 9 | extern "C" 10 | { 11 | #include 12 | #include 13 | } 14 | 15 | #include 16 | 17 | #include 18 | 19 | void bind_to_processor( unsigned int n) 20 | { 21 | cpu_set_t cpuset; 22 | CPU_ZERO( & cpuset); 23 | CPU_SET( n, & cpuset); 24 | 25 | int errno_( ::pthread_setaffinity_np( ::pthread_self(), sizeof( cpuset), & cpuset) ); 26 | if ( errno_ != 0) 27 | throw std::runtime_error("::pthread_setaffinity_np() failed"); 28 | } 29 | 30 | #include 31 | -------------------------------------------------------------------------------- /performance/bind_processor_solaris.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include "bind_processor.hpp" 8 | 9 | extern "C" 10 | { 11 | #include 12 | #include 13 | #include 14 | } 15 | 16 | #include 17 | 18 | #include 19 | 20 | void bind_to_processor( unsigned int n) 21 | { 22 | if ( ::processor_bind( P_LWPID, P_MYID, static_cast< processorid_t >( n), 0) == -1) 23 | throw std::runtime_error("::processor_bind() failed"); 24 | } 25 | 26 | #include 27 | -------------------------------------------------------------------------------- /performance/bind_processor_windows.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include "bind_processor.hpp" 8 | 9 | extern "C" 10 | { 11 | #include 12 | } 13 | 14 | #include 15 | 16 | #include 17 | 18 | void bind_to_processor( unsigned int n) 19 | { 20 | if ( ::SetThreadAffinityMask( ::GetCurrentThread(), ( DWORD_PTR)1 << n) == 0) 21 | throw std::runtime_error("::SetThreadAffinityMask() failed"); 22 | } 23 | 24 | #include 25 | -------------------------------------------------------------------------------- /performance/clock.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | #ifndef CLOCK_H 8 | #define CLOCK_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | typedef boost::chrono::high_resolution_clock clock_type; 20 | typedef clock_type::duration duration_type; 21 | typedef clock_type::time_point time_point_type; 22 | 23 | struct clock_overhead 24 | { 25 | boost::uint64_t operator()() 26 | { 27 | time_point_type start( clock_type::now() ); 28 | return ( clock_type::now() - start).count(); 29 | } 30 | }; 31 | 32 | duration_type overhead_clock() 33 | { 34 | std::size_t iterations( 10); 35 | std::vector< boost::uint64_t > overhead( iterations, 0); 36 | for ( std::size_t i = 0; i < iterations; ++i) 37 | std::generate( 38 | overhead.begin(), overhead.end(), 39 | clock_overhead() ); 40 | BOOST_ASSERT( overhead.begin() != overhead.end() ); 41 | return duration_type( std::accumulate( overhead.begin(), overhead.end(), 0) / iterations); 42 | } 43 | 44 | #endif // CLOCK_H 45 | -------------------------------------------------------------------------------- /performance/cycle.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef CYCLE_H 8 | #define CYCLE_H 9 | 10 | // x86_64 11 | // test x86_64 before i386 because icc might 12 | // define __i686__ for x86_64 too 13 | #if defined(__x86_64__) || defined(__x86_64) \ 14 | || defined(__amd64__) || defined(__amd64) \ 15 | || defined(_M_X64) || defined(_M_AMD64) 16 | # include "cycle_x86-64.hpp" 17 | // i386 18 | #elif defined(i386) || defined(__i386__) || defined(__i386) \ 19 | || defined(__i486__) || defined(__i586__) || defined(__i686__) \ 20 | || defined(__X86__) || defined(_X86_) || defined(__THW_INTEL__) \ 21 | || defined(__I86__) || defined(__INTEL__) || defined(__IA32__) \ 22 | || defined(_M_IX86) || defined(_I86_) 23 | # include "cycle_i386.hpp" 24 | #endif 25 | 26 | #endif // CYCLE_H 27 | -------------------------------------------------------------------------------- /performance/cycle_i386.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef CYCLE_I386_H 8 | #define CYCLE_I386_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #define BOOST_CONTEXT_CYCLE 20 | 21 | typedef boost::uint64_t cycle_type; 22 | 23 | #if _MSC_VER 24 | inline 25 | cycle_type cycles() 26 | { 27 | cycle_type c; 28 | __asm { 29 | cpuid 30 | rdtsc 31 | mov dword ptr [c + 0], eax 32 | mov dword ptr [c + 4], edx 33 | } 34 | return c; 35 | } 36 | #elif defined(__GNUC__) || \ 37 | defined(__INTEL_COMPILER) || defined(__ICC) || defined(_ECC) || defined(__ICL) 38 | inline 39 | cycle_type cycles() 40 | { 41 | boost::uint32_t lo, hi; 42 | 43 | __asm__ __volatile__ ( 44 | "xorl %%eax, %%eax\n" 45 | "cpuid\n" 46 | ::: "%eax", "%ebx", "%ecx", "%edx" 47 | ); 48 | __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi) ); 49 | __asm__ __volatile__ ( 50 | "xorl %%eax, %%eax\n" 51 | "cpuid\n" 52 | ::: "%eax", "%ebx", "%ecx", "%edx" 53 | ); 54 | 55 | return ( cycle_type)hi << 32 | lo; 56 | } 57 | #else 58 | # error "this compiler is not supported" 59 | #endif 60 | 61 | struct cycle_overhead 62 | { 63 | cycle_type operator()() 64 | { 65 | cycle_type start( cycles() ); 66 | return cycles() - start; 67 | } 68 | }; 69 | 70 | inline 71 | cycle_type overhead_cycle() 72 | { 73 | std::size_t iterations( 10); 74 | std::vector< cycle_type > overhead( iterations, 0); 75 | for ( std::size_t i( 0); i < iterations; ++i) 76 | std::generate( 77 | overhead.begin(), overhead.end(), 78 | cycle_overhead() ); 79 | BOOST_ASSERT( overhead.begin() != overhead.end() ); 80 | return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations; 81 | } 82 | 83 | #endif // CYCLE_I386_H 84 | -------------------------------------------------------------------------------- /performance/cycle_x86-64.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef CYCLE_X86_64_H 8 | #define CYCLE_X86_64_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #define BOOST_CONTEXT_CYCLE 20 | 21 | typedef boost::uint64_t cycle_type; 22 | 23 | #if _MSC_VER >= 1400 24 | # include 25 | # pragma intrinsic(__rdtsc) 26 | inline 27 | cycle_type cycles() 28 | { return __rdtsc(); } 29 | #elif defined(__INTEL_COMPILER) || defined(__ICC) || defined(_ECC) || defined(__ICL) 30 | inline 31 | cycle_type cycles() 32 | { return __rdtsc(); } 33 | #elif defined(__GNUC__) || defined(__SUNPRO_C) 34 | inline 35 | cycle_type cycles() 36 | { 37 | boost::uint32_t lo, hi; 38 | 39 | __asm__ __volatile__ ( 40 | "xorl %%eax, %%eax\n" 41 | "cpuid\n" 42 | ::: "%rax", "%rbx", "%rcx", "%rdx" 43 | ); 44 | __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi) ); 45 | __asm__ __volatile__ ( 46 | "xorl %%eax, %%eax\n" 47 | "cpuid\n" 48 | ::: "%rax", "%rbx", "%rcx", "%rdx" 49 | ); 50 | 51 | return ( cycle_type)hi << 32 | lo; 52 | } 53 | #else 54 | # error "this compiler is not supported" 55 | #endif 56 | 57 | struct cycle_overhead 58 | { 59 | cycle_type operator()() 60 | { 61 | cycle_type start( cycles() ); 62 | return cycles() - start; 63 | } 64 | }; 65 | 66 | inline 67 | cycle_type overhead_cycle() 68 | { 69 | std::size_t iterations( 10); 70 | std::vector< cycle_type > overhead( iterations, 0); 71 | for ( std::size_t i( 0); i < iterations; ++i) 72 | std::generate( 73 | overhead.begin(), overhead.end(), 74 | cycle_overhead() ); 75 | BOOST_ASSERT( overhead.begin() != overhead.end() ); 76 | return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations; 77 | } 78 | 79 | #endif // CYCLE_X86_64_H 80 | -------------------------------------------------------------------------------- /performance/preallocated_stack_allocator.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_FIBER_PREALLOCATED_STACK_ALLOCATOR_H 8 | #define BOOST_FIBER_PREALLOCATED_STACK_ALLOCATOR_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #ifdef BOOST_HAS_ABI_HEADERS 23 | # include BOOST_ABI_PREFIX 24 | #endif 25 | 26 | class preallocated_stack_allocator 27 | { 28 | private: 29 | boost::coroutines::stack_context stack_ctx_; 30 | 31 | public: 32 | preallocated_stack_allocator() : 33 | stack_ctx_() 34 | { 35 | boost::coroutines::standard_stack_allocator allocator; 36 | allocator.allocate( 37 | stack_ctx_, 38 | boost::coroutines::standard_stack_allocator::traits_type::default_size() ); 39 | } 40 | 41 | void allocate( boost::coroutines::stack_context & ctx, std::size_t size) 42 | { 43 | ctx.sp = stack_ctx_.sp; 44 | ctx.size = stack_ctx_.size; 45 | } 46 | 47 | void deallocate( boost::coroutines::stack_context & ctx) 48 | { 49 | } 50 | }; 51 | 52 | #ifdef BOOST_HAS_ABI_HEADERS 53 | # include BOOST_ABI_SUFFIX 54 | #endif 55 | 56 | #endif // BOOST_FIBER_PREALLOCATED_STACK_ALLOCATOR_H 57 | -------------------------------------------------------------------------------- /performance/symmetric/Jamfile.v2: -------------------------------------------------------------------------------- 1 | 2 | # Copyright Oliver Kowalke 2009. 3 | # Distributed under the Boost Software License, Version 1.0. 4 | # (See accompanying file LICENSE_1_0.txt or copy at 5 | # http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | # For more information, see http://www.boost.org/ 8 | 9 | import common ; 10 | import feature ; 11 | import indirect ; 12 | import modules ; 13 | import os ; 14 | import toolset ; 15 | 16 | project 17 | : requirements 18 | /boost/chrono//boost_chrono 19 | /boost/context//boost_context 20 | /boost/coroutine//boost_coroutine 21 | /boost/program_options//boost_program_options 22 | linux,gcc,on:-fsplit-stack 23 | linux,gcc,on:-DBOOST_USE_SEGMENTED_STACKS 24 | clang,on:-fsplit-stack 25 | clang,on:-DBOOST_USE_SEGMENTED_STACKS 26 | static 27 | multi 28 | -DBOOST_DISABLE_ASSERTS 29 | speed 30 | release 31 | ; 32 | 33 | alias sources 34 | : ../bind_processor_aix.cpp 35 | : aix 36 | ; 37 | 38 | alias sources 39 | : ../bind_processor_freebsd.cpp 40 | : freebsd 41 | ; 42 | 43 | alias sources 44 | : ../bind_processor_hpux.cpp 45 | : hpux 46 | ; 47 | 48 | alias sources 49 | : ../bind_processor_linux.cpp 50 | : linux 51 | ; 52 | 53 | alias sources 54 | : ../bind_processor_solaris.cpp 55 | : solaris 56 | ; 57 | 58 | alias sources 59 | : ../bind_processor_windows.cpp 60 | : windows 61 | ; 62 | 63 | explicit sources ; 64 | 65 | exe performance_create_protected 66 | : sources 67 | performance_create_protected.cpp 68 | ; 69 | 70 | exe performance_create_standard 71 | : sources 72 | performance_create_standard.cpp 73 | ; 74 | 75 | exe performance_create_prealloc 76 | : sources 77 | performance_create_prealloc.cpp 78 | ; 79 | 80 | exe performance_switch 81 | : sources 82 | performance_switch.cpp 83 | ; 84 | -------------------------------------------------------------------------------- /performance/symmetric/performance_create_prealloc.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../bind_processor.hpp" 17 | #include "../clock.hpp" 18 | #include "../cycle.hpp" 19 | #include "../preallocated_stack_allocator.hpp" 20 | 21 | typedef preallocated_stack_allocator stack_allocator; 22 | typedef boost::coroutines::symmetric_coroutine< void > coro_type; 23 | 24 | boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; 25 | boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind; 26 | boost::uint64_t jobs = 1000; 27 | 28 | void fn( coro_type::yield_type &) {} 29 | 30 | duration_type measure_time( duration_type overhead) 31 | { 32 | stack_allocator stack_alloc; 33 | boost::coroutines::attributes attrs( unwind_stack, preserve_fpu); 34 | 35 | time_point_type start( clock_type::now() ); 36 | for ( std::size_t i = 0; i < jobs; ++i) { 37 | coro_type::call_type c( fn, attrs, stack_alloc); 38 | } 39 | duration_type total = clock_type::now() - start; 40 | total -= overhead; // overhead of measurement 41 | total /= jobs; // loops 42 | 43 | return total; 44 | } 45 | 46 | # ifdef BOOST_CONTEXT_CYCLE 47 | cycle_type measure_cycles( cycle_type overhead) 48 | { 49 | stack_allocator stack_alloc; 50 | 51 | cycle_type start( cycles() ); 52 | for ( std::size_t i = 0; i < jobs; ++i) { 53 | coro_type::call_type c( fn, 54 | boost::coroutines::attributes( unwind_stack, preserve_fpu), 55 | stack_alloc); 56 | } 57 | cycle_type total = cycles() - start; 58 | total -= overhead; // overhead of measurement 59 | total /= jobs; // loops 60 | 61 | return total; 62 | } 63 | # endif 64 | 65 | int main( int argc, char * argv[]) 66 | { 67 | try 68 | { 69 | bool preserve = false, unwind = true, bind = false; 70 | boost::program_options::options_description desc("allowed options"); 71 | desc.add_options() 72 | ("help", "help message") 73 | ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") 74 | ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") 75 | ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack") 76 | ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); 77 | 78 | boost::program_options::variables_map vm; 79 | boost::program_options::store( 80 | boost::program_options::parse_command_line( 81 | argc, 82 | argv, 83 | desc), 84 | vm); 85 | boost::program_options::notify( vm); 86 | 87 | if ( vm.count("help") ) { 88 | std::cout << desc << std::endl; 89 | return EXIT_SUCCESS; 90 | } 91 | 92 | if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; 93 | if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind; 94 | if ( bind) bind_to_processor( 0); 95 | 96 | duration_type overhead_c = overhead_clock(); 97 | std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl; 98 | boost::uint64_t res = measure_time( overhead_c).count(); 99 | std::cout << "average of " << res << " nano seconds" << std::endl; 100 | #ifdef BOOST_CONTEXT_CYCLE 101 | cycle_type overhead_y = overhead_cycle(); 102 | std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl; 103 | res = measure_cycles( overhead_y); 104 | std::cout << "average of " << res << " cpu cycles" << std::endl; 105 | #endif 106 | 107 | return EXIT_SUCCESS; 108 | } 109 | catch ( std::exception const& e) 110 | { std::cerr << "exception: " << e.what() << std::endl; } 111 | catch (...) 112 | { std::cerr << "unhandled exception" << std::endl; } 113 | return EXIT_FAILURE; 114 | } 115 | -------------------------------------------------------------------------------- /performance/symmetric/performance_create_protected.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../bind_processor.hpp" 17 | #include "../clock.hpp" 18 | #include "../cycle.hpp" 19 | 20 | typedef boost::coroutines::protected_stack_allocator stack_allocator; 21 | typedef boost::coroutines::symmetric_coroutine< void > coro_type; 22 | 23 | boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; 24 | boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind; 25 | boost::uint64_t jobs = 1000; 26 | 27 | void fn( coro_type::yield_type &) {} 28 | 29 | duration_type measure_time( duration_type overhead) 30 | { 31 | stack_allocator stack_alloc; 32 | boost::coroutines::attributes attrs( unwind_stack, preserve_fpu); 33 | 34 | time_point_type start( clock_type::now() ); 35 | for ( std::size_t i = 0; i < jobs; ++i) { 36 | coro_type::call_type c( fn, attrs, stack_alloc); 37 | } 38 | duration_type total = clock_type::now() - start; 39 | total -= overhead; // overhead of measurement 40 | total /= jobs; // loops 41 | 42 | return total; 43 | } 44 | 45 | # ifdef BOOST_CONTEXT_CYCLE 46 | cycle_type measure_cycles( cycle_type overhead) 47 | { 48 | stack_allocator stack_alloc; 49 | 50 | cycle_type start( cycles() ); 51 | for ( std::size_t i = 0; i < jobs; ++i) { 52 | coro_type::call_type c( fn, 53 | boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc); 54 | } 55 | cycle_type total = cycles() - start; 56 | total -= overhead; // overhead of measurement 57 | total /= jobs; // loops 58 | 59 | return total; 60 | } 61 | # endif 62 | 63 | int main( int argc, char * argv[]) 64 | { 65 | try 66 | { 67 | bool preserve = false, unwind = true, bind = false; 68 | boost::program_options::options_description desc("allowed options"); 69 | desc.add_options() 70 | ("help", "help message") 71 | ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") 72 | ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") 73 | ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack") 74 | ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); 75 | 76 | boost::program_options::variables_map vm; 77 | boost::program_options::store( 78 | boost::program_options::parse_command_line( 79 | argc, 80 | argv, 81 | desc), 82 | vm); 83 | boost::program_options::notify( vm); 84 | 85 | if ( vm.count("help") ) { 86 | std::cout << desc << std::endl; 87 | return EXIT_SUCCESS; 88 | } 89 | 90 | if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; 91 | if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind; 92 | if ( bind) bind_to_processor( 0); 93 | 94 | duration_type overhead_c = overhead_clock(); 95 | std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl; 96 | boost::uint64_t res = measure_time( overhead_c).count(); 97 | std::cout << "average of " << res << " nano seconds" << std::endl; 98 | #ifdef BOOST_CONTEXT_CYCLE 99 | cycle_type overhead_y = overhead_cycle(); 100 | std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl; 101 | res = measure_cycles( overhead_y); 102 | std::cout << "average of " << res << " cpu cycles" << std::endl; 103 | #endif 104 | 105 | return EXIT_SUCCESS; 106 | } 107 | catch ( std::exception const& e) 108 | { std::cerr << "exception: " << e.what() << std::endl; } 109 | catch (...) 110 | { std::cerr << "unhandled exception" << std::endl; } 111 | return EXIT_FAILURE; 112 | } 113 | -------------------------------------------------------------------------------- /performance/symmetric/performance_create_standard.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../bind_processor.hpp" 17 | #include "../clock.hpp" 18 | #include "../cycle.hpp" 19 | 20 | typedef boost::coroutines::standard_stack_allocator stack_allocator; 21 | typedef boost::coroutines::symmetric_coroutine< void > coro_type; 22 | 23 | boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; 24 | boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind; 25 | boost::uint64_t jobs = 1000; 26 | 27 | void fn( coro_type::yield_type &) {} 28 | 29 | duration_type measure_time( duration_type overhead) 30 | { 31 | stack_allocator stack_alloc; 32 | boost::coroutines::attributes attrs( unwind_stack, preserve_fpu); 33 | 34 | time_point_type start( clock_type::now() ); 35 | for ( std::size_t i = 0; i < jobs; ++i) { 36 | coro_type::call_type c( fn, attrs, stack_alloc); 37 | } 38 | duration_type total = clock_type::now() - start; 39 | total -= overhead; // overhead of measurement 40 | total /= jobs; // loops 41 | 42 | return total; 43 | } 44 | 45 | # ifdef BOOST_CONTEXT_CYCLE 46 | cycle_type measure_cycles( cycle_type overhead) 47 | { 48 | stack_allocator stack_alloc; 49 | 50 | cycle_type start( cycles() ); 51 | for ( std::size_t i = 0; i < jobs; ++i) { 52 | coro_type::call_type c( fn, 53 | boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc); 54 | } 55 | cycle_type total = cycles() - start; 56 | total -= overhead; // overhead of measurement 57 | total /= jobs; // loops 58 | 59 | return total; 60 | } 61 | # endif 62 | 63 | int main( int argc, char * argv[]) 64 | { 65 | try 66 | { 67 | bool preserve = false, unwind = true, bind = false; 68 | boost::program_options::options_description desc("allowed options"); 69 | desc.add_options() 70 | ("help", "help message") 71 | ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") 72 | ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") 73 | ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack") 74 | ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); 75 | 76 | boost::program_options::variables_map vm; 77 | boost::program_options::store( 78 | boost::program_options::parse_command_line( 79 | argc, 80 | argv, 81 | desc), 82 | vm); 83 | boost::program_options::notify( vm); 84 | 85 | if ( vm.count("help") ) { 86 | std::cout << desc << std::endl; 87 | return EXIT_SUCCESS; 88 | } 89 | 90 | if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; 91 | if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind; 92 | if ( bind) bind_to_processor( 0); 93 | 94 | duration_type overhead_c = overhead_clock(); 95 | std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl; 96 | boost::uint64_t res = measure_time( overhead_c).count(); 97 | std::cout << "average of " << res << " nano seconds" << std::endl; 98 | #ifdef BOOST_CONTEXT_CYCLE 99 | cycle_type overhead_y = overhead_cycle(); 100 | std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl; 101 | res = measure_cycles( overhead_y); 102 | std::cout << "average of " << res << " cpu cycles" << std::endl; 103 | #endif 104 | 105 | return EXIT_SUCCESS; 106 | } 107 | catch ( std::exception const& e) 108 | { std::cerr << "exception: " << e.what() << std::endl; } 109 | catch (...) 110 | { std::cerr << "unhandled exception" << std::endl; } 111 | return EXIT_FAILURE; 112 | } 113 | -------------------------------------------------------------------------------- /performance/symmetric/performance_switch.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "../bind_processor.hpp" 18 | #include "../clock.hpp" 19 | #include "../cycle.hpp" 20 | 21 | boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; 22 | boost::uint64_t jobs = 1000; 23 | time_point_type end; 24 | 25 | struct X 26 | { 27 | std::string str; 28 | 29 | X( std::string const& str_) : 30 | str( str_) 31 | {} 32 | }; 33 | 34 | const X x("abc"); 35 | 36 | void fn_void( boost::coroutines::symmetric_coroutine< void >::yield_type & yield) 37 | { while( true) yield(); } 38 | 39 | void fn_int( boost::coroutines::symmetric_coroutine< int >::yield_type & yield) 40 | { while( true) yield(); } 41 | 42 | void fn_x( boost::coroutines::symmetric_coroutine< X >::yield_type & yield) 43 | { while( true) yield(); } 44 | 45 | duration_type measure_time_void( duration_type overhead) 46 | { 47 | boost::coroutines::symmetric_coroutine< void >::call_type c( fn_void, 48 | boost::coroutines::attributes( preserve_fpu) ); 49 | c(); 50 | 51 | time_point_type start( clock_type::now() ); 52 | for ( std::size_t i = 0; i < jobs; ++i) { 53 | c(); 54 | } 55 | duration_type total = clock_type::now() - start; 56 | total -= overhead_clock(); // overhead of measurement 57 | total /= jobs; // loops 58 | total /= 2; // 2x jump_fcontext 59 | 60 | return total; 61 | } 62 | 63 | duration_type measure_time_int( duration_type overhead) 64 | { 65 | boost::coroutines::symmetric_coroutine< int >::call_type c( fn_int, 66 | boost::coroutines::attributes( preserve_fpu) ); 67 | 68 | time_point_type start( clock_type::now() ); 69 | for ( std::size_t i = 0; i < jobs; ++i) { 70 | c( i); 71 | } 72 | duration_type total = clock_type::now() - start; 73 | total -= overhead_clock(); // overhead of measurement 74 | total /= jobs; // loops 75 | total /= 2; // 2x jump_fcontext 76 | 77 | return total; 78 | } 79 | 80 | duration_type measure_time_x( duration_type overhead) 81 | { 82 | boost::coroutines::symmetric_coroutine< X >::call_type c( fn_x, 83 | boost::coroutines::attributes( preserve_fpu) ); 84 | 85 | X x("abc"); 86 | time_point_type start( clock_type::now() ); 87 | for ( std::size_t i = 0; i < jobs; ++i) { 88 | c( x); 89 | } 90 | duration_type total = clock_type::now() - start; 91 | total -= overhead_clock(); // overhead of measurement 92 | total /= jobs; // loops 93 | total /= 2; // 2x jump_fcontext 94 | 95 | return total; 96 | } 97 | 98 | # ifdef BOOST_CONTEXT_CYCLE 99 | cycle_type measure_cycles_void( cycle_type overhead) 100 | { 101 | boost::coroutines::symmetric_coroutine< void >::call_type c( fn_void, 102 | boost::coroutines::attributes( preserve_fpu) ); 103 | 104 | cycle_type start( cycles() ); 105 | for ( std::size_t i = 0; i < jobs; ++i) { 106 | c(); 107 | } 108 | cycle_type total = cycles() - start; 109 | total -= overhead; // overhead of measurement 110 | total /= jobs; // loops 111 | total /= 2; // 2x jump_fcontext 112 | 113 | return total; 114 | } 115 | 116 | cycle_type measure_cycles_int( cycle_type overhead) 117 | { 118 | boost::coroutines::symmetric_coroutine< int >::call_type c( fn_int, 119 | boost::coroutines::attributes( preserve_fpu) ); 120 | 121 | cycle_type start( cycles() ); 122 | for ( std::size_t i = 0; i < jobs; ++i) { 123 | c( i); 124 | } 125 | cycle_type total = cycles() - start; 126 | total -= overhead; // overhead of measurement 127 | total /= jobs; // loops 128 | total /= 2; // 2x jump_fcontext 129 | 130 | return total; 131 | } 132 | 133 | cycle_type measure_cycles_x( cycle_type overhead) 134 | { 135 | boost::coroutines::symmetric_coroutine< X >::call_type c( fn_x, 136 | boost::coroutines::attributes( preserve_fpu) ); 137 | 138 | X x("abc"); 139 | cycle_type start( cycles() ); 140 | for ( std::size_t i = 0; i < jobs; ++i) { 141 | c( x); 142 | } 143 | cycle_type total = cycles() - start; 144 | total -= overhead; // overhead of measurement 145 | total /= jobs; // loops 146 | total /= 2; // 2x jump_fcontext 147 | 148 | return total; 149 | } 150 | # endif 151 | 152 | int main( int argc, char * argv[]) 153 | { 154 | try 155 | { 156 | bool preserve = false, bind = false; 157 | boost::program_options::options_description desc("allowed options"); 158 | desc.add_options() 159 | ("help", "help message") 160 | ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") 161 | ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") 162 | ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); 163 | 164 | boost::program_options::variables_map vm; 165 | boost::program_options::store( 166 | boost::program_options::parse_command_line( 167 | argc, 168 | argv, 169 | desc), 170 | vm); 171 | boost::program_options::notify( vm); 172 | 173 | if ( vm.count("help") ) { 174 | std::cout << desc << std::endl; 175 | return EXIT_SUCCESS; 176 | } 177 | 178 | if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; 179 | if ( bind) bind_to_processor( 0); 180 | 181 | duration_type overhead_c = overhead_clock(); 182 | std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl; 183 | boost::uint64_t res = measure_time_void( overhead_c).count(); 184 | std::cout << "void: average of " << res << " nano seconds" << std::endl; 185 | res = measure_time_int( overhead_c).count(); 186 | std::cout << "int: average of " << res << " nano seconds" << std::endl; 187 | res = measure_time_x( overhead_c).count(); 188 | std::cout << "X: average of " << res << " nano seconds" << std::endl; 189 | #ifdef BOOST_CONTEXT_CYCLE 190 | cycle_type overhead_y = overhead_cycle(); 191 | std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl; 192 | res = measure_cycles_void( overhead_y); 193 | std::cout << "void: average of " << res << " cpu cycles" << std::endl; 194 | res = measure_cycles_int( overhead_y); 195 | std::cout << "int: average of " << res << " cpu cycles" << std::endl; 196 | res = measure_cycles_x( overhead_y); 197 | std::cout << "X: average of " << res << " cpu cycles" << std::endl; 198 | #endif 199 | 200 | return EXIT_SUCCESS; 201 | } 202 | catch ( std::exception const& e) 203 | { std::cerr << "exception: " << e.what() << std::endl; } 204 | catch (...) 205 | { std::cerr << "unhandled exception" << std::endl; } 206 | return EXIT_FAILURE; 207 | } 208 | -------------------------------------------------------------------------------- /performance/symmetric/segmented/Jamfile.v2: -------------------------------------------------------------------------------- 1 | 2 | # Copyright Oliver Kowalke 2009. 3 | # Distributed under the Boost Software License, Version 1.0. 4 | # (See accompanying file LICENSE_1_0.txt or copy at 5 | # http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | # For more information, see http://www.boost.org/ 8 | 9 | import common ; 10 | import feature ; 11 | import indirect ; 12 | import modules ; 13 | import os ; 14 | import toolset ; 15 | 16 | project 17 | : requirements 18 | /boost/chrono//boost_chrono 19 | /boost/context//boost_context 20 | /boost/coroutine//boost_coroutine 21 | /boost/program_options//boost_program_options 22 | gcc,on:-fsplit-stack 23 | gcc,on:-DBOOST_USE_SEGMENTED_STACKS 24 | clang,on:-fsplit-stack 25 | clang,on:-DBOOST_USE_SEGMENTED_STACKS 26 | static 27 | multi 28 | -DBOOST_DISABLE_ASSERTS 29 | speed 30 | release 31 | ; 32 | 33 | alias sources 34 | : ../../bind_processor_aix.cpp 35 | : aix 36 | ; 37 | 38 | alias sources 39 | : ../../bind_processor_freebsd.cpp 40 | : freebsd 41 | ; 42 | 43 | alias sources 44 | : ../../bind_processor_hpux.cpp 45 | : hpux 46 | ; 47 | 48 | alias sources 49 | : ../../bind_processor_linux.cpp 50 | : linux 51 | ; 52 | 53 | alias sources 54 | : ../../bind_processor_solaris.cpp 55 | : solaris 56 | ; 57 | 58 | alias sources 59 | : ../../bind_processor_windows.cpp 60 | : windows 61 | ; 62 | 63 | explicit sources ; 64 | 65 | exe performance_create_segmented 66 | : sources 67 | performance_create_segmented.cpp 68 | ; 69 | -------------------------------------------------------------------------------- /performance/symmetric/segmented/performance_create_segmented.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../../bind_processor.hpp" 17 | #include "../../clock.hpp" 18 | #include "../../cycle.hpp" 19 | 20 | boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; 21 | boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind; 22 | boost::uint64_t jobs = 1000; 23 | 24 | void fn( boost::coroutines::symmetric_coroutine< void >::yield_type &) {} 25 | 26 | duration_type measure_time( duration_type overhead) 27 | { 28 | time_point_type start( clock_type::now() ); 29 | for ( std::size_t i = 0; i < jobs; ++i) { 30 | boost::coroutines::symmetric_coroutine< void >::call_type c( fn, 31 | boost::coroutines::attributes( unwind_stack, preserve_fpu) ); 32 | } 33 | duration_type total = clock_type::now() - start; 34 | total -= overhead; // overhead of measurement 35 | total /= jobs; // loops 36 | 37 | return total; 38 | } 39 | 40 | # ifdef BOOST_CONTEXT_CYCLE 41 | cycle_type measure_cycles( cycle_type overhead) 42 | { 43 | cycle_type start( cycles() ); 44 | for ( std::size_t i = 0; i < jobs; ++i) { 45 | boost::coroutines::symmetric_coroutine< void >::call_type c( fn, 46 | boost::coroutines::attributes( unwind_stack, preserve_fpu) ); 47 | } 48 | cycle_type total = cycles() - start; 49 | total -= overhead; // overhead of measurement 50 | total /= jobs; // loops 51 | 52 | return total; 53 | } 54 | # endif 55 | 56 | int main( int argc, char * argv[]) 57 | { 58 | try 59 | { 60 | bool preserve = false, unwind = true, bind = false; 61 | boost::program_options::options_description desc("allowed options"); 62 | desc.add_options() 63 | ("help", "help message") 64 | ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") 65 | ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") 66 | ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack") 67 | ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); 68 | 69 | boost::program_options::variables_map vm; 70 | boost::program_options::store( 71 | boost::program_options::parse_command_line( 72 | argc, 73 | argv, 74 | desc), 75 | vm); 76 | boost::program_options::notify( vm); 77 | 78 | if ( vm.count("help") ) { 79 | std::cout << desc << std::endl; 80 | return EXIT_SUCCESS; 81 | } 82 | 83 | if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; 84 | if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind; 85 | if ( bind) bind_to_processor( 0); 86 | 87 | duration_type overhead_c = overhead_clock(); 88 | std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl; 89 | boost::uint64_t res = measure_time( overhead_c).count(); 90 | std::cout << "average of " << res << " nano seconds" << std::endl; 91 | #ifdef BOOST_CONTEXT_CYCLE 92 | cycle_type overhead_y = overhead_cycle(); 93 | std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl; 94 | res = measure_cycles( overhead_y); 95 | std::cout << "average of " << res << " cpu cycles" << std::endl; 96 | #endif 97 | 98 | return EXIT_SUCCESS; 99 | } 100 | catch ( std::exception const& e) 101 | { std::cerr << "exception: " << e.what() << std::endl; } 102 | catch (...) 103 | { std::cerr << "unhandled exception" << std::endl; } 104 | return EXIT_FAILURE; 105 | } 106 | -------------------------------------------------------------------------------- /src/detail/coroutine_context.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include "boost/coroutine/detail/coroutine_context.hpp" 8 | 9 | #include "boost/coroutine/detail/data.hpp" 10 | 11 | #ifdef BOOST_HAS_ABI_HEADERS 12 | # include BOOST_ABI_PREFIX 13 | #endif 14 | 15 | #if defined(_MSC_VER) 16 | # pragma warning(push) 17 | # pragma warning(disable:4355) 18 | #endif 19 | 20 | #if defined(BOOST_USE_SEGMENTED_STACKS) 21 | extern "C" { 22 | 23 | void __splitstack_getcontext( void * [BOOST_CONTEXT_SEGMENTS]); 24 | 25 | void __splitstack_setcontext( void * [BOOST_CONTEXT_SEGMENTS]); 26 | 27 | } 28 | #endif 29 | 30 | namespace boost { 31 | namespace coroutines { 32 | namespace detail { 33 | 34 | coroutine_context::coroutine_context() : 35 | palloc_(), 36 | ctx_( 0) 37 | {} 38 | 39 | coroutine_context::coroutine_context( ctx_fn fn, preallocated const& palloc) : 40 | palloc_( palloc), 41 | ctx_( context::detail::make_fcontext( palloc_.sp, palloc_.size, fn) ) 42 | {} 43 | 44 | coroutine_context::coroutine_context( coroutine_context const& other) : 45 | palloc_( other.palloc_), 46 | ctx_( other.ctx_) 47 | {} 48 | 49 | coroutine_context & 50 | coroutine_context::operator=( coroutine_context const& other) 51 | { 52 | if ( this == & other) return * this; 53 | 54 | palloc_ = other.palloc_; 55 | ctx_ = other.ctx_; 56 | 57 | return * this; 58 | } 59 | 60 | void * 61 | coroutine_context::jump( coroutine_context & other, void * param) 62 | { 63 | #if defined(BOOST_USE_SEGMENTED_STACKS) 64 | __splitstack_getcontext( palloc_.sctx.segments_ctx); 65 | __splitstack_setcontext( other.palloc_.sctx.segments_ctx); 66 | #endif 67 | data_t data = { this, param }; 68 | context::detail::transfer_t t = context::detail::jump_fcontext( other.ctx_, & data); 69 | data_t * ret = static_cast< data_t * >( t.data); 70 | ret->from->ctx_ = t.fctx; 71 | return ret->data; 72 | } 73 | 74 | }}} 75 | 76 | #if defined(_MSC_VER) 77 | # pragma warning(pop) 78 | #endif 79 | 80 | #ifdef BOOST_HAS_ABI_HEADERS 81 | # include BOOST_ABI_SUFFIX 82 | #endif 83 | -------------------------------------------------------------------------------- /src/exceptions.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include "boost/coroutine/exceptions.hpp" 8 | 9 | namespace boost { 10 | namespace coroutines { 11 | 12 | class coroutine_error_category : public system::error_category 13 | { 14 | public: 15 | virtual const char* name() const BOOST_NOEXCEPT 16 | { return "coroutine"; } 17 | 18 | virtual std::string message( int ev) const 19 | { 20 | switch (BOOST_SCOPED_ENUM_NATIVE(coroutine_errc)(ev)) 21 | { 22 | case coroutine_errc::no_data: 23 | return std::string("Operation not permitted because coroutine " 24 | "has no valid result."); 25 | } 26 | return std::string("unspecified coroutine_errc value\n"); 27 | } 28 | }; 29 | 30 | BOOST_COROUTINES_DECL 31 | system::error_category const& coroutine_category() BOOST_NOEXCEPT 32 | { 33 | static coroutines::coroutine_error_category cat; 34 | return cat; 35 | } 36 | 37 | }} 38 | -------------------------------------------------------------------------------- /src/posix/stack_traits.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include "boost/coroutine/stack_traits.hpp" 8 | 9 | extern "C" { 10 | #include 11 | #include 12 | #include 13 | #include 14 | } 15 | 16 | //#if _POSIX_C_SOURCE >= 200112L 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #if !defined (SIGSTKSZ) 25 | # define SIGSTKSZ (8 * 1024) 26 | # define UDEF_SIGSTKSZ 27 | #endif 28 | 29 | #ifdef BOOST_HAS_ABI_HEADERS 30 | # include BOOST_ABI_PREFIX 31 | #endif 32 | 33 | namespace { 34 | 35 | std::size_t pagesize() 36 | { 37 | // conform to POSIX.1-2001 38 | return static_cast( ::sysconf( _SC_PAGESIZE) ); 39 | } 40 | 41 | rlim_t stacksize_limit_() 42 | { 43 | rlimit limit; 44 | // conforming to POSIX.1-2001 45 | #if defined(BOOST_DISABLE_ASSERTS) || defined(NDEBUG) 46 | ::getrlimit( RLIMIT_STACK, & limit); 47 | #else 48 | const int result = ::getrlimit( RLIMIT_STACK, & limit); 49 | BOOST_ASSERT( 0 == result); 50 | #endif 51 | return limit.rlim_max; 52 | } 53 | 54 | rlim_t stacksize_limit() BOOST_NOEXCEPT_OR_NOTHROW { 55 | static rlim_t limit = stacksize_limit_(); 56 | return limit; 57 | } 58 | 59 | } 60 | 61 | namespace boost { 62 | namespace coroutines { 63 | 64 | bool 65 | stack_traits::is_unbounded() BOOST_NOEXCEPT 66 | { return RLIM_INFINITY == stacksize_limit(); } 67 | 68 | std::size_t 69 | stack_traits::page_size() BOOST_NOEXCEPT 70 | { 71 | static std::size_t size = pagesize(); 72 | return size; 73 | } 74 | 75 | std::size_t 76 | stack_traits::default_size() BOOST_NOEXCEPT 77 | { 78 | std::size_t size = 8 * minimum_size(); 79 | if ( is_unbounded() ) return size; 80 | 81 | BOOST_ASSERT( maximum_size() >= minimum_size() ); 82 | return maximum_size() == size 83 | ? size 84 | : (std::min)( size, maximum_size() ); 85 | } 86 | 87 | std::size_t 88 | stack_traits::minimum_size() BOOST_NOEXCEPT 89 | { return static_cast( SIGSTKSZ ); } 90 | 91 | std::size_t 92 | stack_traits::maximum_size() BOOST_NOEXCEPT 93 | { 94 | BOOST_ASSERT( ! is_unbounded() ); 95 | return static_cast< std::size_t >( stacksize_limit() ); 96 | } 97 | 98 | }} 99 | 100 | #ifdef BOOST_HAS_ABI_HEADERS 101 | # include BOOST_ABI_SUFFIX 102 | #endif 103 | 104 | #ifdef UDEF_SIGSTKSZ 105 | # undef SIGSTKSZ 106 | #endif 107 | -------------------------------------------------------------------------------- /src/windows/stack_traits.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include "boost/coroutine/stack_traits.hpp" 8 | 9 | extern "C" { 10 | #include 11 | } 12 | 13 | //#if defined (BOOST_WINDOWS) || _POSIX_C_SOURCE >= 200112L 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | // x86_64 27 | // test x86_64 before i386 because icc might 28 | // define __i686__ for x86_64 too 29 | #if defined(__x86_64__) || defined(__x86_64) \ 30 | || defined(__amd64__) || defined(__amd64) \ 31 | || defined(_M_X64) || defined(_M_AMD64) 32 | 33 | // Windows seams not to provide a constant or function 34 | // telling the minimal stacksize 35 | # define MIN_STACKSIZE 8 * 1024 36 | #else 37 | # define MIN_STACKSIZE 4 * 1024 38 | #endif 39 | 40 | #ifdef BOOST_HAS_ABI_HEADERS 41 | # include BOOST_ABI_PREFIX 42 | #endif 43 | 44 | namespace { 45 | 46 | std::size_t pagesize() 47 | { 48 | SYSTEM_INFO si; 49 | ::GetSystemInfo(&si); 50 | return static_cast< std::size_t >( si.dwPageSize ); 51 | } 52 | 53 | } 54 | 55 | namespace boost { 56 | namespace coroutines { 57 | 58 | // Windows seams not to provide a limit for the stacksize 59 | // libcoco uses 32k+4k bytes as minimum 60 | bool 61 | stack_traits::is_unbounded() BOOST_NOEXCEPT 62 | { return true; } 63 | 64 | std::size_t 65 | stack_traits::page_size() BOOST_NOEXCEPT 66 | { 67 | static std::size_t size = pagesize(); 68 | return size; 69 | } 70 | 71 | std::size_t 72 | stack_traits::default_size() BOOST_NOEXCEPT 73 | { 74 | std::size_t size = 64 * 1024; // 64 kB 75 | if ( is_unbounded() ) 76 | return (std::max)( size, minimum_size() ); 77 | 78 | BOOST_ASSERT( maximum_size() >= minimum_size() ); 79 | return maximum_size() == minimum_size() 80 | ? minimum_size() 81 | : ( std::min)( size, maximum_size() ); 82 | } 83 | 84 | // because Windows seams not to provide a limit for minimum stacksize 85 | std::size_t 86 | stack_traits::minimum_size() BOOST_NOEXCEPT 87 | { return MIN_STACKSIZE; } 88 | 89 | // because Windows seams not to provide a limit for maximum stacksize 90 | // maximum_size() can never be called (pre-condition ! is_unbounded() ) 91 | std::size_t 92 | stack_traits::maximum_size() BOOST_NOEXCEPT 93 | { 94 | BOOST_ASSERT( ! is_unbounded() ); 95 | return 1 * 1024 * 1024 * 1024; // 1GB 96 | } 97 | 98 | }} 99 | 100 | #ifdef BOOST_HAS_ABI_HEADERS 101 | # include BOOST_ABI_SUFFIX 102 | #endif 103 | -------------------------------------------------------------------------------- /test/Jamfile.v2: -------------------------------------------------------------------------------- 1 | # Boost.Coroutine Library Tests Jamfile 2 | 3 | # Copyright Oliver Kowalke 2009. 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # (See accompanying file LICENSE_1_0.txt or copy at 6 | # http://www.boost.org/LICENSE_1_0.txt) 7 | 8 | import common ; 9 | import feature ; 10 | import indirect ; 11 | import modules ; 12 | import os ; 13 | import testing ; 14 | import toolset ; 15 | 16 | project 17 | : requirements 18 | /boost/context//boost_context 19 | /boost/coroutine//boost_coroutine 20 | /boost/foreach//boost_foreach 21 | /boost/program_options//boost_program_options 22 | /boost/test//boost_unit_test_framework 23 | linux,gcc,on:-fsplit-stack 24 | linux,gcc,on:-DBOOST_USE_SEGMENTED_STACKS 25 | clang,on:-fsplit-stack 26 | clang,on:-DBOOST_USE_SEGMENTED_STACKS 27 | static 28 | multi 29 | ; 30 | 31 | test-suite "coroutine" : 32 | [ run test_asymmetric_coroutine.cpp ] 33 | [ run test_symmetric_coroutine.cpp ] 34 | ; 35 | --------------------------------------------------------------------------------