mirror of
https://github.com/boostorg/coroutine.git
synced 2026-02-13 00:12:15 +00:00
allocate on stack
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -24,102 +24,53 @@ namespace detail {
|
||||
template< typename Data >
|
||||
struct parameters
|
||||
{
|
||||
coroutine_context * ctx;
|
||||
Data * data;
|
||||
bool do_unwind;
|
||||
|
||||
explicit parameters( coroutine_context * ctx_) :
|
||||
ctx( ctx_), data( 0), do_unwind( false)
|
||||
{ BOOST_ASSERT( ctx); }
|
||||
|
||||
explicit parameters( coroutine_context * ctx_, Data * data_) :
|
||||
ctx( ctx_), data( data_), do_unwind( false)
|
||||
{ BOOST_ASSERT( ctx); }
|
||||
|
||||
explicit parameters( coroutine_context * ctx_, unwind_t::flag_t) :
|
||||
ctx( ctx_), data( 0), do_unwind( true)
|
||||
{
|
||||
BOOST_ASSERT( ctx);
|
||||
BOOST_ASSERT( do_unwind);
|
||||
}
|
||||
|
||||
parameters( parameters const& other) :
|
||||
ctx( other.ctx), data( other.data),
|
||||
do_unwind( other.do_unwind)
|
||||
parameters() :
|
||||
data( 0), do_unwind( false)
|
||||
{}
|
||||
|
||||
parameters & operator=( parameters const& other)
|
||||
{
|
||||
if ( this == & other) return * this;
|
||||
ctx = other.ctx;
|
||||
data = other.data;
|
||||
do_unwind = other.do_unwind;
|
||||
return * this;
|
||||
}
|
||||
explicit parameters( Data * data_) :
|
||||
data( data_), do_unwind( false)
|
||||
{ BOOST_ASSERT( data); }
|
||||
|
||||
explicit parameters( unwind_t::flag_t) :
|
||||
data( 0), do_unwind( true)
|
||||
{}
|
||||
};
|
||||
|
||||
template< typename Data >
|
||||
struct parameters< Data & >
|
||||
{
|
||||
coroutine_context * ctx;
|
||||
Data * data;
|
||||
bool do_unwind;
|
||||
|
||||
explicit parameters( coroutine_context * ctx_) :
|
||||
ctx( ctx_), data( 0), do_unwind( false)
|
||||
{ BOOST_ASSERT( ctx); }
|
||||
|
||||
explicit parameters( coroutine_context * ctx_, Data * data_) :
|
||||
ctx( ctx_), data( data_), do_unwind( false)
|
||||
{ BOOST_ASSERT( ctx); }
|
||||
|
||||
explicit parameters( coroutine_context * ctx_, unwind_t::flag_t) :
|
||||
ctx( ctx_), data( 0), do_unwind( true)
|
||||
{
|
||||
BOOST_ASSERT( ctx);
|
||||
BOOST_ASSERT( do_unwind);
|
||||
}
|
||||
|
||||
parameters( parameters const& other) :
|
||||
ctx( other.ctx), data( other.data),
|
||||
do_unwind( other.do_unwind)
|
||||
parameters() :
|
||||
data( 0), do_unwind( false)
|
||||
{}
|
||||
|
||||
parameters & operator=( parameters const& other)
|
||||
{
|
||||
if ( this == & other) return * this;
|
||||
ctx = other.ctx;
|
||||
data = other.data;
|
||||
do_unwind = other.do_unwind;
|
||||
return * this;
|
||||
}
|
||||
explicit parameters( Data * data_) :
|
||||
data( data_), do_unwind( false)
|
||||
{ BOOST_ASSERT( data); }
|
||||
|
||||
explicit parameters( unwind_t::flag_t) :
|
||||
data( 0), do_unwind( true)
|
||||
{}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct parameters< void >
|
||||
{
|
||||
coroutine_context * ctx;
|
||||
bool do_unwind;
|
||||
|
||||
explicit parameters( coroutine_context * ctx_) :
|
||||
ctx( ctx_), do_unwind( false)
|
||||
{ BOOST_ASSERT( ctx); }
|
||||
|
||||
explicit parameters( coroutine_context * ctx_, unwind_t::flag_t) :
|
||||
ctx( ctx_), do_unwind( true)
|
||||
{ BOOST_ASSERT( ctx); }
|
||||
|
||||
parameters( parameters const& other) :
|
||||
ctx( other.ctx), do_unwind( other.do_unwind)
|
||||
parameters() :
|
||||
do_unwind( false)
|
||||
{}
|
||||
|
||||
parameters & operator=( parameters const& other)
|
||||
{
|
||||
if ( this == & other) return * this;
|
||||
ctx = other.ctx;
|
||||
do_unwind = other.do_unwind;
|
||||
return * this;
|
||||
}
|
||||
explicit parameters( unwind_t::flag_t) :
|
||||
do_unwind( true)
|
||||
{}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/context/fcontext.hpp>
|
||||
#include <boost/exception_ptr.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
@@ -35,50 +33,42 @@ namespace detail {
|
||||
template< typename R >
|
||||
class pull_coroutine_base : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef intrusive_ptr< pull_coroutine_base > ptr_t;
|
||||
|
||||
private:
|
||||
template<
|
||||
typename X, typename Y, typename Z, typename V, typename W
|
||||
typename X, typename Y, typename Z
|
||||
>
|
||||
friend class push_coroutine_object;
|
||||
|
||||
typedef parameters< R > param_type;
|
||||
|
||||
unsigned int use_count_;
|
||||
|
||||
protected:
|
||||
int flags_;
|
||||
exception_ptr except_;
|
||||
coroutine_context caller_;
|
||||
coroutine_context callee_;
|
||||
R * result_;
|
||||
|
||||
virtual void deallocate_object() = 0;
|
||||
int flags_;
|
||||
exception_ptr except_;
|
||||
coroutine_context * caller_;
|
||||
coroutine_context * callee_;
|
||||
R * result_;
|
||||
|
||||
public:
|
||||
pull_coroutine_base( coroutine_context::ctx_fn fn,
|
||||
stack_context * stack_ctx,
|
||||
pull_coroutine_base( coroutine_context * caller,
|
||||
coroutine_context * callee,
|
||||
bool unwind, bool preserve_fpu) :
|
||||
use_count_( 0),
|
||||
flags_( 0),
|
||||
except_(),
|
||||
caller_(),
|
||||
callee_( fn, stack_ctx),
|
||||
caller_( caller),
|
||||
callee_( callee),
|
||||
result_( 0)
|
||||
{
|
||||
if ( unwind) flags_ |= flag_force_unwind;
|
||||
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
|
||||
}
|
||||
|
||||
pull_coroutine_base( coroutine_context const& callee,
|
||||
pull_coroutine_base( coroutine_context * caller,
|
||||
coroutine_context * callee,
|
||||
bool unwind, bool preserve_fpu,
|
||||
R * result) :
|
||||
use_count_( 0),
|
||||
flags_( 0),
|
||||
except_(),
|
||||
caller_(),
|
||||
caller_( caller),
|
||||
callee_( callee),
|
||||
result_( result)
|
||||
{
|
||||
@@ -101,19 +91,33 @@ public:
|
||||
bool is_complete() const BOOST_NOEXCEPT
|
||||
{ return 0 != ( flags_ & flag_complete); }
|
||||
|
||||
void unwind_stack() BOOST_NOEXCEPT
|
||||
{
|
||||
if ( ! is_complete() && force_unwind() )
|
||||
{
|
||||
flags_ |= flag_unwind_stack;
|
||||
param_type to( unwind_t::force_unwind);
|
||||
caller_->jump(
|
||||
* callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
preserve_fpu() );
|
||||
flags_ &= ~flag_unwind_stack;
|
||||
|
||||
BOOST_ASSERT( is_complete() );
|
||||
}
|
||||
}
|
||||
|
||||
void pull()
|
||||
{
|
||||
BOOST_ASSERT( ! is_complete() );
|
||||
|
||||
param_type to( & caller_);
|
||||
param_type to;
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
to.ctx->jump(
|
||||
callee_,
|
||||
caller_->jump(
|
||||
* callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
preserve_fpu() ) ) );
|
||||
BOOST_ASSERT( from->ctx);
|
||||
callee_ = * from->ctx;
|
||||
result_ = from->data;
|
||||
if ( from->do_unwind) throw forced_unwind();
|
||||
if ( except_) rethrow_exception( except_);
|
||||
@@ -137,61 +141,47 @@ public:
|
||||
invalid_result() );
|
||||
return result_;
|
||||
}
|
||||
|
||||
friend inline void intrusive_ptr_add_ref( pull_coroutine_base * p) BOOST_NOEXCEPT
|
||||
{ ++p->use_count_; }
|
||||
|
||||
friend inline void intrusive_ptr_release( pull_coroutine_base * p) BOOST_NOEXCEPT
|
||||
{ if ( --p->use_count_ == 0) p->deallocate_object(); }
|
||||
};
|
||||
|
||||
template< typename R >
|
||||
class pull_coroutine_base< R & > : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef intrusive_ptr< pull_coroutine_base > ptr_t;
|
||||
|
||||
private:
|
||||
template<
|
||||
typename X, typename Y, typename Z, typename V, typename W
|
||||
typename X, typename Y, typename Z
|
||||
>
|
||||
friend class push_coroutine_object;
|
||||
|
||||
typedef parameters< R & > param_type;
|
||||
|
||||
unsigned int use_count_;
|
||||
|
||||
protected:
|
||||
int flags_;
|
||||
exception_ptr except_;
|
||||
coroutine_context caller_;
|
||||
coroutine_context callee_;
|
||||
R * result_;
|
||||
|
||||
virtual void deallocate_object() = 0;
|
||||
int flags_;
|
||||
exception_ptr except_;
|
||||
coroutine_context * caller_;
|
||||
coroutine_context * callee_;
|
||||
R * result_;
|
||||
|
||||
public:
|
||||
pull_coroutine_base( coroutine_context::ctx_fn fn,
|
||||
stack_context * stack_ctx,
|
||||
pull_coroutine_base( coroutine_context * caller,
|
||||
coroutine_context * callee,
|
||||
bool unwind, bool preserve_fpu) :
|
||||
use_count_( 0),
|
||||
flags_( 0),
|
||||
except_(),
|
||||
caller_(),
|
||||
callee_( fn, stack_ctx),
|
||||
caller_( caller),
|
||||
callee_( callee),
|
||||
result_( 0)
|
||||
{
|
||||
if ( unwind) flags_ |= flag_force_unwind;
|
||||
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
|
||||
}
|
||||
|
||||
pull_coroutine_base( coroutine_context const& callee,
|
||||
pull_coroutine_base( coroutine_context * caller,
|
||||
coroutine_context * callee,
|
||||
bool unwind, bool preserve_fpu,
|
||||
R * result) :
|
||||
use_count_( 0),
|
||||
flags_( 0),
|
||||
except_(),
|
||||
caller_(),
|
||||
caller_( caller),
|
||||
callee_( callee),
|
||||
result_( result)
|
||||
{
|
||||
@@ -214,19 +204,33 @@ public:
|
||||
bool is_complete() const BOOST_NOEXCEPT
|
||||
{ return 0 != ( flags_ & flag_complete); }
|
||||
|
||||
void unwind_stack() BOOST_NOEXCEPT
|
||||
{
|
||||
if ( ! is_complete() && force_unwind() )
|
||||
{
|
||||
flags_ |= flag_unwind_stack;
|
||||
param_type to( unwind_t::force_unwind);
|
||||
caller_->jump(
|
||||
* callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
preserve_fpu() );
|
||||
flags_ &= ~flag_unwind_stack;
|
||||
|
||||
BOOST_ASSERT( is_complete() );
|
||||
}
|
||||
}
|
||||
|
||||
void pull()
|
||||
{
|
||||
BOOST_ASSERT( ! is_complete() );
|
||||
|
||||
param_type to( & caller_);
|
||||
param_type to;
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
to.ctx->jump(
|
||||
callee_,
|
||||
caller_->jump(
|
||||
* callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
preserve_fpu() ) ) );
|
||||
BOOST_ASSERT( from->ctx);
|
||||
callee_ = * from->ctx;
|
||||
result_ = from->data;
|
||||
if ( from->do_unwind) throw forced_unwind();
|
||||
if ( except_) rethrow_exception( except_);
|
||||
@@ -250,58 +254,30 @@ public:
|
||||
invalid_result() );
|
||||
return result_;
|
||||
}
|
||||
|
||||
friend inline void intrusive_ptr_add_ref( pull_coroutine_base * p) BOOST_NOEXCEPT
|
||||
{ ++p->use_count_; }
|
||||
|
||||
friend inline void intrusive_ptr_release( pull_coroutine_base * p) BOOST_NOEXCEPT
|
||||
{ if ( --p->use_count_ == 0) p->deallocate_object(); }
|
||||
};
|
||||
|
||||
template<>
|
||||
class pull_coroutine_base< void > : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef intrusive_ptr< pull_coroutine_base > ptr_t;
|
||||
|
||||
private:
|
||||
template<
|
||||
typename X, typename Y, typename Z, typename V, typename W
|
||||
>
|
||||
template< typename X, typename Y, typename Z >
|
||||
friend class push_coroutine_object;
|
||||
|
||||
typedef parameters< void > param_type;
|
||||
|
||||
unsigned int use_count_;
|
||||
|
||||
protected:
|
||||
int flags_;
|
||||
exception_ptr except_;
|
||||
coroutine_context caller_;
|
||||
coroutine_context callee_;
|
||||
|
||||
virtual void deallocate_object() = 0;
|
||||
int flags_;
|
||||
exception_ptr except_;
|
||||
coroutine_context * caller_;
|
||||
coroutine_context * callee_;
|
||||
|
||||
public:
|
||||
pull_coroutine_base( coroutine_context::ctx_fn fn,
|
||||
stack_context * stack_ctx,
|
||||
pull_coroutine_base( coroutine_context * caller,
|
||||
coroutine_context * callee,
|
||||
bool unwind, bool preserve_fpu) :
|
||||
use_count_( 0),
|
||||
flags_( 0),
|
||||
except_(),
|
||||
caller_(),
|
||||
callee_( fn, stack_ctx)
|
||||
{
|
||||
if ( unwind) flags_ |= flag_force_unwind;
|
||||
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
|
||||
}
|
||||
|
||||
pull_coroutine_base( coroutine_context const& callee,
|
||||
bool unwind, bool preserve_fpu) :
|
||||
use_count_( 0),
|
||||
flags_( 0),
|
||||
except_(),
|
||||
caller_(),
|
||||
caller_( caller),
|
||||
callee_( callee)
|
||||
{
|
||||
if ( unwind) flags_ |= flag_force_unwind;
|
||||
@@ -323,28 +299,36 @@ public:
|
||||
bool is_complete() const BOOST_NOEXCEPT
|
||||
{ return 0 != ( flags_ & flag_complete); }
|
||||
|
||||
void unwind_stack() BOOST_NOEXCEPT
|
||||
{
|
||||
if ( ! is_complete() && force_unwind() )
|
||||
{
|
||||
flags_ |= flag_unwind_stack;
|
||||
param_type to( unwind_t::force_unwind);
|
||||
caller_->jump(
|
||||
* callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
preserve_fpu() );
|
||||
flags_ &= ~flag_unwind_stack;
|
||||
|
||||
BOOST_ASSERT( is_complete() );
|
||||
}
|
||||
}
|
||||
|
||||
void pull()
|
||||
{
|
||||
BOOST_ASSERT( ! is_complete() );
|
||||
|
||||
param_type to( & caller_);
|
||||
param_type to;
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
to.ctx->jump(
|
||||
callee_,
|
||||
caller_->jump(
|
||||
* callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
preserve_fpu() ) ) );
|
||||
BOOST_ASSERT( from->ctx);
|
||||
callee_ = * from->ctx;
|
||||
if ( from->do_unwind) throw forced_unwind();
|
||||
if ( except_) rethrow_exception( except_);
|
||||
}
|
||||
|
||||
friend inline void intrusive_ptr_add_ref( pull_coroutine_base * p) BOOST_NOEXCEPT
|
||||
{ ++p->use_count_; }
|
||||
|
||||
friend inline void intrusive_ptr_release( pull_coroutine_base * p) BOOST_NOEXCEPT
|
||||
{ if ( --p->use_count_ == 0) p->deallocate_object(); }
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
// Copyright Oliver Kowalke 2009.
|
||||
// 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_COROUTINES_DETAIL_PULL_COROUTINE_CALLER_H
|
||||
#define BOOST_COROUTINES_DETAIL_PULL_COROUTINE_CALLER_H
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/context/fcontext.hpp>
|
||||
|
||||
#include <boost/coroutine/detail/config.hpp>
|
||||
#include <boost/coroutine/detail/pull_coroutine_base.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace coroutines {
|
||||
namespace detail {
|
||||
|
||||
template< typename R, typename Allocator >
|
||||
class pull_coroutine_caller : public pull_coroutine_base< R >
|
||||
{
|
||||
public:
|
||||
typedef typename Allocator::template rebind<
|
||||
pull_coroutine_caller< R, Allocator >
|
||||
>::other allocator_t;
|
||||
|
||||
pull_coroutine_caller( coroutine_context const& callee, bool unwind, bool preserve_fpu,
|
||||
allocator_t const& alloc, R * data) BOOST_NOEXCEPT :
|
||||
pull_coroutine_base< R >( callee, unwind, preserve_fpu, data),
|
||||
alloc_( alloc)
|
||||
{}
|
||||
|
||||
void deallocate_object()
|
||||
{ destroy_( alloc_, this); }
|
||||
|
||||
private:
|
||||
allocator_t alloc_;
|
||||
|
||||
static void destroy_( allocator_t & alloc, pull_coroutine_caller * p)
|
||||
{
|
||||
alloc.destroy( p);
|
||||
alloc.deallocate( p, 1);
|
||||
}
|
||||
};
|
||||
|
||||
template< typename R, typename Allocator >
|
||||
class pull_coroutine_caller< R &, Allocator > : public pull_coroutine_base< R & >
|
||||
{
|
||||
public:
|
||||
typedef typename Allocator::template rebind<
|
||||
pull_coroutine_caller< R &, Allocator >
|
||||
>::other allocator_t;
|
||||
|
||||
pull_coroutine_caller( coroutine_context const& callee, bool unwind, bool preserve_fpu,
|
||||
allocator_t const& alloc, R * data) BOOST_NOEXCEPT :
|
||||
pull_coroutine_base< R & >( callee, unwind, preserve_fpu, data),
|
||||
alloc_( alloc)
|
||||
{}
|
||||
|
||||
void deallocate_object()
|
||||
{ destroy_( alloc_, this); }
|
||||
|
||||
private:
|
||||
allocator_t alloc_;
|
||||
|
||||
static void destroy_( allocator_t & alloc, pull_coroutine_caller * p)
|
||||
{
|
||||
alloc.destroy( p);
|
||||
alloc.deallocate( p, 1);
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Allocator >
|
||||
class pull_coroutine_caller< void, Allocator > : public pull_coroutine_base< void >
|
||||
{
|
||||
public:
|
||||
typedef typename Allocator::template rebind<
|
||||
pull_coroutine_caller< void, Allocator >
|
||||
>::other allocator_t;
|
||||
|
||||
pull_coroutine_caller( coroutine_context const& callee, bool unwind, bool preserve_fpu,
|
||||
allocator_t const& alloc) BOOST_NOEXCEPT :
|
||||
pull_coroutine_base< void >( callee, unwind, preserve_fpu),
|
||||
alloc_( alloc)
|
||||
{}
|
||||
|
||||
void deallocate_object()
|
||||
{ destroy_( alloc_, this); }
|
||||
|
||||
private:
|
||||
allocator_t alloc_;
|
||||
|
||||
static void destroy_( allocator_t & alloc, pull_coroutine_caller * p)
|
||||
{
|
||||
alloc.destroy( p);
|
||||
alloc.deallocate( p, 1);
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_COROUTINES_DETAIL_PULL_COROUTINE_CALLER_H
|
||||
@@ -20,10 +20,7 @@
|
||||
#include <boost/coroutine/exceptions.hpp>
|
||||
#include <boost/coroutine/detail/flags.hpp>
|
||||
#include <boost/coroutine/detail/parameters.hpp>
|
||||
#include <boost/coroutine/detail/stack_tuple.hpp>
|
||||
#include <boost/coroutine/detail/trampoline.hpp>
|
||||
#include <boost/coroutine/flags.hpp>
|
||||
#include <boost/coroutine/stack_context.hpp>
|
||||
#include <boost/coroutine/detail/pull_coroutine_base.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
@@ -39,409 +36,217 @@ namespace boost {
|
||||
namespace coroutines {
|
||||
namespace detail {
|
||||
|
||||
template<
|
||||
typename R, typename Fn,
|
||||
typename StackAllocator, typename Allocator,
|
||||
typename Caller
|
||||
>
|
||||
class pull_coroutine_object : private stack_tuple< StackAllocator >,
|
||||
public pull_coroutine_base< R >
|
||||
template< typename R, typename Fn, typename Caller >
|
||||
class pull_coroutine_object : public pull_coroutine_base< R >
|
||||
{
|
||||
public:
|
||||
typedef typename Allocator::template rebind<
|
||||
pull_coroutine_object<
|
||||
R, Fn, StackAllocator, Allocator, Caller
|
||||
>
|
||||
>::other allocator_t;
|
||||
|
||||
private:
|
||||
typedef stack_tuple< StackAllocator > pbase_type;
|
||||
typedef pull_coroutine_base< R > base_type;
|
||||
typedef parameters< R > param_type;
|
||||
|
||||
Fn fn_;
|
||||
allocator_t alloc_;
|
||||
|
||||
static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
|
||||
{
|
||||
alloc.destroy( p);
|
||||
alloc.deallocate( p, 1);
|
||||
}
|
||||
|
||||
pull_coroutine_object( pull_coroutine_object &);
|
||||
pull_coroutine_object & operator=( pull_coroutine_object const&);
|
||||
|
||||
void enter_()
|
||||
{
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
this->caller_.jump(
|
||||
this->callee_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() ) ) );
|
||||
this->callee_ = * from->ctx;
|
||||
this->result_ = from->data;
|
||||
if ( this->except_) rethrow_exception( this->except_);
|
||||
}
|
||||
|
||||
void unwind_stack_() BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT( ! this->is_complete() );
|
||||
|
||||
this->flags_ |= flag_unwind_stack;
|
||||
param_type to( & this->caller_, unwind_t::force_unwind);
|
||||
this->caller_.jump(
|
||||
this->callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->preserve_fpu() );
|
||||
this->flags_ &= ~flag_unwind_stack;
|
||||
|
||||
BOOST_ASSERT( this->is_complete() );
|
||||
}
|
||||
|
||||
public:
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
pull_coroutine_object( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< pull_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn)
|
||||
{}
|
||||
#endif
|
||||
pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< pull_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
fn_( fn),
|
||||
fn_( fn)
|
||||
#else
|
||||
fn_( forward< Fn >( fn) ),
|
||||
fn_( forward< Fn >( fn) )
|
||||
#endif
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
|
||||
~pull_coroutine_object()
|
||||
{
|
||||
if ( ! this->is_complete() && this->force_unwind() )
|
||||
unwind_stack_();
|
||||
}
|
||||
{}
|
||||
|
||||
void run()
|
||||
{
|
||||
coroutine_context callee;
|
||||
coroutine_context caller;
|
||||
|
||||
{
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
this->callee_->jump(
|
||||
* this->caller_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() ) ) );
|
||||
this->result_ = from->data;
|
||||
|
||||
// create push_coroutine
|
||||
Caller c( this->caller_, false, this->preserve_fpu(), alloc_);
|
||||
typename Caller::base_t b( this->callee_, this->caller_, false, this->preserve_fpu() );
|
||||
Caller c( & b);
|
||||
try
|
||||
{ fn_( c); }
|
||||
catch ( forced_unwind const&)
|
||||
{}
|
||||
catch (...)
|
||||
{ this->except_ = current_exception(); }
|
||||
callee = c.impl_->callee_;
|
||||
}
|
||||
|
||||
this->flags_ |= flag_complete;
|
||||
param_type to( & caller);
|
||||
caller.jump(
|
||||
callee,
|
||||
param_type to;
|
||||
this->callee_->jump(
|
||||
* this->caller_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->preserve_fpu() );
|
||||
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
||||
}
|
||||
|
||||
void deallocate_object()
|
||||
{ destroy_( alloc_, this); }
|
||||
};
|
||||
|
||||
template<
|
||||
typename R, typename Fn,
|
||||
typename StackAllocator, typename Allocator,
|
||||
typename Caller
|
||||
>
|
||||
class pull_coroutine_object< R &, Fn, StackAllocator, Allocator, Caller > :
|
||||
private stack_tuple< StackAllocator >,
|
||||
public pull_coroutine_base< R & >
|
||||
template< typename R, typename Fn, typename Caller >
|
||||
class pull_coroutine_object< R &, Fn, Caller > : public pull_coroutine_base< R & >
|
||||
{
|
||||
public:
|
||||
typedef typename Allocator::template rebind<
|
||||
pull_coroutine_object<
|
||||
R &, Fn, StackAllocator, Allocator, Caller
|
||||
>
|
||||
>::other allocator_t;
|
||||
|
||||
private:
|
||||
typedef stack_tuple< StackAllocator > pbase_type;
|
||||
typedef pull_coroutine_base< R & > base_type;
|
||||
typedef parameters< R & > param_type;
|
||||
|
||||
Fn fn_;
|
||||
allocator_t alloc_;
|
||||
|
||||
static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
|
||||
{
|
||||
alloc.destroy( p);
|
||||
alloc.deallocate( p, 1);
|
||||
}
|
||||
|
||||
pull_coroutine_object( pull_coroutine_object &);
|
||||
pull_coroutine_object & operator=( pull_coroutine_object const&);
|
||||
|
||||
void enter_()
|
||||
{
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
this->caller_.jump(
|
||||
this->callee_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() ) ) );
|
||||
this->callee_ = * from->ctx;
|
||||
this->result_ = from->data;
|
||||
if ( this->except_) rethrow_exception( this->except_);
|
||||
}
|
||||
|
||||
void unwind_stack_() BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT( ! this->is_complete() );
|
||||
|
||||
this->flags_ |= flag_unwind_stack;
|
||||
param_type to( & this->caller_, unwind_t::force_unwind);
|
||||
this->caller_.jump(
|
||||
this->callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->preserve_fpu() );
|
||||
this->flags_ &= ~flag_unwind_stack;
|
||||
|
||||
BOOST_ASSERT( this->is_complete() );
|
||||
}
|
||||
|
||||
public:
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< pull_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( forward< Fn >( fn) ),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( forward< Fn >( fn) )
|
||||
{}
|
||||
#else
|
||||
pull_coroutine_object( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< pull_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn)
|
||||
{}
|
||||
|
||||
pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< pull_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn)
|
||||
{}
|
||||
#endif
|
||||
|
||||
~pull_coroutine_object()
|
||||
{
|
||||
if ( ! this->is_complete() && this->force_unwind() )
|
||||
unwind_stack_();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
coroutine_context callee;
|
||||
coroutine_context caller;
|
||||
|
||||
{
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
this->callee_->jump(
|
||||
* this->caller_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() ) ) );
|
||||
this->result_ = from->data;
|
||||
|
||||
// create push_coroutine
|
||||
Caller c( this->caller_, false, this->preserve_fpu(), alloc_);
|
||||
typename Caller::base_t b( this->callee_, this->caller_, false, this->preserve_fpu() );
|
||||
Caller c( & b);
|
||||
try
|
||||
{ fn_( c); }
|
||||
catch ( forced_unwind const&)
|
||||
{}
|
||||
catch (...)
|
||||
{ this->except_ = current_exception(); }
|
||||
callee = c.impl_->callee_;
|
||||
}
|
||||
|
||||
this->flags_ |= flag_complete;
|
||||
param_type to( & caller);
|
||||
caller.jump(
|
||||
callee,
|
||||
param_type to;
|
||||
this->callee_->jump(
|
||||
* this->caller_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->preserve_fpu() );
|
||||
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
||||
}
|
||||
|
||||
void deallocate_object()
|
||||
{ destroy_( alloc_, this); }
|
||||
};
|
||||
|
||||
template<
|
||||
typename Fn,
|
||||
typename StackAllocator, typename Allocator,
|
||||
typename Caller
|
||||
>
|
||||
class pull_coroutine_object< void, Fn, StackAllocator, Allocator, Caller > :
|
||||
private stack_tuple< StackAllocator >,
|
||||
public pull_coroutine_base< void >
|
||||
template< typename Fn, typename Caller >
|
||||
class pull_coroutine_object< void, Fn, Caller > : public pull_coroutine_base< void >
|
||||
{
|
||||
public:
|
||||
typedef typename Allocator::template rebind<
|
||||
pull_coroutine_object<
|
||||
void, Fn, StackAllocator, Allocator, Caller
|
||||
>
|
||||
>::other allocator_t;
|
||||
|
||||
private:
|
||||
typedef stack_tuple< StackAllocator > pbase_type;
|
||||
typedef pull_coroutine_base< void > base_type;
|
||||
typedef parameters< void > param_type;
|
||||
|
||||
Fn fn_;
|
||||
allocator_t alloc_;
|
||||
|
||||
static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
|
||||
{
|
||||
alloc.destroy( p);
|
||||
alloc.deallocate( p, 1);
|
||||
}
|
||||
|
||||
pull_coroutine_object( pull_coroutine_object &);
|
||||
pull_coroutine_object & operator=( pull_coroutine_object const&);
|
||||
|
||||
void enter_()
|
||||
{
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
this->caller_.jump(
|
||||
this->callee_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() ) ) );
|
||||
this->callee_ = * from->ctx;
|
||||
if ( this->except_) rethrow_exception( this->except_);
|
||||
}
|
||||
|
||||
void unwind_stack_() BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT( ! this->is_complete() );
|
||||
|
||||
this->flags_ |= flag_unwind_stack;
|
||||
param_type to( & this->caller_, unwind_t::force_unwind);
|
||||
this->caller_.jump(
|
||||
this->callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->preserve_fpu() );
|
||||
this->flags_ &= ~flag_unwind_stack;
|
||||
|
||||
BOOST_ASSERT( this->is_complete() );
|
||||
}
|
||||
|
||||
public:
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< pull_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( forward< Fn >( fn) ),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( forward< Fn >( fn) )
|
||||
{}
|
||||
#else
|
||||
pull_coroutine_object( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< pull_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn)
|
||||
{}
|
||||
|
||||
pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< pull_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn)
|
||||
{}
|
||||
#endif
|
||||
|
||||
~pull_coroutine_object()
|
||||
{
|
||||
if ( ! this->is_complete() && this->force_unwind() )
|
||||
unwind_stack_();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
coroutine_context callee;
|
||||
coroutine_context caller;
|
||||
|
||||
{
|
||||
this->callee_->jump(
|
||||
* this->caller_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() );
|
||||
|
||||
// create push_coroutine
|
||||
Caller c( this->caller_, false, this->preserve_fpu(), alloc_);
|
||||
typename Caller::base_t b( this->callee_, this->caller_, false, this->preserve_fpu() );
|
||||
Caller c( & b);
|
||||
try
|
||||
{ fn_( c); }
|
||||
catch ( forced_unwind const&)
|
||||
{}
|
||||
catch (...)
|
||||
{ this->except_ = current_exception(); }
|
||||
callee = c.impl_->callee_;
|
||||
}
|
||||
|
||||
this->flags_ |= flag_complete;
|
||||
param_type to( & caller);
|
||||
caller.jump(
|
||||
callee,
|
||||
param_type to;
|
||||
this->callee_->jump(
|
||||
* this->caller_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->preserve_fpu() );
|
||||
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
||||
}
|
||||
|
||||
void deallocate_object()
|
||||
{ destroy_( alloc_, this); }
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
@@ -9,15 +9,15 @@
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/context/fcontext.hpp>
|
||||
#include <boost/exception_ptr.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include <boost/coroutine/detail/config.hpp>
|
||||
#include <boost/coroutine/detail/coroutine_context.hpp>
|
||||
#include <boost/coroutine/exceptions.hpp>
|
||||
#include <boost/coroutine/detail/flags.hpp>
|
||||
#include <boost/coroutine/detail/parameters.hpp>
|
||||
#include <boost/coroutine/exceptions.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
@@ -33,47 +33,27 @@ namespace detail {
|
||||
template< typename Arg >
|
||||
class push_coroutine_base : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef intrusive_ptr< push_coroutine_base > ptr_t;
|
||||
|
||||
private:
|
||||
template<
|
||||
typename X, typename Y, typename Z, typename V, typename W
|
||||
typename X, typename Y, typename Z
|
||||
>
|
||||
friend class pull_coroutine_object;
|
||||
|
||||
typedef parameters< Arg > param_type;
|
||||
|
||||
unsigned int use_count_;
|
||||
|
||||
protected:
|
||||
int flags_;
|
||||
exception_ptr except_;
|
||||
coroutine_context caller_;
|
||||
coroutine_context callee_;
|
||||
|
||||
virtual void deallocate_object() = 0;
|
||||
int flags_;
|
||||
exception_ptr except_;
|
||||
coroutine_context * caller_;
|
||||
coroutine_context * callee_;
|
||||
|
||||
public:
|
||||
push_coroutine_base( coroutine_context::ctx_fn fn,
|
||||
stack_context * stack_ctx,
|
||||
push_coroutine_base( coroutine_context * caller,
|
||||
coroutine_context * callee,
|
||||
bool unwind, bool preserve_fpu) :
|
||||
use_count_( 0),
|
||||
flags_( 0),
|
||||
except_(),
|
||||
caller_(),
|
||||
callee_( fn, stack_ctx)
|
||||
{
|
||||
if ( unwind) flags_ |= flag_force_unwind;
|
||||
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
|
||||
}
|
||||
|
||||
push_coroutine_base( coroutine_context const& callee,
|
||||
bool unwind, bool preserve_fpu) :
|
||||
use_count_( 0),
|
||||
flags_( 0),
|
||||
except_(),
|
||||
caller_(),
|
||||
caller_( caller),
|
||||
callee_( callee)
|
||||
{
|
||||
if ( unwind) flags_ |= flag_force_unwind;
|
||||
@@ -95,19 +75,33 @@ public:
|
||||
bool is_complete() const BOOST_NOEXCEPT
|
||||
{ return 0 != ( flags_ & flag_complete); }
|
||||
|
||||
void unwind_stack() BOOST_NOEXCEPT
|
||||
{
|
||||
if ( ! is_complete() && force_unwind() )
|
||||
{
|
||||
flags_ |= flag_unwind_stack;
|
||||
param_type to( unwind_t::force_unwind);
|
||||
caller_->jump(
|
||||
* callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
preserve_fpu() );
|
||||
flags_ &= ~flag_unwind_stack;
|
||||
|
||||
BOOST_ASSERT( is_complete() );
|
||||
}
|
||||
}
|
||||
|
||||
void push( Arg const& arg)
|
||||
{
|
||||
BOOST_ASSERT( ! is_complete() );
|
||||
|
||||
param_type to( & caller_, const_cast< Arg * >( & arg) );
|
||||
param_type to( const_cast< Arg * >( & arg) );
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
to.ctx->jump(
|
||||
callee_,
|
||||
caller_->jump(
|
||||
* callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
preserve_fpu() ) ) );
|
||||
BOOST_ASSERT( from->ctx);
|
||||
callee_ = * from->ctx;
|
||||
if ( from->do_unwind) throw forced_unwind();
|
||||
if ( except_) rethrow_exception( except_);
|
||||
}
|
||||
@@ -116,70 +110,42 @@ public:
|
||||
{
|
||||
BOOST_ASSERT( ! is_complete() );
|
||||
|
||||
param_type to( & caller_, const_cast< Arg * >( & arg) );
|
||||
param_type to( const_cast< Arg * >( & arg) );
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
to.ctx->jump(
|
||||
callee_,
|
||||
caller_->jump(
|
||||
* callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
preserve_fpu() ) ) );
|
||||
BOOST_ASSERT( from->ctx);
|
||||
callee_ = * from->ctx;
|
||||
if ( from->do_unwind) throw forced_unwind();
|
||||
if ( except_) rethrow_exception( except_);
|
||||
}
|
||||
|
||||
friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT
|
||||
{ ++p->use_count_; }
|
||||
|
||||
friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT
|
||||
{ if ( --p->use_count_ == 0) p->deallocate_object(); }
|
||||
};
|
||||
|
||||
template< typename Arg >
|
||||
class push_coroutine_base< Arg & > : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef intrusive_ptr< push_coroutine_base > ptr_t;
|
||||
|
||||
private:
|
||||
template<
|
||||
typename X, typename Y, typename Z, typename V, typename W
|
||||
typename X, typename Y, typename Z
|
||||
>
|
||||
friend class pull_coroutine_object;
|
||||
|
||||
typedef parameters< Arg & > param_type;
|
||||
|
||||
unsigned int use_count_;
|
||||
|
||||
protected:
|
||||
int flags_;
|
||||
exception_ptr except_;
|
||||
coroutine_context caller_;
|
||||
coroutine_context callee_;
|
||||
|
||||
virtual void deallocate_object() = 0;
|
||||
int flags_;
|
||||
exception_ptr except_;
|
||||
coroutine_context * caller_;
|
||||
coroutine_context * callee_;
|
||||
|
||||
public:
|
||||
push_coroutine_base( coroutine_context::ctx_fn fn,
|
||||
stack_context * stack_ctx,
|
||||
push_coroutine_base( coroutine_context * caller,
|
||||
coroutine_context * callee,
|
||||
bool unwind, bool preserve_fpu) :
|
||||
use_count_( 0),
|
||||
flags_( 0),
|
||||
except_(),
|
||||
caller_(),
|
||||
callee_( fn, stack_ctx)
|
||||
{
|
||||
if ( unwind) flags_ |= flag_force_unwind;
|
||||
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
|
||||
}
|
||||
|
||||
push_coroutine_base( coroutine_context const& callee,
|
||||
bool unwind, bool preserve_fpu) :
|
||||
use_count_( 0),
|
||||
flags_( 0),
|
||||
except_(),
|
||||
caller_(),
|
||||
caller_( caller),
|
||||
callee_( callee)
|
||||
{
|
||||
if ( unwind) flags_ |= flag_force_unwind;
|
||||
@@ -201,74 +167,62 @@ public:
|
||||
bool is_complete() const BOOST_NOEXCEPT
|
||||
{ return 0 != ( flags_ & flag_complete); }
|
||||
|
||||
void unwind_stack() BOOST_NOEXCEPT
|
||||
{
|
||||
if ( ! is_complete() && force_unwind() )
|
||||
{
|
||||
flags_ |= flag_unwind_stack;
|
||||
param_type to( unwind_t::force_unwind);
|
||||
caller_->jump(
|
||||
* callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
preserve_fpu() );
|
||||
flags_ &= ~flag_unwind_stack;
|
||||
|
||||
BOOST_ASSERT( is_complete() );
|
||||
}
|
||||
}
|
||||
|
||||
void push( Arg & arg)
|
||||
{
|
||||
BOOST_ASSERT( ! is_complete() );
|
||||
|
||||
param_type to( & caller_, & arg);
|
||||
param_type to( & arg);
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
to.ctx->jump(
|
||||
callee_,
|
||||
caller_->jump(
|
||||
* callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
preserve_fpu() ) ) );
|
||||
BOOST_ASSERT( from->ctx);
|
||||
callee_ = * from->ctx;
|
||||
if ( from->do_unwind) throw forced_unwind();
|
||||
if ( except_) rethrow_exception( except_);
|
||||
}
|
||||
|
||||
friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT
|
||||
{ ++p->use_count_; }
|
||||
|
||||
friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT
|
||||
{ if ( --p->use_count_ == 0) p->deallocate_object(); }
|
||||
};
|
||||
|
||||
template<>
|
||||
class push_coroutine_base< void > : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef intrusive_ptr< push_coroutine_base > ptr_t;
|
||||
|
||||
private:
|
||||
template<
|
||||
typename X, typename Y, typename Z, typename V, typename W
|
||||
typename X, typename Y, typename Z
|
||||
>
|
||||
friend class pull_coroutine_object;
|
||||
|
||||
typedef parameters< void > param_type;
|
||||
|
||||
unsigned int use_count_;
|
||||
|
||||
protected:
|
||||
int flags_;
|
||||
exception_ptr except_;
|
||||
coroutine_context caller_;
|
||||
coroutine_context callee_;
|
||||
|
||||
virtual void deallocate_object() = 0;
|
||||
int flags_;
|
||||
exception_ptr except_;
|
||||
coroutine_context * caller_;
|
||||
coroutine_context * callee_;
|
||||
|
||||
public:
|
||||
push_coroutine_base( coroutine_context::ctx_fn fn,
|
||||
stack_context * stack_ctx,
|
||||
push_coroutine_base( coroutine_context * caller,
|
||||
coroutine_context * callee,
|
||||
bool unwind, bool preserve_fpu) :
|
||||
use_count_( 0),
|
||||
flags_( 0),
|
||||
except_(),
|
||||
caller_(),
|
||||
callee_( fn, stack_ctx)
|
||||
{
|
||||
if ( unwind) flags_ |= flag_force_unwind;
|
||||
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
|
||||
}
|
||||
|
||||
push_coroutine_base( coroutine_context const& callee,
|
||||
bool unwind, bool preserve_fpu) :
|
||||
use_count_( 0),
|
||||
flags_( 0),
|
||||
except_(),
|
||||
caller_(),
|
||||
caller_( caller),
|
||||
callee_( callee)
|
||||
{
|
||||
if ( unwind) flags_ |= flag_force_unwind;
|
||||
@@ -290,28 +244,36 @@ public:
|
||||
bool is_complete() const BOOST_NOEXCEPT
|
||||
{ return 0 != ( flags_ & flag_complete); }
|
||||
|
||||
void unwind_stack() BOOST_NOEXCEPT
|
||||
{
|
||||
if ( ! is_complete() && force_unwind() )
|
||||
{
|
||||
flags_ |= flag_unwind_stack;
|
||||
param_type to( unwind_t::force_unwind);
|
||||
caller_->jump(
|
||||
* callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
preserve_fpu() );
|
||||
flags_ &= ~flag_unwind_stack;
|
||||
|
||||
BOOST_ASSERT( is_complete() );
|
||||
}
|
||||
}
|
||||
|
||||
void push()
|
||||
{
|
||||
BOOST_ASSERT( ! is_complete() );
|
||||
|
||||
param_type to( & caller_);
|
||||
param_type to;
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
to.ctx->jump(
|
||||
callee_,
|
||||
caller_->jump(
|
||||
* callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
preserve_fpu() ) ) );
|
||||
BOOST_ASSERT( from->ctx);
|
||||
callee_ = * from->ctx;
|
||||
if ( from->do_unwind) throw forced_unwind();
|
||||
if ( except_) rethrow_exception( except_);
|
||||
}
|
||||
|
||||
friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT
|
||||
{ ++p->use_count_; }
|
||||
|
||||
friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT
|
||||
{ if ( --p->use_count_ == 0) p->deallocate_object(); }
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright Oliver Kowalke 2009.
|
||||
// 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_COROUTINES_DETAIL_PUSH_COROUTINE_CALLER_H
|
||||
#define BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_CALLER_H
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/context/fcontext.hpp>
|
||||
|
||||
#include <boost/coroutine/detail/config.hpp>
|
||||
#include <boost/coroutine/detail/push_coroutine_base.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace coroutines {
|
||||
namespace detail {
|
||||
|
||||
template< typename Arg, typename Allocator >
|
||||
class push_coroutine_caller : public push_coroutine_base< Arg >
|
||||
{
|
||||
public:
|
||||
typedef typename Allocator::template rebind<
|
||||
push_coroutine_caller< Arg, Allocator >
|
||||
>::other allocator_t;
|
||||
|
||||
push_coroutine_caller( coroutine_context const& callee, bool unwind,
|
||||
bool preserve_fpu, allocator_t const& alloc) BOOST_NOEXCEPT :
|
||||
push_coroutine_base< Arg >( callee, unwind, preserve_fpu),
|
||||
alloc_( alloc)
|
||||
{}
|
||||
|
||||
void deallocate_object()
|
||||
{ destroy_( alloc_, this); }
|
||||
|
||||
private:
|
||||
allocator_t alloc_;
|
||||
|
||||
static void destroy_( allocator_t & alloc, push_coroutine_caller * p)
|
||||
{
|
||||
alloc.destroy( p);
|
||||
alloc.deallocate( p, 1);
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_CALLER_H
|
||||
@@ -21,10 +21,7 @@
|
||||
#include <boost/coroutine/exceptions.hpp>
|
||||
#include <boost/coroutine/detail/flags.hpp>
|
||||
#include <boost/coroutine/detail/parameters.hpp>
|
||||
#include <boost/coroutine/detail/stack_tuple.hpp>
|
||||
#include <boost/coroutine/detail/trampoline.hpp>
|
||||
#include <boost/coroutine/flags.hpp>
|
||||
#include <boost/coroutine/stack_context.hpp>
|
||||
#include <boost/coroutine/detail/push_coroutine_base.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
@@ -40,436 +37,217 @@ namespace boost {
|
||||
namespace coroutines {
|
||||
namespace detail {
|
||||
|
||||
template<
|
||||
typename Arg, typename Fn,
|
||||
typename StackAllocator, typename Allocator,
|
||||
typename Caller
|
||||
>
|
||||
class push_coroutine_object : private stack_tuple< StackAllocator >,
|
||||
public push_coroutine_base< Arg >
|
||||
template< typename Arg, typename Fn, typename Caller >
|
||||
class push_coroutine_object : public push_coroutine_base< Arg >
|
||||
{
|
||||
public:
|
||||
typedef typename Allocator::template rebind<
|
||||
push_coroutine_object<
|
||||
Arg, Fn, StackAllocator, Allocator, Caller
|
||||
>
|
||||
>::other allocator_t;
|
||||
|
||||
private:
|
||||
typedef stack_tuple< StackAllocator > pbase_type;
|
||||
typedef push_coroutine_base< Arg > base_type;
|
||||
typedef parameters< Arg > param_type;
|
||||
|
||||
Fn fn_;
|
||||
allocator_t alloc_;
|
||||
|
||||
static void destroy_( allocator_t & alloc, push_coroutine_object * p)
|
||||
{
|
||||
alloc.destroy( p);
|
||||
alloc.deallocate( p, 1);
|
||||
}
|
||||
|
||||
push_coroutine_object( push_coroutine_object &);
|
||||
push_coroutine_object & operator=( push_coroutine_object const&);
|
||||
|
||||
void enter_()
|
||||
{
|
||||
parameters< void > * from(
|
||||
reinterpret_cast< parameters< void > * >(
|
||||
this->caller_.jump(
|
||||
this->callee_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() ) ) );
|
||||
this->callee_ = * from->ctx;
|
||||
if ( this->except_) rethrow_exception( this->except_);
|
||||
}
|
||||
|
||||
void unwind_stack_() BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT( ! this->is_complete() );
|
||||
|
||||
this->flags_ |= flag_unwind_stack;
|
||||
param_type to( & this->caller_, unwind_t::force_unwind);
|
||||
this->caller_.jump(
|
||||
this->callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->preserve_fpu() );
|
||||
this->flags_ &= ~flag_unwind_stack;
|
||||
|
||||
BOOST_ASSERT( this->is_complete() );
|
||||
}
|
||||
|
||||
public:
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
push_coroutine_object( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< push_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn)
|
||||
{}
|
||||
#endif
|
||||
push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< push_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
fn_( fn),
|
||||
fn_( fn)
|
||||
#else
|
||||
fn_( forward< Fn >( fn) ),
|
||||
fn_( forward< Fn >( fn) )
|
||||
#endif
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
|
||||
~push_coroutine_object()
|
||||
{
|
||||
if ( ! this->is_complete() && this->force_unwind() )
|
||||
unwind_stack_();
|
||||
}
|
||||
{}
|
||||
|
||||
void run()
|
||||
{
|
||||
coroutine_context callee;
|
||||
coroutine_context caller;
|
||||
|
||||
{
|
||||
parameters< void > to( & caller);
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
caller.jump(
|
||||
this->caller_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->callee_->jump(
|
||||
* this->caller_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() ) ) );
|
||||
BOOST_ASSERT( from->ctx);
|
||||
BOOST_ASSERT( from->data);
|
||||
|
||||
// create pull_coroutine
|
||||
Caller c( * from->ctx, false, this->preserve_fpu(), alloc_, from->data);
|
||||
typename Caller::base_t b( this->callee_, this->caller_, false, this->preserve_fpu(), from->data);
|
||||
Caller c( & b);
|
||||
try
|
||||
{ fn_( c); }
|
||||
catch ( forced_unwind const&)
|
||||
{}
|
||||
catch (...)
|
||||
{ this->except_ = current_exception(); }
|
||||
callee = c.impl_->callee_;
|
||||
}
|
||||
|
||||
this->flags_ |= flag_complete;
|
||||
param_type to( & caller);
|
||||
caller.jump(
|
||||
callee,
|
||||
param_type to;
|
||||
this->callee_->jump(
|
||||
* this->caller_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->preserve_fpu() );
|
||||
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
||||
}
|
||||
|
||||
void deallocate_object()
|
||||
{ destroy_( alloc_, this); }
|
||||
};
|
||||
|
||||
template<
|
||||
typename Arg, typename Fn,
|
||||
typename StackAllocator, typename Allocator,
|
||||
typename Caller
|
||||
>
|
||||
class push_coroutine_object< Arg &, Fn, StackAllocator, Allocator, Caller > :
|
||||
private stack_tuple< StackAllocator >,
|
||||
public push_coroutine_base< Arg & >
|
||||
template< typename Arg, typename Fn, typename Caller >
|
||||
class push_coroutine_object< Arg &, Fn, Caller > : public push_coroutine_base< Arg & >
|
||||
{
|
||||
public:
|
||||
typedef typename Allocator::template rebind<
|
||||
push_coroutine_object<
|
||||
Arg &, Fn, StackAllocator, Allocator, Caller
|
||||
>
|
||||
>::other allocator_t;
|
||||
|
||||
private:
|
||||
typedef stack_tuple< StackAllocator > pbase_type;
|
||||
typedef push_coroutine_base< Arg & > base_type;
|
||||
typedef parameters< Arg & > param_type;
|
||||
|
||||
Fn fn_;
|
||||
allocator_t alloc_;
|
||||
|
||||
static void destroy_( allocator_t & alloc, push_coroutine_object * p)
|
||||
{
|
||||
alloc.destroy( p);
|
||||
alloc.deallocate( p, 1);
|
||||
}
|
||||
|
||||
push_coroutine_object( push_coroutine_object &);
|
||||
push_coroutine_object & operator=( push_coroutine_object const&);
|
||||
|
||||
void enter_()
|
||||
{
|
||||
parameters< void > * from(
|
||||
reinterpret_cast< parameters< void > * >(
|
||||
this->caller_.jump(
|
||||
this->callee_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() ) ) );
|
||||
this->callee_ = * from->ctx;
|
||||
if ( this->except_) rethrow_exception( this->except_);
|
||||
}
|
||||
|
||||
void unwind_stack_() BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT( ! this->is_complete() );
|
||||
|
||||
this->flags_ |= flag_unwind_stack;
|
||||
param_type to( & this->caller_, unwind_t::force_unwind);
|
||||
this->caller_.jump(
|
||||
this->callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->preserve_fpu() );
|
||||
this->flags_ &= ~flag_unwind_stack;
|
||||
|
||||
BOOST_ASSERT( this->is_complete() );
|
||||
}
|
||||
|
||||
public:
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< push_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( forward< Fn >( fn) ),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( forward< Fn >( fn) )
|
||||
{}
|
||||
#else
|
||||
push_coroutine_object( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< push_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn)
|
||||
{}
|
||||
|
||||
push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< push_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn)
|
||||
{}
|
||||
#endif
|
||||
|
||||
~push_coroutine_object()
|
||||
{
|
||||
if ( ! this->is_complete() && this->force_unwind() )
|
||||
unwind_stack_();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
coroutine_context callee;
|
||||
coroutine_context caller;
|
||||
|
||||
{
|
||||
parameters< void > to( & caller);
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
caller.jump(
|
||||
this->caller_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->callee_->jump(
|
||||
* this->caller_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() ) ) );
|
||||
BOOST_ASSERT( from->ctx);
|
||||
BOOST_ASSERT( from->data);
|
||||
|
||||
// create pull_coroutine
|
||||
Caller c( * from->ctx, false, this->preserve_fpu(), alloc_, from->data);
|
||||
typename Caller::base_t b( this->callee_, this->caller_, false, this->preserve_fpu(), from->data);
|
||||
Caller c( & b);
|
||||
try
|
||||
{ fn_( c); }
|
||||
catch ( forced_unwind const&)
|
||||
{}
|
||||
catch (...)
|
||||
{ this->except_ = current_exception(); }
|
||||
callee = c.impl_->callee_;
|
||||
}
|
||||
|
||||
this->flags_ |= flag_complete;
|
||||
param_type to( & caller);
|
||||
caller.jump(
|
||||
callee,
|
||||
param_type to;
|
||||
this->callee_->jump(
|
||||
* this->caller_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->preserve_fpu() );
|
||||
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
||||
}
|
||||
|
||||
void deallocate_object()
|
||||
{ destroy_( alloc_, this); }
|
||||
};
|
||||
|
||||
template<
|
||||
typename Fn,
|
||||
typename StackAllocator, typename Allocator,
|
||||
typename Caller
|
||||
>
|
||||
class push_coroutine_object< void, Fn, StackAllocator, Allocator, Caller > :
|
||||
private stack_tuple< StackAllocator >,
|
||||
public push_coroutine_base< void >
|
||||
template< typename Fn, typename Caller >
|
||||
class push_coroutine_object< void, Fn, Caller > : public push_coroutine_base< void >
|
||||
{
|
||||
public:
|
||||
typedef typename Allocator::template rebind<
|
||||
push_coroutine_object<
|
||||
void, Fn, StackAllocator, Allocator, Caller
|
||||
>
|
||||
>::other allocator_t;
|
||||
|
||||
private:
|
||||
typedef stack_tuple< StackAllocator > pbase_type;
|
||||
typedef push_coroutine_base< void > base_type;
|
||||
typedef parameters< void > param_type;
|
||||
|
||||
Fn fn_;
|
||||
allocator_t alloc_;
|
||||
|
||||
static void destroy_( allocator_t & alloc, push_coroutine_object * p)
|
||||
{
|
||||
alloc.destroy( p);
|
||||
alloc.deallocate( p, 1);
|
||||
}
|
||||
|
||||
push_coroutine_object( push_coroutine_object &);
|
||||
push_coroutine_object & operator=( push_coroutine_object const&);
|
||||
|
||||
void enter_()
|
||||
{
|
||||
parameters< void > * from(
|
||||
reinterpret_cast< parameters< void > * >(
|
||||
this->caller_.jump(
|
||||
this->callee_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() ) ) );
|
||||
this->callee_ = * from->ctx;
|
||||
if ( this->except_) rethrow_exception( this->except_);
|
||||
}
|
||||
|
||||
void unwind_stack_() BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT( ! this->is_complete() );
|
||||
|
||||
this->flags_ |= flag_unwind_stack;
|
||||
param_type to( & this->caller_, unwind_t::force_unwind);
|
||||
this->caller_.jump(
|
||||
this->callee_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->preserve_fpu() );
|
||||
this->flags_ &= ~flag_unwind_stack;
|
||||
|
||||
BOOST_ASSERT( this->is_complete() );
|
||||
}
|
||||
|
||||
public:
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< push_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( forward< Fn >( fn) ),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( forward< Fn >( fn) )
|
||||
{}
|
||||
#else
|
||||
push_coroutine_object( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< push_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn)
|
||||
{}
|
||||
|
||||
push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
pbase_type( stack_alloc, attr.size),
|
||||
base_type(
|
||||
trampoline1< push_coroutine_object >,
|
||||
& this->stack_ctx,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
coroutine_context * caller,
|
||||
coroutine_context * callee) :
|
||||
base_type( caller, callee,
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn)
|
||||
{}
|
||||
#endif
|
||||
|
||||
~push_coroutine_object()
|
||||
{
|
||||
if ( ! this->is_complete() && this->force_unwind() )
|
||||
unwind_stack_();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
coroutine_context callee;
|
||||
coroutine_context caller;
|
||||
|
||||
{
|
||||
parameters< void > to( & caller);
|
||||
param_type * from(
|
||||
reinterpret_cast< param_type * >(
|
||||
caller.jump(
|
||||
this->caller_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->preserve_fpu() ) ) );
|
||||
BOOST_ASSERT( from->ctx);
|
||||
this->callee_->jump(
|
||||
* this->caller_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() );
|
||||
|
||||
// create pull_coroutine
|
||||
Caller c( * from->ctx, false, this->preserve_fpu(), alloc_);
|
||||
typename Caller::base_t b( this->callee_, this->caller_, false, this->preserve_fpu() );
|
||||
Caller c( & b);
|
||||
try
|
||||
{ fn_( c); }
|
||||
catch ( forced_unwind const&)
|
||||
{}
|
||||
catch (...)
|
||||
{ this->except_ = current_exception(); }
|
||||
callee = c.impl_->callee_;
|
||||
}
|
||||
|
||||
this->flags_ |= flag_complete;
|
||||
param_type to( & caller);
|
||||
caller.jump(
|
||||
callee,
|
||||
param_type to;
|
||||
this->callee_->jump(
|
||||
* this->caller_,
|
||||
reinterpret_cast< intptr_t >( & to),
|
||||
this->preserve_fpu() );
|
||||
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
||||
}
|
||||
|
||||
void deallocate_object()
|
||||
{ destroy_( alloc_, this); }
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
85
include/boost/coroutine/detail/setup.hpp
Normal file
85
include/boost/coroutine/detail/setup.hpp
Normal file
@@ -0,0 +1,85 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2009.
|
||||
// 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_COROUTINES_DETAIL_SETUP_H
|
||||
#define BOOST_COROUTINES_DETAIL_SETUP_H
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
|
||||
#include <boost/coroutine/detail/coroutine_context.hpp>
|
||||
#include <boost/coroutine/detail/flags.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace coroutines {
|
||||
namespace detail {
|
||||
|
||||
template< typename Fn, typename Coro >
|
||||
struct setup
|
||||
{
|
||||
struct dummy {};
|
||||
|
||||
Fn fn;
|
||||
coroutine_context * caller;
|
||||
coroutine_context * callee;
|
||||
attributes attr;
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
setup( Fn fn_,
|
||||
coroutine_context * caller_,
|
||||
coroutine_context * callee_,
|
||||
attributes const& attr_) :
|
||||
fn( forward< Fn >( fn_) ),
|
||||
caller( caller_),
|
||||
callee( callee_),
|
||||
attr( attr_)
|
||||
{}
|
||||
#else
|
||||
setup( Fn fn_,
|
||||
coroutine_context * caller_,
|
||||
coroutine_context * callee_,
|
||||
attributes const& attr_,
|
||||
typename disable_if<
|
||||
is_convertible< Fn&, BOOST_RV_REF(Fn) >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
fn( fn_),
|
||||
caller( caller_),
|
||||
callee( callee_),
|
||||
attr( attr_)
|
||||
{}
|
||||
|
||||
setup( BOOST_RV_REF( Fn) fn_,
|
||||
coroutine_context * caller_,
|
||||
coroutine_context * callee_,
|
||||
attributes const& attr_,
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, setup >,
|
||||
dummy*
|
||||
>::type = 0) :
|
||||
fn( fn_),
|
||||
caller( caller_),
|
||||
callee( callee_),
|
||||
attr( attr_)
|
||||
{}
|
||||
#endif
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_COROUTINES_DETAIL_SETUP_H
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
#include <boost/coroutine/detail/setup.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
@@ -23,38 +25,17 @@ namespace coroutines {
|
||||
namespace detail {
|
||||
|
||||
template< typename Fn, typename Coro >
|
||||
void trampoline1_ex( intptr_t vp)
|
||||
void trampoline( intptr_t vp)
|
||||
{
|
||||
BOOST_ASSERT( vp);
|
||||
|
||||
init< Fn, Coro > * from(
|
||||
reinterpret_cast< init< Fn, Coro > * >( vp);
|
||||
setup< Fn, Coro > * from(
|
||||
reinterpret_cast< setup< Fn, Coro > * >( vp) );
|
||||
|
||||
Coro c( from->fn, from->attr, from->caller, from->callee);
|
||||
Coro c( forward< Fn >( from->fn), from->attr, from->caller, from->callee);
|
||||
c.run();
|
||||
}
|
||||
|
||||
template< typename Coroutine >
|
||||
void trampoline1( intptr_t vp)
|
||||
{
|
||||
BOOST_ASSERT( vp);
|
||||
|
||||
reinterpret_cast< Coroutine * >( vp)->run();
|
||||
}
|
||||
|
||||
template< typename Coroutine, typename Arg >
|
||||
void trampoline2( intptr_t vp)
|
||||
{
|
||||
BOOST_ASSERT( vp);
|
||||
|
||||
tuple< Coroutine *, Arg > * tpl(
|
||||
reinterpret_cast< tuple< Coroutine *, Arg > * >( vp) );
|
||||
Coroutine * coro( get< 0 >( * tpl) );
|
||||
Arg arg( get< 1 >( * tpl) );
|
||||
|
||||
coro->run( arg);
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
|
||||
Reference in New Issue
Block a user