Merge branch 'develop'

This commit is contained in:
Oliver Kowalke 2016-01-26 17:49:37 +01:00
commit 1f15040a55
22 changed files with 1316 additions and 193 deletions

View File

@ -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 ;

View File

@ -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]

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View 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

View File

@ -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;

View File

@ -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

View File

@ -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();
}
}

View 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

View 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

View File

@ -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;

View File

@ -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

View File

@ -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();
}
}

View File

@ -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
};

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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 ] ;

View File

@ -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) );