From 402a4353f77a58d78a0bcff8d17c7d8b46c39089 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 10 Nov 2014 21:19:28 -0500 Subject: [PATCH] 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*). --- .../migration/workstealing_round_robin.cpp | 12 ++++++------ .../migration/workstealing_round_robin.hpp | 8 ++++---- include/boost/fiber/algorithm.hpp | 16 ++++++++++------ include/boost/fiber/detail/fiber_base.hpp | 6 +++++- include/boost/fiber/detail/fifo.hpp | 18 +++++++++--------- include/boost/fiber/detail/waiting_queue.hpp | 18 +++++++++--------- include/boost/fiber/detail/worker_fiber.hpp | 10 ---------- include/boost/fiber/fiber.hpp | 6 ++++-- include/boost/fiber/round_robin.hpp | 6 +++--- src/detail/worker_fiber.cpp | 1 - src/fiber_manager.cpp | 6 +++--- src/round_robin.cpp | 10 +++++----- 12 files changed, 58 insertions(+), 59 deletions(-) diff --git a/examples/cpp03/migration/workstealing_round_robin.cpp b/examples/cpp03/migration/workstealing_round_robin.cpp index 7617cc11..0ad78ee4 100644 --- a/examples/cpp03/migration/workstealing_round_robin.cpp +++ b/examples/cpp03/migration/workstealing_round_robin.cpp @@ -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(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(); diff --git a/examples/cpp03/migration/workstealing_round_robin.hpp b/examples/cpp03/migration/workstealing_round_robin.hpp index c21fa7d0..7c70fd71 100644 --- a/examples/cpp03/migration/workstealing_round_robin.hpp +++ b/examples/cpp03/migration/workstealing_round_robin.hpp @@ -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(); }; diff --git a/include/boost/fiber/algorithm.hpp b/include/boost/fiber/algorithm.hpp index 2e5f5bda..007b6cd1 100644 --- a/include/boost/fiber/algorithm.hpp +++ b/include/boost/fiber/algorithm.hpp @@ -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 super; // Start every subclass awakened() override with: - // sched_algorithm_with_properties::awakened(f); - virtual void awakened( detail::worker_fiber *f) + // sched_algorithm_with_properties::awakened(fb); + virtual void awakened( fiber_base *fb) { + detail::worker_fiber* f = static_cast(fb); if (! f->get_properties()) { // TODO: would be great if PROPS could be allocated on the new diff --git a/include/boost/fiber/detail/fiber_base.hpp b/include/boost/fiber/detail/fiber_base.hpp index f6ad3b79..d4ff6457 100644 --- a/include/boost/fiber/detail/fiber_base.hpp +++ b/include/boost/fiber/detail/fiber_base.hpp @@ -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_; }; }}} diff --git a/include/boost/fiber/detail/fifo.hpp b/include/boost/fiber/detail/fifo.hpp index adf5aceb..6bc0fb4c 100644 --- a/include/boost/fiber/detail/fifo.hpp +++ b/include/boost/fiber/detail/fifo.hpp @@ -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_; }; }}} diff --git a/include/boost/fiber/detail/waiting_queue.hpp b/include/boost/fiber/detail/waiting_queue.hpp index e53f9632..f9125a89 100644 --- a/include/boost/fiber/detail/waiting_queue.hpp +++ b/include/boost/fiber/detail/waiting_queue.hpp @@ -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(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(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); } diff --git a/include/boost/fiber/detail/worker_fiber.hpp b/include/boost/fiber/detail/worker_fiber.hpp index a562e2c9..fc844fae 100644 --- a/include/boost/fiber/detail/worker_fiber.hpp +++ b/include/boost/fiber/detail/worker_fiber.hpp @@ -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_; } diff --git a/include/boost/fiber/fiber.hpp b/include/boost/fiber/fiber.hpp index b1b74ef2..b1b3885d 100644 --- a/include/boost/fiber/fiber.hpp +++ b/include/boost/fiber/fiber.hpp @@ -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(impl)) {} #ifdef BOOST_MSVC diff --git a/include/boost/fiber/round_robin.hpp b/include/boost/fiber/round_robin.hpp index 09f7d5ef..01ce10fe 100644 --- a/include/boost/fiber/round_robin.hpp +++ b/include/boost/fiber/round_robin.hpp @@ -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; }; }} diff --git a/src/detail/worker_fiber.cpp b/src/detail/worker_fiber.cpp index 39cb2844..a98a0c2e 100644 --- a/src/detail/worker_fiber.cpp +++ b/src/detail/worker_fiber.cpp @@ -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_(), diff --git a/src/fiber_manager.cpp b/src/fiber_manager.cpp index ed5cfeed..be22b478 100644 --- a/src/fiber_manager.cpp +++ b/src/fiber_manager.cpp @@ -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(f)); } else { diff --git a/src/round_robin.cpp b/src/round_robin.cpp index bf398da5..c81d361e 100644 --- a/src/round_robin.cpp +++ b/src/round_robin.cpp @@ -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(f)->priority( prio); } }}