2
0
mirror of https://github.com/boostorg/fiber.git synced 2026-02-16 13:22:17 +00:00

Merge pull request #26 from nat-goodspeed/sched-props-dev

Support arbitrary properties for a user-supplied sched_algorithm implementation.
This commit is contained in:
Oliver Kowalke
2015-05-14 11:56:04 +02:00
17 changed files with 637 additions and 78 deletions

View File

@@ -25,7 +25,8 @@ project boost/fiber
;
lib boost_fiber
: barrier.cpp
: algorithm.cpp
barrier.cpp
condition.cpp
detail/fifo.cpp
detail/spinlock.cpp
@@ -36,6 +37,7 @@ lib boost_fiber
future.cpp
interruption.cpp
mutex.cpp
properties.cpp
recursive_mutex.cpp
recursive_timed_mutex.cpp
round_robin.cpp

View File

@@ -61,6 +61,65 @@ fiber which is to be resumed next.]]
]
To prevent the library from heap-allocating a default scheduler for a given
thread, that thread must call [function_link set_scheduling_algorithm] before
any other __boost_fiber__ entry point.
void thread_fn()
{
my_fiber_scheduler mfs;
boost::fibers::set_scheduling_algorithm( & mfs);
...
}
A fiber-scheduler must implement interface __algo__. __boost_fiber__ provides one
scheduler: [class_link round_robin].
You are explicitly permitted to code your own __algo__ subclass, and to pass
it to [function_link set_scheduling_algorithm].
[class_heading sched_algorithm]
#include <boost/fiber/algorithm.hpp>
struct sched_algorithm
{
virtual ~sched_algorithm() {}
virtual void awakened( detail::worker_fiber *) = 0;
virtual detail::worker_fiber * pick_next() = 0;
virtual void priority( detail::worker_fiber *, int) noexcept = 0;
};
[member_heading sched_algorithm..awakened]
virtual void awakened( detail::worker_fiber * f) = 0;
[variablelist
[[Effects:] [Marks fiber `f`, to be ready to run.]]
]
[member_heading sched_algorithm..pick_next]
virtual detail::worker_fiber * pick_next() = 0;
[variablelist
[[Effects:] [Depending on the scheduling algorithm, this function returns the
fiber which is to be resumed next.]]
]
[member_heading sched_algorithm..priority]
virtual void priority( detail::worker_fiber *, int) noexcept = 0;
[variablelist
[[Effects:] [Resets the priority of fiber `f`.]]
]
[class_heading round_robin]
This class implements __algo__ and schedules fibers in round-robin fashion

View File

@@ -31,6 +31,7 @@ exe futures_mt : futures_mt.cpp ;
exe interrupt : interrupt.cpp ;
exe join : join.cpp ;
exe ping_pong : ping_pong.cpp ;
exe priority : priority.cpp ;
exe segmented_stack : segmented_stack.cpp ;
exe simple : simple.cpp ;

292
examples/priority.cpp Normal file
View File

@@ -0,0 +1,292 @@
// Copyright Nat Goodspeed 2014.
// 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)
#include <boost/fiber/all.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <iostream>
class priority_props: public boost::fibers::fiber_properties
{
public:
priority_props(boost::fibers::fiber_properties::back_ptr p):
fiber_properties(p),
priority_(0)
{}
int get_priority() const { return priority_; }
// Call this method to alter priority, because we must notify
// priority_scheduler of any change.
void set_priority(int p)
{
// Of course, it's only worth reshuffling the queue and all if we're
// actually changing the priority.
if (p != priority_)
{
priority_ = p;
notify();
}
}
// The fiber name of course is solely for purposes of this example
// program; it has nothing to do with implementing scheduler priority.
// This is a public data member -- not requiring set/get access methods --
// because we need not inform the scheduler of any change.
std::string name;
private:
int priority_;
};
class priority_scheduler:
public boost::fibers::sched_algorithm_with_properties<priority_props>
{
private:
// Much as we would like, we don't use std::priority_queue because it
// doesn't appear to provide any way to alter the priority (and hence
// queue position) of a particular item.
boost::fibers::fiber_context* head_;
public:
priority_scheduler():
head_(nullptr)
{}
// For a subclass of sched_algorithm_with_properties<>, it's important to
// override awakened_props(), NOT awakened().
virtual void awakened_props(boost::fibers::fiber_context* f)
{
int f_priority = properties(f).get_priority();
// With this scheduler, fibers with higher priority values are
// preferred over fibers with lower priority values. But fibers with
// equal priority values are processed in round-robin fashion. So when
// we're handed a new fiber_base, put it at the end of the fibers with
// that same priority. In other words: search for the first fiber in
// the queue with LOWER priority, and insert before that one.
boost::fibers::fiber_context** fp = &head_;
for ( ; *fp; fp = &(*fp)->nxt)
if (properties(*fp).get_priority() < f_priority)
break;
// It doesn't matter whether we hit the end of the list or found
// another fiber with lower priority. Either way, insert f here.
f->nxt = *fp;
*fp = f;
std::cout << "awakened(" << properties(f).name << "): ";
describe_ready_queue();
}
virtual boost::fibers::fiber_context* pick_next()
{
// if ready queue is empty, just tell caller
if (! head_)
return nullptr;
// Here we have at least one ready fiber. Unlink and return that.
boost::fibers::fiber_context* f = head_;
head_ = f->nxt;
f->nxt = nullptr;
std::cout << "pick_next() resuming " << properties(f).name << ": ";
describe_ready_queue();
return f;
}
virtual void property_change(boost::fibers::fiber_context* f, priority_props& props)
{
// Although our priority_props class defines multiple properties, only
// one of them (priority) actually calls notify() when changed. The
// point of a property_change() override is to reshuffle the ready
// queue according to the updated priority value.
std::cout << "property_change(" << props.name << '(' << props.get_priority()
<< ")): ";
// Despite the added complexity of the loop body, make a single pass
// over the queue to find both the existing item and the new desired
// insertion point.
bool found = false;
boost::fibers::fiber_context **insert = nullptr, **fp = &head_;
for ( ; *fp; fp = &(*fp)->nxt)
{
if (*fp == f)
{
// found the passed fiber in our list -- unlink it
found = true;
*fp = (*fp)->nxt;
f->nxt = nullptr;
// If that was the last item in the list, stop.
if (! *fp)
break;
// If we've already found the new insertion point, no need to
// continue looping.
if (insert)
break;
}
// As in awakened(), we're looking for the first fiber in the
// queue with priority lower than the passed fiber.
if (properties(*fp).get_priority() < props.get_priority())
{
insert = fp;
// If we've already found and unlinked the passed fiber, no
// need to continue looping.
if (found)
break;
}
}
// property_change() should only be called if f->is_ready(). However,
// a waiting fiber can change state to is_ready() while still on the
// fiber_manager's waiting queue. Every such fiber will be swept onto
// our ready queue before the next pick_next() call, but still it's
// possible to get a property_change() call for a fiber that
// is_ready() but is not yet on our ready queue. If it's not there, no
// action required: we'll handle it next time it hits awakened().
if (! found)
{
// hopefully user will distinguish this case by noticing that
// the fiber with which we were called does not appear in the
// ready queue at all
describe_ready_queue();
return;
}
// There might not be any ready fibers with lower priority. In that
// case, append to the end of the queue.
std::string where;
if (insert)
where = std::string("before ") + properties(*insert).name;
else
{
insert = fp;
where = "to end";
}
// Insert f at the new insertion point in the queue.
f->nxt = *insert;
*insert = f;
std::cout << "moving " << where << ": ";
describe_ready_queue();
}
void describe_ready_queue()
{
if (! head_)
std::cout << "[empty]";
else
{
const char* delim = "";
for (boost::fibers::fiber_context *f = head_; f; f = f->nxt)
{
priority_props& props(properties(f));
std::cout << delim << props.name << '(' << props.get_priority() << ')';
delim = ", ";
}
}
std::cout << std::endl;
}
};
void init(const std::string& name, int priority)
{
priority_props& props(boost::this_fiber::properties<priority_props>());
props.name = name;
props.set_priority(priority);
}
void yield_fn(const std::string& name, int priority)
{
init(name, priority);
for (int i = 0; i < 3; ++i)
{
std::cout << "fiber " << name << " running" << std::endl;
boost::this_fiber::yield();
}
}
void barrier_fn(const std::string& name, int priority, boost::fibers::barrier& barrier)
{
init(name, priority);
std::cout << "fiber " << name << " waiting on barrier" << std::endl;
barrier.wait();
std::cout << "fiber " << name << " yielding" << std::endl;
boost::this_fiber::yield();
std::cout << "fiber " << name << " done" << std::endl;
}
void change_fn(const std::string& name, int priority,
boost::fibers::fiber& other, int other_priority,
boost::fibers::barrier& barrier)
{
init(name, priority);
std::cout << "fiber " << name << " waiting on barrier" << std::endl;
barrier.wait();
// We assume a couple things about 'other':
// - that it was also waiting on the same barrier
// - that it has lower priority than this fiber.
// If both are true, 'other' is now ready to run but is sitting in
// priority_scheduler's ready queue. Change its priority.
priority_props& other_props(other.properties<priority_props>());
std::cout << "fiber " << name << " changing priority of " << other_props.name
<< " to " << other_priority << std::endl;
other_props.set_priority(other_priority);
std::cout << "fiber " << name << " done" << std::endl;
}
int main(int argc, char *argv[])
{
// make sure we use our priority_scheduler rather than default round_robin
priority_scheduler psched;
boost::fibers::set_scheduling_algorithm(&psched);
{
// verify that high-priority fiber always gets scheduled first
boost::fibers::fiber low(boost::bind(yield_fn, "low", 1));
boost::fibers::fiber med(boost::bind(yield_fn, "medium", 2));
boost::fibers::fiber hi(boost::bind(yield_fn, "high", 3));
hi.join();
med.join();
low.join();
std::cout << std::endl;
}
{
// fibers of same priority are scheduled in round-robin order
boost::fibers::fiber a(boost::bind(yield_fn, "a", 0));
boost::fibers::fiber b(boost::bind(yield_fn, "b", 0));
boost::fibers::fiber c(boost::bind(yield_fn, "c", 0));
a.join();
b.join();
c.join();
std::cout << std::endl;
}
{
// using a barrier wakes up all waiting fibers at the same time
boost::fibers::barrier barrier(3);
boost::fibers::fiber low(boost::bind(barrier_fn, "low", 1, boost::ref(barrier)));
boost::fibers::fiber med(boost::bind(barrier_fn, "medium", 2, boost::ref(barrier)));
boost::fibers::fiber hi(boost::bind(barrier_fn, "high", 3, boost::ref(barrier)));
low.join();
med.join();
hi.join();
std::cout << std::endl;
}
{
// change priority of a fiber in priority_scheduler's ready queue
boost::fibers::barrier barrier(3);
boost::fibers::fiber c(boost::bind(barrier_fn, "c", 1, boost::ref(barrier)));
boost::fibers::fiber a(boost::bind(change_fn, "a", 3,
boost::ref(c), 3, boost::ref(barrier)));
boost::fibers::fiber b(boost::bind(barrier_fn, "b", 2, boost::ref(barrier)));
a.join();
b.join();
c.join();
std::cout << std::endl;
}
return 0;
}

View File

@@ -8,6 +8,7 @@
#include <boost/config.hpp>
#include <boost/fiber/properties.hpp>
#include <boost/fiber/detail/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
@@ -27,6 +28,65 @@ struct BOOST_FIBERS_DECL sched_algorithm {
virtual fiber_context * pick_next() = 0;
};
class BOOST_FIBERS_DECL sched_algorithm_with_properties_base: public sched_algorithm
{
public:
// called by fiber_properties::notify() -- don't directly call
virtual void property_change_( fiber_context *f, fiber_properties* props ) = 0;
protected:
static fiber_properties* get_properties(fiber_context* f) noexcept;
static void set_properties(fiber_context* f, fiber_properties* p) noexcept;
};
template <class PROPS>
struct sched_algorithm_with_properties:
public sched_algorithm_with_properties_base
{
typedef sched_algorithm_with_properties_base super;
// Mark this override 'final': sched_algorithm_with_properties subclasses
// must override awakened_props() instead. Otherwise you'd have to
// remember to start every subclass awakened() override with:
// sched_algorithm_with_properties<PROPS>::awakened(fb);
virtual void awakened( fiber_context *f) final
{
fiber_properties* props = super::get_properties(f);
if (! props)
{
// TODO: would be great if PROPS could be allocated on the new
// fiber's stack somehow
props = new PROPS(f);
super::set_properties(f, props);
}
// Set sched_algo_ again every time this fiber becomes READY. That
// handles the case of a fiber migrating to a new thread with a new
// sched_algorithm subclass instance.
props->set_sched_algorithm(this);
// Okay, now forward the call to subclass override.
awakened_props(f);
}
// subclasses override this method instead of the original awakened()
virtual void awakened_props( fiber_context *) = 0;
// used for all internal calls
PROPS& properties(fiber_context* f)
{
return static_cast<PROPS&>(*super::get_properties(f));
}
// override this to be notified by PROPS::notify()
virtual void property_change( fiber_context* f, PROPS& props) {}
// implementation for sched_algorithm_with_properties_base method
void property_change_( fiber_context *f, fiber_properties* props ) final
{
property_change(f, *static_cast<PROPS*>(props));
}
};
}}
#ifdef BOOST_HAS_ABI_HEADERS

View File

@@ -50,6 +50,10 @@ public:
private:
fiber_context * head_;
// tail_ points to the nxt field that contains the null that marks the end
// of the fifo. When the fifo is empty, tail_ points to head_. tail_ must
// never be null: it always points to a real fiber_context*. However, in
// normal use, (*tail_) is always null.
fiber_context ** tail_;
};

View File

@@ -20,6 +20,7 @@
#include <boost/fiber/detail/config.hpp>
#include <boost/fiber/fiber_context.hpp>
#include <boost/fiber/fixedsize_stack.hpp>
#include <boost/fiber/detail/scheduler.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
@@ -27,11 +28,6 @@
namespace boost {
namespace fibers {
namespace detail {
struct scheduler;
}
class fiber_context;
@@ -51,7 +47,7 @@ private:
// reserve space for control structure
std::size_t size = sctx.size - sizeof( fiber_context);
void * sp = static_cast< char * >( sctx.sp) - sizeof( fiber_context);
// placement new of worker_fiber on top of fiber's stack
// placement new of fiber_context on top of fiber's stack
return ptr_t(
new ( sp) fiber_context( context::preallocated( sp, size, sctx), salloc,
std::forward< Fn >( fn), std::forward< Args >( args) ... ) );
@@ -120,15 +116,17 @@ public:
return impl_ ? impl_->get_id() : id();
}
bool thread_affinity() const noexcept;
void thread_affinity( bool) noexcept;
void detach() noexcept;
void join();
void interrupt() noexcept;
template <class PROPS>
PROPS& properties()
{
return dynamic_cast<PROPS&>(*impl_->get_properties());
}
};
inline

View File

@@ -36,6 +36,8 @@
namespace boost {
namespace fibers {
class fiber_properties;
class BOOST_FIBERS_DECL fiber_context {
private:
enum class fiber_status {
@@ -49,8 +51,7 @@ private:
flag_main_fiber = 1 << 1,
flag_interruption_blocked = 1 << 2,
flag_interruption_requested = 1 << 3,
flag_thread_affinity = 1 << 4,
flag_detached = 1 << 5
flag_detached = 1 << 4
};
struct BOOST_FIBERS_DECL fss_data {
@@ -85,6 +86,7 @@ private:
std::vector< fiber_context * > waiting_;
std::exception_ptr except_;
std::chrono::high_resolution_clock::time_point tp_;
fiber_properties * properties_;
// main fiber
fiber_context() :
@@ -92,10 +94,11 @@ private:
ctx_( context::execution_context::current() ),
fss_data_(),
state_( fiber_status::running),
flags_( flag_main_fiber | flag_thread_affinity),
flags_( flag_main_fiber),
waiting_(),
except_(),
tp_( (std::chrono::high_resolution_clock::time_point::max)() ),
properties_( nullptr),
nxt() {
}
@@ -137,6 +140,7 @@ private:
waiting_(),
except_(),
tp_( (std::chrono::high_resolution_clock::time_point::max)() ),
properties_( nullptr),
nxt( nullptr) {
}
@@ -215,9 +219,7 @@ public:
std::index_sequence_for< Args ... >() ) {
}
virtual ~fiber_context() {
BOOST_ASSERT( waiting_.empty() );
}
virtual ~fiber_context();
id get_id() const noexcept {
return id( const_cast< fiber_context * >( this) );
@@ -237,12 +239,6 @@ public:
void request_interruption( bool req) noexcept;
bool thread_affinity() const noexcept {
return 0 != ( flags_.load() & flag_thread_affinity);
}
void thread_affinity( bool req) noexcept;
bool is_terminated() const noexcept {
return fiber_status::terminated == state_;
}
@@ -302,7 +298,9 @@ public:
void resume() {
BOOST_ASSERT( is_running() ); // set by the scheduler-algorithm
ctx_();
// FIXME: post-1.58 boost::context::execution_context has an
// operator()() method. This statement originally called that.
ctx_.resume();
}
std::chrono::high_resolution_clock::time_point const& time_point() const noexcept {
@@ -317,6 +315,13 @@ public:
tp_ = (std::chrono::high_resolution_clock::time_point::max)();
}
void set_properties( fiber_properties* props);
fiber_properties* get_properties() const
{
return properties_;
}
void release();
friend void intrusive_ptr_add_ref( fiber_context * f) {

View File

@@ -81,6 +81,8 @@ public:
fiber_context * active() noexcept;
sched_algorithm* get_sched_algo_();
void set_sched_algo( sched_algorithm *);
void wait_interval( std::chrono::high_resolution_clock::duration const&) noexcept;
@@ -92,8 +94,7 @@ public:
std::chrono::high_resolution_clock::duration wait_interval() noexcept;
bool preserve_fpu();
bool preserve_fpu() const;
void preserve_fpu( bool);
};

View File

@@ -49,17 +49,13 @@ void sleep_for( std::chrono::duration< Rep, Period > const& timeout_duration) {
sleep_until( std::chrono::high_resolution_clock::now() + timeout_duration);
}
inline
bool thread_affinity() noexcept {
return fibers::detail::scheduler::instance()->active()->thread_affinity();
template < class PROPS >
PROPS& properties()
{
return dynamic_cast<PROPS&>(*fibers::detail::scheduler::instance()->active()->get_properties());
}
inline
void thread_affinity( bool req) noexcept {
fibers::detail::scheduler::instance()->active()->thread_affinity( req);
}
}
} // this_fiber
namespace fibers {

View File

@@ -0,0 +1,77 @@
// Copyright Nat Goodspeed 2014.
// 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)
// Define fiber_properties, a base class from which a library consumer can
// derive a subclass with specific properties important to a user-coded
// scheduler.
#ifndef BOOST_FIBERS_PROPERTIES_HPP
#define BOOST_FIBERS_PROPERTIES_HPP
#include <boost/fiber/detail/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
# if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4275)
# endif
namespace boost {
namespace fibers {
struct sched_algorithm;
class fiber_context;
class fiber_properties
{
protected:
// initialized by constructor
fiber_context* fiber_;
// set every time this fiber becomes READY
sched_algorithm* sched_algo_;
// Inform the relevant sched_algorithm instance that something important
// has changed, so it can (presumably) adjust its data structures
// accordingly.
void notify();
public:
// fiber_properties, and by implication every subclass, must accept a back
// pointer to its fiber_context.
typedef fiber_context* back_ptr;
// Any specific property setter method, after updating the relevant
// instance variable, can/should call notify().
fiber_properties(back_ptr f):
fiber_(f),
sched_algo_(nullptr)
{}
// We need a virtual destructor (hence a vtable) because fiber_properties
// is stored polymorphically (as fiber_properties*) in fiber_context, and
// destroyed via that pointer.
virtual ~fiber_properties() {}
// not really intended for public use, but sched_algorithm_with_properties
// must be able to call this
void set_sched_algorithm(sched_algorithm* algo)
{
sched_algo_ = algo;
}
};
}} // namespace boost::fibers
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_FIBERS_PROPERTIES_HPP

38
src/algorithm.cpp Normal file
View File

@@ -0,0 +1,38 @@
// Copyright Oliver Kowalke / Nat Goodspeed 2015.
// 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)
#include "boost/fiber/algorithm.hpp"
#include <boost/config.hpp>
#include <boost/fiber/fiber_context.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace fibers {
//static
fiber_properties*
sched_algorithm_with_properties_base::get_properties(fiber_context* f) noexcept
{
return f->get_properties();
}
//static
void
sched_algorithm_with_properties_base::set_properties(fiber_context* f, fiber_properties* props) noexcept
{
f->set_properties(props);
}
}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif

View File

@@ -31,18 +31,18 @@ waiting_queue::push( fiber_context * item) noexcept {
BOOST_ASSERT( nullptr != item);
BOOST_ASSERT( nullptr == item->nxt);
// Skip past any worker_fibers in the queue whose time_point() is less
// than item->time_point(), looking for the first worker_fiber in the
// Skip past any fiber_contexts in the queue whose time_point() is less
// than item->time_point(), looking for the first fiber_context in the
// queue whose time_point() is at least item->time_point(). Insert
// item before that. In other words, insert item so as to preserve
// ascending order of time_point() values. (Recall that a worker_fiber
// ascending order of time_point() values. (Recall that a fiber_context
// waiting with no timeout uses the maximum time_point value.)
// We do this by walking the linked list of nxt fields with a
// worker_fiber**. In other words, first we point to &head_, then to
// &head_->nxt then to &head_->nxt->nxt and so forth. When we find
// fiber_context**. In other words, first we point to &head_, then to
// &head_->nxt, then to &head_->nxt->nxt and so forth. When we find
// the item with the right time_point(), we're already pointing to the
// worker_fiber* that links it into the list. Insert item right there.
// fiber_context* that links it into the list. Insert item right there.
fiber_context ** f( & head_);
for ( ; nullptr != * f; f = & ( * f)->nxt) {
@@ -65,30 +65,30 @@ waiting_queue::move_to( sched_algorithm * sched_algo) {
std::chrono::high_resolution_clock::time_point now(
std::chrono::high_resolution_clock::now() );
// Search the queue for every worker_fiber 'f' for which fn(f, now)
// returns true. Each time we find such a worker_fiber, unlink it from
// the queue and pass it to sched_algo->awakened().
// Search the queue for every fiber_context 'f' which is_ready(). Each
// time we find a ready fiber_context, unlink it from the queue and pass
// it to sched_algo->awakened().
// Search using a worker_fiber**, starting at &head_.
// Search using a fiber_context**, starting at &head_.
for ( fiber_context ** fp( & head_); nullptr != * fp;) {
fiber_context * f( * fp);
BOOST_ASSERT( ! f->is_running() );
BOOST_ASSERT( ! f->is_terminated() );
// set fiber to state_ready if dead-line was reached
// set fiber to state_ready if deadline was reached
// set fiber to state_ready if interruption was requested
if ( f->time_point() <= now || f->interruption_requested() ) {
f->set_ready();
}
if ( ! f->is_ready() ) {
// If f does NOT meet caller's criteria, skip fp past it.
// If f is NOT ready, skip fp past it.
fp = & ( * fp)->nxt;
} else {
// Here f satisfies our caller. Unlink it from the list.
// Here f is ready. Unlink it from the list.
* fp = ( * fp)->nxt;
f->nxt = nullptr;
// Pass the newly-unlinked worker_fiber* to sched_algo.
// Pass the newly-unlinked fiber_context* to sched_algo.
f->time_point_reset();
sched_algo->awakened( f);
}

View File

@@ -28,27 +28,13 @@ fiber::start_() {
detail::scheduler::instance()->spawn( impl_.get() );
}
bool
fiber::thread_affinity() const noexcept {
BOOST_ASSERT( impl_);
return impl_->thread_affinity();
}
void
fiber::thread_affinity( bool req) noexcept {
BOOST_ASSERT( impl_);
impl_->thread_affinity( req);
}
void
fiber::join() {
BOOST_ASSERT( impl_);
if ( boost::this_fiber::get_id() == get_id() ) {
throw fiber_resource_error( static_cast< int >( std::errc::resource_deadlock_would_occur),
"boost fiber: trying joining itself");
"boost fiber: trying to join itself");
}
if ( ! joinable() ) {

View File

@@ -10,6 +10,7 @@
#include "boost/fiber/detail/scheduler.hpp"
#include "boost/fiber/exceptions.hpp"
#include "boost/fiber/properties.hpp"
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
@@ -18,6 +19,11 @@
namespace boost {
namespace fibers {
fiber_context::~fiber_context() {
BOOST_ASSERT( waiting_.empty() );
delete properties_;
}
fiber_context *
fiber_context::main_fiber() {
static thread_local fiber_context mf;
@@ -79,18 +85,6 @@ fiber_context::request_interruption( bool req) noexcept {
}
}
void
fiber_context::thread_affinity( bool req) noexcept {
// BOOST_ASSERT( 0 == ( flags_.load() & flag_main_fiber) );
if ( 0 == ( flags_.load() & flag_main_fiber) ) {
if ( req) {
flags_ |= flag_thread_affinity;
} else {
flags_ &= ~flag_thread_affinity;
}
}
}
void *
fiber_context::get_fss_data( void const * vp) const {
uintptr_t key( reinterpret_cast< uintptr_t >( vp) );
@@ -130,6 +124,13 @@ fiber_context::set_fss_data( void const * vp,
}
}
void
fiber_context::set_properties( fiber_properties* props)
{
delete properties_;
properties_ = props;
}
}}
#ifdef BOOST_HAS_ABI_HEADERS

View File

@@ -101,7 +101,7 @@ fiber_manager::spawn( fiber_context * f) {
void
fiber_manager::run() {
for (;;) {
// move all fibers witch are ready (state_ready)
// move all fibers which are ready (state_ready)
// from waiting-queue to the runnable-queue
wqueue_.move_to( sched_algo_);
@@ -222,7 +222,7 @@ fiber_manager::wait_interval() noexcept {
}
bool
fiber_manager::preserve_fpu() {
fiber_manager::preserve_fpu() const {
return preserve_fpu_;
}

39
src/properties.cpp Normal file
View File

@@ -0,0 +1,39 @@
// Copyright Oliver Kowalke 2013.
// 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)
#include <boost/assert.hpp>
#include "boost/fiber/properties.hpp"
#include "boost/fiber/algorithm.hpp"
#include "boost/fiber/fiber_manager.hpp"
#include "boost/fiber/fiber_context.hpp"
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace fibers {
void fiber_properties::notify()
{
BOOST_ASSERT(sched_algo_);
// Application code might change an important property for any fiber at
// any time. The fiber in question might be ready, running or waiting.
// Significantly, only a fiber which is ready but not actually running is
// in the sched_algorithm's ready queue. Don't bother the sched_algorithm
// with a change to a fiber it's not currently tracking: it will do the
// right thing next time the fiber is passed to its awakened() method.
if (fiber_->is_ready())
{
static_cast<sched_algorithm_with_properties_base*>(sched_algo_)->
property_change_(fiber_, this);
}
}
}} // boost::fibers
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif