2
0
mirror of https://github.com/boostorg/fiber.git synced 2026-02-22 03:12:28 +00:00

Define sched_algorithm methods on fiber_base*, not worker_fiber*.

Some reviewers disliked that to build a custom sched_algorithm subclass, you
must necessarily manipulate pointers to classes in the boost::fibers::detail
namespace. Redefine all such methods to use fiber_base* rather than
detail::worker_fiber*.

Hoist fiber_base* into boost::fibers namespace. We considered an opaque
typedef rather than fiber_base*, but in fact a sched_algorithm subclass may
need is_ready().

Moreover, a sched_algorithm subclass may well want to use an intrusive linked
list to queue fibers. Hoist worker_fiber::nxt_ pointer into fiber_base, and
remove worker_fiber::next() and next_reset() methods. This allows recasting
detail::fifo in terms of fiber_base*, therefore round_robin can be stated
almost entirely in terms of fiber_base* rather than worker_fiber*.

Recast fiber constructor taking worker_fiber* to take fiber_base* instead.
This constructor is used solely for fiber migration; with relevant functions
now returning fiber_base*, we think we no longer need fiber(worker_fiber*).
This commit is contained in:
Nat Goodspeed
2014-11-10 21:19:28 -05:00
parent ed64ee77f8
commit 402a4353f7
12 changed files with 58 additions and 59 deletions

View File

@@ -13,17 +13,17 @@
#endif
void
workstealing_round_robin::awakened( boost::fibers::detail::worker_fiber * f)
workstealing_round_robin::awakened( boost::fibers::fiber_base * f)
{
boost::mutex::scoped_lock lk( mtx_);
rqueue_.push_back( f);
}
boost::fibers::detail::worker_fiber *
boost::fibers::fiber_base *
workstealing_round_robin::pick_next()
{
boost::mutex::scoped_lock lk( mtx_);
boost::fibers::detail::worker_fiber * f = 0;
boost::fibers::fiber_base * f = 0;
if ( ! rqueue_.empty() )
{
f = rqueue_.front();
@@ -33,20 +33,20 @@ workstealing_round_robin::pick_next()
}
void
workstealing_round_robin::priority( boost::fibers::detail::worker_fiber * f, int prio) BOOST_NOEXCEPT
workstealing_round_robin::priority( boost::fibers::fiber_base * f, int prio) BOOST_NOEXCEPT
{
BOOST_ASSERT( f);
// set only priority to fiber
// round-robin does not respect priorities
f->priority( prio);
static_cast<boost::fibers::detail::worker_fiber*>(f)->priority( prio);
}
boost::fibers::fiber
workstealing_round_robin::steal() BOOST_NOEXCEPT
{
boost::mutex::scoped_lock lk( mtx_);
boost::fibers::detail::worker_fiber * f = 0;
boost::fibers::fiber_base * f = 0;
if ( ! rqueue_.empty() )
{
f = rqueue_.back();

View File

@@ -29,17 +29,17 @@
class workstealing_round_robin : public boost::fibers::sched_algorithm
{
private:
typedef std::deque< boost::fibers::detail::worker_fiber * > rqueue_t;
typedef std::deque< boost::fibers::fiber_base * > rqueue_t;
boost::mutex mtx_;
rqueue_t rqueue_;
public:
virtual void awakened( boost::fibers::detail::worker_fiber *);
virtual void awakened( boost::fibers::fiber_base *);
virtual boost::fibers::detail::worker_fiber * pick_next();
virtual boost::fibers::fiber_base * pick_next();
virtual void priority( boost::fibers::detail::worker_fiber *, int) BOOST_NOEXCEPT;
virtual void priority( boost::fibers::fiber_base *, int) BOOST_NOEXCEPT;
boost::fibers::fiber steal();
};

View File

@@ -25,17 +25,20 @@
namespace boost {
namespace fibers {
// hoist fiber_base out of detail namespace into boost::fibers
typedef detail::fiber_base fiber_base;
struct sched_algorithm
{
virtual ~sched_algorithm() {}
virtual void awakened( detail::worker_fiber *) = 0;
virtual void awakened( fiber_base *) = 0;
virtual detail::worker_fiber * pick_next() = 0;
virtual fiber_base * pick_next() = 0;
virtual void priority( detail::worker_fiber *, int) BOOST_NOEXCEPT = 0;
virtual void priority( fiber_base *, int) BOOST_NOEXCEPT = 0;
virtual void property_change( detail::worker_fiber *, fiber_properties* ) {}
virtual void property_change( fiber_base *, fiber_properties* ) {}
};
namespace detail {
@@ -51,9 +54,10 @@ public:
typedef sched_algorithm_with_properties<PROPS> super;
// Start every subclass awakened() override with:
// sched_algorithm_with_properties<PROPS>::awakened(f);
virtual void awakened( detail::worker_fiber *f)
// sched_algorithm_with_properties<PROPS>::awakened(fb);
virtual void awakened( fiber_base *fb)
{
detail::worker_fiber* f = static_cast<detail::worker_fiber*>(fb);
if (! f->get_properties())
{
// TODO: would be great if PROPS could be allocated on the new

View File

@@ -86,7 +86,8 @@ public:
{ return 0 == impl_; }
};
fiber_base()
fiber_base():
nxt_(0)
{}
virtual ~fiber_base() {};
@@ -96,6 +97,9 @@ public:
virtual void set_ready() BOOST_NOEXCEPT = 0;
virtual id get_id() const BOOST_NOEXCEPT = 0;
// for use by sched_algorithm to queue any subclass instance
fiber_base * nxt_;
};
}}}

View File

@@ -36,28 +36,28 @@ public:
bool empty() const BOOST_NOEXCEPT
{ return 0 == head_; }
void push( worker_fiber * item) BOOST_NOEXCEPT
void push( fiber_base * item) BOOST_NOEXCEPT
{
BOOST_ASSERT( 0 != item);
BOOST_ASSERT( 0 == item->next() );
BOOST_ASSERT( 0 == item->nxt_ );
if ( empty() )
head_ = tail_ = item;
else
{
tail_->next( item);
tail_->nxt_ = item;
tail_ = item;
}
}
worker_fiber * pop() BOOST_NOEXCEPT
fiber_base * pop() BOOST_NOEXCEPT
{
BOOST_ASSERT( ! empty() );
worker_fiber * item = head_;
head_ = head_->next();
fiber_base * item = head_;
head_ = head_->nxt_;
if ( 0 == head_) tail_ = 0;
item->next_reset();
item->nxt_ = 0;
return item;
}
@@ -68,8 +68,8 @@ public:
}
private:
worker_fiber * head_;
worker_fiber * tail_;
fiber_base * head_;
fiber_base * tail_;
};
}}}

View File

@@ -40,7 +40,7 @@ public:
void push( worker_fiber * item) BOOST_NOEXCEPT
{
BOOST_ASSERT( 0 != item);
BOOST_ASSERT( 0 == item->next() );
BOOST_ASSERT( 0 == item->nxt_ );
if ( empty() )
head_ = tail_ = item;
@@ -49,22 +49,22 @@ public:
worker_fiber * f = head_, * prev = 0;
do
{
worker_fiber * nxt = f->next();
worker_fiber * nxt = static_cast<worker_fiber*>(f->nxt_);
if ( item->time_point() <= f->time_point() )
{
if ( head_ == f)
{
BOOST_ASSERT( 0 == prev);
item->next( f);
item->nxt_ = f;
head_ = item;
}
else
{
BOOST_ASSERT( 0 != prev);
item->next( f);
prev->next( item);
item->nxt_ = f;
prev->nxt_ = item;
}
break;
}
@@ -72,7 +72,7 @@ public:
{
BOOST_ASSERT( 0 == nxt);
tail_->next( item);
tail_->nxt_ = item;
tail_ = item;
break;
}
@@ -100,7 +100,7 @@ public:
chrono::high_resolution_clock::time_point now( chrono::high_resolution_clock::now() );
while ( 0 != f)
{
worker_fiber * nxt = f->next();
worker_fiber * nxt = static_cast<worker_fiber*>(f->nxt_);
if ( fn( f, now) )
{
if ( f == head_)
@@ -118,9 +118,9 @@ public:
if ( 0 == nxt)
tail_ = prev;
prev->next( nxt);
prev->nxt_ = nxt;
}
f->next_reset();
f->nxt_ = 0;
f->time_point_reset();
sched_algo->awakened( f);
}

View File

@@ -92,7 +92,6 @@ private:
atomic< std::size_t > use_count_;
fss_data_t fss_data_;
worker_fiber * nxt_;
chrono::high_resolution_clock::time_point tp_;
coro_t::yield_type * callee_;
coro_t::call_type caller_;
@@ -218,15 +217,6 @@ public:
BOOST_ASSERT( is_running() ); // set by the scheduler-algorithm
}
worker_fiber * next() const BOOST_NOEXCEPT
{ return nxt_; }
void next( worker_fiber * nxt) BOOST_NOEXCEPT
{ nxt_ = nxt; }
void next_reset() BOOST_NOEXCEPT
{ nxt_ = 0; }
chrono::high_resolution_clock::time_point const& time_point() const BOOST_NOEXCEPT
{ return tp_; }

View File

@@ -108,8 +108,10 @@ public:
impl_()
{}
explicit fiber( detail::worker_fiber * impl) BOOST_NOEXCEPT :
impl_( impl)
// This fiber_base* is allowed to be 0 -- call joinable() before performing
// operations on such a fiber object!
explicit fiber( fiber_base * impl) BOOST_NOEXCEPT :
impl_( dynamic_cast<detail::worker_fiber*>(impl))
{}
#ifdef BOOST_MSVC

View File

@@ -33,11 +33,11 @@ private:
rqueue_t rqueue_;
public:
virtual void awakened( detail::worker_fiber *);
virtual void awakened( fiber_base *);
virtual detail::worker_fiber * pick_next();
virtual fiber_base * pick_next();
virtual void priority( detail::worker_fiber *, int) BOOST_NOEXCEPT;
virtual void priority( fiber_base *, int) BOOST_NOEXCEPT;
};
}}

View File

@@ -30,7 +30,6 @@ worker_fiber::worker_fiber( coro_t::yield_type * callee) :
fiber_base(),
use_count_( 1), // allocated on stack
fss_data_(),
nxt_( 0),
tp_( (chrono::high_resolution_clock::time_point::max)() ),
callee_( callee),
caller_(),

View File

@@ -172,17 +172,17 @@ void fm_run()
BOOST_ASSERT( 0 != fm);
// move all fibers witch are ready (state_ready)
// move all fibers which are ready (state_ready)
// from waiting-queue to the runnable-queue
fm->wqueue_.move_to( fm->sched_algo_, fetch_ready);
// pop new fiber from ready-queue which is not complete
// (example: fiber in ready-queue could be canceled by active-fiber)
detail::worker_fiber * f( fm->sched_algo_->pick_next() );
fiber_base * f( fm->sched_algo_->pick_next());
if ( f)
{
BOOST_ASSERT_MSG( f->is_ready(), "fiber with invalid state in ready-queue");
fm_resume_( f);
fm_resume_( static_cast<detail::worker_fiber*>(f));
}
else
{

View File

@@ -16,30 +16,30 @@ namespace boost {
namespace fibers {
void
round_robin::awakened( detail::worker_fiber * f)
round_robin::awakened( fiber_base * f)
{
BOOST_ASSERT( 0 != f);
rqueue_.push( f);
}
detail::worker_fiber *
fiber_base *
round_robin::pick_next()
{
detail::worker_fiber * victim = 0;
fiber_base * victim = 0;
if ( ! rqueue_.empty() )
victim = rqueue_.pop();
return victim;
}
void
round_robin::priority( detail::worker_fiber * f, int prio) BOOST_NOEXCEPT
round_robin::priority( fiber_base * f, int prio) BOOST_NOEXCEPT
{
BOOST_ASSERT( f);
// set only priority to fiber
// round-robin does not respect priorities
f->priority( prio);
static_cast<detail::worker_fiber*>(f)->priority( prio);
}
}}