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.
Provide a link to Boost.Context's stack_traits documentation to look up
is_unbounded(), minimum_size() and maximum_size().
Fix spellings of minimum_size() and maximum_size().
When stack_traits::is_unbounded(), we shouldn't have to care about
stack_traits::maximum_size(). Consistently change:
! traits_type::is_unbounded() && size <= traits_type::maximum_size()
to:
traits_type::is_unbounded() || size <= traits_type::maximum_size()
Add a link to the section "No Spurious Wakeups" in the condition_variable
section.
Make a pass over "migrating fibers between threads," adding a link to the
whole new section on that same topic.
Now that rqueue_ is an STL-compatible container,
priority_scheduler::awakened() can use std::find_if() to search for a context
with a lower priority.
Now that rqueue_ is an intrusive_list, priority_scheduler::property_change()
need not search it: it can simply test with context::ready_is_linked(). Now
that it's a doubly-linked list, we can use context::ready_unlink() to unlink.
Now that method parameters have been renamed from 'f' to 'ctx', change all
references in comments accordingly.
Highlight predicate condition_variable::wait() method in condition_variable
front matter.
Rewrite the explanation of wait()'s Precondition.
Add a condition_variables subsection about no spurious condition_variable
wakeups. Remove "or spuriously" from wakeup conditions in wait*() methods.
First pass through "spurious wakeup" section in Rationale.
First pass through migration.qbk. Use lock_t throughout work_sharing.cpp,
instead of lock_t, lock_count and explicit std::unique_lock<std::mutex>
declarations. Unify treatment of main and dispatcher fibers.
Clarify thread-safety requirements on sched_algorithm::notify() and
suspend_until().
Clarify disable_interruption when rethrowing fiber_interrupted.
Consolidate future<T>::get(): returns T whether T is R, R& or void.
Mention nesting of disable_interruption (which matters) versus nesting of
restore_interruption (which doesn't). Mention that a disable_interruption
constructed within the scope of another disable_interruption is a no-op, both
itself and when passed to restore_interruption.
When packaged_task::operator()() stores a value or an exception, state "as if"
by promise::set_value() or set_exception(): the shared state is set ready.
Similarly for ~packaged_task() and ~promise() setting broken_promise.
Sprinkle links to the Allocator concept, std::allocator and
std::allocator_arg_t where referenced. Similarly for StackAllocator.
Add more cross-reference links where Fiber classes and methods are mentioned.
Also things like std::unique_lock and std::mutex.
Clarify error condition for value_pop() when channel is close()d.
Since fiber_specific_ptr::release() does not invoke cleanup, it should not
throw an exception raised during cleanup.
Document boost::fibers::scheduler::ready_queue_t and expand on the
context::ready_link(), ready_unlink() and ready_is_linked() methods.
Explain migrate() restrictions on is_main_context() and
is_dispatcher_context() context instances.