allocate on stack

This commit is contained in:
Oliver Kowalke
2014-01-25 23:41:06 +01:00
parent 8857a31281
commit 7b6bba07c0
17 changed files with 2166 additions and 2580 deletions

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View File

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