mirror of
https://github.com/boostorg/coroutine2.git
synced 2025-05-09 23:24:01 +00:00
Merge branch 'develop'
This commit is contained in:
commit
bce46a83a9
@ -1,107 +0,0 @@
|
|||||||
[/
|
|
||||||
Copyright Oliver Kowalke 2014.
|
|
||||||
Distributed under the Boost Software License, Version 1.0.
|
|
||||||
(See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
http://www.boost.org/LICENSE_1_0.txt
|
|
||||||
]
|
|
||||||
|
|
||||||
[section:attributes Attributes]
|
|
||||||
|
|
||||||
Class `attributes` is used to specify parameters required to setup a
|
|
||||||
coroutine's context.
|
|
||||||
|
|
||||||
enum flag_unwind_t
|
|
||||||
{
|
|
||||||
stack_unwind,
|
|
||||||
no_stack_unwind
|
|
||||||
};
|
|
||||||
|
|
||||||
enum flag_fpu_t
|
|
||||||
{
|
|
||||||
fpu_preserved,
|
|
||||||
fpu_not_preserved
|
|
||||||
};
|
|
||||||
|
|
||||||
struct attributes
|
|
||||||
{
|
|
||||||
std::size_t size;
|
|
||||||
flag_unwind_t do_unwind;
|
|
||||||
flag_fpu_t preserve_fpu;
|
|
||||||
|
|
||||||
attributes() noexcept;
|
|
||||||
|
|
||||||
explicit attributes( std::size_t size_) noexcept;
|
|
||||||
|
|
||||||
explicit attributes( flag_unwind_t do_unwind_) noexcept;
|
|
||||||
|
|
||||||
explicit attributes( flag_fpu_t preserve_fpu_) noexcept;
|
|
||||||
|
|
||||||
explicit attributes( std::size_t size_, flag_unwind_t do_unwind_) noexcept;
|
|
||||||
|
|
||||||
explicit attributes( std::size_t size_, flag_fpu_t preserve_fpu_) noexcept;
|
|
||||||
|
|
||||||
explicit attributes( flag_unwind_t do_unwind_, flag_fpu_t preserve_fpu_) noexcept;
|
|
||||||
|
|
||||||
explicit attributes( std::size_t size_, flag_unwind_t do_unwind_, flag_fpu_t preserve_fpu_) noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
[heading `attributes()`]
|
|
||||||
[variablelist
|
|
||||||
[[Effects:] [Default constructor using `boost::context::default_stacksize()`, does unwind
|
|
||||||
the stack after coroutine/generator is complete and preserves FPU registers.]]
|
|
||||||
[[Throws:] [Nothing.]]
|
|
||||||
]
|
|
||||||
|
|
||||||
[heading `attributes( std::size_t size)`]
|
|
||||||
[variablelist
|
|
||||||
[[Effects:] [Argument `size` defines stack size of the new coroutine.
|
|
||||||
Stack unwinding after termination and preserving FPU registers is set by
|
|
||||||
default.]]
|
|
||||||
[[Throws:] [Nothing.]]
|
|
||||||
]
|
|
||||||
|
|
||||||
[heading `attributes( flag_unwind_t do_unwind)`]
|
|
||||||
[variablelist
|
|
||||||
[[Effects:] [Argument `do_unwind` determines if stack will be unwound after
|
|
||||||
termination or not. The default stacksize is used for the new coroutine
|
|
||||||
and FPU registers are preserved.]]
|
|
||||||
[[Throws:] [Nothing.]]
|
|
||||||
]
|
|
||||||
|
|
||||||
[heading `attributes( flag_fpu_t preserve_fpu)`]
|
|
||||||
[variablelist
|
|
||||||
[[Effects:] [Argument `preserve_fpu` determines if FPU register have to be
|
|
||||||
preserved across context switches. The default stacksize is used for the
|
|
||||||
new coroutine and its stack will be unwound after termination.]]
|
|
||||||
[[Throws:] [Nothing.]]
|
|
||||||
]
|
|
||||||
|
|
||||||
[heading `attributes( std::size_t size, flag_unwind_t do_unwind)`]
|
|
||||||
[variablelist
|
|
||||||
[[Effects:] [Arguments `size` and `do_unwind` are given by the user.
|
|
||||||
FPU registers are preserved across each context switch.]]
|
|
||||||
[[Throws:] [Nothing.]]
|
|
||||||
]
|
|
||||||
|
|
||||||
[heading `attributes( std::size_t size, flag_fpu_t preserve_fpu)`]
|
|
||||||
[variablelist
|
|
||||||
[[Effects:] [Arguments `size` and `preserve_fpu` are given by the user.
|
|
||||||
The stack is automatically unwound after coroutine/generator terminates.]]
|
|
||||||
[[Throws:] [Nothing.]]
|
|
||||||
]
|
|
||||||
|
|
||||||
[heading `attributes( flag_unwind_t do_unwind, flag_fpu_t preserve_fpu)`]
|
|
||||||
[variablelist
|
|
||||||
[[Effects:] [Arguments `do_unwind` and `preserve_fpu` are given by the user.
|
|
||||||
The stack gets a default value of `boost::context::default_stacksize()`.]]
|
|
||||||
[[Throws:] [Nothing.]]
|
|
||||||
]
|
|
||||||
|
|
||||||
[heading `attributes( std::size_t size, flag_unwind_t do_unwind, flag_fpu_t preserve_fpu)`]
|
|
||||||
[variablelist
|
|
||||||
[[Effects:] [Arguments `size`, `do_unwind` and `preserve_fpu` are given by the
|
|
||||||
user.]]
|
|
||||||
[[Throws:] [Nothing.]]
|
|
||||||
]
|
|
||||||
|
|
||||||
[endsect]
|
|
@ -46,7 +46,7 @@
|
|||||||
[def __coro_ns__ ['boost::coroutines2]]
|
[def __coro_ns__ ['boost::coroutines2]]
|
||||||
[def __econtext__ ['execution_context]]
|
[def __econtext__ ['execution_context]]
|
||||||
[def __end__ ['std::end()]]
|
[def __end__ ['std::end()]]
|
||||||
[def __fcontext__ ['boost::contexts::fcontext_t]]
|
[def __fcontext__ [@boost:/libs/context/doc/html/context/cc.html#implementation fcontext_t]]
|
||||||
[def __fetch__ ['inbuf::fetch()]]
|
[def __fetch__ ['inbuf::fetch()]]
|
||||||
[def __fixedsize__ ['fixedsize_stack]]
|
[def __fixedsize__ ['fixedsize_stack]]
|
||||||
[def __forced_unwind__ ['detail::forced_unwind]]
|
[def __forced_unwind__ ['detail::forced_unwind]]
|
||||||
@ -73,6 +73,9 @@
|
|||||||
[def __standard_allocator__ ['fixedsize]]
|
[def __standard_allocator__ ['fixedsize]]
|
||||||
[def __start__ ['session::start()]]
|
[def __start__ ['session::start()]]
|
||||||
[def __terminate__ ['std::terminate()]]
|
[def __terminate__ ['std::terminate()]]
|
||||||
|
[def __ucontext__ ['ucontext_t]]
|
||||||
|
[def __winfib__ ['WinFiber]]
|
||||||
|
[def __cc__ ['call/cc]]
|
||||||
[def __underflow__ ['stream_buf::underflow()]]
|
[def __underflow__ ['stream_buf::underflow()]]
|
||||||
[def __yield_context__ ['boost::asio::yield_context]]
|
[def __yield_context__ ['boost::asio::yield_context]]
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ stack (macro SIGSTKSZ on POSIX).
|
|||||||
At this time of writing only GCC (4.7)
|
At this time of writing only GCC (4.7)
|
||||||
[footnote [@http://gcc.gnu.org/wiki/SplitStacks Ian Lance Taylor, Split Stacks in GCC]]
|
[footnote [@http://gcc.gnu.org/wiki/SplitStacks Ian Lance Taylor, Split Stacks in GCC]]
|
||||||
is known to support segmented stacks. With version 1.54 __boost_coroutine__
|
is known to support segmented stacks. With version 1.54 __boost_coroutine__
|
||||||
provides support for segmented stacks.
|
provides support for [link segmented ['segmented stacks]].
|
||||||
|
|
||||||
The destructor releases the associated stack. The implementer is free to
|
The destructor releases the associated stack. The implementer is free to
|
||||||
deallocate the stack or to cache it for later usage.
|
deallocate the stack or to cache it for later usage.
|
||||||
@ -67,15 +67,6 @@ deallocate the stack or to cache it for later usage.
|
|||||||
A coroutine saves and restores registers according to the underlying ABI on
|
A coroutine saves and restores registers according to the underlying ABI on
|
||||||
each context switch (using __boost_context__).
|
each context switch (using __boost_context__).
|
||||||
|
|
||||||
Some applications do not use floating-point registers and can disable preserving
|
|
||||||
FPU registers for performance reasons.
|
|
||||||
|
|
||||||
[note According to the calling convention the FPU registers are preserved by
|
|
||||||
default.]
|
|
||||||
|
|
||||||
On POSIX systems, the coroutine context switch does not preserve signal masks
|
|
||||||
for performance reasons.
|
|
||||||
|
|
||||||
A context switch is done via __push_coro_op__ and __pull_coro_op__.
|
A context switch is done via __push_coro_op__ and __pull_coro_op__.
|
||||||
|
|
||||||
[warning Calling __push_coro_op__ and __pull_coro_op__ from inside the [_same]
|
[warning Calling __push_coro_op__ and __pull_coro_op__ from inside the [_same]
|
||||||
@ -85,11 +76,48 @@ As an example, the code below will result in undefined behaviour:
|
|||||||
|
|
||||||
boost::coroutines2::coroutine<void>::push_type coro(
|
boost::coroutines2::coroutine<void>::push_type coro(
|
||||||
[&](boost::coroutines2::coroutine<void>::pull_type& yield){
|
[&](boost::coroutines2::coroutine<void>::pull_type& yield){
|
||||||
coro();
|
yield();
|
||||||
});
|
});
|
||||||
coro();
|
coro();
|
||||||
|
|
||||||
|
|
||||||
[include asymmetric.qbk]
|
[include asymmetric.qbk]
|
||||||
|
|
||||||
|
|
||||||
|
[section Implementations: fcontext_t, ucontext_t and WinFiber]
|
||||||
|
|
||||||
|
[heading fcontext_t]
|
||||||
|
|
||||||
|
The implementation uses __fcontext__ per default. fcontext_t is based on
|
||||||
|
assembler and not available for all platforms. It provides a much better
|
||||||
|
performance than __ucontext__
|
||||||
|
(the context switch takes two magnitudes of order less CPU cycles) and __winfib__.
|
||||||
|
|
||||||
|
|
||||||
|
[heading ucontext_t]
|
||||||
|
|
||||||
|
As an alternative, [@https://en.wikipedia.org/wiki/Setcontext __ucontext__]
|
||||||
|
can be used by compiling with `BOOST_USE_UCONTEXT` and b2 property `context-impl=ucontext`.
|
||||||
|
__ucontext__ might be available on a broader range of POSIX-platforms but has
|
||||||
|
some (for instance deprecated since POSIX.1-2003, not C99 conform).
|
||||||
|
|
||||||
|
[note __cc__ supports [link segmented ['Segmented stacks]] only with
|
||||||
|
__ucontext__ as its implementation.]
|
||||||
|
|
||||||
|
|
||||||
|
[heading WinFiber]
|
||||||
|
|
||||||
|
With `BOOST_USE_WINFIB` and b2 property `context-impl=winfib` Win32-Fibers are used
|
||||||
|
as implementation for __cc__.
|
||||||
|
|
||||||
|
Because the TIB (thread information block) is not fully described in the MSDN,
|
||||||
|
it might be possible that not all required TIB-parts are swapped.
|
||||||
|
|
||||||
|
[note The first call of __cc__ converts the thread into a Windows fiber by
|
||||||
|
invoking `ConvertThreadToFiber()`. If desired, `ConvertFiberToThread()` has
|
||||||
|
to be called by the user explicitly in order to release resources allocated
|
||||||
|
by `ConvertThreadToFiber()` (e.g. after using boost.context). ]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
@ -15,7 +15,7 @@ always before the parent. Coroutines (the term was introduced by Melvin
|
|||||||
Conway [footnote Conway, Melvin E.. "Design of a Separable Transition-Diagram Compiler".
|
Conway [footnote Conway, Melvin E.. "Design of a Separable Transition-Diagram Compiler".
|
||||||
Commun. ACM, Volume 6 Issue 7, July 1963, Article No. 7]),
|
Commun. ACM, Volume 6 Issue 7, July 1963, Article No. 7]),
|
||||||
are a generalization of routines (Donald Knuth [footnote Knuth, Donald Ervin (1997).
|
are a generalization of routines (Donald Knuth [footnote Knuth, Donald Ervin (1997).
|
||||||
"Fundamental Algorithms. The Art of Computer Programming 1", (3rd ed.)].
|
"Fundamental Algorithms. The Art of Computer Programming 1", (3rd ed.)]).
|
||||||
The principal difference between coroutines and routines
|
The principal difference between coroutines and routines
|
||||||
is that a coroutine enables explicit suspend and resume of its progress via
|
is that a coroutine enables explicit suspend and resume of its progress via
|
||||||
additional operations by preserving execution state and thus provides an
|
additional operations by preserving execution state and thus provides an
|
||||||
|
@ -7,24 +7,18 @@
|
|||||||
|
|
||||||
[section:performance Performance]
|
[section:performance Performance]
|
||||||
|
|
||||||
Performance of __boost_coroutine__ was measured on the platforms shown in the
|
Performance measurements were taken using `std::chrono::highresolution_clock`,
|
||||||
following table. Performance measurements were taken using `rdtsc` and
|
with overhead corrections.
|
||||||
`boost::chrono::high_resolution_clock`, with overhead corrections, on x86
|
The code was compiled with gcc-6.3.1, using build options:
|
||||||
platforms. In each case, cache warm-up was accounted for, and the one
|
variant = release, optimization = speed.
|
||||||
running thread was pinned to a single CPU.
|
Tests were executed on dual Intel XEON E5 2620 2.2GHz, 16C/32T, 64GB RAM,
|
||||||
|
running Linux (x86_64).
|
||||||
|
|
||||||
[table Performance of asymmetric coroutines (using execution_context)
|
[table Performance of context switch
|
||||||
|
[[using __fcontext__] [using [@boost:/libs/context/doc/html/context/cc.html#implementation ucontext_t]]]
|
||||||
[
|
[
|
||||||
[Platform]
|
[26 ns / 56 CPU cycles]
|
||||||
[switch]
|
[542 ns / 1146 CPU cycles]
|
||||||
[construction (protected stack-allocator)]
|
|
||||||
[construction (standard stack-allocator)]
|
|
||||||
]
|
|
||||||
[
|
|
||||||
[x86_64 [footnote Intel Core i7-4770S 3.10GHz]]
|
|
||||||
[16 ns / 50 cycles]
|
|
||||||
[7 \u00b5s / 22133 cycles]
|
|
||||||
[1.7 \u00b5s / 5383 cycles]
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -183,6 +183,7 @@ address of the stack.]]
|
|||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
[#segmented]
|
||||||
[section:segmented Class ['segmented_stack]]
|
[section:segmented Class ['segmented_stack]]
|
||||||
|
|
||||||
__boost_coroutine__ supports usage of a __segmented__, e. g. the size of
|
__boost_coroutine__ supports usage of a __segmented__, e. g. the size of
|
||||||
@ -193,11 +194,13 @@ In contrast to __protected_fixedsize__ and __fixedsize__ it creates a
|
|||||||
stack which grows on demand.
|
stack which grows on demand.
|
||||||
|
|
||||||
[note Segmented stacks are currently only supported by [*gcc] from version
|
[note Segmented stacks are currently only supported by [*gcc] from version
|
||||||
[*4.7] and [*clang] from version [*3.4] onwards. In order to use a
|
[*4.7] [*clang] from version [*3.4] onwards. In order to use a
|
||||||
__segmented_stack__ __boost_coroutine__ must be built with
|
__segmented_stack__ __boost_context__ must be built with
|
||||||
property `segmented-stacks`, e.g. [*toolset=gcc segmented-stacks=on] at b2/bjam
|
property `segmented-stacks`, e.g. [*toolset=gcc segmented-stacks=on] and
|
||||||
|
applying `BOOST_USE_SEGMENTED_STACKS` and `BOOST_USE_UCONTEXT` at b2/bjam
|
||||||
command line.]
|
command line.]
|
||||||
|
|
||||||
|
|
||||||
#include <boost/coroutine2/segmented_stack.hpp>
|
#include <boost/coroutine2/segmented_stack.hpp>
|
||||||
|
|
||||||
struct segmented_stack {
|
struct segmented_stack {
|
||||||
|
@ -40,6 +40,6 @@ exe parser
|
|||||||
: parser.cpp
|
: parser.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
#exe segmented
|
exe segmented
|
||||||
# : segmented.cpp
|
: segmented.cpp
|
||||||
# ;
|
;
|
||||||
|
@ -6,8 +6,7 @@
|
|||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
#include <boost/config.hpp>
|
|
||||||
|
|
||||||
#include <boost/coroutine2/all.hpp>
|
#include <boost/coroutine2/all.hpp>
|
||||||
|
|
||||||
@ -16,17 +15,13 @@ __declspec(noinline) void access( char *buf);
|
|||||||
#else // GCC
|
#else // GCC
|
||||||
void access( char *buf) __attribute__ ((noinline));
|
void access( char *buf) __attribute__ ((noinline));
|
||||||
#endif
|
#endif
|
||||||
void access( char *buf)
|
void access( char *buf) {
|
||||||
{
|
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void bar( int i)
|
void bar( int i) {
|
||||||
{
|
|
||||||
char buf[4 * 1024];
|
char buf[4 * 1024];
|
||||||
|
if ( i > 0) {
|
||||||
if ( i > 0)
|
|
||||||
{
|
|
||||||
access( buf);
|
access( buf);
|
||||||
std::cout << i << ". iteration" << std::endl;
|
std::cout << i << ". iteration" << std::endl;
|
||||||
bar( i - 1);
|
bar( i - 1);
|
||||||
@ -35,20 +30,19 @@ void bar( int i)
|
|||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
int count = 384;
|
int count = 384;
|
||||||
|
#if defined(BOOST_USE_SEGMENTED_STACKS)
|
||||||
std::cout << "using segmented_stack stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
|
std::cout << "using segmented_stack stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
|
||||||
std::cout << "initial stack size = " << boost::context::segmented_stack::traits_type::default_size() / 1024 << "kB" << std::endl;
|
std::cout << "initial stack size = " << boost::context::segmented_stack::traits_type::default_size() / 1024 << "kB" << std::endl;
|
||||||
std::cout << "application should not fail" << std::endl;
|
std::cout << "application should not fail" << std::endl;
|
||||||
|
#else
|
||||||
boost::coroutines2::coroutine< void >::push_type sink(
|
std::cout << "using standard stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
|
||||||
[&]( boost::coroutines2::coroutine< void >::pull_type & source) {
|
std::cout << "initial stack size = " << boost::context::fixedsize_stack::traits_type::default_size() / 1024 << "kB" << std::endl;
|
||||||
|
std::cout << "application might fail" << std::endl;
|
||||||
|
#endif
|
||||||
|
boost::coroutines2::coroutine< void >::pull_type coro{
|
||||||
|
[count](boost::coroutines2::coroutine< void >::push_type & coro){
|
||||||
bar( count);
|
bar( count);
|
||||||
source();
|
}};
|
||||||
});
|
std::cout << "main: done" << std::endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
sink();
|
|
||||||
|
|
||||||
std::cout << "main: Done" << std::endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
@ -29,26 +29,14 @@ class push_coroutine;
|
|||||||
#include <boost/coroutine2/detail/pull_coroutine.hpp>
|
#include <boost/coroutine2/detail/pull_coroutine.hpp>
|
||||||
#include <boost/coroutine2/detail/push_coroutine.hpp>
|
#include <boost/coroutine2/detail/push_coroutine.hpp>
|
||||||
|
|
||||||
#if defined(BOOST_EXECUTION_CONTEXT)
|
|
||||||
# if (BOOST_EXECUTION_CONTEXT==1)
|
|
||||||
# include <boost/coroutine2/detail/pull_control_block_ecv1.hpp>
|
|
||||||
# include <boost/coroutine2/detail/push_control_block_ecv1.hpp>
|
|
||||||
# else
|
|
||||||
#include <boost/coroutine2/detail/pull_control_block_cc.hpp>
|
#include <boost/coroutine2/detail/pull_control_block_cc.hpp>
|
||||||
#include <boost/coroutine2/detail/push_control_block_cc.hpp>
|
#include <boost/coroutine2/detail/push_control_block_cc.hpp>
|
||||||
# endif
|
|
||||||
|
|
||||||
#include <boost/coroutine2/detail/pull_coroutine.ipp>
|
#include <boost/coroutine2/detail/pull_coroutine.ipp>
|
||||||
#include <boost/coroutine2/detail/push_coroutine.ipp>
|
#include <boost/coroutine2/detail/push_coroutine.ipp>
|
||||||
|
|
||||||
# if (BOOST_EXECUTION_CONTEXT==1)
|
|
||||||
# include <boost/coroutine2/detail/pull_control_block_ecv1.ipp>
|
|
||||||
# include <boost/coroutine2/detail/push_control_block_ecv1.ipp>
|
|
||||||
# else
|
|
||||||
#include <boost/coroutine2/detail/pull_control_block_cc.ipp>
|
#include <boost/coroutine2/detail/pull_control_block_cc.ipp>
|
||||||
#include <boost/coroutine2/detail/push_control_block_cc.ipp>
|
#include <boost/coroutine2/detail/push_control_block_cc.ipp>
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BOOST_HAS_ABI_HEADERS
|
#ifdef BOOST_HAS_ABI_HEADERS
|
||||||
# include BOOST_ABI_SUFFIX
|
# include BOOST_ABI_SUFFIX
|
||||||
|
@ -1,119 +0,0 @@
|
|||||||
|
|
||||||
// Copyright Oliver Kowalke 2014.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
#ifndef BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_HPP
|
|
||||||
#define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_HPP
|
|
||||||
|
|
||||||
#include <exception>
|
|
||||||
#include <functional>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
#include <boost/context/execution_context.hpp>
|
|
||||||
|
|
||||||
#include <boost/coroutine2/detail/state.hpp>
|
|
||||||
|
|
||||||
#ifdef BOOST_HAS_ABI_HEADERS
|
|
||||||
# include BOOST_ABI_PREFIX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
namespace coroutines2 {
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
struct pull_coroutine< T >::control_block {
|
|
||||||
boost::context::execution_context ctx;
|
|
||||||
typename push_coroutine< T >::control_block * other;
|
|
||||||
state_t state;
|
|
||||||
std::exception_ptr except;
|
|
||||||
bool bvalid;
|
|
||||||
typename std::aligned_storage< sizeof( T), alignof( T) >::type storage;
|
|
||||||
|
|
||||||
static void destroy( control_block * cb) noexcept;
|
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
|
||||||
control_block( context::preallocated, StackAllocator, Fn &&);
|
|
||||||
|
|
||||||
control_block( typename push_coroutine< T >::control_block *, boost::context::execution_context const&) noexcept;
|
|
||||||
|
|
||||||
~control_block() noexcept;
|
|
||||||
|
|
||||||
control_block( control_block &) = delete;
|
|
||||||
control_block & operator=( control_block &) = delete;
|
|
||||||
|
|
||||||
void deallocate() noexcept;
|
|
||||||
|
|
||||||
void resume();
|
|
||||||
|
|
||||||
void set( T *);
|
|
||||||
|
|
||||||
T & get() noexcept;
|
|
||||||
|
|
||||||
bool valid() const noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
struct pull_coroutine< T & >::control_block {
|
|
||||||
boost::context::execution_context ctx;
|
|
||||||
typename push_coroutine< T & >::control_block * other;
|
|
||||||
state_t state;
|
|
||||||
std::exception_ptr except;
|
|
||||||
T * t;
|
|
||||||
|
|
||||||
static void destroy( control_block * cb) noexcept;
|
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
|
||||||
control_block( context::preallocated, StackAllocator, Fn &&);
|
|
||||||
|
|
||||||
control_block( typename push_coroutine< T & >::control_block *, boost::context::execution_context const&) noexcept;
|
|
||||||
|
|
||||||
~control_block() noexcept;
|
|
||||||
|
|
||||||
control_block( control_block &) = delete;
|
|
||||||
control_block & operator=( control_block &) = delete;
|
|
||||||
|
|
||||||
void deallocate() noexcept;
|
|
||||||
|
|
||||||
void resume();
|
|
||||||
|
|
||||||
T & get() noexcept;
|
|
||||||
|
|
||||||
bool valid() const noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct pull_coroutine< void >::control_block {
|
|
||||||
boost::context::execution_context ctx;
|
|
||||||
push_coroutine< void >::control_block * other;
|
|
||||||
state_t state;
|
|
||||||
std::exception_ptr except;
|
|
||||||
|
|
||||||
static void destroy( control_block * cb) noexcept;
|
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
|
||||||
control_block( context::preallocated, StackAllocator, Fn &&);
|
|
||||||
|
|
||||||
control_block( push_coroutine< void >::control_block *, boost::context::execution_context const&) noexcept;
|
|
||||||
|
|
||||||
~control_block() noexcept;
|
|
||||||
|
|
||||||
control_block( control_block &) = delete;
|
|
||||||
control_block & operator=( control_block &) = delete;
|
|
||||||
|
|
||||||
void deallocate() noexcept;
|
|
||||||
|
|
||||||
void resume();
|
|
||||||
|
|
||||||
bool valid() const noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
}}}
|
|
||||||
|
|
||||||
#ifdef BOOST_HAS_ABI_HEADERS
|
|
||||||
# include BOOST_ABI_SUFFIX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_HPP
|
|
@ -1,431 +0,0 @@
|
|||||||
|
|
||||||
// Copyright Oliver Kowalke 2014.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
#ifndef BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP
|
|
||||||
#define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP
|
|
||||||
|
|
||||||
#include <exception>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
|
|
||||||
#include <boost/context/execution_context.hpp>
|
|
||||||
|
|
||||||
#include <boost/coroutine2/detail/config.hpp>
|
|
||||||
#include <boost/coroutine2/detail/decay_copy.hpp>
|
|
||||||
#include <boost/coroutine2/detail/forced_unwind.hpp>
|
|
||||||
#include <boost/coroutine2/detail/state.hpp>
|
|
||||||
#include <boost/coroutine2/detail/wrap.hpp>
|
|
||||||
|
|
||||||
#ifdef BOOST_HAS_ABI_HEADERS
|
|
||||||
# include BOOST_ABI_PREFIX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
namespace coroutines2 {
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
// pull_coroutine< T >
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
void
|
|
||||||
pull_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
|
|
||||||
boost::context::execution_context ctx = cb->ctx;
|
|
||||||
// destroy control structure
|
|
||||||
cb->state |= state_t::destroy;
|
|
||||||
cb->~control_block();
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
template< typename StackAllocator, typename Fn >
|
|
||||||
pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
|
||||||
Fn && fn) :
|
|
||||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
|
||||||
wrap( [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void *) mutable noexcept {
|
|
||||||
// create synthesized push_coroutine< T >
|
|
||||||
typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
|
||||||
push_coroutine< T > synthesized{ & synthesized_cb };
|
|
||||||
other = & synthesized_cb;
|
|
||||||
if ( state_t::none == ( state & state_t::destroy) ) {
|
|
||||||
try {
|
|
||||||
auto fn = std::move( fn_);
|
|
||||||
// call coroutine-fn with synthesized push_coroutine as argument
|
|
||||||
fn( synthesized);
|
|
||||||
} catch ( forced_unwind const&) {
|
|
||||||
// do nothing for unwinding exception
|
|
||||||
} catch (...) {
|
|
||||||
// store other exceptions in exception-pointer
|
|
||||||
except = std::current_exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set termination flags
|
|
||||||
state |= state_t::complete;
|
|
||||||
// jump back to ctx
|
|
||||||
other->ctx();
|
|
||||||
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
|
||||||
},
|
|
||||||
std::forward< Fn >( fn),
|
|
||||||
boost::context::execution_context::current() ) },
|
|
||||||
#else
|
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
|
||||||
[this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
|
|
||||||
// create synthesized push_coroutine< T >
|
|
||||||
typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
|
||||||
push_coroutine< T > synthesized{ & synthesized_cb };
|
|
||||||
other = & synthesized_cb;
|
|
||||||
if ( state_t::none == ( state & state_t::destroy) ) {
|
|
||||||
try {
|
|
||||||
auto fn = std::move( fn_);
|
|
||||||
// call coroutine-fn with synthesized push_coroutine as argument
|
|
||||||
fn( synthesized);
|
|
||||||
} catch ( forced_unwind const&) {
|
|
||||||
// do nothing for unwinding exception
|
|
||||||
} catch (...) {
|
|
||||||
// store other exceptions in exception-pointer
|
|
||||||
except = std::current_exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set termination flags
|
|
||||||
state |= state_t::complete;
|
|
||||||
// jump back to ctx
|
|
||||||
other->ctx();
|
|
||||||
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
|
||||||
}},
|
|
||||||
#endif
|
|
||||||
other{ nullptr },
|
|
||||||
state{ state_t::unwind },
|
|
||||||
except{},
|
|
||||||
bvalid{ false },
|
|
||||||
storage{} {
|
|
||||||
// enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
|
|
||||||
set( static_cast< T * >( ctx() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
|
|
||||||
boost::context::execution_context const& ctx_) noexcept :
|
|
||||||
ctx{ ctx_ },
|
|
||||||
other{ cb },
|
|
||||||
state{ state_t::none },
|
|
||||||
except{},
|
|
||||||
bvalid{ false },
|
|
||||||
storage{} {
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
pull_coroutine< T >::control_block::~control_block() {
|
|
||||||
if ( state_t::none == ( state & state_t::complete) &&
|
|
||||||
state_t::none != ( state & state_t::unwind) ) {
|
|
||||||
// unwind coroutine stack
|
|
||||||
other->ctx = boost::context::execution_context::current();
|
|
||||||
ctx( context::exec_ontop_arg, unwind_coroutine);
|
|
||||||
}
|
|
||||||
// destroy data if it set
|
|
||||||
if ( bvalid) {
|
|
||||||
reinterpret_cast< T * >( std::addressof( storage) )->~T();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
void
|
|
||||||
pull_coroutine< T >::control_block::deallocate() noexcept {
|
|
||||||
if ( state_t::none != ( state & state_t::unwind) ) {
|
|
||||||
destroy( this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
void
|
|
||||||
pull_coroutine< T >::control_block::resume() {
|
|
||||||
other->ctx = boost::context::execution_context::current();
|
|
||||||
set( static_cast< T * >( ctx() ) );
|
|
||||||
if ( except) {
|
|
||||||
std::rethrow_exception( except);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
void
|
|
||||||
pull_coroutine< T >::control_block::set( T * t) {
|
|
||||||
// destroy data if it set
|
|
||||||
if ( bvalid) {
|
|
||||||
reinterpret_cast< T * >( std::addressof( storage) )->~T();
|
|
||||||
}
|
|
||||||
if ( nullptr != t) {
|
|
||||||
::new ( static_cast< void * >( std::addressof( storage) ) ) T( std::move( * t) );
|
|
||||||
bvalid = true;
|
|
||||||
} else {
|
|
||||||
bvalid = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
T &
|
|
||||||
pull_coroutine< T >::control_block::get() noexcept {
|
|
||||||
return * reinterpret_cast< T * >( std::addressof( storage) );
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
bool
|
|
||||||
pull_coroutine< T >::control_block::valid() const noexcept {
|
|
||||||
return nullptr != other && state_t::none == ( state & state_t::complete) && bvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// pull_coroutine< T & >
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
void
|
|
||||||
pull_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
|
|
||||||
boost::context::execution_context ctx = cb->ctx;
|
|
||||||
// destroy control structure
|
|
||||||
cb->state |= state_t::destroy;
|
|
||||||
cb->~control_block();
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
template< typename StackAllocator, typename Fn >
|
|
||||||
pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
|
||||||
Fn && fn) :
|
|
||||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
|
||||||
wrap( [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void *) mutable noexcept {
|
|
||||||
// create synthesized push_coroutine< T >
|
|
||||||
typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
|
||||||
push_coroutine< T & > synthesized{ & synthesized_cb };
|
|
||||||
other = & synthesized_cb;
|
|
||||||
if ( state_t::none == ( state & state_t::destroy) ) {
|
|
||||||
try {
|
|
||||||
auto fn = std::move( fn_);
|
|
||||||
// call coroutine-fn with synthesized push_coroutine as argument
|
|
||||||
fn( synthesized);
|
|
||||||
} catch ( forced_unwind const&) {
|
|
||||||
// do nothing for unwinding exception
|
|
||||||
} catch (...) {
|
|
||||||
// store other exceptions in exception-pointer
|
|
||||||
except = std::current_exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set termination flags
|
|
||||||
state |= state_t::complete;
|
|
||||||
// jump back to ctx
|
|
||||||
other->ctx();
|
|
||||||
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
|
||||||
},
|
|
||||||
std::forward< Fn >( fn),
|
|
||||||
boost::context::execution_context::current() ) },
|
|
||||||
#else
|
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
|
||||||
[this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
|
|
||||||
// create synthesized push_coroutine< T >
|
|
||||||
typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
|
||||||
push_coroutine< T & > synthesized{ & synthesized_cb };
|
|
||||||
other = & synthesized_cb;
|
|
||||||
if ( state_t::none == ( state & state_t::destroy) ) {
|
|
||||||
try {
|
|
||||||
auto fn = std::move( fn_);
|
|
||||||
// call coroutine-fn with synthesized push_coroutine as argument
|
|
||||||
fn( synthesized);
|
|
||||||
} catch ( forced_unwind const&) {
|
|
||||||
// do nothing for unwinding exception
|
|
||||||
} catch (...) {
|
|
||||||
// store other exceptions in exception-pointer
|
|
||||||
except = std::current_exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set termination flags
|
|
||||||
state |= state_t::complete;
|
|
||||||
// jump back to ctx
|
|
||||||
other->ctx();
|
|
||||||
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
|
||||||
}},
|
|
||||||
#endif
|
|
||||||
other{ nullptr },
|
|
||||||
state{ state_t::unwind },
|
|
||||||
except{},
|
|
||||||
t{ nullptr } {
|
|
||||||
// enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
|
|
||||||
t = static_cast< T * >( ctx() );
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
|
|
||||||
boost::context::execution_context const& ctx_) noexcept :
|
|
||||||
ctx{ ctx_ },
|
|
||||||
other{ cb },
|
|
||||||
state{ state_t::none },
|
|
||||||
except{},
|
|
||||||
t( nullptr) {
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
pull_coroutine< T & >::control_block::~control_block() {
|
|
||||||
if ( state_t::none == ( state & state_t::complete) &&
|
|
||||||
state_t::none != ( state & state_t::unwind) ) {
|
|
||||||
// unwind coroutine stack
|
|
||||||
other->ctx = boost::context::execution_context::current();
|
|
||||||
ctx( context::exec_ontop_arg, unwind_coroutine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
void
|
|
||||||
pull_coroutine< T & >::control_block::deallocate() noexcept {
|
|
||||||
if ( state_t::none != ( state & state_t::unwind) ) {
|
|
||||||
destroy( this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
void
|
|
||||||
pull_coroutine< T & >::control_block::resume() {
|
|
||||||
other->ctx = boost::context::execution_context::current();
|
|
||||||
t = static_cast< T * >( ctx() );
|
|
||||||
if ( except) {
|
|
||||||
std::rethrow_exception( except);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
T &
|
|
||||||
pull_coroutine< T & >::control_block::get() noexcept {
|
|
||||||
return * static_cast< T * >( t);
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
bool
|
|
||||||
pull_coroutine< T & >::control_block::valid() const noexcept {
|
|
||||||
return nullptr != other && state_t::none == ( state & state_t::complete) && nullptr != t;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// pull_coroutine< void >
|
|
||||||
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
pull_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
|
|
||||||
boost::context::execution_context ctx = cb->ctx;
|
|
||||||
// destroy control structure
|
|
||||||
cb->state |= state_t::destroy;
|
|
||||||
cb->~control_block();
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
|
||||||
pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
|
||||||
Fn && fn) :
|
|
||||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
|
||||||
wrap( [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void *) mutable noexcept {
|
|
||||||
// create synthesized push_coroutine< T >
|
|
||||||
typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
|
||||||
push_coroutine< void > synthesized{ & synthesized_cb };
|
|
||||||
other = & synthesized_cb;
|
|
||||||
if ( state_t::none == ( state & state_t::destroy) ) {
|
|
||||||
try {
|
|
||||||
auto fn = std::move( fn_);
|
|
||||||
// call coroutine-fn with synthesized push_coroutine as argument
|
|
||||||
fn( synthesized);
|
|
||||||
} catch ( forced_unwind const&) {
|
|
||||||
// do nothing for unwinding exception
|
|
||||||
} catch (...) {
|
|
||||||
// store other exceptions in exception-pointer
|
|
||||||
except = std::current_exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set termination flags
|
|
||||||
state |= state_t::complete;
|
|
||||||
// jump back to ctx
|
|
||||||
other->ctx();
|
|
||||||
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
|
||||||
},
|
|
||||||
std::forward< Fn >( fn),
|
|
||||||
boost::context::execution_context::current() ) },
|
|
||||||
#else
|
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
|
||||||
[this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
|
|
||||||
// create synthesized push_coroutine< T >
|
|
||||||
typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
|
||||||
push_coroutine< void > synthesized{ & synthesized_cb };
|
|
||||||
other = & synthesized_cb;
|
|
||||||
if ( state_t::none == ( state & state_t::destroy) ) {
|
|
||||||
try {
|
|
||||||
auto fn = std::move( fn_);
|
|
||||||
// call coroutine-fn with synthesized push_coroutine as argument
|
|
||||||
fn( synthesized);
|
|
||||||
} catch ( forced_unwind const&) {
|
|
||||||
// do nothing for unwinding exception
|
|
||||||
} catch (...) {
|
|
||||||
// store other exceptions in exception-pointer
|
|
||||||
except = std::current_exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set termination flags
|
|
||||||
state |= state_t::complete;
|
|
||||||
// jump back to ctx
|
|
||||||
other->ctx();
|
|
||||||
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
|
||||||
}},
|
|
||||||
#endif
|
|
||||||
other{ nullptr },
|
|
||||||
state{ state_t::unwind },
|
|
||||||
except{} {
|
|
||||||
// enter coroutine-fn in order to have first value available after ctor returns
|
|
||||||
ctx();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
|
|
||||||
boost::context::execution_context const& ctx_) noexcept :
|
|
||||||
ctx{ ctx_ },
|
|
||||||
other{ cb },
|
|
||||||
state{ state_t::none },
|
|
||||||
except{} {
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
pull_coroutine< void >::control_block::~control_block() {
|
|
||||||
if ( state_t::none == ( state & state_t::complete) &&
|
|
||||||
state_t::none != ( state & state_t::unwind) ) {
|
|
||||||
// unwind coroutine stack
|
|
||||||
other->ctx = boost::context::execution_context::current();
|
|
||||||
ctx( context::exec_ontop_arg, unwind_coroutine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
pull_coroutine< void >::control_block::deallocate() noexcept {
|
|
||||||
if ( state_t::none != ( state & state_t::unwind) ) {
|
|
||||||
destroy( this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
pull_coroutine< void >::control_block::resume() {
|
|
||||||
other->ctx = boost::context::execution_context::current();
|
|
||||||
ctx();
|
|
||||||
if ( except) {
|
|
||||||
std::rethrow_exception( except);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
bool
|
|
||||||
pull_coroutine< void >::control_block::valid() const noexcept {
|
|
||||||
return nullptr != other && state_t::none == ( state & state_t::complete);
|
|
||||||
}
|
|
||||||
|
|
||||||
}}}
|
|
||||||
|
|
||||||
#ifdef BOOST_HAS_ABI_HEADERS
|
|
||||||
# include BOOST_ABI_SUFFIX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP
|
|
@ -1,111 +0,0 @@
|
|||||||
|
|
||||||
// Copyright Oliver Kowalke 2014.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
#ifndef BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_HPP
|
|
||||||
#define BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_HPP
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
#include <boost/context/execution_context.hpp>
|
|
||||||
|
|
||||||
#include <boost/coroutine2/detail/state.hpp>
|
|
||||||
|
|
||||||
#ifdef BOOST_HAS_ABI_HEADERS
|
|
||||||
# include BOOST_ABI_PREFIX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
namespace coroutines2 {
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
struct push_coroutine< T >::control_block {
|
|
||||||
boost::context::execution_context ctx;
|
|
||||||
typename pull_coroutine< T >::control_block * other;
|
|
||||||
state_t state;
|
|
||||||
std::exception_ptr except;
|
|
||||||
|
|
||||||
static void destroy( control_block * cb) noexcept;
|
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
|
||||||
control_block( context::preallocated, StackAllocator, Fn &&);
|
|
||||||
|
|
||||||
control_block( typename pull_coroutine< T >::control_block *, boost::context::execution_context const&) noexcept;
|
|
||||||
|
|
||||||
~control_block() noexcept;
|
|
||||||
|
|
||||||
control_block( control_block &) = delete;
|
|
||||||
control_block & operator=( control_block &) = delete;
|
|
||||||
|
|
||||||
void deallocate() noexcept;
|
|
||||||
|
|
||||||
void resume( T const&);
|
|
||||||
|
|
||||||
void resume( T &&);
|
|
||||||
|
|
||||||
bool valid() const noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
struct push_coroutine< T & >::control_block {
|
|
||||||
boost::context::execution_context ctx;
|
|
||||||
typename pull_coroutine< T & >::control_block * other;
|
|
||||||
state_t state;
|
|
||||||
std::exception_ptr except;
|
|
||||||
|
|
||||||
static void destroy( control_block * cb) noexcept;
|
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
|
||||||
control_block( context::preallocated, StackAllocator, Fn &&);
|
|
||||||
|
|
||||||
control_block( typename pull_coroutine< T & >::control_block *, boost::context::execution_context const&) noexcept;
|
|
||||||
|
|
||||||
~control_block() noexcept;
|
|
||||||
|
|
||||||
control_block( control_block &) = delete;
|
|
||||||
control_block & operator=( control_block &) = delete;
|
|
||||||
|
|
||||||
void deallocate() noexcept;
|
|
||||||
|
|
||||||
void resume( T &);
|
|
||||||
|
|
||||||
bool valid() const noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct push_coroutine< void >::control_block {
|
|
||||||
boost::context::execution_context ctx;
|
|
||||||
pull_coroutine< void >::control_block * other;
|
|
||||||
state_t state;
|
|
||||||
std::exception_ptr except;
|
|
||||||
|
|
||||||
static void destroy( control_block * cb) noexcept;
|
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
|
||||||
control_block( context::preallocated, StackAllocator, Fn &&);
|
|
||||||
|
|
||||||
control_block( pull_coroutine< void >::control_block *, boost::context::execution_context const&) noexcept;
|
|
||||||
|
|
||||||
~control_block() noexcept;
|
|
||||||
|
|
||||||
control_block( control_block &) = delete;
|
|
||||||
control_block & operator=( control_block &) = delete;
|
|
||||||
|
|
||||||
void deallocate() noexcept;
|
|
||||||
|
|
||||||
void resume();
|
|
||||||
|
|
||||||
bool valid() const noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
}}}
|
|
||||||
|
|
||||||
#ifdef BOOST_HAS_ABI_HEADERS
|
|
||||||
# include BOOST_ABI_SUFFIX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_HPP
|
|
@ -1,428 +0,0 @@
|
|||||||
|
|
||||||
// Copyright Oliver Kowalke 2014.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
#ifndef BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP
|
|
||||||
#define BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <exception>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
|
|
||||||
#include <boost/context/execution_context.hpp>
|
|
||||||
|
|
||||||
#include <boost/coroutine2/detail/config.hpp>
|
|
||||||
#include <boost/coroutine2/detail/decay_copy.hpp>
|
|
||||||
#include <boost/coroutine2/detail/forced_unwind.hpp>
|
|
||||||
#include <boost/coroutine2/detail/state.hpp>
|
|
||||||
#include <boost/coroutine2/detail/wrap.hpp>
|
|
||||||
|
|
||||||
#ifdef BOOST_HAS_ABI_HEADERS
|
|
||||||
# include BOOST_ABI_PREFIX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
namespace coroutines2 {
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
// push_coroutine< T >
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
void
|
|
||||||
push_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
|
|
||||||
boost::context::execution_context ctx = cb->ctx;
|
|
||||||
// destroy control structure
|
|
||||||
cb->state |= state_t::destroy;
|
|
||||||
cb->~control_block();
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
template< typename StackAllocator, typename Fn >
|
|
||||||
push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
|
||||||
Fn && fn) :
|
|
||||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
|
||||||
wrap( [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void * vp) mutable noexcept {
|
|
||||||
// create synthesized pull_coroutine< T >
|
|
||||||
typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
|
||||||
pull_coroutine< T > synthesized{ & synthesized_cb };
|
|
||||||
other = & synthesized_cb;
|
|
||||||
if ( state_t::none == ( state & state_t::destroy) ) {
|
|
||||||
try {
|
|
||||||
// jump back to ctor
|
|
||||||
T * t = static_cast< T * >( ctx() );
|
|
||||||
// set transferred value
|
|
||||||
synthesized_cb.set( t);
|
|
||||||
auto fn = std::move( fn_);
|
|
||||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
|
||||||
fn( synthesized);
|
|
||||||
} catch ( forced_unwind const&) {
|
|
||||||
// do nothing for unwinding exception
|
|
||||||
} catch (...) {
|
|
||||||
// store other exceptions in exception-pointer
|
|
||||||
except = std::current_exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set termination flags
|
|
||||||
state |= state_t::complete;
|
|
||||||
// jump back to ctx
|
|
||||||
other->ctx();
|
|
||||||
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
|
||||||
},
|
|
||||||
std::forward< Fn >( fn),
|
|
||||||
boost::context::execution_context::current() ) },
|
|
||||||
#else
|
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
|
||||||
[this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
|
|
||||||
// create synthesized pull_coroutine< T >
|
|
||||||
typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
|
||||||
pull_coroutine< T > synthesized{ & synthesized_cb };
|
|
||||||
other = & synthesized_cb;
|
|
||||||
if ( state_t::none == ( state & state_t::destroy) ) {
|
|
||||||
try {
|
|
||||||
// jump back to ctor
|
|
||||||
T * t = static_cast< T * >( ctx() );
|
|
||||||
// set transferred value
|
|
||||||
synthesized_cb.set( t);
|
|
||||||
auto fn = std::move( fn_);
|
|
||||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
|
||||||
fn( synthesized);
|
|
||||||
} catch ( forced_unwind const&) {
|
|
||||||
// do nothing for unwinding exception
|
|
||||||
} catch (...) {
|
|
||||||
// store other exceptions in exception-pointer
|
|
||||||
except = std::current_exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set termination flags
|
|
||||||
state |= state_t::complete;
|
|
||||||
// jump back to ctx
|
|
||||||
other->ctx();
|
|
||||||
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
|
||||||
}},
|
|
||||||
#endif
|
|
||||||
other{ nullptr },
|
|
||||||
state{ state_t::unwind },
|
|
||||||
except{} {
|
|
||||||
// enter coroutine-fn in order to get other set
|
|
||||||
ctx();
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb,
|
|
||||||
boost::context::execution_context const& ctx_) noexcept :
|
|
||||||
ctx{ ctx_ },
|
|
||||||
other{ cb },
|
|
||||||
state{ state_t::none },
|
|
||||||
except{} {
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
push_coroutine< T >::control_block::~control_block() {
|
|
||||||
if ( state_t::none == ( state & state_t::complete) &&
|
|
||||||
state_t::none != ( state & state_t::unwind) ) {
|
|
||||||
// unwind coroutine stack
|
|
||||||
other->ctx = boost::context::execution_context::current();
|
|
||||||
ctx( context::exec_ontop_arg, unwind_coroutine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
void
|
|
||||||
push_coroutine< T >::control_block::deallocate() noexcept {
|
|
||||||
if ( state_t::none != ( state & state_t::unwind) ) {
|
|
||||||
destroy( this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
void
|
|
||||||
push_coroutine< T >::control_block::resume( T const& t) {
|
|
||||||
other->ctx = boost::context::execution_context::current();
|
|
||||||
// pass an pointer to other context
|
|
||||||
ctx( const_cast< T * >( & t) );
|
|
||||||
if ( except) {
|
|
||||||
std::rethrow_exception( except);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
void
|
|
||||||
push_coroutine< T >::control_block::resume( T && t) {
|
|
||||||
other->ctx = boost::context::execution_context::current();
|
|
||||||
// pass an pointer to other context
|
|
||||||
ctx( std::addressof( t) );
|
|
||||||
if ( except) {
|
|
||||||
std::rethrow_exception( except);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
bool
|
|
||||||
push_coroutine< T >::control_block::valid() const noexcept {
|
|
||||||
return state_t::none == ( state & state_t::complete );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// push_coroutine< T & >
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
void
|
|
||||||
push_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
|
|
||||||
boost::context::execution_context ctx = cb->ctx;
|
|
||||||
// destroy control structure
|
|
||||||
cb->state |= state_t::destroy;
|
|
||||||
cb->~control_block();
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
template< typename StackAllocator, typename Fn >
|
|
||||||
push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
|
||||||
Fn && fn) :
|
|
||||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
|
||||||
wrap( [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void * vp) mutable noexcept {
|
|
||||||
// create synthesized pull_coroutine< T >
|
|
||||||
typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
|
||||||
pull_coroutine< T & > synthesized{ & synthesized_cb };
|
|
||||||
other = & synthesized_cb;
|
|
||||||
if ( state_t::none == ( state & state_t::destroy) ) {
|
|
||||||
try {
|
|
||||||
// jump back to ctor
|
|
||||||
T * t = static_cast< T * >( ctx() );
|
|
||||||
// set transferred value
|
|
||||||
synthesized_cb.t = t;
|
|
||||||
auto fn = std::move( fn_);
|
|
||||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
|
||||||
fn( synthesized);
|
|
||||||
} catch ( forced_unwind const&) {
|
|
||||||
// do nothing for unwinding exception
|
|
||||||
} catch (...) {
|
|
||||||
// store other exceptions in exception-pointer
|
|
||||||
except = std::current_exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set termination flags
|
|
||||||
state |= state_t::complete;
|
|
||||||
// jump back to ctx
|
|
||||||
other->ctx();
|
|
||||||
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
|
||||||
},
|
|
||||||
std::forward< Fn >( fn),
|
|
||||||
boost::context::execution_context::current() ) },
|
|
||||||
#else
|
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
|
||||||
[this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
|
|
||||||
// create synthesized pull_coroutine< T >
|
|
||||||
typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
|
||||||
pull_coroutine< T & > synthesized{ & synthesized_cb };
|
|
||||||
other = & synthesized_cb;
|
|
||||||
if ( state_t::none == ( state & state_t::destroy) ) {
|
|
||||||
try {
|
|
||||||
// jump back to ctor
|
|
||||||
T * t = static_cast< T * >( ctx() );
|
|
||||||
// set transferred value
|
|
||||||
synthesized_cb.t = t;
|
|
||||||
auto fn = std::move( fn_);
|
|
||||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
|
||||||
fn( synthesized);
|
|
||||||
} catch ( forced_unwind const&) {
|
|
||||||
// do nothing for unwinding exception
|
|
||||||
} catch (...) {
|
|
||||||
// store other exceptions in exception-pointer
|
|
||||||
except = std::current_exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set termination flags
|
|
||||||
state |= state_t::complete;
|
|
||||||
// jump back to ctx
|
|
||||||
other->ctx();
|
|
||||||
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
|
||||||
}},
|
|
||||||
#endif
|
|
||||||
other{ nullptr },
|
|
||||||
state{ state_t::unwind },
|
|
||||||
except{} {
|
|
||||||
// enter coroutine-fn in order to get other set
|
|
||||||
ctx();
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb,
|
|
||||||
boost::context::execution_context const& ctx_) noexcept :
|
|
||||||
ctx{ ctx_ },
|
|
||||||
other{ cb },
|
|
||||||
state{ state_t::none },
|
|
||||||
except{} {
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
push_coroutine< T & >::control_block::~control_block() {
|
|
||||||
if ( state_t::none == ( state & state_t::complete) &&
|
|
||||||
state_t::none != ( state & state_t::unwind) ) {
|
|
||||||
// unwind coroutine stack
|
|
||||||
other->ctx = boost::context::execution_context::current();
|
|
||||||
ctx( context::exec_ontop_arg, unwind_coroutine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
void
|
|
||||||
push_coroutine< T & >::control_block::deallocate() noexcept {
|
|
||||||
if ( state_t::none != ( state & state_t::unwind) ) {
|
|
||||||
destroy( this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
void
|
|
||||||
push_coroutine< T & >::control_block::resume( T & t) {
|
|
||||||
other->ctx = boost::context::execution_context::current();
|
|
||||||
// pass an pointer to other context
|
|
||||||
ctx( const_cast< typename std::remove_const< T >::type * >( std::addressof( t) ) );
|
|
||||||
if ( except) {
|
|
||||||
std::rethrow_exception( except);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
bool
|
|
||||||
push_coroutine< T & >::control_block::valid() const noexcept {
|
|
||||||
return state_t::none == ( state & state_t::complete );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// push_coroutine< void >
|
|
||||||
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
push_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
|
|
||||||
boost::context::execution_context ctx = cb->ctx;
|
|
||||||
// destroy control structure
|
|
||||||
cb->state |= state_t::destroy;
|
|
||||||
cb->~control_block();
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
|
||||||
push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) :
|
|
||||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
|
||||||
wrap( [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx,
|
|
||||||
void * vp) mutable noexcept {
|
|
||||||
// create synthesized pull_coroutine< T >
|
|
||||||
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
|
||||||
pull_coroutine< void > synthesized{ & synthesized_cb };
|
|
||||||
other = & synthesized_cb;
|
|
||||||
if ( state_t::none == ( state & state_t::destroy) ) {
|
|
||||||
try {
|
|
||||||
// jump back to ctor
|
|
||||||
ctx();
|
|
||||||
auto fn = std::move( fn_);
|
|
||||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
|
||||||
fn( synthesized);
|
|
||||||
} catch ( forced_unwind const&) {
|
|
||||||
// do nothing for unwinding exception
|
|
||||||
} catch (...) {
|
|
||||||
// store other exceptions in exception-pointer
|
|
||||||
except = std::current_exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set termination flags
|
|
||||||
state |= state_t::complete;
|
|
||||||
// jump back to ctx
|
|
||||||
other->ctx();
|
|
||||||
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
|
||||||
},
|
|
||||||
std::forward< Fn >( fn),
|
|
||||||
boost::context::execution_context::current() ) },
|
|
||||||
#else
|
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
|
||||||
[this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
|
|
||||||
// create synthesized pull_coroutine< T >
|
|
||||||
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
|
||||||
pull_coroutine< void > synthesized{ & synthesized_cb };
|
|
||||||
other = & synthesized_cb;
|
|
||||||
if ( state_t::none == ( state & state_t::destroy) ) {
|
|
||||||
try {
|
|
||||||
// jump back to ctor
|
|
||||||
ctx();
|
|
||||||
auto fn = std::move( fn_);
|
|
||||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
|
||||||
fn( synthesized);
|
|
||||||
} catch ( forced_unwind const&) {
|
|
||||||
// do nothing for unwinding exception
|
|
||||||
} catch (...) {
|
|
||||||
// store other exceptions in exception-pointer
|
|
||||||
except = std::current_exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set termination flags
|
|
||||||
state |= state_t::complete;
|
|
||||||
// jump back to ctx
|
|
||||||
other->ctx();
|
|
||||||
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
|
||||||
}},
|
|
||||||
#endif
|
|
||||||
other{ nullptr },
|
|
||||||
state{ state_t::unwind },
|
|
||||||
except{} {
|
|
||||||
// enter coroutine-fn in order to get other set
|
|
||||||
ctx();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb,
|
|
||||||
boost::context::execution_context const& ctx_) noexcept :
|
|
||||||
ctx{ ctx_ },
|
|
||||||
other{ cb },
|
|
||||||
state{ state_t::none },
|
|
||||||
except{} {
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
push_coroutine< void >::control_block::~control_block() {
|
|
||||||
if ( state_t::none == ( state & state_t::complete) &&
|
|
||||||
state_t::none != ( state & state_t::unwind) ) {
|
|
||||||
// unwind coroutine stack
|
|
||||||
other->ctx = boost::context::execution_context::current();
|
|
||||||
ctx( context::exec_ontop_arg, unwind_coroutine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
push_coroutine< void >::control_block::deallocate() noexcept {
|
|
||||||
if ( state_t::none != ( state & state_t::unwind) ) {
|
|
||||||
destroy( this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
push_coroutine< void >::control_block::resume() {
|
|
||||||
other->ctx = boost::context::execution_context::current();
|
|
||||||
ctx();
|
|
||||||
if ( except) {
|
|
||||||
std::rethrow_exception( except);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
bool
|
|
||||||
push_coroutine< void >::control_block::valid() const noexcept {
|
|
||||||
return state_t::none == ( state & state_t::complete );
|
|
||||||
}
|
|
||||||
|
|
||||||
}}}
|
|
||||||
|
|
||||||
#ifdef BOOST_HAS_ABI_HEADERS
|
|
||||||
# include BOOST_ABI_SUFFIX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP
|
|
@ -11,11 +11,7 @@
|
|||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#include <boost/context/detail/invoke.hpp>
|
#include <boost/context/detail/invoke.hpp>
|
||||||
#if (BOOST_EXECUTION_CONTEXT==1)
|
|
||||||
# include <boost/context/execution_context.hpp>
|
|
||||||
#else
|
|
||||||
#include <boost/context/continuation.hpp>
|
#include <boost/context/continuation.hpp>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <boost/fiber/detail/config.hpp>
|
#include <boost/fiber/detail/config.hpp>
|
||||||
#include <boost/fiber/detail/data.hpp>
|
#include <boost/fiber/detail/data.hpp>
|
||||||
@ -28,45 +24,6 @@ namespace boost {
|
|||||||
namespace coroutines2 {
|
namespace coroutines2 {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
#if (BOOST_EXECUTION_CONTEXT==1)
|
|
||||||
template< typename Fn1, typename Fn2 >
|
|
||||||
class wrapper {
|
|
||||||
private:
|
|
||||||
typename std::decay< Fn1 >::type fn1_;
|
|
||||||
typename std::decay< Fn2 >::type fn2_;
|
|
||||||
boost::context::execution_context ctx_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
wrapper( Fn1 && fn1, Fn2 && fn2,
|
|
||||||
boost::context::execution_context const& ctx) :
|
|
||||||
fn1_( std::move( fn1) ),
|
|
||||||
fn2_( std::move( fn2) ),
|
|
||||||
ctx_{ ctx } {
|
|
||||||
}
|
|
||||||
|
|
||||||
wrapper( wrapper const&) = delete;
|
|
||||||
wrapper & operator=( wrapper const&) = delete;
|
|
||||||
|
|
||||||
wrapper( wrapper && other) = default;
|
|
||||||
wrapper & operator=( wrapper && other) = default;
|
|
||||||
|
|
||||||
void operator()( void * vp) {
|
|
||||||
boost::context::detail::invoke(
|
|
||||||
std::move( fn1_),
|
|
||||||
fn2_, ctx_, vp);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template< typename Fn1, typename Fn2 >
|
|
||||||
wrapper< Fn1, Fn2 >
|
|
||||||
wrap( Fn1 && fn1, Fn2 && fn2,
|
|
||||||
boost::context::execution_context const& ctx) {
|
|
||||||
return wrapper< Fn1, Fn2 >(
|
|
||||||
std::forward< Fn1 >( fn1),
|
|
||||||
std::forward< Fn2 >( fn2),
|
|
||||||
ctx);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
template< typename Fn1, typename Fn2 >
|
template< typename Fn1, typename Fn2 >
|
||||||
class wrapper {
|
class wrapper {
|
||||||
private:
|
private:
|
||||||
@ -101,7 +58,6 @@ wrap( Fn1 && fn1, Fn2 && fn2) {
|
|||||||
std::forward< Fn1 >( fn1),
|
std::forward< Fn1 >( fn1),
|
||||||
std::forward< Fn2 >( fn2) );
|
std::forward< Fn2 >( fn2) );
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
}}}
|
}}}
|
||||||
|
|
||||||
|
@ -61,17 +61,7 @@ alias sources
|
|||||||
|
|
||||||
explicit sources ;
|
explicit sources ;
|
||||||
|
|
||||||
exe performance_create_protected
|
exe performance
|
||||||
: sources
|
: sources
|
||||||
performance_create_protected.cpp
|
performance.cpp
|
||||||
;
|
|
||||||
|
|
||||||
exe performance_create_standard
|
|
||||||
: sources
|
|
||||||
performance_create_standard.cpp
|
|
||||||
;
|
|
||||||
|
|
||||||
exe performance_switch
|
|
||||||
: sources
|
|
||||||
performance_switch.cpp
|
|
||||||
;
|
;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <boost/chrono.hpp>
|
#include <boost/chrono.hpp>
|
||||||
#include <boost/coroutine2/all.hpp>
|
#include <boost/coroutine2/all.hpp>
|
||||||
@ -17,57 +18,52 @@
|
|||||||
#include "clock.hpp"
|
#include "clock.hpp"
|
||||||
#include "cycle.hpp"
|
#include "cycle.hpp"
|
||||||
|
|
||||||
typedef boost::coroutines2::fixedsize_stack stack_allocator;
|
|
||||||
typedef boost::coroutines2::coroutine< void > coro_type;
|
|
||||||
|
|
||||||
boost::uint64_t jobs = 1000;
|
boost::uint64_t jobs = 1000;
|
||||||
|
|
||||||
void fn( coro_type::pull_type & c)
|
void fn( boost::coroutines2::coroutine< void >::push_type & c) {
|
||||||
{ while ( true) c(); }
|
while ( true) {
|
||||||
|
c();
|
||||||
duration_type measure_time( duration_type overhead)
|
}
|
||||||
{
|
}
|
||||||
stack_allocator stack_alloc;
|
|
||||||
|
|
||||||
|
duration_type measure_time_void( duration_type overhead) {
|
||||||
|
boost::coroutines2::coroutine< void >::pull_type c{ fn };
|
||||||
time_point_type start( clock_type::now() );
|
time_point_type start( clock_type::now() );
|
||||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||||
coro_type::push_type c( stack_alloc, fn);
|
c();
|
||||||
}
|
}
|
||||||
duration_type total = clock_type::now() - start;
|
duration_type total = clock_type::now() - start;
|
||||||
total -= overhead_clock(); // overhead of measurement
|
total -= overhead_clock(); // overhead of measurement
|
||||||
total /= jobs; // loops
|
total /= jobs; // loops
|
||||||
|
total /= 2; // 2x jump_fcontext
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
# ifdef BOOST_CONTEXT_CYCLE
|
# ifdef BOOST_CONTEXT_CYCLE
|
||||||
cycle_type measure_cycles( cycle_type overhead)
|
cycle_type measure_cycles_void( cycle_type overhead) {
|
||||||
{
|
boost::coroutines2::coroutine< void >::pull_type c{ fn };
|
||||||
stack_allocator stack_alloc;
|
|
||||||
|
|
||||||
cycle_type start( cycles() );
|
cycle_type start( cycles() );
|
||||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
for ( std::size_t i = 0; i < jobs; ++i) {
|
||||||
coro_type::push_type c( stack_alloc, fn);
|
c();
|
||||||
}
|
}
|
||||||
cycle_type total = cycles() - start;
|
cycle_type total = cycles() - start;
|
||||||
total -= overhead; // overhead of measurement
|
total -= overhead; // overhead of measurement
|
||||||
total /= jobs; // loops
|
total /= jobs; // loops
|
||||||
|
total /= 2; // 2x jump_fcontext
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
int main( int argc, char * argv[])
|
int main( int argc, char * argv[]) {
|
||||||
{
|
try {
|
||||||
try
|
|
||||||
{
|
|
||||||
bool bind = false;
|
bool bind = false;
|
||||||
boost::program_options::options_description desc("allowed options");
|
boost::program_options::options_description desc("allowed options");
|
||||||
desc.add_options()
|
desc.add_options()
|
||||||
("help", "help message")
|
("help", "help message")
|
||||||
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
|
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
|
||||||
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
|
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
|
||||||
|
|
||||||
boost::program_options::variables_map vm;
|
boost::program_options::variables_map vm;
|
||||||
boost::program_options::store(
|
boost::program_options::store(
|
||||||
boost::program_options::parse_command_line(
|
boost::program_options::parse_command_line(
|
||||||
@ -76,28 +72,27 @@ int main( int argc, char * argv[])
|
|||||||
desc),
|
desc),
|
||||||
vm);
|
vm);
|
||||||
boost::program_options::notify( vm);
|
boost::program_options::notify( vm);
|
||||||
|
|
||||||
if ( vm.count("help") ) {
|
if ( vm.count("help") ) {
|
||||||
std::cout << desc << std::endl;
|
std::cout << desc << std::endl;
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
if ( bind) {
|
||||||
if ( bind) bind_to_processor( 0);
|
bind_to_processor( 0);
|
||||||
|
}
|
||||||
duration_type overhead_c = overhead_clock();
|
duration_type overhead_c = overhead_clock();
|
||||||
boost::uint64_t res = measure_time( overhead_c).count();
|
boost::uint64_t res = measure_time_void( overhead_c).count();
|
||||||
std::cout << "average of " << res << " nano seconds" << std::endl;
|
std::cout << "average of " << res << " nano seconds" << std::endl;
|
||||||
#ifdef BOOST_CONTEXT_CYCLE
|
#ifdef BOOST_CONTEXT_CYCLE
|
||||||
cycle_type overhead_y = overhead_cycle();
|
cycle_type overhead_y = overhead_cycle();
|
||||||
res = measure_cycles( overhead_y);
|
res = measure_cycles_void( overhead_y);
|
||||||
std::cout << "average of " << res << " cpu cycles" << std::endl;
|
std::cout << "average of " << res << " cpu cycles" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
catch ( std::exception const& e)
|
catch ( std::exception const& e) {
|
||||||
{ std::cerr << "exception: " << e.what() << std::endl; }
|
std::cerr << "exception: " << e.what() << std::endl;
|
||||||
catch (...)
|
} catch (...) {
|
||||||
{ std::cerr << "unhandled exception" << std::endl; }
|
std::cerr << "unhandled exception" << std::endl;
|
||||||
|
}
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
@ -1,103 +0,0 @@
|
|||||||
|
|
||||||
// Copyright Oliver Kowalke 2014.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <iostream>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#include <boost/chrono.hpp>
|
|
||||||
#include <boost/coroutine2/all.hpp>
|
|
||||||
#include <boost/cstdint.hpp>
|
|
||||||
#include <boost/program_options.hpp>
|
|
||||||
|
|
||||||
#include "bind_processor.hpp"
|
|
||||||
#include "clock.hpp"
|
|
||||||
#include "cycle.hpp"
|
|
||||||
|
|
||||||
typedef boost::coroutines2::protected_fixedsize_stack stack_allocator;
|
|
||||||
typedef boost::coroutines2::coroutine< void > coro_type;
|
|
||||||
|
|
||||||
boost::uint64_t jobs = 1000;
|
|
||||||
|
|
||||||
void fn( coro_type::pull_type & c)
|
|
||||||
{ while ( true) c(); }
|
|
||||||
|
|
||||||
duration_type measure_time( duration_type overhead)
|
|
||||||
{
|
|
||||||
stack_allocator stack_alloc;
|
|
||||||
|
|
||||||
time_point_type start( clock_type::now() );
|
|
||||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
|
||||||
coro_type::push_type c( stack_alloc, fn);
|
|
||||||
}
|
|
||||||
duration_type total = clock_type::now() - start;
|
|
||||||
total -= overhead_clock(); // overhead of measurement
|
|
||||||
total /= jobs; // loops
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
# ifdef BOOST_CONTEXT_CYCLE
|
|
||||||
cycle_type measure_cycles( cycle_type overhead)
|
|
||||||
{
|
|
||||||
stack_allocator stack_alloc;
|
|
||||||
|
|
||||||
cycle_type start( cycles() );
|
|
||||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
|
||||||
coro_type::push_type c( stack_alloc, fn);
|
|
||||||
}
|
|
||||||
cycle_type total = cycles() - start;
|
|
||||||
total -= overhead; // overhead of measurement
|
|
||||||
total /= jobs; // loops
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
int main( int argc, char * argv[])
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bool bind = false;
|
|
||||||
boost::program_options::options_description desc("allowed options");
|
|
||||||
desc.add_options()
|
|
||||||
("help", "help message")
|
|
||||||
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
|
|
||||||
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
|
|
||||||
|
|
||||||
boost::program_options::variables_map vm;
|
|
||||||
boost::program_options::store(
|
|
||||||
boost::program_options::parse_command_line(
|
|
||||||
argc,
|
|
||||||
argv,
|
|
||||||
desc),
|
|
||||||
vm);
|
|
||||||
boost::program_options::notify( vm);
|
|
||||||
|
|
||||||
if ( vm.count("help") ) {
|
|
||||||
std::cout << desc << std::endl;
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( bind) bind_to_processor( 0);
|
|
||||||
|
|
||||||
duration_type overhead_c = overhead_clock();
|
|
||||||
boost::uint64_t res = measure_time( overhead_c).count();
|
|
||||||
std::cout << "average of " << res << " nano seconds" << std::endl;
|
|
||||||
#ifdef BOOST_CONTEXT_CYCLE
|
|
||||||
cycle_type overhead_y = overhead_cycle();
|
|
||||||
res = measure_cycles( overhead_y);
|
|
||||||
std::cout << "average of " << res << " cpu cycles" << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
catch ( std::exception const& e)
|
|
||||||
{ std::cerr << "exception: " << e.what() << std::endl; }
|
|
||||||
catch (...)
|
|
||||||
{ std::cerr << "unhandled exception" << std::endl; }
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
@ -1,194 +0,0 @@
|
|||||||
|
|
||||||
// Copyright Oliver Kowalke 2014.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <iostream>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <boost/chrono.hpp>
|
|
||||||
#include <boost/coroutine2/all.hpp>
|
|
||||||
#include <boost/cstdint.hpp>
|
|
||||||
#include <boost/program_options.hpp>
|
|
||||||
|
|
||||||
#include "bind_processor.hpp"
|
|
||||||
#include "clock.hpp"
|
|
||||||
#include "cycle.hpp"
|
|
||||||
|
|
||||||
boost::uint64_t jobs = 1000;
|
|
||||||
|
|
||||||
struct X
|
|
||||||
{
|
|
||||||
std::string str;
|
|
||||||
|
|
||||||
X( std::string const& str_) :
|
|
||||||
str( str_)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
const X x("abc");
|
|
||||||
|
|
||||||
void fn_void( boost::coroutines2::coroutine< void >::push_type & c)
|
|
||||||
{ while ( true) c(); }
|
|
||||||
|
|
||||||
void fn_int( boost::coroutines2::coroutine< int >::push_type & c)
|
|
||||||
{ while ( true) c( 7); }
|
|
||||||
|
|
||||||
void fn_x( boost::coroutines2::coroutine< X >::push_type & c)
|
|
||||||
{
|
|
||||||
while ( true) c( x);
|
|
||||||
}
|
|
||||||
|
|
||||||
duration_type measure_time_void( duration_type overhead)
|
|
||||||
{
|
|
||||||
boost::coroutines2::coroutine< void >::pull_type c( fn_void);
|
|
||||||
|
|
||||||
time_point_type start( clock_type::now() );
|
|
||||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
duration_type total = clock_type::now() - start;
|
|
||||||
total -= overhead_clock(); // overhead of measurement
|
|
||||||
total /= jobs; // loops
|
|
||||||
total /= 2; // 2x jump_fcontext
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
duration_type measure_time_int( duration_type overhead)
|
|
||||||
{
|
|
||||||
boost::coroutines2::coroutine< int >::pull_type c( fn_int);
|
|
||||||
|
|
||||||
time_point_type start( clock_type::now() );
|
|
||||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
duration_type total = clock_type::now() - start;
|
|
||||||
total -= overhead_clock(); // overhead of measurement
|
|
||||||
total /= jobs; // loops
|
|
||||||
total /= 2; // 2x jump_fcontext
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
duration_type measure_time_x( duration_type overhead)
|
|
||||||
{
|
|
||||||
boost::coroutines2::coroutine< X >::pull_type c( fn_x);
|
|
||||||
|
|
||||||
time_point_type start( clock_type::now() );
|
|
||||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
duration_type total = clock_type::now() - start;
|
|
||||||
total -= overhead_clock(); // overhead of measurement
|
|
||||||
total /= jobs; // loops
|
|
||||||
total /= 2; // 2x jump_fcontext
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
# ifdef BOOST_CONTEXT_CYCLE
|
|
||||||
cycle_type measure_cycles_void( cycle_type overhead)
|
|
||||||
{
|
|
||||||
boost::coroutines2::coroutine< void >::pull_type c( fn_void);
|
|
||||||
|
|
||||||
cycle_type start( cycles() );
|
|
||||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
cycle_type total = cycles() - start;
|
|
||||||
total -= overhead; // overhead of measurement
|
|
||||||
total /= jobs; // loops
|
|
||||||
total /= 2; // 2x jump_fcontext
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
cycle_type measure_cycles_int( cycle_type overhead)
|
|
||||||
{
|
|
||||||
boost::coroutines2::coroutine< int >::pull_type c( fn_int);
|
|
||||||
|
|
||||||
cycle_type start( cycles() );
|
|
||||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
cycle_type total = cycles() - start;
|
|
||||||
total -= overhead; // overhead of measurement
|
|
||||||
total /= jobs; // loops
|
|
||||||
total /= 2; // 2x jump_fcontext
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
cycle_type measure_cycles_x( cycle_type overhead)
|
|
||||||
{
|
|
||||||
boost::coroutines2::coroutine< X >::pull_type c( fn_x);
|
|
||||||
|
|
||||||
cycle_type start( cycles() );
|
|
||||||
for ( std::size_t i = 0; i < jobs; ++i) {
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
cycle_type total = cycles() - start;
|
|
||||||
total -= overhead; // overhead of measurement
|
|
||||||
total /= jobs; // loops
|
|
||||||
total /= 2; // 2x jump_fcontext
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
int main( int argc, char * argv[])
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bool bind = false;
|
|
||||||
boost::program_options::options_description desc("allowed options");
|
|
||||||
desc.add_options()
|
|
||||||
("help", "help message")
|
|
||||||
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
|
|
||||||
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
|
|
||||||
|
|
||||||
boost::program_options::variables_map vm;
|
|
||||||
boost::program_options::store(
|
|
||||||
boost::program_options::parse_command_line(
|
|
||||||
argc,
|
|
||||||
argv,
|
|
||||||
desc),
|
|
||||||
vm);
|
|
||||||
boost::program_options::notify( vm);
|
|
||||||
|
|
||||||
if ( vm.count("help") ) {
|
|
||||||
std::cout << desc << std::endl;
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( bind) bind_to_processor( 0);
|
|
||||||
|
|
||||||
duration_type overhead_c = overhead_clock();
|
|
||||||
boost::uint64_t res = measure_time_void( overhead_c).count();
|
|
||||||
std::cout << "void: average of " << res << " nano seconds" << std::endl;
|
|
||||||
res = measure_time_int( overhead_c).count();
|
|
||||||
std::cout << "int: average of " << res << " nano seconds" << std::endl;
|
|
||||||
res = measure_time_x( overhead_c).count();
|
|
||||||
std::cout << "X: average of " << res << " nano seconds" << std::endl;
|
|
||||||
#ifdef BOOST_CONTEXT_CYCLE
|
|
||||||
cycle_type overhead_y = overhead_cycle();
|
|
||||||
res = measure_cycles_void( overhead_y);
|
|
||||||
std::cout << "void: average of " << res << " cpu cycles" << std::endl;
|
|
||||||
res = measure_cycles_int( overhead_y);
|
|
||||||
std::cout << "int: average of " << res << " cpu cycles" << std::endl;
|
|
||||||
res = measure_cycles_x( overhead_y);
|
|
||||||
std::cout << "X: average of " << res << " cpu cycles" << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
catch ( std::exception const& e)
|
|
||||||
{ std::cerr << "exception: " << e.what() << std::endl; }
|
|
||||||
catch (...)
|
|
||||||
{ std::cerr << "unhandled exception" << std::endl; }
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user