mirror of
https://github.com/boostorg/fiber.git
synced 2026-02-19 14:22:23 +00:00
modification for fiberswq
This commit is contained in:
@@ -4,8 +4,8 @@
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_STRATUM_BASE_H
|
||||
#define BOOST_FIBERS_DETAIL_STRATUM_BASE_H
|
||||
#ifndef BOOST_FIBERS_DETAIL_FIBER_BASE_H
|
||||
#define BOOST_FIBERS_DETAIL_FIBER_BASE_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
@@ -15,12 +15,13 @@
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/context/fcontext.hpp>
|
||||
#include <boost/context/stack_allocator.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/exception_ptr.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/detail/flags.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
@@ -30,63 +31,28 @@ namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
struct forced_unwind {};
|
||||
|
||||
enum flag_t
|
||||
{
|
||||
flag_resumed = 1 << 1,
|
||||
flag_complete = 1 << 2,
|
||||
flag_unwind_stack = 1 << 3,
|
||||
flag_canceled = 1 << 4
|
||||
};
|
||||
|
||||
template< typename Fiber >
|
||||
void trampoline( intptr_t vp)
|
||||
{
|
||||
BOOST_ASSERT( vp);
|
||||
|
||||
Fiber * f( reinterpret_cast< Fiber * >( vp) );
|
||||
BOOST_ASSERT( ! f->is_complete() );
|
||||
BOOST_ASSERT( f->is_resumed() );
|
||||
try
|
||||
{ f->exec(); }
|
||||
catch ( forced_unwind const&)
|
||||
{}
|
||||
catch (...)
|
||||
{
|
||||
//TODO: call std::terminate() or do nothing?
|
||||
}
|
||||
f->flags_ &= ~flag_resumed;
|
||||
f->flags_ &= ~flag_unwind_stack;
|
||||
f->flags_ |= flag_complete;
|
||||
|
||||
ctx::jump_fcontext( & f->callee_, & f->caller_, 0, f->preserve_fpu_);
|
||||
}
|
||||
|
||||
class BOOST_FIBERS_DECL fiber_base : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef intrusive_ptr< fiber_base > ptr_t;
|
||||
|
||||
private:
|
||||
template< typename T >
|
||||
friend void trampoline( intptr_t);
|
||||
friend class scheduler;
|
||||
template< typename X, typename Y, typename Z >
|
||||
friend class fiber_object;
|
||||
|
||||
std::size_t use_count_;
|
||||
ctx::stack_allocator alloc_;
|
||||
ctx::fcontext_t caller_;
|
||||
ctx::fcontext_t callee_;
|
||||
context::fcontext_t caller_;
|
||||
context::fcontext_t * callee_;
|
||||
int flags_;
|
||||
bool preserve_fpu_;
|
||||
exception_ptr except_;
|
||||
std::vector< ptr_t > joining_;
|
||||
|
||||
void unwind_stack_();
|
||||
|
||||
void terminate_();
|
||||
|
||||
void notify_();
|
||||
|
||||
protected:
|
||||
virtual void deallocate_object() = 0;
|
||||
|
||||
public:
|
||||
class id
|
||||
{
|
||||
@@ -95,31 +61,31 @@ public:
|
||||
|
||||
fiber_base::ptr_t impl_;
|
||||
|
||||
id( fiber_base::ptr_t const& impl) :
|
||||
explicit id( fiber_base::ptr_t const& impl) BOOST_NOEXCEPT :
|
||||
impl_( impl)
|
||||
{}
|
||||
|
||||
public:
|
||||
id() :
|
||||
id() BOOST_NOEXCEPT :
|
||||
impl_()
|
||||
{}
|
||||
|
||||
bool operator==( id const& other) const
|
||||
bool operator==( id const& other) const BOOST_NOEXCEPT
|
||||
{ return impl_ == other.impl_; }
|
||||
|
||||
bool operator!=( id const& other) const
|
||||
bool operator!=( id const& other) const BOOST_NOEXCEPT
|
||||
{ return impl_ != other.impl_; }
|
||||
|
||||
bool operator<( id const& other) const
|
||||
bool operator<( id const& other) const BOOST_NOEXCEPT
|
||||
{ return impl_ < other.impl_; }
|
||||
|
||||
bool operator>( id const& other) const
|
||||
bool operator>( id const& other) const BOOST_NOEXCEPT
|
||||
{ return other.impl_ < impl_; }
|
||||
|
||||
bool operator<=( id const& other) const
|
||||
bool operator<=( id const& other) const BOOST_NOEXCEPT
|
||||
{ return ! ( * this > other); }
|
||||
|
||||
bool operator>=( id const& other) const
|
||||
bool operator>=( id const& other) const BOOST_NOEXCEPT
|
||||
{ return ! ( * this < other); }
|
||||
|
||||
template< typename charT, class traitsT >
|
||||
@@ -132,26 +98,23 @@ public:
|
||||
return os << "{not-valid}";
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
operator bool() const BOOST_NOEXCEPT
|
||||
{ return 0 != impl_; }
|
||||
|
||||
bool operator!() const
|
||||
bool operator!() const BOOST_NOEXCEPT
|
||||
{ return 0 == impl_; }
|
||||
};
|
||||
|
||||
fiber_base( std::size_t size, bool preserve_fpu);
|
||||
fiber_base( context::fcontext_t *, bool, bool);
|
||||
|
||||
virtual ~fiber_base();
|
||||
virtual ~fiber_base() {}
|
||||
|
||||
id get_id() const;
|
||||
virtual void terminate() = 0;
|
||||
|
||||
bool is_canceled() const;
|
||||
id get_id() const BOOST_NOEXCEPT
|
||||
{ return id( ptr_t( const_cast< fiber_base * >( this) ) ); }
|
||||
|
||||
bool is_complete() const;
|
||||
|
||||
bool is_resumed() const;
|
||||
|
||||
void join( ptr_t const& p);
|
||||
void join( ptr_t const&);
|
||||
|
||||
void resume();
|
||||
|
||||
@@ -165,13 +128,29 @@ public:
|
||||
|
||||
void sleep( chrono::system_clock::time_point const& abs_time);
|
||||
|
||||
virtual void exec() = 0;
|
||||
bool force_unwind() const BOOST_NOEXCEPT
|
||||
{ return 0 != ( flags_ & flag_forced_unwind); }
|
||||
|
||||
friend inline void intrusive_ptr_add_ref( fiber_base * p)
|
||||
bool unwind_requested() const BOOST_NOEXCEPT
|
||||
{ return 0 != ( flags_ & flag_unwind_stack); }
|
||||
|
||||
bool preserve_fpu() const BOOST_NOEXCEPT
|
||||
{ return 0 != ( flags_ & flag_preserve_fpu); }
|
||||
|
||||
bool is_complete() const BOOST_NOEXCEPT
|
||||
{ return 0 != ( flags_ & flag_complete); }
|
||||
|
||||
bool is_canceled() const BOOST_NOEXCEPT
|
||||
{ return 0 != ( flags_ & flag_canceled); }
|
||||
|
||||
bool is_resumed() const BOOST_NOEXCEPT
|
||||
{ return 0 != ( flags_ & flag_resumed); }
|
||||
|
||||
friend inline void intrusive_ptr_add_ref( fiber_base * p) BOOST_NOEXCEPT
|
||||
{ ++p->use_count_; }
|
||||
|
||||
friend inline void intrusive_ptr_release( fiber_base * p)
|
||||
{ if ( --p->use_count_ == 0) delete p; }
|
||||
{ if ( --p->use_count_ == 0) p->deallocate_object(); }
|
||||
};
|
||||
|
||||
}}}
|
||||
@@ -180,4 +159,4 @@ public:
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_STRATUM_BASE_H
|
||||
#endif // BOOST_FIBERS_DETAIL_FIBER_BASE_H
|
||||
|
||||
@@ -4,17 +4,22 @@
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_STRATUM_OBJECT_H
|
||||
#define BOOST_FIBERS_DETAIL_STRATUM_OBJECT_H
|
||||
#ifndef BOOST_FIBERS_DETAIL_FIBER_OBJECT_H
|
||||
#define BOOST_FIBERS_DETAIL_FIBER_OBJECT_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/context/fcontext.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
|
||||
#include <boost/fiber/attributes.hpp>
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/detail/fiber_base.hpp>
|
||||
#include <boost/fiber/detail/flags.hpp>
|
||||
#include <boost/fiber/flags.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
@@ -24,66 +29,291 @@ namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
template< typename Fn >
|
||||
struct forced_unwind {};
|
||||
|
||||
template< typename Fiber >
|
||||
void trampoline( intptr_t vp)
|
||||
{
|
||||
BOOST_ASSERT( vp);
|
||||
|
||||
Fiber * f( reinterpret_cast< Fiber * >( vp) );
|
||||
f->exec();
|
||||
}
|
||||
|
||||
template< typename Fn, typename StackAllocator, typename Allocator >
|
||||
class fiber_object : public fiber_base
|
||||
{
|
||||
private:
|
||||
Fn fn_;
|
||||
public:
|
||||
typedef typename Allocator::template rebind<
|
||||
fiber_object<
|
||||
Fn, StackAllocator, Allocator
|
||||
>
|
||||
>::other allocator_t;
|
||||
|
||||
fiber_object( fiber_object &);
|
||||
fiber_object & operator=( fiber_object const&);
|
||||
private:
|
||||
Fn fn_;
|
||||
context::stack_t stack_;
|
||||
StackAllocator stack_alloc_;
|
||||
allocator_t alloc_;
|
||||
|
||||
static void destroy_( allocator_t & alloc, fiber_object * p)
|
||||
{
|
||||
alloc.destroy( p);
|
||||
alloc.deallocate( p, 1);
|
||||
}
|
||||
|
||||
fiber_object( fiber_object &);
|
||||
fiber_object & operator=( fiber_object const&);
|
||||
|
||||
void enter_()
|
||||
{
|
||||
context::jump_fcontext(
|
||||
& this->caller_, this->callee_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() );
|
||||
if ( this->except_) rethrow_exception( this->except_);
|
||||
}
|
||||
|
||||
void unwind_stack_()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public:
|
||||
fiber_object( Fn fn, std::size_t size, bool preserve_fpu) :
|
||||
fiber_base( size, preserve_fpu),
|
||||
fn_( fn)
|
||||
{}
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
fiber_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
fiber_base(
|
||||
context::make_fcontext(
|
||||
stack_alloc.allocate( attr.size), attr.size,
|
||||
trampoline< fiber_object >),
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( forward< Fn >( fn) ),
|
||||
stack_( fiber_base::callee_->fc_stack),
|
||||
stack_alloc_( stack_alloc),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
#else
|
||||
fiber_object( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
fiber_base(
|
||||
context::make_fcontext(
|
||||
stack_alloc.allocate( attr.size), attr.size,
|
||||
trampoline< fiber_object >),
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn),
|
||||
stack_( fiber_base::callee_->fc_stack),
|
||||
stack_alloc_( stack_alloc),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
|
||||
fiber_object( BOOST_RV_REF( Fn) fn, std::size_t size, bool preserve_fpu) :
|
||||
fiber_base( size, preserve_fpu),
|
||||
fn_( boost::move( fn) )
|
||||
{}
|
||||
fiber_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
fiber_base(
|
||||
context::make_fcontext(
|
||||
stack_alloc.allocate( attr.size), attr.size,
|
||||
trampoline< fiber_object >),
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn),
|
||||
stack_( fiber_base::callee_->fc_stack),
|
||||
stack_alloc_( stack_alloc),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
#endif
|
||||
|
||||
void exec()
|
||||
{ fn_(); }
|
||||
void exec()
|
||||
{
|
||||
BOOST_ASSERT( ! is_complete() );
|
||||
|
||||
suspend();
|
||||
|
||||
try
|
||||
{ fn_(); }
|
||||
catch ( forced_unwind const&)
|
||||
{}
|
||||
catch (...)
|
||||
{ except_ = current_exception(); }
|
||||
|
||||
flags_ &= ~flag_resumed;
|
||||
flags_ |= flag_complete;
|
||||
|
||||
context::jump_fcontext( callee_, & caller_, 0, preserve_fpu() );
|
||||
BOOST_ASSERT_MSG( false, "fiber is complete");
|
||||
}
|
||||
|
||||
void deallocate_object()
|
||||
{ destroy_( alloc_, this); }
|
||||
|
||||
void terminate()
|
||||
{
|
||||
BOOST_ASSERT( ! is_resumed() );
|
||||
|
||||
if ( ! is_complete() )
|
||||
{
|
||||
flags_ |= flag_canceled;
|
||||
unwind_stack_();
|
||||
}
|
||||
|
||||
notify_();
|
||||
|
||||
BOOST_ASSERT( is_complete() );
|
||||
BOOST_ASSERT( ! is_resumed() );
|
||||
BOOST_ASSERT( joining_.empty() );
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Fn >
|
||||
class fiber_object< reference_wrapper< Fn > > : public fiber_base
|
||||
template< typename Fn, typename StackAllocator, typename Allocator >
|
||||
class fiber_object< reference_wrapper< Fn >, StackAllocator, Allocator > : public fiber_base
|
||||
{
|
||||
private:
|
||||
Fn fn_;
|
||||
public:
|
||||
typedef typename Allocator::template rebind<
|
||||
fiber_object<
|
||||
Fn, StackAllocator, Allocator
|
||||
>
|
||||
>::other allocator_t;
|
||||
|
||||
fiber_object( fiber_object &);
|
||||
fiber_object & operator=( fiber_object const&);
|
||||
private:
|
||||
Fn fn_;
|
||||
context::stack_t stack_;
|
||||
StackAllocator stack_alloc_;
|
||||
allocator_t alloc_;
|
||||
|
||||
static void destroy_( allocator_t & alloc, fiber_object * p)
|
||||
{
|
||||
alloc.destroy( p);
|
||||
alloc.deallocate( p, 1);
|
||||
}
|
||||
|
||||
fiber_object( fiber_object &);
|
||||
fiber_object & operator=( fiber_object const&);
|
||||
|
||||
void enter_()
|
||||
{
|
||||
context::jump_fcontext(
|
||||
& this->caller_, this->callee_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() );
|
||||
if ( this->except_) rethrow_exception( this->except_);
|
||||
}
|
||||
|
||||
public:
|
||||
fiber_object( reference_wrapper< Fn > fn, std::size_t size, bool preserve_fpu) :
|
||||
fiber_base( size, preserve_fpu),
|
||||
fn_( fn)
|
||||
{}
|
||||
fiber_object( reference_wrapper< Fn > fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
fiber_base(
|
||||
context::make_fcontext(
|
||||
stack_alloc.allocate( attr.size), attr.size,
|
||||
trampoline< fiber_object >),
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn),
|
||||
stack_( fiber_base::callee_->fc_stack),
|
||||
stack_alloc_( stack_alloc),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
|
||||
void exec()
|
||||
{ fn_(); }
|
||||
void exec()
|
||||
{
|
||||
BOOST_ASSERT( ! is_complete() );
|
||||
|
||||
suspend();
|
||||
|
||||
try
|
||||
{ fn_(); }
|
||||
catch ( forced_unwind const&)
|
||||
{}
|
||||
catch (...)
|
||||
{ except_ = current_exception(); }
|
||||
|
||||
flags_ &= ~flag_resumed;
|
||||
flags_ |= flag_complete;
|
||||
|
||||
context::jump_fcontext( callee_, & caller_, 0, preserve_fpu() );
|
||||
BOOST_ASSERT_MSG( false, "fiber is complete");
|
||||
}
|
||||
|
||||
void deallocate_object()
|
||||
{ destroy_( alloc_, this); }
|
||||
};
|
||||
|
||||
template< typename Fn >
|
||||
class fiber_object< const reference_wrapper< Fn > > : public fiber_base
|
||||
template< typename Fn, typename StackAllocator, typename Allocator >
|
||||
class fiber_object< const reference_wrapper< Fn >, StackAllocator, Allocator > : public fiber_base
|
||||
{
|
||||
private:
|
||||
Fn fn_;
|
||||
public:
|
||||
typedef typename Allocator::template rebind<
|
||||
fiber_object<
|
||||
Fn, StackAllocator, Allocator
|
||||
>
|
||||
>::other allocator_t;
|
||||
|
||||
fiber_object( fiber_object &);
|
||||
fiber_object & operator=( fiber_object const&);
|
||||
private:
|
||||
Fn fn_;
|
||||
context::stack_t stack_;
|
||||
StackAllocator stack_alloc_;
|
||||
allocator_t alloc_;
|
||||
|
||||
static void destroy_( allocator_t & alloc, fiber_object * p)
|
||||
{
|
||||
alloc.destroy( p);
|
||||
alloc.deallocate( p, 1);
|
||||
}
|
||||
|
||||
fiber_object( fiber_object &);
|
||||
fiber_object & operator=( fiber_object const&);
|
||||
|
||||
void enter_()
|
||||
{
|
||||
context::jump_fcontext(
|
||||
& this->caller_, this->callee_,
|
||||
reinterpret_cast< intptr_t >( this),
|
||||
this->preserve_fpu() );
|
||||
if ( this->except_) rethrow_exception( this->except_);
|
||||
}
|
||||
|
||||
public:
|
||||
fiber_object( const reference_wrapper< Fn > fn, std::size_t size, bool preserve_fpu) :
|
||||
fiber_base( size, preserve_fpu),
|
||||
fn_( fn)
|
||||
{}
|
||||
fiber_object( const reference_wrapper< Fn > fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
allocator_t const& alloc) :
|
||||
fiber_base(
|
||||
context::make_fcontext(
|
||||
stack_alloc.allocate( attr.size), attr.size,
|
||||
trampoline< fiber_object >),
|
||||
stack_unwind == attr.do_unwind,
|
||||
fpu_preserved == attr.preserve_fpu),
|
||||
fn_( fn),
|
||||
stack_( fiber_base::callee_->fc_stack),
|
||||
stack_alloc_( stack_alloc),
|
||||
alloc_( alloc)
|
||||
{ enter_(); }
|
||||
|
||||
void exec()
|
||||
{ fn_(); }
|
||||
void exec()
|
||||
{
|
||||
BOOST_ASSERT( ! is_complete() );
|
||||
|
||||
suspend();
|
||||
|
||||
try
|
||||
{ fn_(); }
|
||||
catch ( forced_unwind const&)
|
||||
{}
|
||||
catch (...)
|
||||
{ except_ = current_exception(); }
|
||||
|
||||
flags_ &= ~flag_resumed;
|
||||
flags_ |= flag_complete;
|
||||
|
||||
context::jump_fcontext( callee_, & caller_, 0, preserve_fpu() );
|
||||
BOOST_ASSERT_MSG( false, "fiber is complete");
|
||||
}
|
||||
|
||||
void deallocate_object()
|
||||
{ destroy_( alloc_, this); }
|
||||
};
|
||||
|
||||
}}}
|
||||
@@ -92,4 +322,4 @@ public:
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_STRATUM_OBJECT_H
|
||||
#endif // BOOST_FIBERS_DETAIL_FIBER_OBJECT_H
|
||||
|
||||
38
boost/fiber/detail/flags.hpp
Normal file
38
boost/fiber/detail/flags.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
// 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_FIBERS_DETAIL_FLAGS_H
|
||||
#define BOOST_FIBERS_DETAIL_FLAGS_H
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
enum flag_t
|
||||
{
|
||||
flag_forced_unwind = 1 << 1,
|
||||
flag_unwind_stack = 1 << 2,
|
||||
flag_preserve_fpu = 1 << 3,
|
||||
flag_complete = 1 << 4,
|
||||
flag_resumed = 1 << 5,
|
||||
flag_canceled = 1 << 6
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_FLAGS_H
|
||||
@@ -92,25 +92,7 @@ private:
|
||||
public:
|
||||
static scheduler & instance();
|
||||
|
||||
template< typename Fn >
|
||||
fiber spawn( Fn fn, std::size_t size, bool preserve_fpu)
|
||||
{
|
||||
fiber f( fn, size, preserve_fpu);
|
||||
active_fiber_.swap( f.impl_);
|
||||
resume_();
|
||||
active_fiber_.swap( f.impl_);
|
||||
return f;
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
fiber spawn( BOOST_RV_REF( Fn) fn, std::size_t size, bool preserve_fpu)
|
||||
{
|
||||
fiber f( boost::move( fn), size, preserve_fpu);
|
||||
active_fiber_.swap( f.impl_);
|
||||
resume_();
|
||||
active_fiber_.swap( f.impl_);
|
||||
return f;
|
||||
}
|
||||
void spawn( fiber_base::ptr_t const&);
|
||||
|
||||
void join( fiber_base::ptr_t const&);
|
||||
|
||||
|
||||
@@ -11,9 +11,13 @@
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/context/stack_utils.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/utility/enable_if.hpp>
|
||||
|
||||
#include <boost/fiber/attributes.hpp>
|
||||
#include <boost/fiber/detail/fiber_base.hpp>
|
||||
#include <boost/fiber/detail/fiber_object.hpp>
|
||||
|
||||
@@ -45,68 +49,130 @@ private:
|
||||
friend void migrate_to( BOOST_RV_REF( fiber) );
|
||||
friend class detail::scheduler;
|
||||
|
||||
struct dummy
|
||||
{ void nonnull() {} };
|
||||
|
||||
typedef detail::fiber_base base_t;
|
||||
typedef base_t::ptr_t ptr_t;
|
||||
typedef void ( dummy::*safe_bool)();
|
||||
|
||||
ptr_t impl_;
|
||||
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE( fiber);
|
||||
|
||||
fiber( ptr_t const& impl) :
|
||||
fiber( ptr_t const& impl) BOOST_NOEXCEPT :
|
||||
impl_( impl)
|
||||
{ BOOST_ASSERT( impl_); }
|
||||
|
||||
template< typename Fn >
|
||||
fiber( Fn fn, std::size_t size = ctx::default_stacksize(),
|
||||
bool preserve_fpu = true) :
|
||||
impl_(
|
||||
new detail::fiber_object< Fn >(
|
||||
fn, size, preserve_fpu) )
|
||||
{}
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
#ifdef BOOST_MSVC
|
||||
typedef void ( * fiber_fn)();
|
||||
|
||||
template< typename Fn >
|
||||
fiber( BOOST_RV_REF( Fn) fn, std::size_t size = ctx::default_stacksize(),
|
||||
bool preserve_fpu = true) :
|
||||
impl_(
|
||||
new detail::fiber_object< Fn >(
|
||||
boost::move( fn), size, preserve_fpu) )
|
||||
{}
|
||||
template< typename StackAllocator, typename Allocator >
|
||||
explicit fiber( fiber_fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
Allocacator const& alloc) :
|
||||
impl_()
|
||||
{
|
||||
typedef detail::fiber_object<
|
||||
fiber_fn, StackAllocator, Allocator
|
||||
> object_t;
|
||||
typename object_t::allocator_t a( alloc);
|
||||
impl_ = ptr_t(
|
||||
// placement new
|
||||
::new( a.allocate( 1) ) object_t( forward< fiber_fn >( fn), attr, stack_alloc, a) );
|
||||
}
|
||||
#endif
|
||||
template< typename Fn, typename StackAllocator, typename Allocator >
|
||||
explicit fiber( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
Allocacator const& alloc,
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, fiber >,
|
||||
dummy *
|
||||
>::type = 0) :
|
||||
impl_()
|
||||
{
|
||||
typedef detail::fiber_object<
|
||||
Fn, StackAllocator, Allocator
|
||||
> object_t;
|
||||
typename object_t::allocator_t a( alloc);
|
||||
impl_ = ptr_t(
|
||||
// placement new
|
||||
::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
|
||||
}
|
||||
#else
|
||||
template< typename Fn, typename StackAllocator, typename Allocator >
|
||||
explicit fiber( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
Allocator const& alloc,
|
||||
typename disable_if<
|
||||
is_convertible< Fn &, BOOST_RV_REF( Fn) >,
|
||||
dummy *
|
||||
>::type = 0) :
|
||||
impl_()
|
||||
{
|
||||
typedef detail::fiber_object<
|
||||
Fn, StackAllocator, Allocator
|
||||
> object_t;
|
||||
typename object_t::allocator_t a( alloc);
|
||||
impl_ = ptr_t(
|
||||
// placement new
|
||||
::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
|
||||
}
|
||||
|
||||
template< typename Fn, typename StackAllocator, typename Allocator >
|
||||
explicit fiber( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
Allocator const& alloc,
|
||||
typename disable_if<
|
||||
is_same< typename decay< Fn >::type, fiber >,
|
||||
dummy *
|
||||
>::type = 0) :
|
||||
impl_()
|
||||
{
|
||||
typedef detail::fiber_object<
|
||||
Fn, StackAllocator, Allocator
|
||||
> object_t;
|
||||
typename object_t::allocator_t a( alloc);
|
||||
impl_ = ptr_t(
|
||||
// placement new
|
||||
::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
typedef detail::fiber_base::id id;
|
||||
typedef void ( * unspecified_bool_type)( fiber ***);
|
||||
|
||||
static void unspecified_bool( fiber ***) {}
|
||||
|
||||
fiber() :
|
||||
fiber() BOOST_NOEXCEPT :
|
||||
impl_()
|
||||
{}
|
||||
|
||||
fiber( BOOST_RV_REF( fiber) other) :
|
||||
fiber( BOOST_RV_REF( fiber) other) BOOST_NOEXCEPT :
|
||||
impl_()
|
||||
{ impl_.swap( other.impl_); }
|
||||
{ swap( other); }
|
||||
|
||||
fiber & operator=( BOOST_RV_REF( fiber) other)
|
||||
fiber & operator=( BOOST_RV_REF( fiber) other) BOOST_NOEXCEPT
|
||||
{
|
||||
fiber tmp( other);
|
||||
fiber tmp( move( other) );
|
||||
swap( tmp);
|
||||
return * this;
|
||||
}
|
||||
|
||||
operator unspecified_bool_type() const;
|
||||
operator safe_bool() const BOOST_NOEXCEPT
|
||||
{ return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; }
|
||||
|
||||
bool operator!() const;
|
||||
bool operator!() const BOOST_NOEXCEPT
|
||||
{ return empty() || impl_->is_complete(); }
|
||||
|
||||
void swap( fiber & other);
|
||||
void swap( fiber & other) BOOST_NOEXCEPT
|
||||
{ impl_.swap( other.impl_); }
|
||||
|
||||
bool operator==( fiber const& other) const;
|
||||
bool operator!=( fiber const& other) const;
|
||||
bool empty() const BOOST_NOEXCEPT
|
||||
{ return ! impl_; }
|
||||
|
||||
id get_id() const;
|
||||
|
||||
bool is_joinable() const;
|
||||
|
||||
bool is_complete() const;
|
||||
id get_id() const BOOST_NOEXCEPT
|
||||
{ return impl_ ? impl_->get_id() : id(); }
|
||||
|
||||
void cancel();
|
||||
|
||||
|
||||
27
boost/fiber/flags.hpp
Normal file
27
boost/fiber/flags.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
// 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_FIBERS_FLAGS_H
|
||||
#define BOOST_FIBERS_FLAGS_H
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
enum flag_unwind_t
|
||||
{
|
||||
stack_unwind = 0,
|
||||
no_stack_unwind
|
||||
};
|
||||
|
||||
enum flag_fpu_t
|
||||
{
|
||||
fpu_preserved = 0,
|
||||
fpu_not_preserved
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif // BOOST_FIBERS_FLAGS_H
|
||||
@@ -6,10 +6,11 @@
|
||||
#ifndef BOOST_THIS_STRATUM_OPERATIONS_H
|
||||
#define BOOST_THIS_STRATUM_OPERATIONS_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/context/stack_utils.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/punctuation/comma_if.hpp>
|
||||
@@ -66,15 +67,70 @@ void yield_break()
|
||||
|
||||
namespace fibers {
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
#ifdef BOOST_MSVC
|
||||
#endif
|
||||
#else
|
||||
template< typename Fn >
|
||||
fiber spawn( Fn fn, std::size_t size = ctx::default_stacksize(),
|
||||
bool preserve_fpu = true)
|
||||
{ return detail::scheduler::instance().spawn( fn, size, preserve_fpu); }
|
||||
fiber spawn( Fn fn, attributes const& attr = attributes(),
|
||||
stack_allocator const& stack_alloc = stack_allocator(),
|
||||
std::allocator< fiber > const& alloc = std::allocator< fiber >() )
|
||||
{
|
||||
fiber f( fn, attr, stack_alloc, alloc);
|
||||
detail::scheduler::instance().spawn( f.impl_);
|
||||
return f;
|
||||
}
|
||||
|
||||
template< typename Fn, typename StackAllocator >
|
||||
fiber spawn( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
std::allocator< fiber > const& alloc = std::allocator< fiber >() )
|
||||
{
|
||||
fiber f( fn, attr, stack_alloc, alloc);
|
||||
detail::scheduler::instance().spawn( f.impl_);
|
||||
return f;
|
||||
}
|
||||
|
||||
template< typename Fn, typename StackAllocator, typename Allocator >
|
||||
fiber spawn( Fn fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
Allocator const& alloc)
|
||||
{
|
||||
fiber f( fn, attr, stack_alloc, alloc);
|
||||
detail::scheduler::instance().spawn( f.impl_);
|
||||
return f;
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
fiber spawn( BOOST_RV_REF( Fn) fn, std::size_t size = ctx::default_stacksize(),
|
||||
bool preserve_fpu = true)
|
||||
{ return detail::scheduler::instance().spawn( boost::move( fn), size, preserve_fpu); }
|
||||
fiber spawn( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
|
||||
stack_allocator const& stack_alloc = stack_allocator(),
|
||||
std::allocator< fiber > const& alloc = std::allocator< fiber >() )
|
||||
{
|
||||
fiber f( fn, attr, stack_alloc, alloc);
|
||||
detail::scheduler::instance().spawn( f.impl_);
|
||||
return f;
|
||||
}
|
||||
|
||||
template< typename Fn, typename StackAllocator >
|
||||
fiber spawn( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
std::allocator< fiber > const& alloc = std::allocator< fiber >() )
|
||||
{
|
||||
fiber f( fn, attr, stack_alloc, alloc);
|
||||
detail::scheduler::instance().spawn( f.impl_);
|
||||
return f;
|
||||
}
|
||||
|
||||
template< typename Fn, typename StackAllocator, typename Allocator >
|
||||
fiber spawn( BOOST_RV_REF( Fn) fn, attributes const& attr,
|
||||
StackAllocator const& stack_alloc,
|
||||
Allocator const& alloc)
|
||||
{
|
||||
fiber f( fn, attr, stack_alloc, alloc);
|
||||
detail::scheduler::instance().spawn( f.impl_);
|
||||
return f;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline
|
||||
bool run()
|
||||
@@ -87,17 +143,17 @@ bool run()
|
||||
BOOST_PP_ENUM(n,BOOST_FIBERS_WAITFOR_STRATUM_FN_ARG,~)
|
||||
|
||||
#define BOOST_FIBERS_WAITFOR_STRATUM_AND(z,n,t) \
|
||||
BOOST_PP_EXPR_IF(n,&&) BOOST_PP_CAT(s,n).is_complete()
|
||||
BOOST_PP_EXPR_IF(n,&&) BOOST_PP_CAT(s,n)
|
||||
|
||||
#define BOOST_FIBERS_WAITFOR_STRATUM_OR(z,n,t) \
|
||||
BOOST_PP_EXPR_IF(n,||) BOOST_PP_CAT(s,n).is_complete()
|
||||
BOOST_PP_EXPR_IF(n,||) BOOST_PP_CAT(s,n)
|
||||
|
||||
#define BOOST_FIBERS_WAITFOR_STRATUM_CANCEL(z,n,t) \
|
||||
if ( ! BOOST_PP_CAT(s,n).is_complete() ) \
|
||||
if ( ! BOOST_PP_CAT(s,n) ) \
|
||||
BOOST_PP_CAT(s,n).cancel();
|
||||
|
||||
#define BOOST_FIBERS_WAITFOR_STRATUM_READY(z,n,t) \
|
||||
if ( BOOST_PP_CAT(s,n).is_complete() ) return n;
|
||||
if ( BOOST_PP_CAT(s,n) ) return n;
|
||||
|
||||
#define BOOST_FIBERS_WAITFOR_STRATUM_ALL(z,n,unused) \
|
||||
inline \
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace coroutines {
|
||||
namespace fibers {
|
||||
using detail::stack_allocator;
|
||||
}}
|
||||
|
||||
|
||||
@@ -29,11 +29,11 @@ exe asio/host
|
||||
: asio/host.cpp
|
||||
;
|
||||
|
||||
exe barrier : barrier.cpp ;
|
||||
exe future : future.cpp ;
|
||||
exe join : join.cpp ;
|
||||
exe ping_pong : ping_pong.cpp ;
|
||||
#exe barrier : barrier.cpp ;
|
||||
#exe future : future.cpp ;
|
||||
#exe join : join.cpp ;
|
||||
#exe ping_pong : ping_pong.cpp ;
|
||||
exe simple : simple.cpp ;
|
||||
exe wait_all : wait_all.cpp ;
|
||||
exe wait_any : wait_any.cpp ;
|
||||
exe wait_any_cancel : wait_any_cancel.cpp ;
|
||||
#exe wait_all : wait_all.cpp ;
|
||||
#exe wait_any : wait_any.cpp ;
|
||||
#exe wait_any_cancel : wait_any_cancel.cpp ;
|
||||
|
||||
@@ -26,7 +26,7 @@ int main()
|
||||
stm::fiber s1( stm::spawn( boost::bind( fn, "abc", 5) ) );
|
||||
stm::fiber s2( stm::spawn( boost::bind( fn, "xyz", 7) ) );
|
||||
|
||||
while ( ! s1.is_complete() || ! s2.is_complete() )
|
||||
while ( s1 || s2 )
|
||||
stm::run();
|
||||
|
||||
std::cout << "done." << std::endl;
|
||||
|
||||
@@ -20,37 +20,6 @@ namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
void
|
||||
fiber_base::unwind_stack_()
|
||||
{
|
||||
BOOST_ASSERT( ! is_complete() );
|
||||
BOOST_ASSERT( ! is_resumed() );
|
||||
|
||||
flags_ |= flag_resumed;
|
||||
flags_ |= flag_unwind_stack;
|
||||
ctx::jump_fcontext( & caller_, & callee_, 0, preserve_fpu_);
|
||||
BOOST_ASSERT( is_complete() );
|
||||
BOOST_ASSERT( ! is_resumed() );
|
||||
}
|
||||
|
||||
void
|
||||
fiber_base::terminate_()
|
||||
{
|
||||
BOOST_ASSERT( ! is_resumed() );
|
||||
|
||||
if ( ! is_complete() )
|
||||
{
|
||||
flags_ |= flag_canceled;
|
||||
unwind_stack_();
|
||||
}
|
||||
|
||||
notify_();
|
||||
|
||||
BOOST_ASSERT( is_complete() );
|
||||
BOOST_ASSERT( ! is_resumed() );
|
||||
BOOST_ASSERT( joining_.empty() );
|
||||
}
|
||||
|
||||
void
|
||||
fiber_base::notify_()
|
||||
{
|
||||
@@ -62,43 +31,18 @@ fiber_base::notify_()
|
||||
joining_.clear();
|
||||
}
|
||||
|
||||
fiber_base::fiber_base( std::size_t size, bool preserve_fpu) :
|
||||
fiber_base::fiber_base( context::fcontext_t * callee, bool unwind, bool preserve_fpu) :
|
||||
use_count_( 0),
|
||||
alloc_(),
|
||||
caller_(),
|
||||
callee_(),
|
||||
callee_( callee),
|
||||
flags_( 0),
|
||||
preserve_fpu_( preserve_fpu),
|
||||
except_(),
|
||||
joining_()
|
||||
{
|
||||
callee_.fc_stack.base = alloc_.allocate( size);
|
||||
callee_.fc_stack.size = size;
|
||||
|
||||
ctx::make_fcontext( & callee_, trampoline< fiber_base >);
|
||||
if ( unwind) flags_ |= flag_forced_unwind;
|
||||
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
|
||||
}
|
||||
|
||||
fiber_base::~fiber_base()
|
||||
{
|
||||
terminate_();
|
||||
alloc_.deallocate( callee_.fc_stack.base, callee_.fc_stack.size);
|
||||
}
|
||||
|
||||
fiber_base::id
|
||||
fiber_base::get_id() const
|
||||
{ return id( ptr_t( const_cast< fiber_base * >( this) ) ); }
|
||||
|
||||
bool
|
||||
fiber_base::is_canceled() const
|
||||
{ return 0 != ( flags_ & flag_canceled); }
|
||||
|
||||
bool
|
||||
fiber_base::is_complete() const
|
||||
{ return 0 != ( flags_ & flag_complete); }
|
||||
|
||||
bool
|
||||
fiber_base::is_resumed() const
|
||||
{ return 0 != ( flags_ & flag_resumed); }
|
||||
|
||||
void
|
||||
fiber_base::join( ptr_t const& p)
|
||||
{
|
||||
@@ -116,7 +60,7 @@ fiber_base::resume()
|
||||
BOOST_ASSERT( ! is_resumed() );
|
||||
|
||||
flags_ |= flag_resumed;
|
||||
ctx::jump_fcontext( & caller_, & callee_, ( intptr_t) this, preserve_fpu_);
|
||||
context::jump_fcontext( & caller_, callee_, ( intptr_t) this, preserve_fpu() );
|
||||
|
||||
if ( is_complete() ) notify_();
|
||||
|
||||
@@ -130,7 +74,7 @@ fiber_base::suspend()
|
||||
BOOST_ASSERT( is_resumed() );
|
||||
|
||||
flags_ &= ~flag_resumed;
|
||||
ctx::jump_fcontext( & callee_, & caller_, 0, preserve_fpu_);
|
||||
context::jump_fcontext( callee_, & caller_, 0, preserve_fpu() );
|
||||
|
||||
BOOST_ASSERT( is_resumed() );
|
||||
|
||||
|
||||
@@ -58,6 +58,19 @@ scheduler::instance()
|
||||
return * static_local.get();
|
||||
}
|
||||
|
||||
void
|
||||
scheduler::spawn( fiber_base::ptr_t const& f)
|
||||
{
|
||||
BOOST_ASSERT( f);
|
||||
BOOST_ASSERT( ! f->is_complete() );
|
||||
BOOST_ASSERT( f != active_fiber_);
|
||||
|
||||
fiber_base::ptr_t tmp = active_fiber_;
|
||||
active_fiber_ = f;
|
||||
resume_();
|
||||
active_fiber_ = tmp;
|
||||
}
|
||||
|
||||
void
|
||||
scheduler::join( fiber_base::ptr_t const& f)
|
||||
{
|
||||
@@ -98,7 +111,7 @@ scheduler::cancel( fiber_base::ptr_t const& f)
|
||||
// terminate fiber means unwinding its stack
|
||||
// so it becomes complete and joining strati
|
||||
// will be notified
|
||||
active_fiber_->terminate_();
|
||||
active_fiber_->terminate();
|
||||
active_fiber_ = tmp;
|
||||
// erase completed fiber from waiting-queue
|
||||
f_idx_.erase( f);
|
||||
|
||||
@@ -20,40 +20,6 @@
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
fiber::operator unspecified_bool_type() const
|
||||
{ return impl_ ? unspecified_bool : 0; }
|
||||
|
||||
bool
|
||||
fiber::operator!() const
|
||||
{ return ! impl_; }
|
||||
|
||||
bool
|
||||
fiber::operator==( fiber const& other) const
|
||||
{ return get_id() == other.get_id(); }
|
||||
|
||||
bool
|
||||
fiber::operator!=( fiber const& other) const
|
||||
{ return ! ( get_id() == other.get_id() ); }
|
||||
|
||||
void
|
||||
fiber::swap( fiber & other)
|
||||
{ impl_.swap( other.impl_); }
|
||||
|
||||
fiber::id
|
||||
fiber::get_id() const
|
||||
{ return impl_ ? impl_->get_id() : id(); }
|
||||
|
||||
bool
|
||||
fiber::is_joinable() const
|
||||
{ return impl_ && ! impl_->is_complete(); }
|
||||
|
||||
bool
|
||||
fiber::is_complete() const
|
||||
{
|
||||
BOOST_ASSERT( impl_);
|
||||
return impl_->is_complete();
|
||||
}
|
||||
|
||||
void
|
||||
fiber::cancel()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user