mirror of
https://github.com/boostorg/fiber.git
synced 2026-02-20 14:42:21 +00:00
fix assertions for link-state
This commit is contained in:
@@ -28,16 +28,15 @@ scheduler::release_terminated_() noexcept {
|
||||
for ( terminated_queue_t::iterator i( terminated_queue_.begin() );
|
||||
i != e;) {
|
||||
context * ctx = & ( * i);
|
||||
BOOST_ASSERT( ! ctx->is_context( type::main_context) );
|
||||
BOOST_ASSERT( ! ctx->is_context( type::dispatcher_context) );
|
||||
BOOST_ASSERT( ctx->worker_is_linked() );
|
||||
BOOST_ASSERT( ctx->is_terminated() );
|
||||
BOOST_ASSERT( ! ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->sleep_is_linked() );
|
||||
// remove context from worker-queue
|
||||
ctx->worker_unlink();
|
||||
// remove context from terminated-queue
|
||||
i = terminated_queue_.erase( i);
|
||||
BOOST_ASSERT( ctx->is_context( type::worker_context) );
|
||||
BOOST_ASSERT( ! ctx->is_context( type::pinned_context) );
|
||||
BOOST_ASSERT( ctx->is_terminated() );
|
||||
BOOST_ASSERT( ! ctx->worker_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->sleep_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->wait_is_linked() );
|
||||
// if last reference, e.g. fiber::join() or fiber::detach()
|
||||
// have been already called, this will call ~context(),
|
||||
// the context is automatically removeid from worker-queue
|
||||
@@ -67,13 +66,14 @@ scheduler::sleep2ready_() noexcept {
|
||||
sleep_queue_t::iterator e = sleep_queue_.end();
|
||||
for ( sleep_queue_t::iterator i = sleep_queue_.begin(); i != e;) {
|
||||
context * ctx = & ( * i);
|
||||
// dipatcher context must never be pushed to sleep-queue
|
||||
BOOST_ASSERT( ! ctx->is_context( type::dispatcher_context) );
|
||||
//BOOST_ASSERT( main_ctx_ == ctx || ctx->worker_is_linked() );
|
||||
BOOST_ASSERT( main_ctx_ == ctx || ctx->worker_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->is_terminated() );
|
||||
BOOST_ASSERT( ! ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ctx->sleep_is_linked() );
|
||||
// ctx->wait_is_linked() might return true if
|
||||
// context is waiting in time_mutex::try_lock_until()
|
||||
BOOST_ASSERT( ! ctx->terminated_is_linked() );
|
||||
// no test for wait-queue because ctx
|
||||
// might be waiting in time_mutex::try_lock_until()
|
||||
// set fiber to state_ready if deadline was reached
|
||||
if ( ctx->tp_ <= now) {
|
||||
// remove context from sleep-queue
|
||||
@@ -121,11 +121,10 @@ void
|
||||
scheduler::dispatch() noexcept {
|
||||
BOOST_ASSERT( context::active() == dispatcher_ctx_);
|
||||
for (;;) {
|
||||
bool no_worker = worker_queue_.empty();
|
||||
if ( shutdown_) {
|
||||
// notify sched-algorithm about termination
|
||||
algo_->notify();
|
||||
if ( no_worker) {
|
||||
if ( worker_queue_.empty() ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -168,11 +167,10 @@ boost::context::continuation
|
||||
scheduler::dispatch() noexcept {
|
||||
BOOST_ASSERT( context::active() == dispatcher_ctx_);
|
||||
for (;;) {
|
||||
bool no_worker = worker_queue_.empty();
|
||||
if ( shutdown_) {
|
||||
// notify sched-algorithm about termination
|
||||
algo_->notify();
|
||||
if ( no_worker) {
|
||||
if ( worker_queue_.empty() ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -216,10 +214,9 @@ void
|
||||
scheduler::set_ready( context * ctx) noexcept {
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
BOOST_ASSERT( ! ctx->is_terminated() );
|
||||
// we do not test for wait-queue because
|
||||
// context::wait_is_linked() is not synchronized
|
||||
// with other threads
|
||||
//BOOST_ASSERT( active_ctx->wait_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->terminated_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->wait_is_linked() );
|
||||
// remove context ctx from sleep-queue
|
||||
// (might happen if blocked in timed_mutex::try_lock_until())
|
||||
if ( ctx->sleep_is_linked() ) {
|
||||
@@ -234,14 +231,14 @@ scheduler::set_ready( context * ctx) noexcept {
|
||||
void
|
||||
scheduler::set_remote_ready( context * ctx) noexcept {
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
// another thread might signal the main-context of this thread
|
||||
BOOST_ASSERT( ! ctx->is_context( type::dispatcher_context) );
|
||||
BOOST_ASSERT( this == ctx->get_scheduler() );
|
||||
// another thread might signal the main-context
|
||||
// from this thread
|
||||
//BOOST_ASSERT( ! ctx->is_context( type::main_context) );
|
||||
// context ctx might in wait-/ready-/sleep-queue
|
||||
// we do not test this in this function
|
||||
// scheduler::dispatcher() has to take care
|
||||
BOOST_ASSERT( ! ctx->is_terminated() );
|
||||
BOOST_ASSERT( ! ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->sleep_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->terminated_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->wait_is_linked() );
|
||||
// push new context to remote ready-queue
|
||||
remote_ready_queue_.push( ctx);
|
||||
// notify scheduler
|
||||
@@ -251,85 +248,75 @@ scheduler::set_remote_ready( context * ctx) noexcept {
|
||||
|
||||
#if (BOOST_EXECUTION_CONTEXT==1)
|
||||
void
|
||||
scheduler::set_terminated( context * active_ctx) noexcept {
|
||||
BOOST_ASSERT( nullptr != active_ctx);
|
||||
BOOST_ASSERT( context::active() == active_ctx);
|
||||
BOOST_ASSERT( ! active_ctx->is_context( type::main_context) );
|
||||
BOOST_ASSERT( ! active_ctx->is_context( type::dispatcher_context) );
|
||||
//BOOST_ASSERT( active_ctx->worker_is_linked() );
|
||||
BOOST_ASSERT( active_ctx->is_terminated() );
|
||||
BOOST_ASSERT( ! active_ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ! active_ctx->sleep_is_linked() );
|
||||
BOOST_ASSERT( ! active_ctx->wait_is_linked() );
|
||||
scheduler::set_terminated( context * ctx) noexcept {
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
BOOST_ASSERT( context::active() == ctx);
|
||||
BOOST_ASSERT( ctx->is_context( type::worker_context) );
|
||||
BOOST_ASSERT( ! ctx->is_context( type::pinned_context) );
|
||||
BOOST_ASSERT( ctx->is_terminated() );
|
||||
BOOST_ASSERT( ! ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->sleep_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->terminated_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->wait_is_linked() );
|
||||
// store the terminated fiber in the terminated-queue
|
||||
// the dispatcher-context will call
|
||||
// the dispatcher-context will call
|
||||
// intrusive_ptr_release( ctx);
|
||||
active_ctx->terminated_link( terminated_queue_);
|
||||
ctx->terminated_link( terminated_queue_);
|
||||
// remove from the worker-queue
|
||||
ctx->worker_unlink();
|
||||
// resume another fiber
|
||||
algo_->pick_next()->resume();
|
||||
}
|
||||
#else
|
||||
boost::context::continuation
|
||||
scheduler::set_terminated( context * active_ctx) noexcept {
|
||||
BOOST_ASSERT( nullptr != active_ctx);
|
||||
BOOST_ASSERT( context::active() == active_ctx);
|
||||
BOOST_ASSERT( ! active_ctx->is_context( type::main_context) );
|
||||
BOOST_ASSERT( ! active_ctx->is_context( type::dispatcher_context) );
|
||||
//BOOST_ASSERT( active_ctx->worker_is_linked() );
|
||||
BOOST_ASSERT( active_ctx->is_terminated() );
|
||||
BOOST_ASSERT( ! active_ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ! active_ctx->sleep_is_linked() );
|
||||
BOOST_ASSERT( ! active_ctx->wait_is_linked() );
|
||||
scheduler::set_terminated( context * ctx) noexcept {
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
BOOST_ASSERT( context::active() == ctx);
|
||||
BOOST_ASSERT( ctx->is_context( type::worker_context) );
|
||||
BOOST_ASSERT( ! ctx->is_context( type::pinned_context) );
|
||||
BOOST_ASSERT( ctx->is_terminated() );
|
||||
BOOST_ASSERT( ! ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->sleep_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->terminated_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->wait_is_linked() );
|
||||
// store the terminated fiber in the terminated-queue
|
||||
// the dispatcher-context will call
|
||||
// the dispatcher-context will call
|
||||
// intrusive_ptr_release( ctx);
|
||||
active_ctx->terminated_link( terminated_queue_);
|
||||
ctx->terminated_link( terminated_queue_);
|
||||
// remove from the worker-queue
|
||||
ctx->worker_unlink();
|
||||
// resume another fiber
|
||||
return algo_->pick_next()->suspend_with_cc();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
scheduler::yield( context * active_ctx) noexcept {
|
||||
BOOST_ASSERT( nullptr != active_ctx);
|
||||
//BOOST_ASSERT( main_ctx_ == active_ctx || dispatcher_ctx_.get() == active_ctx || active_ctx->worker_is_linked() );
|
||||
BOOST_ASSERT( ! active_ctx->is_terminated() );
|
||||
BOOST_ASSERT( ! active_ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ! active_ctx->sleep_is_linked() );
|
||||
// we do not test for wait-queue because
|
||||
// context::wait_is_linked() is not sychronized
|
||||
// with other threads
|
||||
// defer passing active context to set_ready()
|
||||
// in work-sharing context (multiple threads read
|
||||
// from one ready-queue) the context must be
|
||||
// already suspended until another thread resumes it
|
||||
// (== maked as ready)
|
||||
scheduler::yield( context * ctx) noexcept {
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
BOOST_ASSERT( context::active() == ctx);
|
||||
BOOST_ASSERT( ctx->is_context( type::worker_context) || ctx->is_context( type::main_context) );
|
||||
BOOST_ASSERT( ! ctx->is_terminated() );
|
||||
BOOST_ASSERT( ! ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->sleep_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->terminated_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->wait_is_linked() );
|
||||
// resume another fiber
|
||||
algo_->pick_next()->resume( active_ctx);
|
||||
algo_->pick_next()->resume( ctx);
|
||||
}
|
||||
|
||||
bool
|
||||
scheduler::wait_until( context * active_ctx,
|
||||
scheduler::wait_until( context * ctx,
|
||||
std::chrono::steady_clock::time_point const& sleep_tp) noexcept {
|
||||
BOOST_ASSERT( nullptr != active_ctx);
|
||||
//BOOST_ASSERT( main_ctx_ == active_ctx || dispatcher_ctx_.get() == active_ctx || active_ctx->worker_is_linked() );
|
||||
BOOST_ASSERT( ! active_ctx->is_terminated() );
|
||||
// if the active-fiber running in this thread calls
|
||||
// condition_variable:wait() and code in another thread calls
|
||||
// condition_variable::notify_one(), it might happen that the
|
||||
// other thread pushes the fiber to remote ready-queue first
|
||||
// the dispatcher-context migh have been moved the fiber from
|
||||
// the remote ready-queue to the local ready-queue
|
||||
// so we do not check
|
||||
//BOOST_ASSERT( active_ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ! active_ctx->sleep_is_linked() );
|
||||
// active_ctx->wait_is_linked() might return true
|
||||
// if context was locked inside timed_mutex::try_lock_until()
|
||||
// context::wait_is_linked() is not sychronized
|
||||
// with other threads
|
||||
// push active context to sleep-queue
|
||||
active_ctx->tp_ = sleep_tp;
|
||||
active_ctx->sleep_link( sleep_queue_);
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
BOOST_ASSERT( context::active() == ctx);
|
||||
BOOST_ASSERT( ctx->is_context( type::worker_context) || ctx->is_context( type::main_context) );
|
||||
BOOST_ASSERT( ! ctx->is_terminated() );
|
||||
BOOST_ASSERT( ! ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->sleep_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->terminated_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->wait_is_linked() );
|
||||
ctx->tp_ = sleep_tp;
|
||||
ctx->sleep_link( sleep_queue_);
|
||||
// resume another context
|
||||
algo_->pick_next()->resume();
|
||||
// context has been resumed
|
||||
@@ -338,28 +325,21 @@ scheduler::wait_until( context * active_ctx,
|
||||
}
|
||||
|
||||
bool
|
||||
scheduler::wait_until( context * active_ctx,
|
||||
scheduler::wait_until( context * ctx,
|
||||
std::chrono::steady_clock::time_point const& sleep_tp,
|
||||
detail::spinlock_lock & lk) noexcept {
|
||||
BOOST_ASSERT( nullptr != active_ctx);
|
||||
//BOOST_ASSERT( main_ctx_ == active_ctx || dispatcher_ctx_.get() == active_ctx || active_ctx->worker_is_linked() );
|
||||
BOOST_ASSERT( ! active_ctx->is_terminated() );
|
||||
// if the active-fiber running in this thread calls
|
||||
// condition_variable:wait() and code in another thread calls
|
||||
// condition_variable::notify_one(), it might happen that the
|
||||
// other thread pushes the fiber to remote ready-queue first
|
||||
// the dispatcher-context migh have been moved the fiber from
|
||||
// the remote ready-queue to the local ready-queue
|
||||
// so we do not check
|
||||
//BOOST_ASSERT( active_ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ! active_ctx->sleep_is_linked() );
|
||||
// active_ctx->wait_is_linked() might return true
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
BOOST_ASSERT( context::active() == ctx);
|
||||
BOOST_ASSERT( ctx->is_context( type::worker_context) || ctx->is_context( type::main_context) );
|
||||
BOOST_ASSERT( ! ctx->is_terminated() );
|
||||
BOOST_ASSERT( ! ctx->ready_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->sleep_is_linked() );
|
||||
BOOST_ASSERT( ! ctx->terminated_is_linked() );
|
||||
// ctx->wait_is_linked() might return true
|
||||
// if context was locked inside timed_mutex::try_lock_until()
|
||||
// context::wait_is_linked() is not sychronized
|
||||
// with other threads
|
||||
// push active context to sleep-queue
|
||||
active_ctx->tp_ = sleep_tp;
|
||||
active_ctx->sleep_link( sleep_queue_);
|
||||
ctx->tp_ = sleep_tp;
|
||||
ctx->sleep_link( sleep_queue_);
|
||||
// resume another context
|
||||
algo_->pick_next()->resume( lk);
|
||||
// context has been resumed
|
||||
@@ -394,12 +374,12 @@ scheduler::set_algo( std::unique_ptr< algo::algorithm > algo) noexcept {
|
||||
}
|
||||
|
||||
void
|
||||
scheduler::attach_main_context( context * main_ctx) noexcept {
|
||||
BOOST_ASSERT( nullptr != main_ctx);
|
||||
scheduler::attach_main_context( context * ctx) noexcept {
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
// main-context represents the execution context created
|
||||
// by the system, e.g. main()- or thread-context
|
||||
// should not be in worker-queue
|
||||
main_ctx_ = main_ctx;
|
||||
main_ctx_ = ctx;
|
||||
#if ! defined(BOOST_FIBERS_NO_ATOMICS)
|
||||
main_ctx_->scheduler_.store( this, std::memory_order_relaxed);
|
||||
#else
|
||||
@@ -408,15 +388,15 @@ scheduler::attach_main_context( context * main_ctx) noexcept {
|
||||
}
|
||||
|
||||
void
|
||||
scheduler::attach_dispatcher_context( intrusive_ptr< context > dispatcher_ctx) noexcept {
|
||||
BOOST_ASSERT( dispatcher_ctx);
|
||||
scheduler::attach_dispatcher_context( intrusive_ptr< context > ctx) noexcept {
|
||||
BOOST_ASSERT( ctx);
|
||||
// dispatcher context has to handle
|
||||
// - remote ready context'
|
||||
// - sleeping context'
|
||||
// - extern event-loops
|
||||
// - suspending the thread if ready-queue is empty (waiting on external event)
|
||||
// should not be in worker-queue
|
||||
dispatcher_ctx_.swap( dispatcher_ctx);
|
||||
dispatcher_ctx_.swap( ctx);
|
||||
// add dispatcher-context to ready-queue
|
||||
// so it is the first element in the ready-queue
|
||||
// if the main context tries to suspend the first time
|
||||
|
||||
Reference in New Issue
Block a user