- the callable and its arguments before set_teminated() is called
- otherwise a copy of the callable remains on fiber's stack and
will never destructed
- the user is responsible that all worker fibers terminate
- dispatcher fiber must run till all worker fiber are terminated and
the the scheduler is shut down
- flag shutdown is set in ~scheduler before resuming the ready fibers
- the ready fibers must contain at least the dispatcher fiber
- the lambda posted inside iasio::rond_robin will be shared by different
threads running io_service::run()
- the lambda must remain/executed by the thread
- re-introduction of run_svc() method
Given the necessity for fibers::asio::round_robin to share its ready queue
among all threads calling io_service::run() on the same io_service instance,
the capability to allow hop (or not) in the fibers::asio::yield mechanism is
redundant.
If the async operation invoked by the asio async function immediately calls
yield_handler_base::operator() even before control reaches
async_result_base::get(), which would suspend the calling fiber, the context*
bound by yield_handler_base's constructor is still the active() context. This
may not be passed to context::migrate(). It probably shouldn't be passed to
context::set_ready(), either.
The whole yield / yield_hop dichotomy becomes much easier to read and explain
if we stick to a single yield_t class. Since the intention is for a consumer
to pass canonical instances rather than manipulating that class in any other
way, we can instantiate it however we want.
This gets rid of lots of ugly redundant boost::asio::handler_type<>
specializations.
Introduce yield_base with subclasses yield_t and yield_hop_t, each with a
canonical instance yield and yield_hop. yield_base adds allow_hop_ bool to
communicate the distinction to yield_handler: yield_t sets false, yield_hop_t
sets true.
Extract common base class yield_handler_base from yield_handler<T> and
yield_handler<void>. In fact yield_handler_base is almost identical to
yield_handler<void>; yield_handler<T> adds value processing.
Instead of capturing just the error_code* from the passed yield_base instance,
capture the whole yield_base: both its error_code* and the new allow_hop_ bool.
yield_handler_base provides operator()(error_code) method. This operator()
sets a new completed_ bool so calling fiber need NOT suspend if the async
operation completes immediately. That bool must be defended with a mutex.
This operator() also avoids migrating a pinned_context, or when a caller
passes plain yield instead of yield_hop.
New wait() method suspends the calling fiber only if (! completed_).
Extract common base class async_result_base from async_result<T> and
async_result<void>. In fact async_result_base is almost identical to
async_result<void>; async_result<T> adds value processing.
Add handler_type<> specializations for new yield_base and yield_hop_t
completion token types.
Do not document the specific values of enum class type values. Consuming code
should be based solely on enum names; their values are an implementation
detail.
Ensure that all enum class type values are mentioned in note for is_context()
method.