This illustrates use of a sched_algorithm_with_properties<PROPS> subclass that
defines, and supports, a priority property. The example includes a (somewhat
contrived) case in which a fiber must be moved within the scheduler's ready
queue due to a priority change.
Every sched_algorithm_with_properties<PROPS> subclass awakened() call must
ensure that control reaches sched_algorithm_with_properties<PROPS>::awakened()
_before_ any logic in the subclass method attempts to access properties. This
turns out to be all too easy to forget.
So instead, advise subclasses to overrride new awakened_props() method. Base-
class method sets things up and then calls awakened_props(). Moreover, when
the compiler supports it, sched_algorithm_with_properties<PROPS>::awakened()
is now marked 'final' to remind subclass authors to override awakened_props()
instead.
While it's true that not every READY fiber is always in the scheduler's ready
queue -- there's a time window in which a READY fiber can be on the
fiber_manager's wait queue -- only READY fibers will ever be on the
scheduler's ready queue. So if (! fiber.is_ready()), there's no point in
bothering the sched_algorithm implementation with a change to its properties.
sched_algorithm knows nothing about properties, so that class isn't really the
best place for the property_change() virtual method. Introduce intermediate
sched_algorithm_with_properties_base class, which introduces property_change_()
virtual method accepting fiber_properties*. Then the properties-specific
sched_algorithm_with_properties<PROPS> implementation calls property_change()
(no trailing underscore) with fiber_properties* cast to PROPS&. Thus the user-
coded sched_algorithm implementation can override property_change() and accept
PROPS& rather than the generic fiber_properties* pointer. But
fiber_properties::notify() -- which doesn't know its own PROPS subclass -- can
nonetheless call sched_algorithm_with_properties_base::property_change_().
- Change some doc references from 'algorithm' to 'sched_algorithm'.
- Initial cut at supporting arbitrary user-coded scheduler properties.
- Set fiber_properties::sched_algo_ every time through awakened().
- Define sched_algorithm methods on fiber_base*, not worker_fiber*.
- Simplify detail::fifo by making tail_ point to last link pointer.
- Reimplement waiting_queue::push() using pointer-to-pointer trick.
- Reimplement waiting_queue::move_to() using fiber_base** scan.
- Make bounded_queue::tail_ a ptr* to simplify appending new nodes.
- Make unbounded_queue::tail_ a ptr* to simplify linking new nodes.
- Remove thread_affinity flag and access methods.
- Re-add thread_affinity specific to workstealing_round_robin.
- Remove 'priority' for every fiber, and its support methods.
Priority is another property that's only relevant for future sched_algorithm
implementations. We don't even have an example yet. It's a good candidate for
moving to a specific fiber_properties subclass for that specific
sched_algorithm implementation.
thread_affinity is a good example of a property relevant only to a particular
sched_algorithm implementation. In examples/cpp03/migration, introduce an
'affinity' subclass of fiber_properties with a thread_affinity data
member.
Derive workstealing_round_robin from sched_algorithm_with_properties<affinity>
and, as required by that base class, forward awakened() calls to base-class
awakened() method.
Reimplement workstealing_round_robin's queue from a std::deque to a "by hand"
intrusive singly-linked list so we can efficiently remove an arbitrary item.
Make steal() method, instead of always popping the last item, scan the list to
find the last item willing to migrate (! thread_affinity).
From examples/cpp03/migration/workstealing_round_robin.hpp, an example of a
user-supplied sched_algorithm implementation, remove all boost/fiber/detail
#includes. These should no longer be needed.
Change sched_algorithm_with_properties::properties(worker_fiber*) method to
accept fiber_base* instead. The original signature was introduced when every
sched_algorithm implementation necessarily manipulated worker_fiber* pointers.
Now we're intentionally avoiding the need.
For the same reason, introduce a fiber_properties::back_ptr typedef so
subclasses can opaquely pass such pointers through their own constructor to
the base-class constructor.