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
1f15040a55
@ -3,7 +3,7 @@
|
||||
# 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)
|
||||
|
||||
project coroutine/doc ;
|
||||
project coroutine2/doc ;
|
||||
|
||||
import boostbook ;
|
||||
import quickbook ;
|
||||
|
@ -13,28 +13,35 @@ following table. Performance measurements were taken using `rdtsc` and
|
||||
platforms. In each case, cache warm-up was accounted for, and the one
|
||||
running thread was pinned to a single CPU.
|
||||
|
||||
[table Performance of asymmetric coroutines
|
||||
[table Performance of asymmetric coroutines (using captured_context)
|
||||
[
|
||||
[Platform]
|
||||
[switch]
|
||||
[construction (protected stack-allocator)]
|
||||
[construction (preallocated stack-allocator)]
|
||||
[construction (standard stack-allocator)]
|
||||
]
|
||||
[
|
||||
[i386 (AMD Athlon 64 DualCore 4400+, Linux 32bit)]
|
||||
[49 ns / 50 cycles]
|
||||
[51 \u00b5s / 51407 cycles]
|
||||
[14 \u00b5s / 15231 cycles]
|
||||
[14 \u00b5s / 15216 cycles]
|
||||
[x86_64 (Intel Core2 Q6700, Linux 64bit)]
|
||||
[7 ns / 20 cycles]
|
||||
[19 \u00b5s / cw6306445402 cycles]
|
||||
[10 \u00b5s / 29896 cycles]
|
||||
]
|
||||
]
|
||||
[/
|
||||
[table Performance of asymmetric coroutines (using execution_context)
|
||||
[
|
||||
[Platform]
|
||||
[switch]
|
||||
[construction (protected stack-allocator)]
|
||||
[construction (standard stack-allocator)]
|
||||
]
|
||||
[
|
||||
[x86_64 (Intel Core2 Q6700, Linux 64bit)]
|
||||
[12 ns / 39 cycles]
|
||||
[16 \u00b5s / 41802 cycles]
|
||||
[6 \u00b5s / 10350 cycles]
|
||||
[6 \u00b5s / 18817 cycles]
|
||||
[140 ns / 424 cycles]
|
||||
[14 \u00b5s / 32750 cycles]
|
||||
[8 \u00b5s / 15313 cycles]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
@ -89,77 +89,83 @@ void traverse(node::ptr_t n, boost::coroutines2::coroutine<std::string>::push_ty
|
||||
int main() {
|
||||
{
|
||||
node::ptr_t left_d(create_left_tree_from("d"));
|
||||
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
|
||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||
traverse(left_d,out);
|
||||
});
|
||||
std::cout << "left tree from d:\n";
|
||||
std::copy(begin(left_d_reader),
|
||||
end(left_d_reader),
|
||||
std::ostream_iterator<std::string>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
node::ptr_t right_b(create_right_tree_from("b"));
|
||||
boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
|
||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||
traverse(right_b,out);
|
||||
});
|
||||
std::cout << "right tree from b:\n";
|
||||
std::copy(begin(right_b_reader),
|
||||
end(right_b_reader),
|
||||
std::ostream_iterator<std::string>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
node::ptr_t right_x(create_right_tree_from("x"));
|
||||
boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
|
||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||
traverse(right_x,out);
|
||||
});
|
||||
std::cout << "right tree from x:\n";
|
||||
std::copy(begin(right_x_reader),
|
||||
end(right_x_reader),
|
||||
std::ostream_iterator<std::string>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
{
|
||||
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
|
||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||
traverse(left_d,out);
|
||||
});
|
||||
std::cout << "left tree from d:\n";
|
||||
std::copy(begin(left_d_reader),
|
||||
end(left_d_reader),
|
||||
std::ostream_iterator<std::string>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
|
||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||
traverse(right_b,out);
|
||||
});
|
||||
std::cout << "right tree from b:\n";
|
||||
std::copy(begin(right_b_reader),
|
||||
end(right_b_reader),
|
||||
std::ostream_iterator<std::string>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
|
||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||
traverse(right_x,out);
|
||||
});
|
||||
std::cout << "right tree from x:\n";
|
||||
std::copy(begin(right_x_reader),
|
||||
end(right_x_reader),
|
||||
std::ostream_iterator<std::string>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
{
|
||||
node::ptr_t left_d(create_left_tree_from("d"));
|
||||
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
|
||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||
traverse(left_d,out);
|
||||
});
|
||||
|
||||
node::ptr_t right_b(create_right_tree_from("b"));
|
||||
boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
|
||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||
traverse(right_b,out);
|
||||
});
|
||||
{
|
||||
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
|
||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||
traverse(left_d,out);
|
||||
});
|
||||
|
||||
std::cout << "left tree from d == right tree from b? "
|
||||
<< std::boolalpha
|
||||
<< std::equal(begin(left_d_reader),
|
||||
end(left_d_reader),
|
||||
begin(right_b_reader))
|
||||
<< std::endl;
|
||||
boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
|
||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||
traverse(right_b,out);
|
||||
});
|
||||
|
||||
std::cout << "left tree from d == right tree from b? "
|
||||
<< std::boolalpha
|
||||
<< std::equal(begin(left_d_reader),
|
||||
end(left_d_reader),
|
||||
begin(right_b_reader))
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
{
|
||||
node::ptr_t left_d(create_left_tree_from("d"));
|
||||
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
|
||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||
traverse(left_d,out);
|
||||
});
|
||||
|
||||
node::ptr_t right_x(create_right_tree_from("x"));
|
||||
boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
|
||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||
traverse(right_x,out);
|
||||
});
|
||||
{
|
||||
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
|
||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||
traverse(left_d,out);
|
||||
});
|
||||
|
||||
std::cout << "left tree from d == right tree from x? "
|
||||
<< std::boolalpha
|
||||
<< std::equal(begin(left_d_reader),
|
||||
end(left_d_reader),
|
||||
begin(right_x_reader))
|
||||
<< std::endl;
|
||||
boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
|
||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||
traverse(right_x,out);
|
||||
});
|
||||
|
||||
std::cout << "left tree from d == right tree from x? "
|
||||
<< std::boolalpha
|
||||
<< std::equal(begin(left_d_reader),
|
||||
end(left_d_reader),
|
||||
begin(right_x_reader))
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << "Done" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
|
@ -28,14 +28,25 @@ class push_coroutine;
|
||||
#include <boost/coroutine2/detail/pull_coroutine.hpp>
|
||||
#include <boost/coroutine2/detail/push_coroutine.hpp>
|
||||
|
||||
#include <boost/coroutine2/detail/pull_control_block.hpp>
|
||||
#include <boost/coroutine2/detail/push_control_block.hpp>
|
||||
#if ! defined(BOOST_USE_EXECUTION_CONTEXT)
|
||||
#include <boost/coroutine2/detail/pull_control_block_cc.hpp>
|
||||
#include <boost/coroutine2/detail/push_control_block_cc.hpp>
|
||||
#else
|
||||
#include <boost/coroutine2/detail/pull_control_block_ec.hpp>
|
||||
#include <boost/coroutine2/detail/push_control_block_ec.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/coroutine2/detail/pull_coroutine.ipp>
|
||||
#include <boost/coroutine2/detail/push_coroutine.ipp>
|
||||
|
||||
#include <boost/coroutine2/detail/pull_control_block.ipp>
|
||||
#include <boost/coroutine2/detail/push_control_block.ipp>
|
||||
#if ! defined(BOOST_USE_EXECUTION_CONTEXT)
|
||||
#include <boost/coroutine2/detail/pull_control_block_cc.hpp>
|
||||
#include <boost/coroutine2/detail/pull_control_block_cc.ipp>
|
||||
#include <boost/coroutine2/detail/push_control_block_cc.ipp>
|
||||
#else
|
||||
#include <boost/coroutine2/detail/pull_control_block_ec.ipp>
|
||||
#include <boost/coroutine2/detail/push_control_block_ec.ipp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
|
@ -31,7 +31,7 @@ template< typename ControlBlock, typename StackAllocator, typename Fn >
|
||||
ControlBlock * create_control_block( StackAllocator salloc, Fn && fn) {
|
||||
auto sctx = salloc.allocate();
|
||||
// reserve space for control structure
|
||||
#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
|
||||
#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
|
||||
void * sp = static_cast< char * >( sctx.sp) - sizeof( ControlBlock);
|
||||
const std::size_t size = sctx.size - sizeof( ControlBlock);
|
||||
#else
|
||||
|
@ -24,6 +24,12 @@ namespace detail {
|
||||
|
||||
struct forced_unwind {};
|
||||
|
||||
inline
|
||||
void * unwind_coroutine( void * data) {
|
||||
throw forced_unwind{};
|
||||
return data;
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
|
114
include/boost/coroutine2/detail/pull_control_block_cc.hpp
Normal file
114
include/boost/coroutine2/detail/pull_control_block_cc.hpp
Normal file
@ -0,0 +1,114 @@
|
||||
|
||||
// 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 <type_traits>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/context/captured_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::captured_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::captured_context &) noexcept;
|
||||
|
||||
~control_block();
|
||||
|
||||
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::captured_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::captured_context &) 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::captured_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::captured_context &) 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
|
416
include/boost/coroutine2/detail/pull_control_block_cc.ipp
Normal file
416
include/boost/coroutine2/detail/pull_control_block_cc.ipp
Normal file
@ -0,0 +1,416 @@
|
||||
|
||||
// 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 <algorithm>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/context/captured_context.hpp>
|
||||
|
||||
#include <boost/coroutine2/detail/config.hpp>
|
||||
#include <boost/coroutine2/detail/forced_unwind.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::captured_context ctx = std::move( cb->ctx);
|
||||
// destroy control structure
|
||||
cb->~control_block();
|
||||
// destroy coroutine's stack
|
||||
ctx();
|
||||
}
|
||||
|
||||
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,
|
||||
std::move(
|
||||
std::bind(
|
||||
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void *) mutable {
|
||||
// create synthesized push_coroutine< T >
|
||||
typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
||||
push_coroutine< T > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
try {
|
||||
auto fn = std::move( fn_);
|
||||
// call coroutine-fn with synthesized push_coroutine as argument
|
||||
fn( synthesized);
|
||||
} catch ( boost::context::detail::forced_unwind const&) {
|
||||
throw;
|
||||
} catch (...) {
|
||||
// store other exceptions in exception-pointer
|
||||
except = std::current_exception();
|
||||
}
|
||||
// set termination flags
|
||||
state |= state_t::complete;
|
||||
// jump back to ctx
|
||||
auto result = other->ctx();
|
||||
other->ctx = std::move( std::get< 0 >( result) );
|
||||
return std::move( other->ctx);
|
||||
},
|
||||
std::forward< Fn >( fn),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2))},
|
||||
#else
|
||||
ctx{ std::allocator_arg, palloc, salloc,
|
||||
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void *) mutable {
|
||||
// create synthesized push_coroutine< T >
|
||||
typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
||||
push_coroutine< T > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
try {
|
||||
auto fn = std::move( fn_);
|
||||
// call coroutine-fn with synthesized push_coroutine as argument
|
||||
fn( synthesized);
|
||||
} catch ( boost::context::detail::forced_unwind const&) {
|
||||
throw;
|
||||
} catch (...) {
|
||||
// store other exceptions in exception-pointer
|
||||
except = std::current_exception();
|
||||
}
|
||||
// set termination flags
|
||||
state |= state_t::complete;
|
||||
// jump back to ctx
|
||||
auto result = other->ctx();
|
||||
other->ctx = std::move( std::get< 0 >( result) );
|
||||
return std::move( other->ctx);
|
||||
}},
|
||||
#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
|
||||
auto result = ctx();
|
||||
ctx = std::move( std::get< 0 >( result) );
|
||||
set( static_cast< T * >( std::get< 1 >( result) ) );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
|
||||
boost::context::captured_context & ctx_) noexcept :
|
||||
ctx{ std::move( ctx_) },
|
||||
other{ cb },
|
||||
state{ state_t::none },
|
||||
except{},
|
||||
bvalid{ false },
|
||||
storage{} {
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
pull_coroutine< T >::control_block::~control_block() {
|
||||
// destroy data if 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() {
|
||||
auto result = ctx();
|
||||
ctx = std::move( std::get< 0 >( result) );
|
||||
set( static_cast< T * >( std::get< 1 >( result) ) );
|
||||
if ( except) {
|
||||
std::rethrow_exception( except);
|
||||
}
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
void
|
||||
pull_coroutine< T >::control_block::set( T * t) {
|
||||
// destroy data if 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::captured_context ctx = std::move( cb->ctx);
|
||||
// destroy control structure
|
||||
cb->~control_block();
|
||||
// destroy coroutine's stack
|
||||
ctx();
|
||||
}
|
||||
|
||||
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,
|
||||
std::move(
|
||||
std::bind(
|
||||
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void *) mutable {
|
||||
// create synthesized push_coroutine< T >
|
||||
typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
||||
push_coroutine< T & > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
try {
|
||||
auto fn = std::move( fn_);
|
||||
// call coroutine-fn with synthesized push_coroutine as argument
|
||||
fn( synthesized);
|
||||
} catch ( boost::context::detail::forced_unwind const&) {
|
||||
throw;
|
||||
} catch (...) {
|
||||
// store other exceptions in exception-pointer
|
||||
except = std::current_exception();
|
||||
}
|
||||
// set termination flags
|
||||
state |= state_t::complete;
|
||||
// jump back to ctx
|
||||
auto result = other->ctx();
|
||||
other->ctx = std::move( std::get< 0 >( result) );
|
||||
return std::move( other->ctx);
|
||||
},
|
||||
std::forward< Fn >( fn),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2))},
|
||||
#else
|
||||
ctx{ std::allocator_arg, palloc, salloc,
|
||||
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void *) mutable {
|
||||
// create synthesized push_coroutine< T >
|
||||
typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
||||
push_coroutine< T & > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
try {
|
||||
auto fn = std::move( fn_);
|
||||
// call coroutine-fn with synthesized push_coroutine as argument
|
||||
fn( synthesized);
|
||||
} catch ( boost::context::detail::forced_unwind const&) {
|
||||
throw;
|
||||
} catch (...) {
|
||||
// store other exceptions in exception-pointer
|
||||
except = std::current_exception();
|
||||
}
|
||||
// set termination flags
|
||||
state |= state_t::complete;
|
||||
// jump back to ctx
|
||||
auto result = other->ctx();
|
||||
other->ctx = std::move( std::get< 0 >( result) );
|
||||
return std::move( other->ctx);
|
||||
}},
|
||||
#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
|
||||
auto result = ctx();
|
||||
ctx = std::move( std::get< 0 >( result) );
|
||||
t = static_cast< T * >( std::get< 1 >( result) );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
|
||||
boost::context::captured_context & ctx_) noexcept :
|
||||
ctx{ std::move( ctx_) },
|
||||
other{ cb },
|
||||
state{ state_t::none },
|
||||
except{},
|
||||
t{ nullptr } {
|
||||
}
|
||||
|
||||
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() {
|
||||
auto result = ctx();
|
||||
ctx = std::move( std::get< 0 >( result) );
|
||||
t = static_cast< T * >( std::get< 1 >( result) );
|
||||
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::captured_context ctx = std::move( cb->ctx);
|
||||
// destroy control structure
|
||||
cb->~control_block();
|
||||
// destroy coroutine's stack
|
||||
ctx();
|
||||
}
|
||||
|
||||
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,
|
||||
std::move(
|
||||
std::bind(
|
||||
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void *) mutable {
|
||||
// create synthesized push_coroutine< T >
|
||||
typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
||||
push_coroutine< void > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
try {
|
||||
auto fn = std::move( fn_);
|
||||
// call coroutine-fn with synthesized push_coroutine as argument
|
||||
fn( synthesized);
|
||||
} catch ( boost::context::detail::forced_unwind const&) {
|
||||
throw;
|
||||
} catch (...) {
|
||||
// store other exceptions in exception-pointer
|
||||
except = std::current_exception();
|
||||
}
|
||||
// set termination flags
|
||||
state |= state_t::complete;
|
||||
// jump back to ctx
|
||||
auto result = other->ctx();
|
||||
other->ctx = std::move( std::get< 0 >( result) );
|
||||
return std::move( other->ctx);
|
||||
},
|
||||
std::forward< Fn >( fn),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2))},
|
||||
#else
|
||||
ctx{ std::allocator_arg, palloc, salloc,
|
||||
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void *) mutable {
|
||||
// create synthesized push_coroutine< T >
|
||||
typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
||||
push_coroutine< void > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
try {
|
||||
auto fn = std::move( fn_);
|
||||
// call coroutine-fn with synthesized push_coroutine as argument
|
||||
fn( synthesized);
|
||||
} catch ( boost::context::detail::forced_unwind const&) {
|
||||
throw;
|
||||
} catch (...) {
|
||||
// store other exceptions in exception-pointer
|
||||
except = std::current_exception();
|
||||
}
|
||||
// set termination flags
|
||||
state |= state_t::complete;
|
||||
// jump back to ctx
|
||||
auto result = other->ctx();
|
||||
other->ctx = std::move( std::get< 0 >( result) );
|
||||
return std::move( other->ctx);
|
||||
}},
|
||||
#endif
|
||||
other{ nullptr },
|
||||
state{ state_t::unwind },
|
||||
except{} {
|
||||
// enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
|
||||
auto result = ctx();
|
||||
ctx = std::move( std::get< 0 >( result) );
|
||||
}
|
||||
|
||||
inline
|
||||
pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
|
||||
boost::context::captured_context & ctx_) noexcept :
|
||||
ctx{ std::move( ctx_) },
|
||||
other{ cb },
|
||||
state{ state_t::none },
|
||||
except{} {
|
||||
}
|
||||
|
||||
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() {
|
||||
auto result = ctx();
|
||||
ctx = std::move( std::get< 0 >( result) );
|
||||
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
|
@ -26,13 +26,15 @@ namespace detail {
|
||||
|
||||
template< typename T >
|
||||
struct pull_coroutine< T >::control_block {
|
||||
typename push_coroutine< T >::control_block * other;
|
||||
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 &&);
|
||||
|
||||
@ -43,6 +45,8 @@ struct pull_coroutine< T >::control_block {
|
||||
control_block( control_block &) = delete;
|
||||
control_block & operator=( control_block &) = delete;
|
||||
|
||||
void deallocate() noexcept;
|
||||
|
||||
void resume();
|
||||
|
||||
void set( T *);
|
||||
@ -54,12 +58,14 @@ struct pull_coroutine< T >::control_block {
|
||||
|
||||
template< typename T >
|
||||
struct pull_coroutine< T & >::control_block {
|
||||
typename push_coroutine< T & >::control_block * other;
|
||||
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 &&);
|
||||
|
||||
@ -70,6 +76,8 @@ struct pull_coroutine< T & >::control_block {
|
||||
control_block( control_block &) = delete;
|
||||
control_block & operator=( control_block &) = delete;
|
||||
|
||||
void deallocate() noexcept;
|
||||
|
||||
void resume();
|
||||
|
||||
T & get() noexcept;
|
||||
@ -78,11 +86,13 @@ struct pull_coroutine< T & >::control_block {
|
||||
};
|
||||
|
||||
struct pull_coroutine< void >::control_block {
|
||||
push_coroutine< void >::control_block * other;
|
||||
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 &&);
|
||||
|
||||
@ -93,6 +103,8 @@ struct pull_coroutine< void >::control_block {
|
||||
control_block( control_block &) = delete;
|
||||
control_block & operator=( control_block &) = delete;
|
||||
|
||||
void deallocate() noexcept;
|
||||
|
||||
void resume();
|
||||
|
||||
bool valid() const noexcept;
|
@ -31,11 +31,18 @@ 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->~control_block();
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template< typename StackAllocator, typename Fn >
|
||||
pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||
Fn && fn) :
|
||||
other{ nullptr },
|
||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||
ctx{ std::allocator_arg, palloc, salloc,
|
||||
std::move(
|
||||
@ -88,6 +95,7 @@ pull_coroutine< T >::control_block::control_block( context::preallocated palloc,
|
||||
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
||||
}},
|
||||
#endif
|
||||
other{ nullptr },
|
||||
state{ state_t::unwind },
|
||||
except{},
|
||||
bvalid{ false },
|
||||
@ -99,8 +107,8 @@ pull_coroutine< T >::control_block::control_block( context::preallocated palloc,
|
||||
template< typename T >
|
||||
pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
|
||||
boost::context::execution_context const& ctx_) noexcept :
|
||||
other{ cb },
|
||||
ctx{ ctx_ },
|
||||
other{ cb },
|
||||
state{ state_t::none },
|
||||
except{},
|
||||
bvalid{ false },
|
||||
@ -108,12 +116,11 @@ pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >:
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
pull_coroutine< T >::control_block::~control_block() noexcept {
|
||||
pull_coroutine< T >::control_block::~control_block() {
|
||||
if ( state_t::none == ( state & state_t::complete) &&
|
||||
state_t::none != ( state & state_t::unwind) ) {
|
||||
// set early-exit flag
|
||||
state |= state_t::early_exit;
|
||||
ctx();
|
||||
// unwind coroutine stack
|
||||
ctx( context::exec_ontop_arg, unwind_coroutine);
|
||||
}
|
||||
// destroy data if it set
|
||||
if ( bvalid) {
|
||||
@ -121,6 +128,14 @@ pull_coroutine< T >::control_block::~control_block() noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
@ -129,10 +144,6 @@ pull_coroutine< T >::control_block::resume() {
|
||||
if ( except) {
|
||||
std::rethrow_exception( except);
|
||||
}
|
||||
// test early-exit-flag
|
||||
if ( state_t::none != ( other->state & state_t::early_exit) ) {
|
||||
throw forced_unwind();
|
||||
}
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
@ -165,11 +176,18 @@ pull_coroutine< T >::control_block::valid() const noexcept {
|
||||
|
||||
// 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->~control_block();
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template< typename StackAllocator, typename Fn >
|
||||
pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||
Fn && fn) :
|
||||
other{ nullptr },
|
||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||
ctx{ std::allocator_arg, palloc, salloc,
|
||||
std::move(
|
||||
@ -222,6 +240,7 @@ pull_coroutine< T & >::control_block::control_block( context::preallocated pallo
|
||||
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
||||
}},
|
||||
#endif
|
||||
other{ nullptr },
|
||||
state{ state_t::unwind },
|
||||
except{},
|
||||
t{ nullptr } {
|
||||
@ -232,20 +251,27 @@ pull_coroutine< T & >::control_block::control_block( context::preallocated pallo
|
||||
template< typename T >
|
||||
pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
|
||||
boost::context::execution_context const& ctx_) noexcept :
|
||||
other{ cb },
|
||||
ctx{ ctx_ },
|
||||
other{ cb },
|
||||
state{ state_t::none },
|
||||
except{},
|
||||
t( nullptr) {
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
pull_coroutine< T & >::control_block::~control_block() noexcept {
|
||||
pull_coroutine< T & >::control_block::~control_block() {
|
||||
if ( state_t::none == ( state & state_t::complete) &&
|
||||
state_t::none != ( state & state_t::unwind) ) {
|
||||
// set early-exit flag
|
||||
state |= state_t::early_exit;
|
||||
ctx();
|
||||
// unwind coroutine stack
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -257,10 +283,6 @@ pull_coroutine< T & >::control_block::resume() {
|
||||
if ( except) {
|
||||
std::rethrow_exception( except);
|
||||
}
|
||||
// test early-exit-flag
|
||||
if ( state_t::none != ( other->state & state_t::early_exit) ) {
|
||||
throw forced_unwind();
|
||||
}
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
@ -278,10 +300,17 @@ pull_coroutine< T & >::control_block::valid() const noexcept {
|
||||
|
||||
// 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->~control_block();
|
||||
}
|
||||
|
||||
template< typename StackAllocator, typename Fn >
|
||||
pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||
Fn && fn) :
|
||||
other{ nullptr },
|
||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||
ctx{ std::allocator_arg, palloc, salloc,
|
||||
std::move(
|
||||
@ -334,6 +363,7 @@ pull_coroutine< void >::control_block::control_block( context::preallocated pall
|
||||
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
|
||||
@ -343,19 +373,26 @@ pull_coroutine< void >::control_block::control_block( context::preallocated pall
|
||||
inline
|
||||
pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
|
||||
boost::context::execution_context const& ctx_) noexcept :
|
||||
other{ cb },
|
||||
ctx{ ctx_ },
|
||||
other{ cb },
|
||||
state{ state_t::none },
|
||||
except{} {
|
||||
}
|
||||
|
||||
inline
|
||||
pull_coroutine< void >::control_block::~control_block() noexcept {
|
||||
pull_coroutine< void >::control_block::~control_block() {
|
||||
if ( state_t::none == ( state & state_t::complete) &&
|
||||
state_t::none != ( state & state_t::unwind) ) {
|
||||
// set early-exit flag
|
||||
state |= state_t::early_exit;
|
||||
ctx();
|
||||
// unwind coroutine stack
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,10 +404,6 @@ pull_coroutine< void >::control_block::resume() {
|
||||
if ( except) {
|
||||
std::rethrow_exception( except);
|
||||
}
|
||||
// test early-exit-flag
|
||||
if ( state_t::none != ( other->state & state_t::early_exit) ) {
|
||||
throw forced_unwind();
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
@ -53,7 +53,7 @@ template< typename StackAllocator, typename Fn >
|
||||
pull_coroutine< T >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
||||
cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
|
||||
if ( ! cb_->valid() ) {
|
||||
cb_->~control_block();
|
||||
cb_->deallocate();
|
||||
cb_ = nullptr;
|
||||
}
|
||||
}
|
||||
@ -61,7 +61,7 @@ pull_coroutine< T >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
||||
template< typename T >
|
||||
pull_coroutine< T >::~pull_coroutine() noexcept {
|
||||
if ( nullptr != cb_) {
|
||||
cb_->~control_block();
|
||||
cb_->deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ template< typename StackAllocator, typename Fn >
|
||||
pull_coroutine< T & >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
||||
cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
|
||||
if ( ! cb_->valid() ) {
|
||||
cb_->~control_block();
|
||||
cb_->deallocate();
|
||||
cb_ = nullptr;
|
||||
}
|
||||
}
|
||||
@ -130,7 +130,7 @@ pull_coroutine< T & >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
||||
template< typename T >
|
||||
pull_coroutine< T & >::~pull_coroutine() noexcept {
|
||||
if ( nullptr != cb_) {
|
||||
cb_->~control_block();
|
||||
cb_->deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,7 +183,7 @@ template< typename StackAllocator, typename Fn >
|
||||
pull_coroutine< void >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
||||
cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
|
||||
if ( ! cb_->valid() ) {
|
||||
cb_->~control_block();
|
||||
cb_->deallocate();
|
||||
cb_ = nullptr;
|
||||
}
|
||||
}
|
||||
@ -191,7 +191,7 @@ pull_coroutine< void >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
||||
inline
|
||||
pull_coroutine< void >::~pull_coroutine() noexcept {
|
||||
if ( nullptr != cb_) {
|
||||
cb_->~control_block();
|
||||
cb_->deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
|
104
include/boost/coroutine2/detail/push_control_block_cc.hpp
Normal file
104
include/boost/coroutine2/detail/push_control_block_cc.hpp
Normal file
@ -0,0 +1,104 @@
|
||||
|
||||
// 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 <exception>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/context/captured_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::captured_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::captured_context &) 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::captured_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::captured_context &) 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::captured_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::captured_context &) 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
|
381
include/boost/coroutine2/detail/push_control_block_cc.ipp
Normal file
381
include/boost/coroutine2/detail/push_control_block_cc.ipp
Normal file
@ -0,0 +1,381 @@
|
||||
|
||||
// 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 <memory>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/context/captured_context.hpp>
|
||||
|
||||
#include <boost/coroutine2/detail/config.hpp>
|
||||
#include <boost/coroutine2/detail/forced_unwind.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::captured_context ctx = std::move( cb->ctx);
|
||||
// destroy control structure
|
||||
cb->~control_block();
|
||||
// destroy coroutine's stack
|
||||
ctx();
|
||||
}
|
||||
|
||||
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,
|
||||
std::move(
|
||||
std::bind(
|
||||
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void * data) mutable {
|
||||
// create synthesized pull_coroutine< T >
|
||||
typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
||||
pull_coroutine< T > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
// set transferred value
|
||||
synthesized_cb.set( static_cast< T * >( data) );
|
||||
try {
|
||||
auto fn = std::move( fn_);
|
||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||
fn( synthesized);
|
||||
} catch ( boost::context::detail::forced_unwind const&) {
|
||||
throw;
|
||||
} catch (...) {
|
||||
// store other exceptions in exception-pointer
|
||||
except = std::current_exception();
|
||||
}
|
||||
// set termination flags
|
||||
state |= state_t::complete;
|
||||
// jump back to ctx
|
||||
auto result = other->ctx();
|
||||
other->ctx = std::move( std::get< 0 >( result) );
|
||||
return std::move( other->ctx);
|
||||
},
|
||||
std::forward< Fn >( fn),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2))},
|
||||
#else
|
||||
ctx{ std::allocator_arg, palloc, salloc,
|
||||
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void * data) mutable {
|
||||
// create synthesized pull_coroutine< T >
|
||||
typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
||||
pull_coroutine< T > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
// set transferred value
|
||||
synthesized_cb.set( static_cast< T * >( data) );
|
||||
try {
|
||||
auto fn = std::move( fn_);
|
||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||
fn( synthesized);
|
||||
} catch ( boost::context::detail::forced_unwind const&) {
|
||||
throw;
|
||||
} catch (...) {
|
||||
// store other exceptions in exception-pointer
|
||||
except = std::current_exception();
|
||||
}
|
||||
// set termination flags
|
||||
state |= state_t::complete;
|
||||
// jump back to ctx
|
||||
auto result = other->ctx();
|
||||
other->ctx = std::move( std::get< 0 >( result) );
|
||||
return std::move( other->ctx);
|
||||
}},
|
||||
#endif
|
||||
other{ nullptr },
|
||||
state{ state_t::unwind },
|
||||
except{} {
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb,
|
||||
boost::context::captured_context & ctx_) noexcept :
|
||||
ctx{ std::move( ctx_) },
|
||||
other{ cb },
|
||||
state{ state_t::none },
|
||||
except{} {
|
||||
}
|
||||
|
||||
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& data) {
|
||||
// pass an pointer to other context
|
||||
auto result = ctx( const_cast< T * >( & data) );
|
||||
ctx = std::move( std::get< 0 >( result) );
|
||||
if ( except) {
|
||||
std::rethrow_exception( except);
|
||||
}
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
void
|
||||
push_coroutine< T >::control_block::resume( T && data) {
|
||||
// pass an pointer to other context
|
||||
auto result = ctx( std::addressof( data) );
|
||||
ctx = std::move( std::get< 0 >( result) );
|
||||
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::captured_context ctx = std::move( cb->ctx);
|
||||
// destroy control structure
|
||||
cb->~control_block();
|
||||
// destroy coroutine's stack
|
||||
ctx();
|
||||
}
|
||||
|
||||
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,
|
||||
std::move(
|
||||
std::bind(
|
||||
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void * data) mutable {
|
||||
// create synthesized pull_coroutine< T >
|
||||
typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
||||
pull_coroutine< T & > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
// set transferred value
|
||||
synthesized_cb.t = static_cast< T * >( data);
|
||||
try {
|
||||
auto fn = std::move( fn_);
|
||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||
fn( synthesized);
|
||||
} catch ( boost::context::detail::forced_unwind const&) {
|
||||
throw;
|
||||
} catch (...) {
|
||||
// store other exceptions in exception-pointer
|
||||
except = std::current_exception();
|
||||
}
|
||||
// set termination flags
|
||||
state |= state_t::complete;
|
||||
// jump back to ctx
|
||||
auto result = other->ctx();
|
||||
other->ctx = std::move( std::get< 0 >( result) );
|
||||
return std::move( other->ctx);
|
||||
},
|
||||
std::forward< Fn >( fn),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2))},
|
||||
#else
|
||||
ctx{ std::allocator_arg, palloc, salloc,
|
||||
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void * data) mutable {
|
||||
// create synthesized pull_coroutine< T >
|
||||
typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
||||
pull_coroutine< T & > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
// set transferred value
|
||||
synthesized_cb.t = static_cast< T * >( data);
|
||||
try {
|
||||
auto fn = std::move( fn_);
|
||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||
fn( synthesized);
|
||||
} catch ( boost::context::detail::forced_unwind const&) {
|
||||
throw;
|
||||
} catch (...) {
|
||||
// store other exceptions in exception-pointer
|
||||
except = std::current_exception();
|
||||
}
|
||||
// set termination flags
|
||||
state |= state_t::complete;
|
||||
// jump back to ctx
|
||||
auto result = other->ctx();
|
||||
other->ctx = std::move( std::get< 0 >( result) );
|
||||
return std::move( other->ctx);
|
||||
}},
|
||||
#endif
|
||||
other{ nullptr },
|
||||
state{ state_t::unwind },
|
||||
except{} {
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb,
|
||||
boost::context::captured_context & ctx_) noexcept :
|
||||
ctx{ std::move( ctx_) },
|
||||
other{ cb },
|
||||
state{ state_t::none },
|
||||
except{} {
|
||||
}
|
||||
|
||||
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) {
|
||||
// pass an pointer to other context
|
||||
auto result = ctx( const_cast< typename std::remove_const< T >::type * >( std::addressof( t) ) );
|
||||
ctx = std::move( std::get< 0 >( result) );
|
||||
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::captured_context ctx = std::move( cb->ctx);
|
||||
// destroy control structure
|
||||
cb->~control_block();
|
||||
// destroy coroutine's stack
|
||||
ctx();
|
||||
}
|
||||
|
||||
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,
|
||||
std::move(
|
||||
std::bind(
|
||||
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void *) mutable {
|
||||
// create synthesized pull_coroutine< T >
|
||||
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
||||
pull_coroutine< void > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
try {
|
||||
auto fn = std::move( fn_);
|
||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||
fn( synthesized);
|
||||
} catch ( boost::context::detail::forced_unwind const&) {
|
||||
throw;
|
||||
} catch (...) {
|
||||
// store other exceptions in exception-pointer
|
||||
except = std::current_exception();
|
||||
}
|
||||
// set termination flags
|
||||
state |= state_t::complete;
|
||||
// jump back to ctx
|
||||
auto result = other->ctx();
|
||||
other->ctx = std::move( std::get< 0 >( result) );
|
||||
return std::move( other->ctx);
|
||||
},
|
||||
std::forward< Fn >( fn),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2))},
|
||||
#else
|
||||
ctx{ std::allocator_arg, palloc, salloc,
|
||||
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void *) mutable {
|
||||
// create synthesized pull_coroutine< T >
|
||||
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx};
|
||||
pull_coroutine< void > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
try {
|
||||
auto fn = std::move( fn_);
|
||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||
fn( synthesized);
|
||||
} catch ( boost::context::detail::forced_unwind const&) {
|
||||
throw;
|
||||
} catch (...) {
|
||||
// store other exceptions in exception-pointer
|
||||
except = std::current_exception();
|
||||
}
|
||||
// set termination flags
|
||||
state |= state_t::complete;
|
||||
// jump back to ctx
|
||||
auto result = other->ctx();
|
||||
other->ctx = std::move( std::get< 0 >( result) );
|
||||
return std::move( other->ctx);
|
||||
}},
|
||||
#endif
|
||||
other{ nullptr },
|
||||
state{ state_t::unwind },
|
||||
except{} {
|
||||
}
|
||||
|
||||
inline
|
||||
push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb,
|
||||
boost::context::captured_context & ctx_) noexcept :
|
||||
ctx{ std::move( ctx_) },
|
||||
other{ cb },
|
||||
state{ state_t::none },
|
||||
except{} {
|
||||
}
|
||||
|
||||
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() {
|
||||
auto result = ctx();
|
||||
ctx = std::move( std::get< 0 >( result) );
|
||||
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
|
@ -25,11 +25,13 @@ namespace detail {
|
||||
|
||||
template< typename T >
|
||||
struct push_coroutine< T >::control_block {
|
||||
typename pull_coroutine< T >::control_block * other;
|
||||
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 &&);
|
||||
|
||||
@ -40,6 +42,8 @@ struct push_coroutine< T >::control_block {
|
||||
control_block( control_block &) = delete;
|
||||
control_block & operator=( control_block &) = delete;
|
||||
|
||||
void deallocate() noexcept;
|
||||
|
||||
void resume( T const&);
|
||||
|
||||
void resume( T &&);
|
||||
@ -49,11 +53,13 @@ struct push_coroutine< T >::control_block {
|
||||
|
||||
template< typename T >
|
||||
struct push_coroutine< T & >::control_block {
|
||||
typename pull_coroutine< T & >::control_block * other;
|
||||
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 &&);
|
||||
|
||||
@ -64,17 +70,21 @@ struct push_coroutine< T & >::control_block {
|
||||
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 {
|
||||
pull_coroutine< void >::control_block * other;
|
||||
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 &&);
|
||||
|
||||
@ -85,6 +95,8 @@ struct push_coroutine< void >::control_block {
|
||||
control_block( control_block &) = delete;
|
||||
control_block & operator=( control_block &) = delete;
|
||||
|
||||
void deallocate() noexcept;
|
||||
|
||||
void resume();
|
||||
|
||||
bool valid() const noexcept;
|
@ -32,11 +32,18 @@ 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->~control_block();
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template< typename StackAllocator, typename Fn >
|
||||
push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||
Fn && fn) :
|
||||
other{ nullptr },
|
||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||
ctx{ std::allocator_arg, palloc, salloc,
|
||||
std::move(
|
||||
@ -46,11 +53,11 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc,
|
||||
typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
||||
pull_coroutine< T > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
// jump back to ctor
|
||||
T * t = static_cast< T * >( ctx() );
|
||||
// set transferred value
|
||||
synthesized_cb.set( t);
|
||||
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);
|
||||
@ -76,11 +83,11 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc,
|
||||
typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
||||
pull_coroutine< T > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
// jump back to ctor
|
||||
T * t = static_cast< T * >( ctx() );
|
||||
// set transferred value
|
||||
synthesized_cb.set( t);
|
||||
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);
|
||||
@ -97,6 +104,7 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc,
|
||||
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
|
||||
@ -106,19 +114,26 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc,
|
||||
template< typename T >
|
||||
push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb,
|
||||
boost::context::execution_context const& ctx_) noexcept :
|
||||
other{ cb },
|
||||
ctx{ ctx_ },
|
||||
other{ cb },
|
||||
state{ state_t::none },
|
||||
except{} {
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
push_coroutine< T >::control_block::~control_block() noexcept {
|
||||
push_coroutine< T >::control_block::~control_block() {
|
||||
if ( state_t::none == ( state & state_t::complete) &&
|
||||
state_t::none != ( state & state_t::unwind) ) {
|
||||
// set early-exit flag
|
||||
state |= state_t::early_exit;
|
||||
ctx();
|
||||
// unwind coroutine stack
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,10 +146,6 @@ push_coroutine< T >::control_block::resume( T const& t) {
|
||||
if ( except) {
|
||||
std::rethrow_exception( except);
|
||||
}
|
||||
// test early-exit-flag
|
||||
if ( state_t::none != ( other->state & state_t::early_exit) ) {
|
||||
throw forced_unwind();
|
||||
}
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
@ -146,10 +157,6 @@ push_coroutine< T >::control_block::resume( T && t) {
|
||||
if ( except) {
|
||||
std::rethrow_exception( except);
|
||||
}
|
||||
// test early-exit-flag
|
||||
if ( state_t::none != ( other->state & state_t::early_exit) ) {
|
||||
throw forced_unwind();
|
||||
}
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
@ -161,11 +168,18 @@ push_coroutine< T >::control_block::valid() const noexcept {
|
||||
|
||||
// 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->~control_block();
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template< typename StackAllocator, typename Fn >
|
||||
push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||
Fn && fn) :
|
||||
other{ nullptr },
|
||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||
ctx{ std::allocator_arg, palloc, salloc,
|
||||
std::move(
|
||||
@ -175,11 +189,11 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo
|
||||
typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
||||
pull_coroutine< T & > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
// jump back to ctor
|
||||
T * t = static_cast< T * >( ctx() );
|
||||
// set transferred value
|
||||
synthesized_cb.t = t;
|
||||
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);
|
||||
@ -205,11 +219,11 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo
|
||||
typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
||||
pull_coroutine< T & > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
// jump back to ctor
|
||||
T * t = static_cast< T * >( ctx() );
|
||||
// set transferred value
|
||||
synthesized_cb.t = t;
|
||||
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);
|
||||
@ -226,6 +240,7 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo
|
||||
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
|
||||
@ -235,19 +250,26 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo
|
||||
template< typename T >
|
||||
push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb,
|
||||
boost::context::execution_context const& ctx_) noexcept :
|
||||
other{ cb },
|
||||
ctx{ ctx_ },
|
||||
other{ cb },
|
||||
state{ state_t::none },
|
||||
except{} {
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
push_coroutine< T & >::control_block::~control_block() noexcept {
|
||||
push_coroutine< T & >::control_block::~control_block() {
|
||||
if ( state_t::none == ( state & state_t::complete) &&
|
||||
state_t::none != ( state & state_t::unwind) ) {
|
||||
// set early-exit flag
|
||||
state |= state_t::early_exit;
|
||||
ctx();
|
||||
// unwind coroutine stack
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -260,10 +282,6 @@ push_coroutine< T & >::control_block::resume( T & t) {
|
||||
if ( except) {
|
||||
std::rethrow_exception( except);
|
||||
}
|
||||
// test early-exit-flag
|
||||
if ( state_t::none != ( other->state & state_t::early_exit) ) {
|
||||
throw forced_unwind();
|
||||
}
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
@ -275,9 +293,16 @@ push_coroutine< T & >::control_block::valid() const noexcept {
|
||||
|
||||
// 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->~control_block();
|
||||
}
|
||||
|
||||
template< typename StackAllocator, typename Fn >
|
||||
push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) :
|
||||
other{ nullptr },
|
||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||
ctx{ std::allocator_arg, palloc, salloc,
|
||||
std::move(
|
||||
@ -288,9 +313,9 @@ push_coroutine< void >::control_block::control_block( context::preallocated pall
|
||||
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
||||
pull_coroutine< void > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
// jump back to ctor
|
||||
ctx();
|
||||
try {
|
||||
// jump back to ctor
|
||||
ctx();
|
||||
auto fn = std::move( fn_);
|
||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||
fn( synthesized);
|
||||
@ -316,9 +341,9 @@ push_coroutine< void >::control_block::control_block( context::preallocated pall
|
||||
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
||||
pull_coroutine< void > synthesized{ & synthesized_cb };
|
||||
other = & synthesized_cb;
|
||||
// jump back to ctor
|
||||
ctx();
|
||||
try {
|
||||
// jump back to ctor
|
||||
ctx();
|
||||
auto fn = std::move( fn_);
|
||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||
fn( synthesized);
|
||||
@ -335,6 +360,7 @@ push_coroutine< void >::control_block::control_block( context::preallocated pall
|
||||
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
|
||||
@ -344,19 +370,26 @@ push_coroutine< void >::control_block::control_block( context::preallocated pall
|
||||
inline
|
||||
push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb,
|
||||
boost::context::execution_context const& ctx_) noexcept :
|
||||
other{ cb },
|
||||
ctx{ ctx_ },
|
||||
other{ cb },
|
||||
state{ state_t::none },
|
||||
except{} {
|
||||
}
|
||||
|
||||
inline
|
||||
push_coroutine< void >::control_block::~control_block() noexcept {
|
||||
push_coroutine< void >::control_block::~control_block() {
|
||||
if ( state_t::none == ( state & state_t::complete) &&
|
||||
state_t::none != ( state & state_t::unwind) ) {
|
||||
// set early-exit flag
|
||||
state |= state_t::early_exit;
|
||||
ctx();
|
||||
// unwind coroutine stack
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -368,10 +401,6 @@ push_coroutine< void >::control_block::resume() {
|
||||
if ( except) {
|
||||
std::rethrow_exception( except);
|
||||
}
|
||||
// test early-exit-flag
|
||||
if ( state_t::none != ( other->state & state_t::early_exit) ) {
|
||||
throw forced_unwind();
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
@ -50,7 +50,7 @@ push_coroutine< T >::push_coroutine( StackAllocator salloc, Fn && fn) :
|
||||
template< typename T >
|
||||
push_coroutine< T >::~push_coroutine() noexcept {
|
||||
if ( nullptr != cb_) {
|
||||
cb_->~control_block();
|
||||
cb_->deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +110,7 @@ push_coroutine< T & >::push_coroutine( StackAllocator salloc, Fn && fn) :
|
||||
template< typename T >
|
||||
push_coroutine< T & >::~push_coroutine() noexcept {
|
||||
if ( nullptr != cb_) {
|
||||
cb_->~control_block();
|
||||
cb_->deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,7 +161,7 @@ push_coroutine< void >::push_coroutine( StackAllocator salloc, Fn && fn) :
|
||||
inline
|
||||
push_coroutine< void >::~push_coroutine() noexcept {
|
||||
if ( nullptr != cb_) {
|
||||
cb_->~control_block();
|
||||
cb_->deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,7 @@ namespace detail {
|
||||
enum class state_t : unsigned int {
|
||||
none = 0,
|
||||
complete = 1 << 1,
|
||||
unwind = 1 << 2,
|
||||
early_exit = 1 << 3
|
||||
unwind = 1 << 2
|
||||
};
|
||||
|
||||
|
||||
|
@ -85,12 +85,10 @@ int main( int argc, char * argv[])
|
||||
if ( bind) bind_to_processor( 0);
|
||||
|
||||
duration_type overhead_c = overhead_clock();
|
||||
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
|
||||
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();
|
||||
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
|
||||
res = measure_cycles( overhead_y);
|
||||
std::cout << "average of " << res << " cpu cycles" << std::endl;
|
||||
#endif
|
||||
|
@ -85,12 +85,10 @@ int main( int argc, char * argv[])
|
||||
if ( bind) bind_to_processor( 0);
|
||||
|
||||
duration_type overhead_c = overhead_clock();
|
||||
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
|
||||
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();
|
||||
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
|
||||
res = measure_cycles( overhead_y);
|
||||
std::cout << "average of " << res << " cpu cycles" << std::endl;
|
||||
#endif
|
||||
|
@ -168,7 +168,6 @@ int main( int argc, char * argv[])
|
||||
if ( bind) bind_to_processor( 0);
|
||||
|
||||
duration_type overhead_c = overhead_clock();
|
||||
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
|
||||
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();
|
||||
@ -177,7 +176,6 @@ int main( int argc, char * argv[])
|
||||
std::cout << "X: average of " << res << " nano seconds" << std::endl;
|
||||
#ifdef BOOST_CONTEXT_CYCLE
|
||||
cycle_type overhead_y = overhead_cycle();
|
||||
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
|
||||
res = measure_cycles_void( overhead_y);
|
||||
std::cout << "void: average of " << res << " cpu cycles" << std::endl;
|
||||
res = measure_cycles_int( overhead_y);
|
||||
|
@ -28,15 +28,14 @@ project boost/coroutine2/test
|
||||
|
||||
run test_coroutine.cpp :
|
||||
: :
|
||||
[ requires cxx11_constexpr
|
||||
cxx11_decltype
|
||||
cxx11_deleted_functions
|
||||
cxx11_explicit_conversion_operators
|
||||
cxx11_hdr_tuple cxx11_lambdas
|
||||
[ requires cxx11_auto_declarations
|
||||
cxx11_constexpr
|
||||
cxx11_defaulted_functions
|
||||
cxx11_final
|
||||
cxx11_hdr_tuple
|
||||
cxx11_lambdas
|
||||
cxx11_noexcept
|
||||
cxx11_nullptr
|
||||
cxx11_template_aliases
|
||||
cxx11_rvalue_references
|
||||
cxx11_variadic_macros
|
||||
cxx11_variadic_templates
|
||||
cxx14_initialized_lambda_captures ] ;
|
||||
cxx11_template_aliases
|
||||
cxx11_variadic_templates ] ;
|
||||
|
@ -613,7 +613,7 @@ void test_chaining()
|
||||
boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
|
||||
{
|
||||
boost::unit_test::test_suite * test =
|
||||
BOOST_TEST_SUITE("Boost.coroutine: coroutine test suite");
|
||||
BOOST_TEST_SUITE("Boost.Coroutine2: coroutine test suite");
|
||||
|
||||
test->add( BOOST_TEST_CASE( & test_move) );
|
||||
test->add( BOOST_TEST_CASE( & test_complete) );
|
||||
|
Loading…
x
Reference in New Issue
Block a user