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.
The casual reader, on encountering these in the Fiber examples directory,
might otherwise assume they're intended to illustrate something about the
Fiber library.
This covers both generic callbacks (adapt_callbacks.cpp,
adapt_method_calls.cpp) and custom Asio completion tokens (yield.hpp,
promise_completion_token.hpp, detail/yield.hpp, detail/promise_handler.hpp).
Mark up the relevant source files to provide code snippets for callbacks.qbk.
In essence, yield_t et al. become very like use_future_t et al. The only real
difference is the async_result return type and get() method. Factor out common
functionality into promise_completion_token and promise_handler.
Remove the boost::fibers::asio::spawn() function and its basic_yield_context
infrastructure. Fix up all existing references in example source code.