adapt new execution_context API

This commit is contained in:
Oliver Kowalke 2015-11-10 20:02:33 +01:00
parent fb8254cadb
commit a73e4b1ace
22 changed files with 501 additions and 544 deletions

View File

@ -9,26 +9,22 @@
#include <boost/coroutine2/all.hpp> #include <boost/coroutine2/all.hpp>
int main() int main() {
{
boost::coroutines2::coroutine< int >::pull_type source( boost::coroutines2::coroutine< int >::pull_type source(
[&]( boost::coroutines2::coroutine< int >::push_type & sink) { []( boost::coroutines2::coroutine< int >::push_type & sink) {
int first = 1, second = 1; int first = 1, second = 1;
sink( first); sink( first);
sink( second); sink( second);
for ( int i = 0; i < 8; ++i) for ( int i = 0; i < 8; ++i) {
{
int third = first + second; int third = first + second;
first = second; first = second;
second = third; second = third;
sink( third); sink( third);
} }
}); });
for ( auto i : source) {
for ( auto i : source)
std::cout << i << " "; std::cout << i << " ";
}
std::cout << "\nDone" << std::endl; std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -21,13 +21,11 @@ struct FinalEOL{
int main(int argc,char* argv[]){ int main(int argc,char* argv[]){
using std::begin; using std::begin;
using std::end; using std::end;
std::vector<std::string> words{ std::vector<std::string> words{
"peas", "porridge", "hot", "peas", "peas", "porridge", "hot", "peas",
"porridge", "cold", "peas", "porridge", "porridge", "cold", "peas", "porridge",
"in", "the", "pot", "nine", "in", "the", "pot", "nine",
"days", "old" }; "days", "old" };
int num=5,width=15; int num=5,width=15;
boost::coroutines2::coroutine<std::string>::push_type writer( boost::coroutines2::coroutine<std::string>::push_type writer(
[&](boost::coroutines2::coroutine<std::string>::pull_type& in){ [&](boost::coroutines2::coroutine<std::string>::pull_type& in){
@ -46,10 +44,7 @@ int main(int argc,char* argv[]){
std::cout << std::endl; std::cout << std::endl;
} }
}); });
std::copy(begin(words),end(words),begin(writer)); std::copy(begin(words),end(words),begin(writer));
std::cout << "\nDone";
std::cout << "\nDone" << std::endl; return EXIT_SUCCESS;
return 0;
} }

View File

@ -108,14 +108,11 @@ int main() {
}); });
p.run(); p.run();
}); });
// user-code pulls parsed data from parser // user-code pulls parsed data from parser
for(char c:seq){ for(char c:seq){
printf("Parsed: %c\n",c); printf("Parsed: %c\n",c);
} }
std::cout << "\nDone" << std::endl; std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} catch ( std::exception const& ex) { } catch ( std::exception const& ex) {
std::cerr << "exception: " << ex.what() << std::endl; std::cerr << "exception: " << ex.what() << std::endl;

View File

@ -13,8 +13,7 @@
#include <boost/coroutine2/all.hpp> #include <boost/coroutine2/all.hpp>
struct node struct node {
{
typedef std::shared_ptr< node > ptr_t; typedef std::shared_ptr< node > ptr_t;
// Each tree node has an optional left subtree, an optional right subtree // Each tree node has an optional left subtree, an optional right subtree
@ -25,26 +24,24 @@ struct node
// construct leaf // construct leaf
node(const std::string& v): node(const std::string& v):
left(),right(),value(v) left(),right(),value(v) {
{} }
// construct nonleaf // construct nonleaf
node(ptr_t l, const std::string& v, ptr_t r): node(ptr_t l, const std::string& v, ptr_t r):
left(l),right(r),value(v) left(l),right(r),value(v) {
{} }
static ptr_t create(const std::string& v) static ptr_t create(const std::string& v) {
{
return ptr_t(new node(v)); return ptr_t(new node(v));
} }
static ptr_t create(ptr_t l, const std::string& v, ptr_t r) static ptr_t create(ptr_t l, const std::string& v, ptr_t r) {
{
return ptr_t(new node(l, v, r)); return ptr_t(new node(l, v, r));
} }
}; };
node::ptr_t create_left_tree_from(const std::string& root) node::ptr_t create_left_tree_from(const std::string& root) {
{
/* -------- /* --------
root root
/ \ / \
@ -62,8 +59,7 @@ node::ptr_t create_left_tree_from(const std::string& root)
node::create("e")); node::create("e"));
} }
node::ptr_t create_right_tree_from(const std::string& root) node::ptr_t create_right_tree_from(const std::string& root) {
{
/* -------- /* --------
root root
/ \ / \
@ -82,8 +78,7 @@ node::ptr_t create_right_tree_from(const std::string& root)
} }
// recursively walk the tree, delivering values in order // recursively walk the tree, delivering values in order
void traverse(node::ptr_t n, boost::coroutines2::coroutine<std::string>::push_type& out) void traverse(node::ptr_t n, boost::coroutines2::coroutine<std::string>::push_type& out) {
{
if (n->left) if (n->left)
traverse(n->left,out); traverse(n->left,out);
out(n->value); out(n->value);
@ -91,8 +86,7 @@ void traverse(node::ptr_t n, boost::coroutines2::coroutine<std::string>::push_ty
traverse(n->right,out); traverse(n->right,out);
} }
int main() int main() {
{
{ {
node::ptr_t left_d(create_left_tree_from("d")); 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>::pull_type left_d_reader(
@ -127,7 +121,6 @@ int main()
std::ostream_iterator<std::string>(std::cout, " ")); std::ostream_iterator<std::string>(std::cout, " "));
std::cout << std::endl; std::cout << std::endl;
} }
{ {
node::ptr_t left_d(create_left_tree_from("d")); 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>::pull_type left_d_reader(
@ -148,7 +141,6 @@ int main()
begin(right_b_reader)) begin(right_b_reader))
<< std::endl; << std::endl;
} }
{ {
node::ptr_t left_d(create_left_tree_from("d")); 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>::pull_type left_d_reader(
@ -169,8 +161,6 @@ int main()
begin(right_x_reader)) begin(right_x_reader))
<< std::endl; << std::endl;
} }
std::cout << "Done" << std::endl; std::cout << "Done" << std::endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -54,7 +54,7 @@ int main() {
sink(); sink();
std::cout << "main: done" << std::endl; std::cout << "main: Done" << std::endl;
return 0; return 0;
} }

View File

@ -9,15 +9,12 @@
#include <boost/coroutine2/all.hpp> #include <boost/coroutine2/all.hpp>
int main() int main() {
{
boost::coroutines2::coroutine< void >::push_type sink( boost::coroutines2::coroutine< void >::push_type sink(
[&]( boost::coroutines2::coroutine< void >::pull_type & source) { []( boost::coroutines2::coroutine< void >::pull_type & source) {
std::cout << "inside coroutine-fn" << std::endl; std::cout << "inside coroutine-fn" << std::endl;
}); });
sink(); sink();
std::cout << "Done" << std::endl; std::cout << "Done" << std::endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -0,0 +1,60 @@
// 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_CREATE_CONTROLBLOCK_IPP
#define BOOST_COROUTINES2_DETAIL_CREATE_CONTROLBLOCK_IPP
#include <cstddef>
#include <memory>
#include <utility>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/context/preallocated.hpp>
#include <boost/context/stack_context.hpp>
#include <boost/coroutine2/detail/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace coroutines2 {
namespace detail {
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)
void * sp = static_cast< char * >( sctx.sp) - sizeof( ControlBlock);
std::size_t size = sctx.size - sizeof( ControlBlock);
#else
constexpr std::size_t func_alignment = 64; // alignof( ControlBlock);
constexpr std::size_t func_size = sizeof( ControlBlock);
// reserve space on stack
void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
// align sp pointer
std::size_t space = func_size + func_alignment;
sp = std::align( func_alignment, func_size, sp, space);
BOOST_ASSERT( nullptr != sp);
// calculate remaining size
std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
#endif
// placment new for control structure on coroutine stack
return new ( sp) ControlBlock{ context::preallocated( sp, size, sctx),
salloc, std::forward< Fn >( fn) };
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES2_DETAIL_CREATE_CONTROLBLOCK_IPP

View File

@ -24,6 +24,12 @@ namespace detail {
struct forced_unwind {}; struct forced_unwind {};
inline
void * unwind_coroutine( void * data) {
throw forced_unwind{};
return data;
}
}}} }}}
#ifdef BOOST_HAS_ABI_HEADERS #ifdef BOOST_HAS_ABI_HEADERS

View File

@ -13,6 +13,8 @@
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/context/execution_context.hpp> #include <boost/context/execution_context.hpp>
#include <boost/coroutine2/detail/state.hpp>
#ifdef BOOST_HAS_ABI_HEADERS #ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX # include BOOST_ABI_PREFIX
#endif #endif
@ -25,18 +27,17 @@ template< typename T >
struct pull_coroutine< T >::control_block { struct pull_coroutine< T >::control_block {
typename push_coroutine< T >::control_block * other; typename push_coroutine< T >::control_block * other;
boost::context::execution_context ctx; boost::context::execution_context ctx;
bool preserve_fpu; state_t state;
int state;
std::exception_ptr except; std::exception_ptr except;
bool bvalid; bool bvalid;
typename std::aligned_storage< sizeof( T), alignof( T) >::type storage[1]; typename std::aligned_storage< sizeof( T), alignof( T) >::type storage[1];
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&, bool); control_block( context::preallocated, StackAllocator, Fn &&);
explicit control_block( typename push_coroutine< T >::control_block *, boost::context::execution_context const&); control_block( typename push_coroutine< T >::control_block *, boost::context::execution_context const&) noexcept;
~control_block(); ~control_block() noexcept;
control_block( control_block &) = delete; control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete; control_block & operator=( control_block &) = delete;
@ -45,7 +46,7 @@ struct pull_coroutine< T >::control_block {
void set( T *); void set( T *);
T & get(); T & get() noexcept;
bool valid() const noexcept; bool valid() const noexcept;
}; };
@ -54,24 +55,23 @@ template< typename T >
struct pull_coroutine< T & >::control_block { struct pull_coroutine< T & >::control_block {
typename push_coroutine< T & >::control_block * other; typename push_coroutine< T & >::control_block * other;
boost::context::execution_context ctx; boost::context::execution_context ctx;
bool preserve_fpu; state_t state;
int state;
std::exception_ptr except; std::exception_ptr except;
T * t; T * t;
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&, bool); control_block( context::preallocated, StackAllocator, Fn &&);
explicit control_block( typename push_coroutine< T & >::control_block *, boost::context::execution_context const&); control_block( typename push_coroutine< T & >::control_block *, boost::context::execution_context const&) noexcept;
~control_block(); ~control_block() noexcept;
control_block( control_block &) = delete; control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete; control_block & operator=( control_block &) = delete;
void resume(); void resume();
T & get(); T & get() noexcept;
bool valid() const noexcept; bool valid() const noexcept;
}; };
@ -79,16 +79,15 @@ struct pull_coroutine< T & >::control_block {
struct pull_coroutine< void >::control_block { struct pull_coroutine< void >::control_block {
push_coroutine< void >::control_block * other; push_coroutine< void >::control_block * other;
boost::context::execution_context ctx; boost::context::execution_context ctx;
bool preserve_fpu; state_t state;
int state;
std::exception_ptr except; std::exception_ptr except;
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&, bool); control_block( context::preallocated, StackAllocator, Fn &&);
explicit control_block( push_coroutine< void >::control_block *, boost::context::execution_context const&); control_block( push_coroutine< void >::control_block *, boost::context::execution_context const&) noexcept;
~control_block(); ~control_block() noexcept;
control_block( control_block &) = delete; control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete; control_block & operator=( control_block &) = delete;

View File

@ -32,13 +32,13 @@ namespace detail {
template< typename T > template< typename T >
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn_, bool preserve_fpu_) : Fn && fn_) :
other( nullptr), other{ nullptr },
ctx( std::allocator_arg, palloc, salloc, ctx{ std::allocator_arg, palloc, salloc,
[=,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable -> void { [this,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
// create synthesized push_coroutine< T > // create synthesized push_coroutine< T >
typename push_coroutine< T >::control_block synthesized_cb( this, ctx); typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
push_coroutine< T > synthesized( & synthesized_cb); push_coroutine< T > synthesized{ & synthesized_cb };
other = & synthesized_cb; other = & synthesized_cb;
try { try {
// call coroutine-fn with synthesized push_coroutine as argument // call coroutine-fn with synthesized push_coroutine as argument
@ -50,39 +50,37 @@ pull_coroutine< T >::control_block::control_block( context::preallocated palloc,
except = std::current_exception(); except = std::current_exception();
} }
// set termination flags // set termination flags
state |= static_cast< int >( state_t::complete); state |= state_t::complete;
// jump back to ctx // jump back to ctx
other->ctx( nullptr, preserve_fpu); other->ctx();
BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
}), }},
preserve_fpu( preserve_fpu_), state{ state_t::unwind },
state( static_cast< int >( state_t::unwind) ), except{},
except(), bvalid{ false },
bvalid( false), storage{} {
storage() {
// enter coroutine-fn in order to have first value available after ctor (of `*this`) returns // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
set( reinterpret_cast< T * >( ctx( nullptr, preserve_fpu) ) ); set( static_cast< T * >( ctx() ) );
} }
template< typename T > template< typename T >
pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb, pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
boost::context::execution_context const& ctx_) : boost::context::execution_context const& ctx_) noexcept :
other( cb), other{ cb },
ctx( ctx_), ctx{ ctx_ },
preserve_fpu( other->preserve_fpu), state{ state_t::none },
state( 0), except{},
except(), bvalid{ false },
bvalid( false), storage{} {
storage() {
} }
template< typename T > template< typename T >
pull_coroutine< T >::control_block::~control_block() { pull_coroutine< T >::control_block::~control_block() noexcept {
if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && if ( state_t::none == ( state & state_t::complete) &&
0 != ( state & static_cast< int >( state_t::unwind) ) ) { state_t::none != ( state & state_t::unwind) ) {
// set early-exit flag // set early-exit flag
state |= static_cast< int >( state_t::early_exit); state |= state_t::early_exit;
ctx( nullptr, preserve_fpu); ctx();
} }
// destroy data if it set // destroy data if it set
if ( bvalid) { if ( bvalid) {
@ -94,12 +92,12 @@ template< typename T >
void void
pull_coroutine< T >::control_block::resume() { pull_coroutine< T >::control_block::resume() {
other->ctx = boost::context::execution_context::current(); other->ctx = boost::context::execution_context::current();
set( reinterpret_cast< T * >( ctx( nullptr, preserve_fpu) ) ); set( static_cast< T * >( ctx() ) );
if ( except) { if ( except) {
std::rethrow_exception( except); std::rethrow_exception( except);
} }
// test early-exit-flag // test early-exit-flag
if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { if ( state_t::none != ( other->state & state_t::early_exit) ) {
throw forced_unwind(); throw forced_unwind();
} }
} }
@ -121,14 +119,14 @@ pull_coroutine< T >::control_block::set( T * t) {
template< typename T > template< typename T >
T & T &
pull_coroutine< T >::control_block::get() { pull_coroutine< T >::control_block::get() noexcept {
return * reinterpret_cast< T * >( storage); return * reinterpret_cast< T * >( storage);
} }
template< typename T > template< typename T >
bool bool
pull_coroutine< T >::control_block::valid() const noexcept { pull_coroutine< T >::control_block::valid() const noexcept {
return nullptr != other && 0 == ( state & static_cast< int >( state_t::complete) ) && bvalid; return nullptr != other && state_t::none == ( state & state_t::complete) && bvalid;
} }
@ -137,13 +135,13 @@ pull_coroutine< T >::control_block::valid() const noexcept {
template< typename T > template< typename T >
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn_, bool preserve_fpu_) : Fn && fn_) :
other( nullptr), other{ nullptr },
ctx( std::allocator_arg, palloc, salloc, ctx{ std::allocator_arg, palloc, salloc,
[=,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable -> void { [this,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
// create synthesized push_coroutine< T > // create synthesized push_coroutine< T >
typename push_coroutine< T & >::control_block synthesized_cb( this, ctx); typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
push_coroutine< T & > synthesized( & synthesized_cb); push_coroutine< T & > synthesized{ & synthesized_cb };
other = & synthesized_cb; other = & synthesized_cb;
try { try {
// call coroutine-fn with synthesized push_coroutine as argument // call coroutine-fn with synthesized push_coroutine as argument
@ -155,37 +153,35 @@ pull_coroutine< T & >::control_block::control_block( context::preallocated pallo
except = std::current_exception(); except = std::current_exception();
} }
// set termination flags // set termination flags
state |= static_cast< int >( state_t::complete); state |= state_t::complete;
// jump back to ctx // jump back to ctx
other->ctx( nullptr, preserve_fpu); other->ctx();
BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
}), }},
preserve_fpu( preserve_fpu_), state{ state_t::unwind },
state( static_cast< int >( state_t::unwind) ), except{},
except(),
t( nullptr) { t( nullptr) {
// enter coroutine-fn in order to have first value available after ctor (of `*this`) returns // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
t = reinterpret_cast< T * >( ctx( nullptr, preserve_fpu) ); t = static_cast< T * >( ctx() );
} }
template< typename T > template< typename T >
pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb, pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
boost::context::execution_context const& ctx_) : boost::context::execution_context const& ctx_) noexcept :
other( cb), other{ cb },
ctx( ctx_), ctx{ ctx_ },
preserve_fpu( other->preserve_fpu), state{ state_t::none },
state( 0), except{},
except(),
t( nullptr) { t( nullptr) {
} }
template< typename T > template< typename T >
pull_coroutine< T & >::control_block::~control_block() { pull_coroutine< T & >::control_block::~control_block() noexcept {
if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && if ( state_t::none == ( state & state_t::complete) &&
0 != ( state & static_cast< int >( state_t::unwind) ) ) { state_t::none != ( state & state_t::unwind) ) {
// set early-exit flag // set early-exit flag
state |= static_cast< int >( state_t::early_exit); state |= state_t::early_exit;
ctx( nullptr, preserve_fpu); ctx();
} }
} }
@ -193,26 +189,26 @@ template< typename T >
void void
pull_coroutine< T & >::control_block::resume() { pull_coroutine< T & >::control_block::resume() {
other->ctx = boost::context::execution_context::current(); other->ctx = boost::context::execution_context::current();
t = reinterpret_cast< T * >( ctx( nullptr, preserve_fpu) ); t = static_cast< T * >( ctx() );
if ( except) { if ( except) {
std::rethrow_exception( except); std::rethrow_exception( except);
} }
// test early-exit-flag // test early-exit-flag
if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { if ( state_t::none != ( other->state & state_t::early_exit) ) {
throw forced_unwind(); throw forced_unwind();
} }
} }
template< typename T > template< typename T >
T & T &
pull_coroutine< T & >::control_block::get() { pull_coroutine< T & >::control_block::get() noexcept {
return * reinterpret_cast< T * >( t); return * static_cast< T * >( t);
} }
template< typename T > template< typename T >
bool bool
pull_coroutine< T & >::control_block::valid() const noexcept { pull_coroutine< T & >::control_block::valid() const noexcept {
return nullptr != other && 0 == ( state & static_cast< int >( state_t::complete) ) && nullptr != t; return nullptr != other && state_t::none == ( state & state_t::complete) && nullptr != t;
} }
@ -220,13 +216,13 @@ pull_coroutine< T & >::control_block::valid() const noexcept {
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn_, bool preserve_fpu_) : Fn && fn_) :
other( nullptr), other{ nullptr },
ctx( std::allocator_arg, palloc, salloc, ctx{ std::allocator_arg, palloc, salloc,
[=,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable -> void { [this,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
// create synthesized push_coroutine< T > // create synthesized push_coroutine< T >
typename push_coroutine< void >::control_block synthesized_cb( this, ctx); typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
push_coroutine< void > synthesized( & synthesized_cb); push_coroutine< void > synthesized{ & synthesized_cb };
other = & synthesized_cb; other = & synthesized_cb;
try { try {
// call coroutine-fn with synthesized push_coroutine as argument // call coroutine-fn with synthesized push_coroutine as argument
@ -238,35 +234,33 @@ pull_coroutine< void >::control_block::control_block( context::preallocated pall
except = std::current_exception(); except = std::current_exception();
} }
// set termination flags // set termination flags
state |= static_cast< int >( state_t::complete); state |= state_t::complete;
// jump back to ctx // jump back to ctx
other->ctx( nullptr, preserve_fpu); other->ctx();
BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
}), }},
preserve_fpu( preserve_fpu_), state{ state_t::unwind },
state( static_cast< int >( state_t::unwind) ), except{} {
except() {
// enter coroutine-fn in order to have first value available after ctor returns // enter coroutine-fn in order to have first value available after ctor returns
ctx( nullptr, preserve_fpu); ctx();
} }
inline inline
pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb, pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
boost::context::execution_context const& ctx_) : boost::context::execution_context const& ctx_) noexcept :
other( cb), other{ cb },
ctx( ctx_), ctx{ ctx_ },
preserve_fpu( other->preserve_fpu), state{ state_t::none },
state( 0), except{} {
except() {
} }
inline inline
pull_coroutine< void >::control_block::~control_block() { pull_coroutine< void >::control_block::~control_block() noexcept {
if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && if ( state_t::none == ( state & state_t::complete) &&
0 != ( state & static_cast< int >( state_t::unwind) ) ) { state_t::none != ( state & state_t::unwind) ) {
// set early-exit flag // set early-exit flag
state |= static_cast< int >( state_t::early_exit); state |= state_t::early_exit;
ctx( nullptr, preserve_fpu); ctx();
} }
} }
@ -274,12 +268,12 @@ inline
void void
pull_coroutine< void >::control_block::resume() { pull_coroutine< void >::control_block::resume() {
other->ctx = boost::context::execution_context::current(); other->ctx = boost::context::execution_context::current();
ctx( nullptr, preserve_fpu); ctx();
if ( except) { if ( except) {
std::rethrow_exception( except); std::rethrow_exception( except);
} }
// test early-exit-flag // test early-exit-flag
if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { if ( state_t::none != ( other->state & state_t::early_exit) ) {
throw forced_unwind(); throw forced_unwind();
} }
} }
@ -287,7 +281,7 @@ pull_coroutine< void >::control_block::resume() {
inline inline
bool bool
pull_coroutine< void >::control_block::valid() const noexcept { pull_coroutine< void >::control_block::valid() const noexcept {
return nullptr != other && 0 == ( state & static_cast< int >( state_t::complete) ); return nullptr != other && state_t::none == ( state & state_t::complete);
} }
}}} }}}

View File

@ -12,7 +12,6 @@
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/context/execution_context.hpp>
#include <boost/coroutine2/detail/config.hpp> #include <boost/coroutine2/detail/config.hpp>
@ -34,25 +33,25 @@ private:
control_block * cb_; control_block * cb_;
explicit pull_coroutine( control_block *); explicit pull_coroutine( control_block *) noexcept;
bool has_result_() const; bool has_result_() const noexcept;
public: public:
template< typename Fn > template< typename Fn >
explicit pull_coroutine( Fn &&, bool = false); explicit pull_coroutine( Fn &&);
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
explicit pull_coroutine( StackAllocator, Fn &&, bool = false); pull_coroutine( StackAllocator, Fn &&);
~pull_coroutine(); ~pull_coroutine() noexcept;
pull_coroutine( pull_coroutine const&) = delete; pull_coroutine( pull_coroutine const&) = delete;
pull_coroutine & operator=( pull_coroutine const&) = delete; pull_coroutine & operator=( pull_coroutine const&) = delete;
pull_coroutine( pull_coroutine &&); pull_coroutine( pull_coroutine &&) noexcept;
pull_coroutine & operator=( pull_coroutine && other) { pull_coroutine & operator=( pull_coroutine && other) noexcept {
if ( this != & other) { if ( this != & other) {
cb_ = other.cb_; cb_ = other.cb_;
other.cb_ = nullptr; other.cb_ = nullptr;
@ -66,7 +65,7 @@ public:
bool operator!() const noexcept; bool operator!() const noexcept;
T get(); T get() noexcept;
class iterator : public std::iterator< std::input_iterator_tag, typename std::remove_reference< T >::type > { class iterator : public std::iterator< std::input_iterator_tag, typename std::remove_reference< T >::type > {
private: private:
@ -91,30 +90,31 @@ public:
typedef typename iterator::pointer pointer_t; typedef typename iterator::pointer pointer_t;
typedef typename iterator::reference reference_t; typedef typename iterator::reference reference_t;
iterator() : iterator() noexcept :
c_( nullptr) { c_{ nullptr } {
} }
explicit iterator( pull_coroutine< T > * c) : explicit iterator( pull_coroutine< T > * c) :
c_( c) { c_{ c } {
fetch_(); fetch_();
} }
iterator( iterator const& other) : iterator( iterator const& other) noexcept :
c_( other.c_) { c_{ other.c_ } {
} }
iterator & operator=( iterator const& other) { iterator & operator=( iterator const& other) noexcept {
if ( this == & other) return * this; if ( this != & other) {
c_ = other.c_; c_ = other.c_;
}
return * this; return * this;
} }
bool operator==( iterator const& other) const { bool operator==( iterator const& other) const noexcept {
return other.c_ == c_; return other.c_ == c_;
} }
bool operator!=( iterator const& other) const { bool operator!=( iterator const& other) const noexcept {
return other.c_ != c_; return other.c_ != c_;
} }
@ -125,11 +125,11 @@ public:
iterator operator++( int) = delete; iterator operator++( int) = delete;
reference_t operator*() const { reference_t operator*() const noexcept {
return c_->cb_->get(); return c_->cb_->get();
} }
pointer_t operator->() const { pointer_t operator->() const noexcept {
return std::addressof( c_->cb_->get() ); return std::addressof( c_->cb_->get() );
} }
}; };
@ -147,25 +147,25 @@ private:
control_block * cb_; control_block * cb_;
explicit pull_coroutine( control_block *); explicit pull_coroutine( control_block *) noexcept;
bool has_result_() const; bool has_result_() const noexcept;
public: public:
template< typename Fn > template< typename Fn >
explicit pull_coroutine( Fn &&, bool = false); explicit pull_coroutine( Fn &&);
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
explicit pull_coroutine( StackAllocator, Fn &&, bool = false); pull_coroutine( StackAllocator, Fn &&);
~pull_coroutine(); ~pull_coroutine() noexcept;
pull_coroutine( pull_coroutine const&) = delete; pull_coroutine( pull_coroutine const&) = delete;
pull_coroutine & operator=( pull_coroutine const&) = delete; pull_coroutine & operator=( pull_coroutine const&) = delete;
pull_coroutine( pull_coroutine &&); pull_coroutine( pull_coroutine &&) noexcept;
pull_coroutine & operator=( pull_coroutine && other) { pull_coroutine & operator=( pull_coroutine && other) noexcept {
if ( this != & other) { if ( this != & other) {
cb_ = other.cb_; cb_ = other.cb_;
other.cb_ = nullptr; other.cb_ = nullptr;
@ -179,7 +179,7 @@ public:
bool operator!() const noexcept; bool operator!() const noexcept;
T & get(); T & get() noexcept;
class iterator : public std::iterator< std::input_iterator_tag, typename std::remove_reference< T >::type > { class iterator : public std::iterator< std::input_iterator_tag, typename std::remove_reference< T >::type > {
private: private:
@ -204,30 +204,31 @@ public:
typedef typename iterator::pointer pointer_t; typedef typename iterator::pointer pointer_t;
typedef typename iterator::reference reference_t; typedef typename iterator::reference reference_t;
iterator() : iterator() noexcept :
c_( nullptr) { c_{ nullptr } {
} }
explicit iterator( pull_coroutine< T & > * c) : explicit iterator( pull_coroutine< T & > * c) :
c_( c) { c_{ c } {
fetch_(); fetch_();
} }
iterator( iterator const& other) : iterator( iterator const& other) noexcept :
c_( other.c_) { c_{ other.c_ } {
} }
iterator & operator=( iterator const& other) { iterator & operator=( iterator const& other) noexcept {
if ( this == & other) return * this; if ( this != & other) {
c_ = other.c_; c_ = other.c_;
}
return * this; return * this;
} }
bool operator==( iterator const& other) const { bool operator==( iterator const& other) const noexcept {
return other.c_ == c_; return other.c_ == c_;
} }
bool operator!=( iterator const& other) const { bool operator!=( iterator const& other) const noexcept {
return other.c_ != c_; return other.c_ != c_;
} }
@ -238,11 +239,11 @@ public:
iterator operator++( int) = delete; iterator operator++( int) = delete;
reference_t operator*() const { reference_t operator*() const noexcept {
return c_->cb_->get(); return c_->cb_->get();
} }
pointer_t operator->() const { pointer_t operator->() const noexcept {
return std::addressof( c_->cb_->get() ); return std::addressof( c_->cb_->get() );
} }
}; };
@ -260,23 +261,23 @@ private:
control_block * cb_; control_block * cb_;
explicit pull_coroutine( control_block *); explicit pull_coroutine( control_block *) noexcept;
public: public:
template< typename Fn > template< typename Fn >
explicit pull_coroutine( Fn &&, bool = false); explicit pull_coroutine( Fn &&);
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
explicit pull_coroutine( StackAllocator, Fn &&, bool = false); pull_coroutine( StackAllocator, Fn &&);
~pull_coroutine(); ~pull_coroutine() noexcept;
pull_coroutine( pull_coroutine const&) = delete; pull_coroutine( pull_coroutine const&) = delete;
pull_coroutine & operator=( pull_coroutine const&) = delete; pull_coroutine & operator=( pull_coroutine const&) = delete;
pull_coroutine( pull_coroutine &&); pull_coroutine( pull_coroutine &&) noexcept;
pull_coroutine & operator=( pull_coroutine && other) { pull_coroutine & operator=( pull_coroutine && other) noexcept {
if ( this != & other) { if ( this != & other) {
cb_ = other.cb_; cb_ = other.cb_;
other.cb_ = nullptr; other.cb_ = nullptr;

View File

@ -8,16 +8,13 @@
#define BOOST_COROUTINES2_DETAIL_PULL_COROUTINE_IPP #define BOOST_COROUTINES2_DETAIL_PULL_COROUTINE_IPP
#include <algorithm> #include <algorithm>
#include <memory>
#include <utility> #include <utility>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/context/execution_context.hpp>
#include <boost/context/stack_context.hpp>
#include <boost/coroutine2/detail/config.hpp> #include <boost/coroutine2/detail/config.hpp>
#include <boost/coroutine2/detail/create_control_block.ipp>
#include <boost/coroutine2/fixedsize_stack.hpp> #include <boost/coroutine2/fixedsize_stack.hpp>
#include <boost/coroutine2/segmented_stack.hpp> #include <boost/coroutine2/segmented_stack.hpp>
@ -32,57 +29,41 @@ namespace detail {
// pull_coroutine< T > // pull_coroutine< T >
template< typename T > template< typename T >
pull_coroutine< T >::pull_coroutine( control_block * cb) : pull_coroutine< T >::pull_coroutine( control_block * cb) noexcept :
cb_( cb) { cb_{ cb } {
} }
template< typename T > template< typename T >
bool bool
pull_coroutine< T >::has_result_() const { pull_coroutine< T >::has_result_() const noexcept {
return nullptr != cb_->other->t; return nullptr != cb_->other->t;
} }
template< typename T > template< typename T >
template< typename Fn > template< typename Fn >
pull_coroutine< T >::pull_coroutine( Fn && fn, bool preserve_fpu) : pull_coroutine< T >::pull_coroutine( Fn && fn) :
pull_coroutine( default_stack(), std::forward< Fn >( fn), preserve_fpu) { pull_coroutine{ default_stack(), std::forward< Fn >( fn) } {
} }
template< typename T > template< typename T >
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
pull_coroutine< T >::pull_coroutine( StackAllocator salloc, Fn && fn, bool preserve_fpu) : pull_coroutine< T >::pull_coroutine( StackAllocator salloc, Fn && fn) :
cb_( nullptr) { cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
context::stack_context sctx( salloc.allocate() ); if ( ! cb_->valid() ) {
// reserve space for control structure cb_->~control_block();
#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN) cb_ = nullptr;
void * sp = static_cast< char * >( sctx.sp) - sizeof( control_block); }
std::size_t size = sctx.size - sizeof( control_block);
#else
constexpr std::size_t func_alignment = 64; // alignof( control_block);
constexpr std::size_t func_size = sizeof( control_block);
// reserve space on stack
void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
// align sp pointer
std::size_t space = func_size + func_alignment;
sp = std::align( func_alignment, func_size, sp, space);
BOOST_ASSERT( nullptr != sp);
// calculate remaining size
std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
#endif
// placment new for control structure on coroutine stack
cb_ = new ( sp) control_block( context::preallocated( sp, size, sctx),
salloc, std::forward< Fn >( fn), preserve_fpu);
} }
template< typename T > template< typename T >
pull_coroutine< T >::~pull_coroutine() { pull_coroutine< T >::~pull_coroutine() noexcept {
if ( nullptr != cb_) { if ( nullptr != cb_) {
cb_->~control_block(); cb_->~control_block();
} }
} }
template< typename T > template< typename T >
pull_coroutine< T >::pull_coroutine( pull_coroutine && other) : pull_coroutine< T >::pull_coroutine( pull_coroutine && other) noexcept :
cb_( other.cb_) { cb_( other.cb_) {
other.cb_ = nullptr; other.cb_ = nullptr;
} }
@ -107,7 +88,7 @@ pull_coroutine< T >::operator!() const noexcept {
template< typename T > template< typename T >
T T
pull_coroutine< T >::get() { pull_coroutine< T >::get() noexcept {
return std::move( cb_->get() ); return std::move( cb_->get() );
} }
@ -115,57 +96,41 @@ pull_coroutine< T >::get() {
// pull_coroutine< T & > // pull_coroutine< T & >
template< typename T > template< typename T >
pull_coroutine< T & >::pull_coroutine( control_block * cb) : pull_coroutine< T & >::pull_coroutine( control_block * cb) noexcept :
cb_( cb) { cb_( cb) {
} }
template< typename T > template< typename T >
bool bool
pull_coroutine< T & >::has_result_() const { pull_coroutine< T & >::has_result_() const noexcept {
return nullptr != cb_->other->t; return nullptr != cb_->other->t;
} }
template< typename T > template< typename T >
template< typename Fn > template< typename Fn >
pull_coroutine< T & >::pull_coroutine( Fn && fn, bool preserve_fpu) : pull_coroutine< T & >::pull_coroutine( Fn && fn) :
pull_coroutine( default_stack(), std::forward< Fn >( fn), preserve_fpu) { pull_coroutine{ default_stack(), std::forward< Fn >( fn) } {
} }
template< typename T > template< typename T >
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
pull_coroutine< T & >::pull_coroutine( StackAllocator salloc, Fn && fn, bool preserve_fpu) : pull_coroutine< T & >::pull_coroutine( StackAllocator salloc, Fn && fn) :
cb_( nullptr) { cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
context::stack_context sctx( salloc.allocate() ); if ( ! cb_->valid() ) {
// reserve space for control structure cb_->~control_block();
#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN) cb_ = nullptr;
void * sp = static_cast< char * >( sctx.sp) - sizeof( control_block); }
std::size_t size = sctx.size - sizeof( control_block);
#else
constexpr std::size_t func_alignment = 64; // alignof( control_block);
constexpr std::size_t func_size = sizeof( control_block);
// reserve space on stack
void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
// align sp pointer
std::size_t space = func_size + func_alignment;
sp = std::align( func_alignment, func_size, sp, space);
BOOST_ASSERT( nullptr != sp);
// calculate remaining size
std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
#endif
// placment new for control structure on coroutine stack
cb_ = new ( sp) control_block( context::preallocated( sp, size, sctx),
salloc, std::forward< Fn >( fn), preserve_fpu);
} }
template< typename T > template< typename T >
pull_coroutine< T & >::~pull_coroutine() { pull_coroutine< T & >::~pull_coroutine() noexcept {
if ( nullptr != cb_) { if ( nullptr != cb_) {
cb_->~control_block(); cb_->~control_block();
} }
} }
template< typename T > template< typename T >
pull_coroutine< T & >::pull_coroutine( pull_coroutine && other) : pull_coroutine< T & >::pull_coroutine( pull_coroutine && other) noexcept :
cb_( other.cb_) { cb_( other.cb_) {
other.cb_ = nullptr; other.cb_ = nullptr;
} }
@ -190,7 +155,7 @@ pull_coroutine< T & >::operator!() const noexcept {
template< typename T > template< typename T >
T & T &
pull_coroutine< T & >::get() { pull_coroutine< T & >::get() noexcept {
return cb_->get(); return cb_->get();
} }
@ -198,49 +163,33 @@ pull_coroutine< T & >::get() {
// pull_coroutine< void > // pull_coroutine< void >
inline inline
pull_coroutine< void >::pull_coroutine( control_block * cb) : pull_coroutine< void >::pull_coroutine( control_block * cb) noexcept :
cb_( cb) { cb_( cb) {
} }
template< typename Fn > template< typename Fn >
pull_coroutine< void >::pull_coroutine( Fn && fn, bool preserve_fpu) : pull_coroutine< void >::pull_coroutine( Fn && fn) :
pull_coroutine( default_stack(), std::forward< Fn >( fn), preserve_fpu) { pull_coroutine{ default_stack(), std::forward< Fn >( fn) } {
} }
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
pull_coroutine< void >::pull_coroutine( StackAllocator salloc, Fn && fn, bool preserve_fpu) : pull_coroutine< void >::pull_coroutine( StackAllocator salloc, Fn && fn) :
cb_( nullptr) { cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
context::stack_context sctx( salloc.allocate() ); if ( ! cb_->valid() ) {
// reserve space for control structure cb_->~control_block();
#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN) cb_ = nullptr;
void * sp = static_cast< char * >( sctx.sp) - sizeof( control_block); }
std::size_t size = sctx.size - sizeof( control_block);
#else
constexpr std::size_t func_alignment = 64; // alignof( control_block);
constexpr std::size_t func_size = sizeof( control_block);
// reserve space on stack
void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
// align sp pointer
std::size_t space = func_size + func_alignment;
sp = std::align( func_alignment, func_size, sp, space);
BOOST_ASSERT( nullptr != sp);
// calculate remaining size
std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
#endif
// placment new for control structure on coroutine stack
cb_ = new ( sp) control_block( context::preallocated( sp, size, sctx),
salloc, std::forward< Fn >( fn), preserve_fpu);
} }
inline inline
pull_coroutine< void >::~pull_coroutine() { pull_coroutine< void >::~pull_coroutine() noexcept {
if ( nullptr != cb_) { if ( nullptr != cb_) {
cb_->~control_block(); cb_->~control_block();
} }
} }
inline inline
pull_coroutine< void >::pull_coroutine( pull_coroutine && other) : pull_coroutine< void >::pull_coroutine( pull_coroutine && other) noexcept :
cb_( other.cb_) { cb_( other.cb_) {
other.cb_ = nullptr; other.cb_ = nullptr;
} }

View File

@ -12,6 +12,8 @@
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/context/execution_context.hpp> #include <boost/context/execution_context.hpp>
#include <boost/coroutine2/detail/state.hpp>
#ifdef BOOST_HAS_ABI_HEADERS #ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX # include BOOST_ABI_PREFIX
#endif #endif
@ -24,16 +26,15 @@ template< typename T >
struct push_coroutine< T >::control_block { struct push_coroutine< T >::control_block {
typename pull_coroutine< T >::control_block * other; typename pull_coroutine< T >::control_block * other;
boost::context::execution_context ctx; boost::context::execution_context ctx;
bool preserve_fpu; state_t state;
int state;
std::exception_ptr except; std::exception_ptr except;
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&, bool); control_block( context::preallocated, StackAllocator, Fn &&);
explicit control_block( typename pull_coroutine< T >::control_block *, boost::context::execution_context const&); control_block( typename pull_coroutine< T >::control_block *, boost::context::execution_context const&) noexcept;
~control_block(); ~control_block() noexcept;
control_block( control_block &) = delete; control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete; control_block & operator=( control_block &) = delete;
@ -49,16 +50,15 @@ template< typename T >
struct push_coroutine< T & >::control_block { struct push_coroutine< T & >::control_block {
typename pull_coroutine< T & >::control_block * other; typename pull_coroutine< T & >::control_block * other;
boost::context::execution_context ctx; boost::context::execution_context ctx;
bool preserve_fpu; state_t state;
int state;
std::exception_ptr except; std::exception_ptr except;
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&, bool); control_block( context::preallocated, StackAllocator, Fn &&);
explicit control_block( typename pull_coroutine< T & >::control_block *, boost::context::execution_context const&); control_block( typename pull_coroutine< T & >::control_block *, boost::context::execution_context const&) noexcept;
~control_block(); ~control_block() noexcept;
control_block( control_block &) = delete; control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete; control_block & operator=( control_block &) = delete;
@ -71,16 +71,15 @@ struct push_coroutine< T & >::control_block {
struct push_coroutine< void >::control_block { struct push_coroutine< void >::control_block {
pull_coroutine< void >::control_block * other; pull_coroutine< void >::control_block * other;
boost::context::execution_context ctx; boost::context::execution_context ctx;
bool preserve_fpu; state_t state;
int state;
std::exception_ptr except; std::exception_ptr except;
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
control_block( context::preallocated, StackAllocator, Fn &&, bool); control_block( context::preallocated, StackAllocator, Fn &&);
explicit control_block( pull_coroutine< void >::control_block *, boost::context::execution_context const&); control_block( pull_coroutine< void >::control_block *, boost::context::execution_context const&) noexcept;
~control_block(); ~control_block() noexcept;
control_block( control_block &) = delete; control_block( control_block &) = delete;
control_block & operator=( control_block &) = delete; control_block & operator=( control_block &) = delete;

View File

@ -33,16 +33,16 @@ namespace detail {
template< typename T > template< typename T >
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn_, bool preserve_fpu_) : Fn && fn_) :
other( nullptr), other{ nullptr },
ctx( std::allocator_arg, palloc, salloc, ctx{ std::allocator_arg, palloc, salloc,
[=,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable -> void { [this,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
// create synthesized pull_coroutine< T > // create synthesized pull_coroutine< T >
typename pull_coroutine< T >::control_block synthesized_cb( this, ctx); typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
pull_coroutine< T > synthesized( & synthesized_cb); pull_coroutine< T > synthesized{ & synthesized_cb };
other = & synthesized_cb; other = & synthesized_cb;
// jump back to ctor // jump back to ctor
T * t = reinterpret_cast< T * >( ctx( nullptr, preserve_fpu) ); T * t = static_cast< T * >( ctx() );
// set transferred value // set transferred value
synthesized_cb.set( t); synthesized_cb.set( t);
try { try {
@ -55,35 +55,33 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc,
except = std::current_exception(); except = std::current_exception();
} }
// set termination flags // set termination flags
state |= static_cast< int >( state_t::complete); state |= state_t::complete;
// jump back to ctx // jump back to ctx
other->ctx( nullptr, preserve_fpu); other->ctx();
BOOST_ASSERT_MSG( false, "push_coroutine is complete"); BOOST_ASSERT_MSG( false, "push_coroutine is complete");
}), }},
preserve_fpu( preserve_fpu_), state{ state_t::unwind },
state( static_cast< int >( state_t::unwind) ), except{} {
except() {
// enter coroutine-fn in order to get other set // enter coroutine-fn in order to get other set
ctx( nullptr, preserve_fpu); ctx();
} }
template< typename T > template< typename T >
push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb, push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb,
boost::context::execution_context const& ctx_) : boost::context::execution_context const& ctx_) noexcept :
other( cb), other{ cb },
ctx( ctx_), ctx{ ctx_ },
preserve_fpu( other->preserve_fpu), state{ state_t::none },
state( 0), except{} {
except() {
} }
template< typename T > template< typename T >
push_coroutine< T >::control_block::~control_block() { push_coroutine< T >::control_block::~control_block() noexcept {
if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && if ( state_t::none == ( state & state_t::complete) &&
0 != ( state & static_cast< int >( state_t::unwind) ) ) { state_t::none != ( state & state_t::unwind) ) {
// set early-exit flag // set early-exit flag
state |= static_cast< int >( state_t::early_exit); state |= state_t::early_exit;
ctx( nullptr, preserve_fpu); ctx();
} }
} }
@ -92,12 +90,12 @@ void
push_coroutine< T >::control_block::resume( T const& t) { push_coroutine< T >::control_block::resume( T const& t) {
other->ctx = boost::context::execution_context::current(); other->ctx = boost::context::execution_context::current();
// pass an pointer to other context // pass an pointer to other context
ctx( const_cast< T * >( & t), preserve_fpu); ctx( const_cast< T * >( & t) );
if ( except) { if ( except) {
std::rethrow_exception( except); std::rethrow_exception( except);
} }
// test early-exit-flag // test early-exit-flag
if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { if ( state_t::none != ( other->state & state_t::early_exit) ) {
throw forced_unwind(); throw forced_unwind();
} }
} }
@ -107,12 +105,12 @@ void
push_coroutine< T >::control_block::resume( T && t) { push_coroutine< T >::control_block::resume( T && t) {
other->ctx = boost::context::execution_context::current(); other->ctx = boost::context::execution_context::current();
// pass an pointer to other context // pass an pointer to other context
ctx( std::addressof( t), preserve_fpu); ctx( std::addressof( t) );
if ( except) { if ( except) {
std::rethrow_exception( except); std::rethrow_exception( except);
} }
// test early-exit-flag // test early-exit-flag
if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { if ( state_t::none != ( other->state & state_t::early_exit) ) {
throw forced_unwind(); throw forced_unwind();
} }
} }
@ -120,7 +118,7 @@ push_coroutine< T >::control_block::resume( T && t) {
template< typename T > template< typename T >
bool bool
push_coroutine< T >::control_block::valid() const noexcept { push_coroutine< T >::control_block::valid() const noexcept {
return 0 == ( state & static_cast< int >( state_t::complete) ); return state_t::none == ( state & state_t::complete );
} }
@ -129,16 +127,16 @@ push_coroutine< T >::control_block::valid() const noexcept {
template< typename T > template< typename T >
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
Fn && fn_, bool preserve_fpu_) : Fn && fn_) :
other( nullptr), other{ nullptr },
ctx( std::allocator_arg, palloc, salloc, ctx{ std::allocator_arg, palloc, salloc,
[=,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable -> void { [this,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
// create synthesized pull_coroutine< T > // create synthesized pull_coroutine< T >
typename pull_coroutine< T & >::control_block synthesized_cb( this, ctx); typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
pull_coroutine< T & > synthesized( & synthesized_cb); pull_coroutine< T & > synthesized{ & synthesized_cb };
other = & synthesized_cb; other = & synthesized_cb;
// jump back to ctor // jump back to ctor
T * t = reinterpret_cast< T * >( ctx( nullptr, preserve_fpu) ); T * t = static_cast< T * >( ctx() );
// set transferred value // set transferred value
synthesized_cb.t = t; synthesized_cb.t = t;
try { try {
@ -151,35 +149,33 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo
except = std::current_exception(); except = std::current_exception();
} }
// set termination flags // set termination flags
state |= static_cast< int >( state_t::complete); state |= state_t::complete;
// jump back to ctx // jump back to ctx
other->ctx( nullptr, preserve_fpu); other->ctx();
BOOST_ASSERT_MSG( false, "push_coroutine is complete"); BOOST_ASSERT_MSG( false, "push_coroutine is complete");
}), }},
preserve_fpu( preserve_fpu_), state{ state_t::unwind },
state( static_cast< int >( state_t::unwind) ), except{} {
except() {
// enter coroutine-fn in order to get other set // enter coroutine-fn in order to get other set
ctx( nullptr, preserve_fpu); ctx();
} }
template< typename T > template< typename T >
push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb, push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb,
boost::context::execution_context const& ctx_) : boost::context::execution_context const& ctx_) noexcept :
other( cb), other{ cb },
ctx( ctx_), ctx{ ctx_ },
preserve_fpu( other->preserve_fpu), state{ state_t::none },
state( 0), except{} {
except() {
} }
template< typename T > template< typename T >
push_coroutine< T & >::control_block::~control_block() { push_coroutine< T & >::control_block::~control_block() noexcept {
if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && if ( state_t::none == ( state & state_t::complete) &&
0 != ( state & static_cast< int >( state_t::unwind) ) ) { state_t::none != ( state & state_t::unwind) ) {
// set early-exit flag // set early-exit flag
state |= static_cast< int >( state_t::early_exit); state |= state_t::early_exit;
ctx( nullptr, preserve_fpu); ctx();
} }
} }
@ -188,12 +184,12 @@ void
push_coroutine< T & >::control_block::resume( T & t) { push_coroutine< T & >::control_block::resume( T & t) {
other->ctx = boost::context::execution_context::current(); other->ctx = boost::context::execution_context::current();
// pass an pointer to other context // pass an pointer to other context
ctx( const_cast< typename std::remove_const< T >::type * >( std::addressof( t) ), preserve_fpu); ctx( const_cast< typename std::remove_const< T >::type * >( std::addressof( t) ) );
if ( except) { if ( except) {
std::rethrow_exception( except); std::rethrow_exception( except);
} }
// test early-exit-flag // test early-exit-flag
if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { if ( state_t::none != ( other->state & state_t::early_exit) ) {
throw forced_unwind(); throw forced_unwind();
} }
} }
@ -201,23 +197,23 @@ push_coroutine< T & >::control_block::resume( T & t) {
template< typename T > template< typename T >
bool bool
push_coroutine< T & >::control_block::valid() const noexcept { push_coroutine< T & >::control_block::valid() const noexcept {
return 0 == ( state & static_cast< int >( state_t::complete) ); return state_t::none == ( state & state_t::complete );
} }
// push_coroutine< void > // push_coroutine< void >
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn_, bool preserve_fpu_) : push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn_) :
other( nullptr), other{ nullptr },
ctx( std::allocator_arg, palloc, salloc, ctx{ std::allocator_arg, palloc, salloc,
[=,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable -> void { [this,fn=std::forward< Fn >( fn_),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
// create synthesized pull_coroutine< T > // create synthesized pull_coroutine< T >
typename pull_coroutine< void >::control_block synthesized_cb( this, ctx); typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
pull_coroutine< void > synthesized( & synthesized_cb); pull_coroutine< void > synthesized{ & synthesized_cb };
other = & synthesized_cb; other = & synthesized_cb;
// jump back to ctor // jump back to ctor
ctx( nullptr, preserve_fpu); ctx();
try { try {
// call coroutine-fn with synthesized pull_coroutine as argument // call coroutine-fn with synthesized pull_coroutine as argument
fn( synthesized); fn( synthesized);
@ -228,35 +224,33 @@ push_coroutine< void >::control_block::control_block( context::preallocated pall
except = std::current_exception(); except = std::current_exception();
} }
// set termination flags // set termination flags
state |= static_cast< int >( state_t::complete); state |= state_t::complete;
// jump back to ctx // jump back to ctx
other->ctx( nullptr, preserve_fpu); other->ctx();
BOOST_ASSERT_MSG( false, "push_coroutine is complete"); BOOST_ASSERT_MSG( false, "push_coroutine is complete");
}), }},
preserve_fpu( preserve_fpu_), state{ state_t::unwind },
state( static_cast< int >( state_t::unwind) ), except{} {
except() {
// enter coroutine-fn in order to get other set // enter coroutine-fn in order to get other set
ctx( nullptr, preserve_fpu); ctx();
} }
inline inline
push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb, push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb,
boost::context::execution_context const& ctx_) : boost::context::execution_context const& ctx_) noexcept :
other( cb), other{ cb },
ctx( ctx_), ctx{ ctx_ },
preserve_fpu( other->preserve_fpu), state{ state_t::none },
state( 0), except{} {
except() {
} }
inline inline
push_coroutine< void >::control_block::~control_block() { push_coroutine< void >::control_block::~control_block() noexcept {
if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && if ( state_t::none == ( state & state_t::complete) &&
0 != ( state & static_cast< int >( state_t::unwind) ) ) { state_t::none != ( state & state_t::unwind) ) {
// set early-exit flag // set early-exit flag
state |= static_cast< int >( state_t::early_exit); state |= state_t::early_exit;
ctx( nullptr, preserve_fpu); ctx();
} }
} }
@ -264,12 +258,12 @@ inline
void void
push_coroutine< void >::control_block::resume() { push_coroutine< void >::control_block::resume() {
other->ctx = boost::context::execution_context::current(); other->ctx = boost::context::execution_context::current();
ctx( nullptr, preserve_fpu); ctx();
if ( except) { if ( except) {
std::rethrow_exception( except); std::rethrow_exception( except);
} }
// test early-exit-flag // test early-exit-flag
if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { if ( state_t::none != ( other->state & state_t::early_exit) ) {
throw forced_unwind(); throw forced_unwind();
} }
} }
@ -277,7 +271,7 @@ push_coroutine< void >::control_block::resume() {
inline inline
bool bool
push_coroutine< void >::control_block::valid() const noexcept { push_coroutine< void >::control_block::valid() const noexcept {
return 0 == ( state & static_cast< int >( state_t::complete) ); return state_t::none == ( state & state_t::complete );
} }
}}} }}}

View File

@ -12,7 +12,6 @@
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/context/execution_context.hpp>
#include <boost/coroutine2/detail/config.hpp> #include <boost/coroutine2/detail/config.hpp>
@ -34,23 +33,23 @@ private:
control_block * cb_; control_block * cb_;
explicit push_coroutine( control_block *); explicit push_coroutine( control_block *) noexcept;
public: public:
template< typename Fn > template< typename Fn >
explicit push_coroutine( Fn &&, bool = false); explicit push_coroutine( Fn &&);
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
explicit push_coroutine( StackAllocator, Fn &&, bool = false); push_coroutine( StackAllocator, Fn &&);
~push_coroutine(); ~push_coroutine() noexcept;
push_coroutine( push_coroutine const&) = delete; push_coroutine( push_coroutine const&) = delete;
push_coroutine & operator=( push_coroutine const&) = delete; push_coroutine & operator=( push_coroutine const&) = delete;
push_coroutine( push_coroutine &&); push_coroutine( push_coroutine &&) noexcept;
push_coroutine & operator=( push_coroutine && other) { push_coroutine & operator=( push_coroutine && other) noexcept {
if ( this != & other) { if ( this != & other) {
cb_ = other.cb_; cb_ = other.cb_;
other.cb_ = nullptr; other.cb_ = nullptr;
@ -71,33 +70,35 @@ public:
push_coroutine< T > * c_; push_coroutine< T > * c_;
public: public:
iterator() : iterator() noexcept :
c_( nullptr) { c_{ nullptr } {
} }
explicit iterator( push_coroutine< T > * c) : explicit iterator( push_coroutine< T > * c) noexcept :
c_( c) { c_{ c } {
} }
iterator & operator=( T t) { iterator & operator=( T t) {
BOOST_ASSERT( c_); BOOST_ASSERT( c_);
if ( ! ( * c_)( t) ) c_ = 0; if ( ! ( * c_)( t) ) {
c_ = nullptr;
}
return * this; return * this;
} }
bool operator==( iterator const& other) const { bool operator==( iterator const& other) const noexcept {
return other.c_ == c_; return other.c_ == c_;
} }
bool operator!=( iterator const& other) const { bool operator!=( iterator const& other) const noexcept {
return other.c_ != c_; return other.c_ != c_;
} }
iterator & operator*() { iterator & operator*() noexcept {
return * this; return * this;
} }
iterator & operator++() { iterator & operator++() noexcept {
return * this; return * this;
} }
}; };
@ -113,23 +114,23 @@ private:
control_block * cb_; control_block * cb_;
explicit push_coroutine( control_block *); explicit push_coroutine( control_block *) noexcept;
public: public:
template< typename Fn > template< typename Fn >
explicit push_coroutine( Fn &&, bool = false); explicit push_coroutine( Fn &&);
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
explicit push_coroutine( StackAllocator, Fn &&, bool = false); push_coroutine( StackAllocator, Fn &&);
~push_coroutine(); ~push_coroutine() noexcept;
push_coroutine( push_coroutine const&) = delete; push_coroutine( push_coroutine const&) = delete;
push_coroutine & operator=( push_coroutine const&) = delete; push_coroutine & operator=( push_coroutine const&) = delete;
push_coroutine( push_coroutine &&); push_coroutine( push_coroutine &&) noexcept;
push_coroutine & operator=( push_coroutine && other) { push_coroutine & operator=( push_coroutine && other) noexcept {
if ( this != & other) { if ( this != & other) {
cb_ = other.cb_; cb_ = other.cb_;
other.cb_ = nullptr; other.cb_ = nullptr;
@ -148,33 +149,35 @@ public:
push_coroutine< T & > * c_; push_coroutine< T & > * c_;
public: public:
iterator() : iterator() noexcept :
c_( nullptr) { c_{ nullptr } {
} }
explicit iterator( push_coroutine< T & > * c) : explicit iterator( push_coroutine< T & > * c) noexcept :
c_( c) { c_{ c } {
} }
iterator & operator=( T & t) { iterator & operator=( T & t) {
BOOST_ASSERT( c_); BOOST_ASSERT( c_);
if ( ! ( * c_)( t) ) c_ = 0; if ( ! ( * c_)( t) ) {
c_ = nullptr;
}
return * this; return * this;
} }
bool operator==( iterator const& other) const { bool operator==( iterator const& other) const noexcept {
return other.c_ == c_; return other.c_ == c_;
} }
bool operator!=( iterator const& other) const { bool operator!=( iterator const& other) const noexcept {
return other.c_ != c_; return other.c_ != c_;
} }
iterator & operator*() { iterator & operator*() noexcept {
return * this; return * this;
} }
iterator & operator++() { iterator & operator++() noexcept {
return * this; return * this;
} }
}; };
@ -190,23 +193,23 @@ private:
control_block * cb_; control_block * cb_;
explicit push_coroutine( control_block *); explicit push_coroutine( control_block *) noexcept;
public: public:
template< typename Fn > template< typename Fn >
explicit push_coroutine( Fn &&, bool = false); explicit push_coroutine( Fn &&);
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
explicit push_coroutine( StackAllocator, Fn &&, bool = false); push_coroutine( StackAllocator, Fn &&);
~push_coroutine(); ~push_coroutine() noexcept;
push_coroutine( push_coroutine const&) = delete; push_coroutine( push_coroutine const&) = delete;
push_coroutine & operator=( push_coroutine const&) = delete; push_coroutine & operator=( push_coroutine const&) = delete;
push_coroutine( push_coroutine &&); push_coroutine( push_coroutine &&) noexcept;
push_coroutine & operator=( push_coroutine && other) { push_coroutine & operator=( push_coroutine && other) noexcept {
if ( this != & other) { if ( this != & other) {
cb_ = other.cb_; cb_ = other.cb_;
other.cb_ = nullptr; other.cb_ = nullptr;

View File

@ -7,16 +7,13 @@
#ifndef BOOST_COROUTINES2_DETAIL_PUSH_COROUTINE_IPP #ifndef BOOST_COROUTINES2_DETAIL_PUSH_COROUTINE_IPP
#define BOOST_COROUTINES2_DETAIL_PUSH_COROUTINE_IPP #define BOOST_COROUTINES2_DETAIL_PUSH_COROUTINE_IPP
#include <memory>
#include <utility> #include <utility>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/context/execution_context.hpp>
#include <boost/context/stack_context.hpp>
#include <boost/coroutine2/detail/config.hpp> #include <boost/coroutine2/detail/config.hpp>
#include <boost/coroutine2/detail/create_control_block.ipp>
#include <boost/coroutine2/fixedsize_stack.hpp> #include <boost/coroutine2/fixedsize_stack.hpp>
#include <boost/coroutine2/segmented_stack.hpp> #include <boost/coroutine2/segmented_stack.hpp>
@ -31,51 +28,31 @@ namespace detail {
// push_coroutine< T > // push_coroutine< T >
template< typename T > template< typename T >
push_coroutine< T >::push_coroutine( control_block * cb) : push_coroutine< T >::push_coroutine( control_block * cb) noexcept :
cb_( cb) { cb_{ cb } {
} }
template< typename T > template< typename T >
template< typename Fn > template< typename Fn >
push_coroutine< T >::push_coroutine( Fn && fn, bool preserve_fpu) : push_coroutine< T >::push_coroutine( Fn && fn) :
push_coroutine( default_stack(), std::forward< Fn >( fn), preserve_fpu) { push_coroutine{ default_stack(), std::forward< Fn >( fn) } {
} }
template< typename T > template< typename T >
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
push_coroutine< T >::push_coroutine( StackAllocator salloc, Fn && fn, bool preserve_fpu) : push_coroutine< T >::push_coroutine( StackAllocator salloc, Fn && fn) :
cb_( nullptr) { cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
context::stack_context sctx( salloc.allocate() );
// reserve space for control structure
#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
void * sp = static_cast< char * >( sctx.sp) - sizeof( control_block);
std::size_t size = sctx.size - sizeof( control_block);
#else
constexpr std::size_t func_alignment = 64; // alignof( control_block);
constexpr std::size_t func_size = sizeof( control_block);
// reserve space on stack
void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
// align sp pointer
std::size_t space = func_size + func_alignment;
sp = std::align( func_alignment, func_size, sp, space);
BOOST_ASSERT( nullptr != sp);
// calculate remaining size
std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
#endif
// placment new for control structure on coroutine stack
cb_= new ( sp) control_block( context::preallocated( sp, size, sctx),
salloc, std::forward< Fn >( fn), preserve_fpu);
} }
template< typename T > template< typename T >
push_coroutine< T >::~push_coroutine() { push_coroutine< T >::~push_coroutine() noexcept {
if ( nullptr != cb_) { if ( nullptr != cb_) {
cb_->~control_block(); cb_->~control_block();
} }
} }
template< typename T > template< typename T >
push_coroutine< T >::push_coroutine( push_coroutine && other) : push_coroutine< T >::push_coroutine( push_coroutine && other) noexcept :
cb_( other.cb_) { cb_( other.cb_) {
other.cb_ = nullptr; other.cb_ = nullptr;
} }
@ -109,51 +86,31 @@ push_coroutine< T >::operator!() const noexcept {
// push_coroutine< T & > // push_coroutine< T & >
template< typename T > template< typename T >
push_coroutine< T & >::push_coroutine( control_block * cb) : push_coroutine< T & >::push_coroutine( control_block * cb) noexcept :
cb_( cb) { cb_{ cb } {
} }
template< typename T > template< typename T >
template< typename Fn > template< typename Fn >
push_coroutine< T & >::push_coroutine( Fn && fn, bool preserve_fpu) : push_coroutine< T & >::push_coroutine( Fn && fn) :
push_coroutine( default_stack(), std::forward< Fn >( fn), preserve_fpu) { push_coroutine{ default_stack(), std::forward< Fn >( fn) } {
} }
template< typename T > template< typename T >
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
push_coroutine< T & >::push_coroutine( StackAllocator salloc, Fn && fn, bool preserve_fpu) : push_coroutine< T & >::push_coroutine( StackAllocator salloc, Fn && fn) :
cb_( nullptr) { cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
context::stack_context sctx( salloc.allocate() );
// reserve space for control structure
#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
void * sp = static_cast< char * >( sctx.sp) - sizeof( control_block);
std::size_t size = sctx.size - sizeof( control_block);
#else
constexpr std::size_t func_alignment = 64; // alignof( control_block);
constexpr std::size_t func_size = sizeof( control_block);
// reserve space on stack
void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
// align sp pointer
std::size_t space = func_size + func_alignment;
sp = std::align( func_alignment, func_size, sp, space);
BOOST_ASSERT( nullptr != sp);
// calculate remaining size
std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
#endif
// placment new for control structure on coroutine stack
cb_ = new ( sp) control_block( context::preallocated( sp, size, sctx),
salloc, std::forward< Fn >( fn), preserve_fpu);
} }
template< typename T > template< typename T >
push_coroutine< T & >::~push_coroutine() { push_coroutine< T & >::~push_coroutine() noexcept {
if ( nullptr != cb_) { if ( nullptr != cb_) {
cb_->~control_block(); cb_->~control_block();
} }
} }
template< typename T > template< typename T >
push_coroutine< T & >::push_coroutine( push_coroutine && other) : push_coroutine< T & >::push_coroutine( push_coroutine && other) noexcept :
cb_( other.cb_) { cb_( other.cb_) {
other.cb_ = nullptr; other.cb_ = nullptr;
} }
@ -180,49 +137,29 @@ push_coroutine< T & >::operator!() const noexcept {
// push_coroutine< void > // push_coroutine< void >
inline inline
push_coroutine< void >::push_coroutine( control_block * cb) : push_coroutine< void >::push_coroutine( control_block * cb) noexcept :
cb_( cb) { cb_{ cb } {
} }
template< typename Fn > template< typename Fn >
push_coroutine< void >::push_coroutine( Fn && fn, bool preserve_fpu) : push_coroutine< void >::push_coroutine( Fn && fn) :
push_coroutine( default_stack(), std::forward< Fn >( fn), preserve_fpu) { push_coroutine{ default_stack(), std::forward< Fn >( fn) } {
} }
template< typename StackAllocator, typename Fn > template< typename StackAllocator, typename Fn >
push_coroutine< void >::push_coroutine( StackAllocator salloc, Fn && fn, bool preserve_fpu) : push_coroutine< void >::push_coroutine( StackAllocator salloc, Fn && fn) :
cb_( nullptr) { cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
context::stack_context sctx( salloc.allocate() );
// reserve space for control structure
#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
void * sp = static_cast< char * >( sctx.sp) - sizeof( control_block);
std::size_t size = sctx.size - sizeof( control_block);
#else
constexpr std::size_t func_alignment = 64; // alignof( control_block);
constexpr std::size_t func_size = sizeof( control_block);
// reserve space on stack
void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
// align sp pointer
std::size_t space = func_size + func_alignment;
sp = std::align( func_alignment, func_size, sp, space);
BOOST_ASSERT( nullptr != sp);
// calculate remaining size
std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
#endif
// placment new for control structure on coroutine stack
cb_ = new ( sp) control_block( context::preallocated( sp, size, sctx),
salloc, std::forward< Fn >( fn), preserve_fpu);
} }
inline inline
push_coroutine< void >::~push_coroutine() { push_coroutine< void >::~push_coroutine() noexcept {
if ( nullptr != cb_) { if ( nullptr != cb_) {
cb_->~control_block(); cb_->~control_block();
} }
} }
inline inline
push_coroutine< void >::push_coroutine( push_coroutine && other) : push_coroutine< void >::push_coroutine( push_coroutine && other) noexcept :
cb_( other.cb_) { cb_( other.cb_) {
other.cb_ = nullptr; other.cb_ = nullptr;
} }

View File

@ -23,11 +23,61 @@ namespace coroutines2 {
namespace detail { namespace detail {
enum class state_t : unsigned int { enum class state_t : unsigned int {
none = 0,
complete = 1 << 1, complete = 1 << 1,
unwind = 1 << 2, unwind = 1 << 2,
early_exit = 1 << 3 early_exit = 1 << 3
}; };
inline
constexpr state_t
operator&( state_t l, state_t r) {
return static_cast< state_t >(
static_cast< unsigned int >( l) & static_cast< unsigned int >( r) );
}
inline
constexpr state_t
operator|( state_t l, state_t r) {
return static_cast< state_t >(
static_cast< unsigned int >( l) | static_cast< unsigned int >( r) );
}
inline
constexpr state_t
operator^( state_t l, state_t r) {
return static_cast< state_t >(
static_cast< unsigned int >( l) ^ static_cast< unsigned int >( r) );
}
inline
constexpr state_t
operator~( state_t l) {
return static_cast< state_t >( ~static_cast< unsigned int >( l) );
}
inline
state_t &
operator&=( state_t & l, state_t r) {
l = l & r;
return l;
}
inline
state_t &
operator|=( state_t & l, state_t r) {
l = l | r;
return l;
}
inline
state_t &
operator^=( state_t & l, state_t r) {
l = l ^ r;
return l;
}
}}} }}}
#ifdef BOOST_HAS_ABI_HEADERS #ifdef BOOST_HAS_ABI_HEADERS

View File

@ -20,7 +20,6 @@
typedef boost::coroutines2::protected_fixedsize_stack stack_allocator; typedef boost::coroutines2::protected_fixedsize_stack stack_allocator;
typedef boost::coroutines2::coroutine< void > coro_type; typedef boost::coroutines2::coroutine< void > coro_type;
bool preserve = false;
boost::uint64_t jobs = 1000; boost::uint64_t jobs = 1000;
void fn( coro_type::pull_type & c) void fn( coro_type::pull_type & c)
@ -32,7 +31,7 @@ duration_type measure_time( duration_type overhead)
time_point_type start( clock_type::now() ); time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::push_type c( stack_alloc, fn, preserve); coro_type::push_type c( stack_alloc, fn);
} }
duration_type total = clock_type::now() - start; duration_type total = clock_type::now() - start;
total -= overhead_clock(); // overhead of measurement total -= overhead_clock(); // overhead of measurement
@ -48,7 +47,7 @@ cycle_type measure_cycles( cycle_type overhead)
cycle_type start( cycles() ); cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::push_type c( stack_alloc, fn, preserve); coro_type::push_type c( stack_alloc, fn);
} }
cycle_type total = cycles() - start; cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement total -= overhead; // overhead of measurement
@ -67,7 +66,6 @@ int main( int argc, char * argv[])
desc.add_options() desc.add_options()
("help", "help message") ("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm; boost::program_options::variables_map vm;

View File

@ -20,7 +20,6 @@
typedef boost::coroutines2::fixedsize_stack stack_allocator; typedef boost::coroutines2::fixedsize_stack stack_allocator;
typedef boost::coroutines2::coroutine< void > coro_type; typedef boost::coroutines2::coroutine< void > coro_type;
bool preserve = false;
boost::uint64_t jobs = 1000; boost::uint64_t jobs = 1000;
void fn( coro_type::pull_type & c) void fn( coro_type::pull_type & c)
@ -32,7 +31,7 @@ duration_type measure_time( duration_type overhead)
time_point_type start( clock_type::now() ); time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::push_type c( stack_alloc, fn, preserve); coro_type::push_type c( stack_alloc, fn);
} }
duration_type total = clock_type::now() - start; duration_type total = clock_type::now() - start;
total -= overhead_clock(); // overhead of measurement total -= overhead_clock(); // overhead of measurement
@ -48,7 +47,7 @@ cycle_type measure_cycles( cycle_type overhead)
cycle_type start( cycles() ); cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::push_type c( stack_alloc, fn, preserve); coro_type::push_type c( stack_alloc, fn);
} }
cycle_type total = cycles() - start; cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement total -= overhead; // overhead of measurement
@ -67,7 +66,6 @@ int main( int argc, char * argv[])
desc.add_options() desc.add_options()
("help", "help message") ("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm; boost::program_options::variables_map vm;

View File

@ -18,7 +18,6 @@
#include "clock.hpp" #include "clock.hpp"
#include "cycle.hpp" #include "cycle.hpp"
bool preserve = false;
boost::uint64_t jobs = 1000; boost::uint64_t jobs = 1000;
struct X struct X
@ -45,7 +44,7 @@ void fn_x( boost::coroutines2::coroutine< X >::push_type & c)
duration_type measure_time_void( duration_type overhead) duration_type measure_time_void( duration_type overhead)
{ {
boost::coroutines2::coroutine< void >::pull_type c( fn_void, preserve); boost::coroutines2::coroutine< void >::pull_type c( fn_void);
time_point_type start( clock_type::now() ); time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
@ -61,7 +60,7 @@ duration_type measure_time_void( duration_type overhead)
duration_type measure_time_int( duration_type overhead) duration_type measure_time_int( duration_type overhead)
{ {
boost::coroutines2::coroutine< int >::pull_type c( fn_int, preserve); boost::coroutines2::coroutine< int >::pull_type c( fn_int);
time_point_type start( clock_type::now() ); time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
@ -77,7 +76,7 @@ duration_type measure_time_int( duration_type overhead)
duration_type measure_time_x( duration_type overhead) duration_type measure_time_x( duration_type overhead)
{ {
boost::coroutines2::coroutine< X >::pull_type c( fn_x, preserve); boost::coroutines2::coroutine< X >::pull_type c( fn_x);
time_point_type start( clock_type::now() ); time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
@ -94,7 +93,7 @@ duration_type measure_time_x( duration_type overhead)
# ifdef BOOST_CONTEXT_CYCLE # ifdef BOOST_CONTEXT_CYCLE
cycle_type measure_cycles_void( cycle_type overhead) cycle_type measure_cycles_void( cycle_type overhead)
{ {
boost::coroutines2::coroutine< void >::pull_type c( fn_void, preserve); boost::coroutines2::coroutine< void >::pull_type c( fn_void);
cycle_type start( cycles() ); cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
@ -110,7 +109,7 @@ cycle_type measure_cycles_void( cycle_type overhead)
cycle_type measure_cycles_int( cycle_type overhead) cycle_type measure_cycles_int( cycle_type overhead)
{ {
boost::coroutines2::coroutine< int >::pull_type c( fn_int, preserve); boost::coroutines2::coroutine< int >::pull_type c( fn_int);
cycle_type start( cycles() ); cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
@ -126,7 +125,7 @@ cycle_type measure_cycles_int( cycle_type overhead)
cycle_type measure_cycles_x( cycle_type overhead) cycle_type measure_cycles_x( cycle_type overhead)
{ {
boost::coroutines2::coroutine< X >::pull_type c( fn_x, preserve); boost::coroutines2::coroutine< X >::pull_type c( fn_x);
cycle_type start( cycles() ); cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
@ -150,7 +149,6 @@ int main( int argc, char * argv[])
desc.add_options() desc.add_options()
("help", "help message") ("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm; boost::program_options::variables_map vm;

View File

@ -20,7 +20,6 @@
typedef boost::coroutines2::segmented_stack stack_allocator; typedef boost::coroutines2::segmented_stack stack_allocator;
typedef boost::coroutines2::coroutine< void > coro_type; typedef boost::coroutines2::coroutine< void > coro_type;
bool preserve = false;
boost::uint64_t jobs = 1000; boost::uint64_t jobs = 1000;
void fn( coro_type::push_type & c) void fn( coro_type::push_type & c)
@ -32,7 +31,7 @@ duration_type measure_time( duration_type overhead)
time_point_type start( clock_type::now() ); time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::pull_type c( stack_alloc, fn, preserve); coro_type::pull_type c( stack_alloc, fn);
} }
duration_type total = clock_type::now() - start; duration_type total = clock_type::now() - start;
total -= overhead_clock(); // overhead of measurement total -= overhead_clock(); // overhead of measurement
@ -48,7 +47,7 @@ cycle_type measure_cycles( cycle_type overhead)
cycle_type start( cycles() ); cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
coro_type::pull_type c( stack_alloc, fn, preserve); coro_type::pull_type c( stack_alloc, fn);
} }
cycle_type total = cycles() - start; cycle_type total = cycles() - start;
total -= overhead; // overhead of measurement total -= overhead; // overhead of measurement
@ -62,12 +61,11 @@ int main( int argc, char * argv[])
{ {
try try
{ {
bool preserve = false, unwind = true, bind = false; bool bind = false;
boost::program_options::options_description desc("allowed options"); boost::program_options::options_description desc("allowed options");
desc.add_options() desc.add_options()
("help", "help message") ("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm; boost::program_options::variables_map vm;

View File

@ -18,7 +18,6 @@
#include "../clock.hpp" #include "../clock.hpp"
#include "../cycle.hpp" #include "../cycle.hpp"
bool preserve = false;
boost::uint64_t jobs = 1000; boost::uint64_t jobs = 1000;
struct X struct X
@ -46,7 +45,7 @@ void fn_x( boost::coroutines2::coroutine< X >::push_type & c)
duration_type measure_time_void( duration_type overhead) duration_type measure_time_void( duration_type overhead)
{ {
boost::coroutines2::segmented_stack stack_alloc; boost::coroutines2::segmented_stack stack_alloc;
boost::coroutines2::coroutine< void >::pull_type c( stack_alloc, fn_void, preserve); boost::coroutines2::coroutine< void >::pull_type c( stack_alloc, fn_void);
time_point_type start( clock_type::now() ); time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
@ -63,7 +62,7 @@ duration_type measure_time_void( duration_type overhead)
duration_type measure_time_int( duration_type overhead) duration_type measure_time_int( duration_type overhead)
{ {
boost::coroutines2::segmented_stack stack_alloc; boost::coroutines2::segmented_stack stack_alloc;
boost::coroutines2::coroutine< int >::pull_type c( stack_alloc, fn_int, preserve); boost::coroutines2::coroutine< int >::pull_type c( stack_alloc, fn_int);
time_point_type start( clock_type::now() ); time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
@ -80,7 +79,7 @@ duration_type measure_time_int( duration_type overhead)
duration_type measure_time_x( duration_type overhead) duration_type measure_time_x( duration_type overhead)
{ {
boost::coroutines2::segmented_stack stack_alloc; boost::coroutines2::segmented_stack stack_alloc;
boost::coroutines2::coroutine< X >::pull_type c( stack_alloc, fn_x, preserve); boost::coroutines2::coroutine< X >::pull_type c( stack_alloc, fn_x);
time_point_type start( clock_type::now() ); time_point_type start( clock_type::now() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
@ -98,7 +97,7 @@ duration_type measure_time_x( duration_type overhead)
cycle_type measure_cycles_void( cycle_type overhead) cycle_type measure_cycles_void( cycle_type overhead)
{ {
boost::coroutines2::segmented_stack stack_alloc; boost::coroutines2::segmented_stack stack_alloc;
boost::coroutines2::coroutine< void >::pull_type c( stack_alloc, fn_void, preserve); boost::coroutines2::coroutine< void >::pull_type c( stack_alloc, fn_void);
cycle_type start( cycles() ); cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
@ -115,7 +114,7 @@ cycle_type measure_cycles_void( cycle_type overhead)
cycle_type measure_cycles_int( cycle_type overhead) cycle_type measure_cycles_int( cycle_type overhead)
{ {
boost::coroutines2::segmented_stack stack_alloc; boost::coroutines2::segmented_stack stack_alloc;
boost::coroutines2::coroutine< int >::pull_type c( stack_alloc, fn_int, preserve); boost::coroutines2::coroutine< int >::pull_type c( stack_alloc, fn_int);
cycle_type start( cycles() ); cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
@ -132,7 +131,7 @@ cycle_type measure_cycles_int( cycle_type overhead)
cycle_type measure_cycles_x( cycle_type overhead) cycle_type measure_cycles_x( cycle_type overhead)
{ {
boost::coroutines2::segmented_stack stack_alloc; boost::coroutines2::segmented_stack stack_alloc;
boost::coroutines2::coroutine< X >::pull_type c( stack_alloc, fn_x, preserve); boost::coroutines2::coroutine< X >::pull_type c( stack_alloc, fn_x);
cycle_type start( cycles() ); cycle_type start( cycles() );
for ( std::size_t i = 0; i < jobs; ++i) { for ( std::size_t i = 0; i < jobs; ++i) {
@ -156,7 +155,6 @@ int main( int argc, char * argv[])
desc.add_options() desc.add_options()
("help", "help message") ("help", "help message")
("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU") ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
boost::program_options::variables_map vm; boost::program_options::variables_map vm;