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_().
Instead of setting a fiber_properties subclass's sched_algo_ back pointer once
at construction time, unconditionally set it every time that fiber becomes
READY (and is therefore passed to sched_algorithm::awakened()). This handles
the case in which that fiber migrates to a different thread with a different
sched_algorithm subclass instance.
Break out fiber_properties::notify() implementation to a separate .cpp
implementation file so it can bring in algorithm.hpp. We don't want
properties.hpp to depend on algorithm.hpp.