Imported Upstream version 1.64.0
[platform/upstream/boost.git] / libs / fiber / src / scheduler.cpp
index 8843301..ac6f4ea 100644 (file)
 namespace boost {
 namespace fibers {
 
-context *
-scheduler::get_next_() noexcept {
-    context * ctx = algo_->pick_next();
-    //BOOST_ASSERT( nullptr == ctx);
-    //BOOST_ASSERT( this == ctx->get_scheduler() );
-    return ctx;
-}
-
 void
 scheduler::release_terminated_() noexcept {
-    terminated_queue_t::iterator e( terminated_queue_.end() );
-    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() );
+    while ( ! terminated_queue_.empty() ) {
+        context * ctx = & terminated_queue_.front();
+        terminated_queue_.pop_front();
+        BOOST_ASSERT( ctx->is_context( type::worker_context) );
+        BOOST_ASSERT( ! ctx->is_context( type::pinned_context) );
+        BOOST_ASSERT( this == ctx->get_scheduler() );
+        BOOST_ASSERT( ctx->is_resumable() );
+        BOOST_ASSERT( ! ctx->worker_is_linked() );
         BOOST_ASSERT( ! ctx->ready_is_linked() );
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+        BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
+#endif
         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->wait_is_linked() );
+        BOOST_ASSERT( ctx->wait_queue_.empty() );
+        BOOST_ASSERT( ctx->terminated_);
         // 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
@@ -56,11 +50,16 @@ scheduler::release_terminated_() noexcept {
 #if ! defined(BOOST_FIBERS_NO_ATOMICS)
 void
 scheduler::remote_ready2ready_() noexcept {
-    context * ctx = nullptr;
+    remote_ready_queue_type tmp;
+    detail::spinlock_lock lk{ remote_ready_splk_ };
+    remote_ready_queue_.swap( tmp);
+    lk.unlock();
     // get context from remote ready-queue
-    while ( nullptr != ( ctx = remote_ready_queue_.pop() ) ) {
+    while ( ! tmp.empty() ) {
+        context * ctx = & tmp.front();
+        tmp.pop_front();
         // store context in local queues
-        set_ready( ctx);
+        schedule( ctx);
     }
 }
 #endif
@@ -70,18 +69,20 @@ scheduler::sleep2ready_() noexcept {
     // move context which the deadline has reached
     // to ready-queue
     // sleep-queue is sorted (ascending)
-    std::chrono::steady_clock::time_point now =
-        std::chrono::steady_clock::now();
-    sleep_queue_t::iterator e = sleep_queue_.end();
-    for ( sleep_queue_t::iterator i = sleep_queue_.begin(); i != e;) {
+    std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
+    sleep_queue_type::iterator e = sleep_queue_.end();
+    for ( sleep_queue_type::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( ! ctx->is_terminated() );
+        BOOST_ASSERT( main_ctx_ == ctx || ctx->worker_is_linked() );
         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()
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+        BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
+#endif
+        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
@@ -104,6 +105,13 @@ scheduler::~scheduler() {
     BOOST_ASSERT( nullptr != main_ctx_);
     BOOST_ASSERT( nullptr != dispatcher_ctx_.get() );
     BOOST_ASSERT( context::active() == main_ctx_);
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+    // protect for concurrent access
+    // required because main-context might have been
+    // signaled from remote and algorithm::notify()
+    // must be called fro mremote too
+    detail::spinlock_lock lk{ remote_ready_splk_ };
+#endif
     // signal dispatcher-context termination
     shutdown_ = true;
     // resume pending fibers
@@ -112,8 +120,6 @@ scheduler::~scheduler() {
     // no context' in worker-queue
     BOOST_ASSERT( worker_queue_.empty() );
     BOOST_ASSERT( terminated_queue_.empty() );
-#if ! defined(BOOST_FIBERS_NO_ATOMICS)
-#endif
     BOOST_ASSERT( sleep_queue_.empty() );
     // set active context to nullptr
     context::reset_active();
@@ -127,17 +133,12 @@ scheduler::~scheduler() {
 #if (BOOST_EXECUTION_CONTEXT==1)
 void
 scheduler::dispatch() noexcept {
-#else
-boost::context::execution_context< detail::data_t * >
-scheduler::dispatch() noexcept {
-#endif
     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;
             }
         }
@@ -150,8 +151,18 @@ scheduler::dispatch() noexcept {
         // get sleeping context'
         sleep2ready_();
         // get next ready context
-        context * ctx = get_next_();
+        context * ctx = algo_->pick_next();
         if ( nullptr != ctx) {
+            BOOST_ASSERT( ctx->is_resumable() );
+            BOOST_ASSERT( ! ctx->ready_is_linked() );
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+            BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
+#endif
+            BOOST_ASSERT( ! ctx->sleep_is_linked() );
+            BOOST_ASSERT( ! ctx->terminated_is_linked() );
+            // no test for '! ctx->wait_is_linked()' because
+            // context is registered in wait-queue of sync. primitives
+            // via wait_for()/wait_until()
             // push dispatcher-context to ready-queue
             // so that ready-queue never becomes empty
             ctx->resume( dispatcher_ctx_.get() );
@@ -162,7 +173,7 @@ scheduler::dispatch() noexcept {
             std::chrono::steady_clock::time_point suspend_time =
                     (std::chrono::steady_clock::time_point::max)();
             // get lowest deadline from sleep-queue
-            sleep_queue_t::iterator i = sleep_queue_.begin();
+            sleep_queue_type::iterator i = sleep_queue_.begin();
             if ( sleep_queue_.end() != i) {
                 suspend_time = i->tp_;
             }
@@ -173,47 +184,104 @@ scheduler::dispatch() noexcept {
     // release termianted context'
     release_terminated_();
     // return to main-context
-#if (BOOST_EXECUTION_CONTEXT==1)
     main_ctx_->resume();
+}
 #else
-    return main_ctx_->suspend_with_cc();
+boost::context::continuation
+scheduler::dispatch() noexcept {
+    BOOST_ASSERT( context::active() == dispatcher_ctx_);
+    for (;;) {
+        if ( shutdown_) {
+            // notify sched-algorithm about termination
+            algo_->notify();
+            if ( worker_queue_.empty() ) {
+                break;
+            }
+        }
+        // release terminated context'
+        release_terminated_();
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+        // get context' from remote ready-queue
+        remote_ready2ready_();
+#endif
+        // get sleeping context'
+        sleep2ready_();
+        // get next ready context
+        context * ctx = algo_->pick_next();
+        if ( nullptr != ctx) {
+            BOOST_ASSERT( ctx->is_resumable() );
+            BOOST_ASSERT( ! ctx->ready_is_linked() );
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+            BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
 #endif
+            BOOST_ASSERT( ! ctx->sleep_is_linked() );
+            BOOST_ASSERT( ! ctx->terminated_is_linked() );
+            // no test for '! ctx->wait_is_linked()' because
+            // context is registered in wait-queue of sync. primitives
+            // via wait_for()/wait_until()
+            // push dispatcher-context to ready-queue
+            // so that ready-queue never becomes empty
+            ctx->resume( dispatcher_ctx_.get() );
+            BOOST_ASSERT( context::active() == dispatcher_ctx_.get() );
+        } else {
+            // no ready context, wait till signaled
+            // set deadline to highest value
+            std::chrono::steady_clock::time_point suspend_time =
+                    (std::chrono::steady_clock::time_point::max)();
+            // get lowest deadline from sleep-queue
+            sleep_queue_type::iterator i = sleep_queue_.begin();
+            if ( sleep_queue_.end() != i) {
+                suspend_time = i->tp_;
+            }
+            // no ready context, wait till signaled
+            algo_->suspend_until( suspend_time);
+        }
+    }
+    // release termianted context'
+    release_terminated_();
+    // return to main-context
+    return main_ctx_->suspend_with_cc();
 }
+#endif
 
 void
-scheduler::set_ready( context * ctx) noexcept {
+scheduler::schedule( 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() );
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+    BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
+#endif
+    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() ) {
         // unlink it from sleep-queue
         ctx->sleep_unlink();
     }
-    // for safety unlink it from ready-queue
-    ctx->ready_unlink();
     // push new context to ready-queue
     algo_->awakened( ctx);
 }
 
 #if ! defined(BOOST_FIBERS_NO_ATOMICS)
 void
-scheduler::set_remote_ready( context * ctx) noexcept {
+scheduler::schedule_from_remote( 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->ready_is_linked() );
+    BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
+    BOOST_ASSERT( ! ctx->sleep_is_linked() );
+    BOOST_ASSERT( ! ctx->terminated_is_linked() );
+    BOOST_ASSERT( ! ctx->wait_is_linked() );
+    // protect for concurrent access
+    detail::spinlock_lock lk{ remote_ready_splk_ };
+    BOOST_ASSERT( ! shutdown_);
+    BOOST_ASSERT( nullptr != main_ctx_);
+    BOOST_ASSERT( nullptr != dispatcher_ctx_.get() );
     // push new context to remote ready-queue
-    remote_ready_queue_.push( ctx);
+    ctx->remote_ready_link( remote_ready_queue_);
     // notify scheduler
     algo_->notify();
 }
@@ -221,105 +289,118 @@ scheduler::set_remote_ready( context * ctx) noexcept {
 
 #if (BOOST_EXECUTION_CONTEXT==1)
 void
-scheduler::set_terminated( context * active_ctx) noexcept {
-#else
-boost::context::execution_context< detail::data_t * >
-scheduler::set_terminated( context * active_ctx) noexcept {
+scheduler::terminate( detail::spinlock_lock & lk, context * ctx) noexcept {
+    BOOST_ASSERT( nullptr != ctx);
+    BOOST_ASSERT( context::active() == ctx);
+    BOOST_ASSERT( this == ctx->get_scheduler() );
+    BOOST_ASSERT( ctx->is_context( type::worker_context) );
+    BOOST_ASSERT( ! ctx->is_context( type::pinned_context) );
+    BOOST_ASSERT( ! ctx->ready_is_linked() );
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+    BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
 #endif
-    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() );
+    BOOST_ASSERT( ! ctx->sleep_is_linked() );
+    BOOST_ASSERT( ! ctx->terminated_is_linked() );
+    BOOST_ASSERT( ! ctx->wait_is_linked() );
+    BOOST_ASSERT( ctx->wait_queue_.empty() );
     // 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();
+    // release lock
+    lk.unlock();
     // resume another fiber
-#if (BOOST_EXECUTION_CONTEXT==1)
-    get_next_()->resume();
+    algo_->pick_next()->resume();
+}
 #else
-    return get_next_()->suspend_with_cc();
+boost::context::continuation
+scheduler::terminate( detail::spinlock_lock & lk, context * ctx) noexcept {
+    BOOST_ASSERT( nullptr != ctx);
+    BOOST_ASSERT( context::active() == ctx);
+    BOOST_ASSERT( this == ctx->get_scheduler() );
+    BOOST_ASSERT( ctx->is_context( type::worker_context) );
+    BOOST_ASSERT( ! ctx->is_context( type::pinned_context) );
+    BOOST_ASSERT( ! ctx->ready_is_linked() );
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+    BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
 #endif
+    BOOST_ASSERT( ! ctx->sleep_is_linked() );
+    BOOST_ASSERT( ! ctx->terminated_is_linked() );
+    BOOST_ASSERT( ! ctx->wait_is_linked() );
+    BOOST_ASSERT( ctx->wait_queue_.empty() );
+    // store the terminated fiber in the terminated-queue
+    // the dispatcher-context will call
+    // intrusive_ptr_release( ctx);
+    ctx->terminated_link( terminated_queue_);
+    // remove from the worker-queue
+    ctx->worker_unlink();
+    // release lock
+    lk.unlock();
+    // 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->ready_is_linked() );
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+    BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
+#endif
+    BOOST_ASSERT( ! ctx->sleep_is_linked() );
+    BOOST_ASSERT( ! ctx->terminated_is_linked() );
+    BOOST_ASSERT( ! ctx->wait_is_linked() );
     // resume another fiber
-    get_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->ready_is_linked() );
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+    BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
+#endif
+    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
-    get_next_()->resume();
+    algo_->pick_next()->resume();
     // context has been resumed
     // check if deadline has reached
     return std::chrono::steady_clock::now() < sleep_tp;
 }
 
 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->ready_is_linked() );
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+    BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
+#endif
+    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
-    get_next_()->resume( lk);
+    algo_->pick_next()->resume( lk);
     // context has been resumed
     // check if deadline has reached
     return std::chrono::steady_clock::now() < sleep_tp;
@@ -328,13 +409,13 @@ scheduler::wait_until( context * active_ctx,
 void
 scheduler::suspend() noexcept {
     // resume another context
-    get_next_()->resume();
+    algo_->pick_next()->resume();
 }
 
 void
 scheduler::suspend( detail::spinlock_lock & lk) noexcept {
     // resume another context
-    get_next_()->resume( lk);
+    algo_->pick_next()->resume( lk);
 }
 
 bool
@@ -352,77 +433,64 @@ 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;
-#if ! defined(BOOST_FIBERS_NO_ATOMICS)
-    main_ctx_->scheduler_.store( this, std::memory_order_relaxed);
-#else
+    main_ctx_ = ctx;
     main_ctx_->scheduler_ = this;
-#endif
 }
 
 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
     // the dispatcher-context is resumed and
     // scheduler::dispatch() is executed
-#if ! defined(BOOST_FIBERS_NO_ATOMICS)
-    dispatcher_ctx_->scheduler_.store( this, std::memory_order_relaxed);
-#else
     dispatcher_ctx_->scheduler_ = this;
-#endif
     algo_->awakened( dispatcher_ctx_.get() );
 }
 
 void
 scheduler::attach_worker_context( context * ctx) noexcept {
     BOOST_ASSERT( nullptr != ctx);
+    BOOST_ASSERT( nullptr == ctx->get_scheduler() );
     BOOST_ASSERT( ! ctx->ready_is_linked() );
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+    BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
+#endif
     BOOST_ASSERT( ! ctx->sleep_is_linked() );
     BOOST_ASSERT( ! ctx->terminated_is_linked() );
     BOOST_ASSERT( ! ctx->wait_is_linked() );
     BOOST_ASSERT( ! ctx->worker_is_linked() );
-#if ! defined(BOOST_FIBERS_NO_ATOMICS)
-    std::atomic_thread_fence( std::memory_order_acquire);
-    BOOST_ASSERT( nullptr == ctx->scheduler_.load( std::memory_order_relaxed) );
-    ctx->scheduler_.store( this, std::memory_order_relaxed);
-#else
-    BOOST_ASSERT( nullptr == ctx->scheduler_);
-    ctx->scheduler_ = this;
-#endif
     ctx->worker_link( worker_queue_);
+    ctx->scheduler_ = this;
 }
 
 void
 scheduler::detach_worker_context( context * ctx) noexcept {
     BOOST_ASSERT( nullptr != ctx);
     BOOST_ASSERT( ! ctx->ready_is_linked() );
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
+    BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
+#endif
     BOOST_ASSERT( ! ctx->sleep_is_linked() );
     BOOST_ASSERT( ! ctx->terminated_is_linked() );
     BOOST_ASSERT( ! ctx->wait_is_linked() );
-    BOOST_ASSERT( ! ctx->wait_is_linked() );
+    BOOST_ASSERT( ctx->worker_is_linked() );
     BOOST_ASSERT( ! ctx->is_context( type::pinned_context) );
     ctx->worker_unlink();
-#if ! defined(BOOST_FIBERS_NO_ATOMICS)
-    ctx->scheduler_.store( nullptr, std::memory_order_relaxed);
-    std::atomic_thread_fence( std::memory_order_release);
-#else
     ctx->scheduler_ = nullptr;
-#endif
 }
 
 }}