]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/boost/libs/fiber/src/context.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / fiber / src / context.cpp
index 14b8fb4dbaedc32e83d0eceff0fd79ab0f863740..b2fed9bea896303c2de73eb0d9ab1e75dcf18862 100644 (file)
 namespace boost {
 namespace fibers {
 
-static intrusive_ptr< context > make_dispatcher_context( scheduler * sched) {
-    BOOST_ASSERT( nullptr != sched);
+class main_context final : public context {
+public:
+    main_context() noexcept :
+        context{ 1, type::main_context, launch::post } {
+    }
+};
+
+class dispatcher_context final : public context {
+private:
+    boost::context::continuation
+    run_( boost::context::continuation && c) {
+        c.resume();
+               // execute scheduler::dispatch()
+               return get_scheduler()->dispatch();
+    }
+
+public:
+    dispatcher_context( boost::context::preallocated const& palloc, default_stack const& salloc) :
+        context{ 0, type::dispatcher_context, launch::post } {
+        c_ = boost::context::callcc(
+                std::allocator_arg, palloc, salloc,
+                std::bind( & dispatcher_context::run_, this, std::placeholders::_1) );
+    }
+};
+
+static intrusive_ptr< context > make_dispatcher_context() {
     default_stack salloc; // use default satck-size
-    boost::context::stack_context sctx = salloc.allocate();
-#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
+    auto sctx = salloc.allocate();
     // reserve space for control structure
-    const std::size_t size = sctx.size - sizeof( context);
-    void * sp = static_cast< char * >( sctx.sp) - sizeof( context);
-#else
-    constexpr std::size_t func_alignment = 64; // alignof( context);
-    constexpr std::size_t func_size = sizeof( context);
-    // reserve space on stack
-    void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
-    // align sp pointer
-    std::size_t space = func_size + func_alignment;
-    sp = std::align( func_alignment, func_size, sp, space);
-    BOOST_ASSERT( nullptr != sp);
-    // calculate remaining size
-    const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
-#endif
+    void * storage = reinterpret_cast< void * >(
+            ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( dispatcher_context) ) )
+            & ~ static_cast< uintptr_t >( 0xff) );
+    void * stack_bottom = reinterpret_cast< void * >(
+            reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) );
+    const std::size_t size = reinterpret_cast< uintptr_t >( storage) - reinterpret_cast< uintptr_t >( stack_bottom);
     // placement new of context on top of fiber's stack
-    return intrusive_ptr< context >( 
-        ::new ( sp) context(
-                dispatcher_context,
-                boost::context::preallocated( sp, size, sctx),
-                salloc,
-                sched) );
+    return intrusive_ptr< context >{
+        new ( storage) dispatcher_context{
+                boost::context::preallocated{ storage, size, sctx }, salloc } };
 }
 
 // schwarz counter
@@ -56,58 +68,16 @@ struct context_initializer {
 
     context_initializer() {
         if ( 0 == counter_++) {
-# if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
-            // allocate memory for main context and scheduler
-            constexpr std::size_t size = sizeof( context) + sizeof( scheduler);
-            void * vp = std::malloc( size);
-            if ( nullptr == vp) {
-                throw std::bad_alloc();
-            }
             // main fiber context of this thread
-            context * main_ctx = ::new ( vp) context( main_context);
+            context * main_ctx = new main_context{};
             // scheduler of this thread
-            scheduler * sched = ::new ( static_cast< char * >( vp) + sizeof( context) ) scheduler();
+            scheduler * sched = new scheduler{};
             // attach main context to scheduler
             sched->attach_main_context( main_ctx);
             // create and attach dispatcher context to scheduler
-            sched->attach_dispatcher_context(
-                    make_dispatcher_context( sched) );
+            sched->attach_dispatcher_context( make_dispatcher_context() );
             // make main context to active context
             active_ = main_ctx;
-# else
-            constexpr std::size_t alignment = 64; // alignof( capture_t);
-            constexpr std::size_t ctx_size = sizeof( context);
-            constexpr std::size_t sched_size = sizeof( scheduler);
-            constexpr std::size_t size = 2 * alignment + ctx_size + sched_size;
-            void * vp = std::malloc( size);
-            if ( nullptr == vp) {
-                throw std::bad_alloc();
-            }
-            // reserve space for shift
-            void * vp1 = static_cast< char * >( vp) + sizeof( int); 
-            // align context pointer
-            std::size_t space = ctx_size + alignment;
-            vp1 = std::align( alignment, ctx_size, vp1, space);
-            // reserves space for integer holding shifted size
-            int * shift = reinterpret_cast< int * >( static_cast< char * >( vp1) - sizeof( int) );
-            // store shifted size in fornt of context
-            * shift = static_cast< char * >( vp1) - static_cast< char * >( vp);
-            // main fiber context of this thread
-            context * main_ctx = ::new ( vp1) context( main_context);
-            vp1 = static_cast< char * >( vp1) + ctx_size;
-            // align scheduler pointer
-            space = sched_size + alignment;
-            vp1 = std::align( alignment, sched_size, vp1, space);
-            // scheduler of this thread
-            scheduler * sched = ::new ( vp1) scheduler();
-            // attach main context to scheduler
-            sched->attach_main_context( main_ctx);
-            // create and attach dispatcher context to scheduler
-            sched->attach_dispatcher_context(
-                    make_dispatcher_context( sched) );
-            // make main context to active context
-            active_ = main_ctx;
-# endif
         }
     }
 
@@ -116,29 +86,18 @@ struct context_initializer {
             context * main_ctx = active_;
             BOOST_ASSERT( main_ctx->is_context( type::main_context) );
             scheduler * sched = main_ctx->get_scheduler();
-            sched->~scheduler();
-            main_ctx->~context();
-# if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
-            std::free( main_ctx);
-# else
-            int * shift = reinterpret_cast< int * >( reinterpret_cast< char * >( main_ctx) - sizeof( int) );
-            void * vp = reinterpret_cast< char * >( main_ctx) - ( * shift);
-            std::free( vp);
-# endif
+            delete sched;
+            delete main_ctx;
         }
     }
 };
 
 // zero-initialization
-thread_local context * context_initializer::active_;
-thread_local std::size_t context_initializer::counter_;
+thread_local context * context_initializer::active_{ nullptr };
+thread_local std::size_t context_initializer::counter_{ 0 };
 
 context *
 context::active() noexcept {
-#if (BOOST_EXECUTION_CONTEXT==1)
-    // initialized the first time control passes; per thread
-    thread_local static boost::context::detail::activation_record_initializer rec_initializer;
-#endif
     // initialized the first time control passes; per thread
     thread_local static context_initializer ctx_initializer;
     return context_initializer::active_;
@@ -149,100 +108,32 @@ context::reset_active() noexcept {
     context_initializer::active_ = nullptr;
 }
 
-#if (BOOST_EXECUTION_CONTEXT==1)
-void
-context::resume_( detail::data_t & d) noexcept {
-    detail::data_t * dp = static_cast< detail::data_t * >( ctx_( & d) );
-    if ( nullptr != dp->lk) {
-        dp->lk->unlock();
-    } else if ( nullptr != dp->ctx) {
-        context_initializer::active_->set_ready_( dp->ctx);
-    }
-}
-#else
-void
-context::resume_( detail::data_t & d) noexcept {
-    auto result = ctx_( & d);
-    detail::data_t * dp( std::get< 1 >( result) );
-    if ( nullptr != dp) {
-        dp->from->ctx_ = std::move( std::get< 0 >( result) );
-        if ( nullptr != dp->lk) {
-            dp->lk->unlock();
-        } else if ( nullptr != dp->ctx) {
-            context_initializer::active_->set_ready_( dp->ctx);
-        }
-    }
-}
-#endif
-
-void
-context::set_ready_( context * ctx) noexcept {
-    scheduler_->set_ready( ctx);
-}
-
-// main fiber context
-context::context( main_context_t) noexcept :
-    use_count_{ 1 }, // allocated on main- or thread-stack
-    flags_{ 0 },
-    type_{ type::main_context },
-#if (BOOST_EXECUTION_CONTEXT==1)
-    ctx_{ boost::context::execution_context::current() } {
-#else
-    ctx_{} {
-#endif
-}
-
-// dispatcher fiber context
-context::context( dispatcher_context_t, boost::context::preallocated const& palloc,
-                  default_stack const& salloc, scheduler * sched) :
-    flags_{ 0 },
-    type_{ type::dispatcher_context },
-#if (BOOST_EXECUTION_CONTEXT==1)
-    ctx_{ std::allocator_arg, palloc, salloc,
-          [this,sched](void * vp) noexcept {
-              detail::data_t * dp = static_cast< detail::data_t * >( vp);
-            if ( nullptr != dp->lk) {
-                dp->lk->unlock();
-            } else if ( nullptr != dp->ctx) {
-                context_initializer::active_->set_ready_( dp->ctx);
-            }
-            // execute scheduler::dispatch()
-            sched->dispatch();
-            // dispatcher context should never return from scheduler::dispatch()
-            BOOST_ASSERT_MSG( false, "disatcher fiber already terminated");
-          }}
-#else
-    ctx_{ std::allocator_arg, palloc, salloc,
-          [this,sched](boost::context::execution_context< detail::data_t * > ctx, detail::data_t * dp) noexcept {
-            // update execution_context of calling fiber
-            dp->from->ctx_ = std::move( ctx);
-            if ( nullptr != dp->lk) {
-                dp->lk->unlock();
-            } else if ( nullptr != dp->ctx) {
-                context_initializer::active_->set_ready_( dp->ctx);
-            }
-            // execute scheduler::dispatch()
-            return sched->dispatch();
-          }}
-#endif
-{}
-
 context::~context() {
-    BOOST_ASSERT( wait_queue_.empty() );
+    // protect for concurrent access
+    std::unique_lock< detail::spinlock > lk{ splk_ };
     BOOST_ASSERT( ! ready_is_linked() );
+    BOOST_ASSERT( ! remote_ready_is_linked() );
     BOOST_ASSERT( ! sleep_is_linked() );
     BOOST_ASSERT( ! wait_is_linked() );
+    if ( is_context( type::dispatcher_context) ) {
+        // dispatcher-context is resumed by main-context
+        // while the scheduler is deconstructed
+#ifdef BOOST_DISABLE_ASSERTS
+        wait_queue_.pop_front();
+#else
+        context * ctx = & wait_queue_.front();
+        wait_queue_.pop_front();
+        BOOST_ASSERT( ctx->is_context( type::main_context) );
+        BOOST_ASSERT( nullptr == active() );
+#endif
+    }
+    BOOST_ASSERT( wait_queue_.empty() );
     delete properties_;
 }
 
-scheduler *
-context::get_scheduler() const noexcept {
-    return scheduler_;
-}
-
 context::id
 context::get_id() const noexcept {
-    return id( const_cast< context * >( this) );
+    return id{ const_cast< context * >( this) };
 }
 
 void
@@ -251,12 +142,11 @@ context::resume() noexcept {
     // context_initializer::active_ will point to `this`
     // prev will point to previous active context
     std::swap( context_initializer::active_, prev);
-#if (BOOST_EXECUTION_CONTEXT==1)
-    detail::data_t d{};
-#else
-    detail::data_t d{ prev };
-#endif
-    resume_( d);
+    // pass pointer to the context that resumes `this`
+    c_.resume_with([prev](boost::context::continuation && c){
+                prev->c_ = std::move( c);
+                return boost::context::continuation{};
+            });
 }
 
 void
@@ -265,12 +155,12 @@ context::resume( detail::spinlock_lock & lk) noexcept {
     // context_initializer::active_ will point to `this`
     // prev will point to previous active context
     std::swap( context_initializer::active_, prev);
-#if (BOOST_EXECUTION_CONTEXT==1)
-    detail::data_t d{ & lk };
-#else
-    detail::data_t d{ & lk, prev };
-#endif
-    resume_( d);
+    // pass pointer to the context that resumes `this`
+    c_.resume_with([prev,&lk](boost::context::continuation && c){
+                prev->c_ = std::move( c);
+                lk.unlock();
+                return boost::context::continuation{};
+            });
 }
 
 void
@@ -279,22 +169,22 @@ context::resume( context * ready_ctx) noexcept {
     // context_initializer::active_ will point to `this`
     // prev will point to previous active context
     std::swap( context_initializer::active_, prev);
-#if (BOOST_EXECUTION_CONTEXT==1)
-    detail::data_t d{ ready_ctx };
-#else
-    detail::data_t d{ ready_ctx, prev };
-#endif
-    resume_( d);
+    // pass pointer to the context that resumes `this`
+    c_.resume_with([prev,ready_ctx](boost::context::continuation && c){
+                prev->c_ = std::move( c);
+                context::active()->schedule( ready_ctx);
+                return boost::context::continuation{};
+            });
 }
 
 void
 context::suspend() noexcept {
-    scheduler_->suspend();
+    get_scheduler()->suspend();
 }
 
 void
 context::suspend( detail::spinlock_lock & lk) noexcept {
-    scheduler_->suspend( lk);
+    get_scheduler()->suspend( lk);
 }
 
 void
@@ -302,18 +192,15 @@ context::join() {
     // get active context
     context * active_ctx = context::active();
     // protect for concurrent access
-    std::unique_lock< detail::spinlock > lk( splk_);
+    std::unique_lock< detail::spinlock > lk{ splk_ };
     // wait for context which is not terminated
-    if ( 0 == ( flags_ & flag_terminated) ) {
+    if ( ! terminated_) {
         // push active context to wait-queue, member
         // of the context which has to be joined by
         // the active context
         active_ctx->wait_link( wait_queue_);
-        lk.unlock();
         // suspend active context
-        scheduler_->suspend();
-        // remove from wait-queue
-        active_ctx->wait_unlink();
+        active_ctx->get_scheduler()->suspend( lk);
         // active context resumed
         BOOST_ASSERT( context::active() == active_ctx);
     }
@@ -322,91 +209,88 @@ context::join() {
 void
 context::yield() noexcept {
     // yield active context
-    scheduler_->yield( context::active() );
+    get_scheduler()->yield( context::active() );
 }
 
-#if (BOOST_EXECUTION_CONTEXT>1)
-boost::context::execution_context< detail::data_t * >
+boost::context::continuation
 context::suspend_with_cc() noexcept {
     context * prev = this;
     // context_initializer::active_ will point to `this`
     // prev will point to previous active context
     std::swap( context_initializer::active_, prev);
-    detail::data_t d{ prev };
-    // context switch
-    return std::move( std::get< 0 >( ctx_( & d) ) );
+    // pass pointer to the context that resumes `this`
+    return c_.resume_with([prev](boost::context::continuation && c){
+                prev->c_ = std::move( c);
+                return boost::context::continuation{};
+            });
 }
-#endif
 
-#if (BOOST_EXECUTION_CONTEXT==1)
-void
-#else
-boost::context::execution_context< detail::data_t * >
-#endif
-context::set_terminated() noexcept {
+boost::context::continuation
+context::terminate() noexcept {
     // protect for concurrent access
-    std::unique_lock< detail::spinlock > lk( splk_);
+    std::unique_lock< detail::spinlock > lk{ splk_ };
     // mark as terminated
-    flags_ |= flag_terminated;
+    terminated_ = true;
     // notify all waiting fibers
     while ( ! wait_queue_.empty() ) {
         context * ctx = & wait_queue_.front();
         // remove fiber from wait-queue
         wait_queue_.pop_front();
         // notify scheduler
-        set_ready( ctx);
+        schedule( ctx);
     }
-    lk.unlock();
+    BOOST_ASSERT( wait_queue_.empty() );
     // release fiber-specific-data
     for ( fss_data_t::value_type & data : fss_data_) {
         data.second.do_cleanup();
     }
     fss_data_.clear();
     // switch to another context
-#if (BOOST_EXECUTION_CONTEXT==1)
-    scheduler_->set_terminated( this);
-#else
-    return scheduler_->set_terminated( this);
-#endif
+    return get_scheduler()->terminate( lk, this);
 }
 
 bool
 context::wait_until( std::chrono::steady_clock::time_point const& tp) noexcept {
-    BOOST_ASSERT( nullptr != scheduler_ );
-    BOOST_ASSERT( this == context_initializer::active_);
-    return scheduler_->wait_until( this, tp);
+    BOOST_ASSERT( nullptr != get_scheduler() );
+    BOOST_ASSERT( this == active() );
+    return get_scheduler()->wait_until( this, tp);
 }
 
 bool
 context::wait_until( std::chrono::steady_clock::time_point const& tp,
                      detail::spinlock_lock & lk) noexcept {
-    BOOST_ASSERT( nullptr != scheduler_ );
-    BOOST_ASSERT( this == context_initializer::active_);
-    return scheduler_->wait_until( this, tp, lk);
+    BOOST_ASSERT( nullptr != get_scheduler() );
+    BOOST_ASSERT( this == active() );
+    return get_scheduler()->wait_until( this, tp, lk);
 }
 
 void
-context::set_ready( context * ctx) noexcept {
+context::schedule( context * ctx) noexcept {
     //BOOST_ASSERT( nullptr != ctx);
     BOOST_ASSERT( this != ctx);
-    BOOST_ASSERT( nullptr != scheduler_ );
-    BOOST_ASSERT( nullptr != ctx->scheduler_ );
+    BOOST_ASSERT( nullptr != get_scheduler() );
+    BOOST_ASSERT( nullptr != ctx->get_scheduler() );
+#if ! defined(BOOST_FIBERS_NO_ATOMICS)
     // FIXME: comparing scheduler address' must be synchronized?
     //        what if ctx is migrated between threads
     //        (other scheduler assigned)
-    if ( scheduler_ == ctx->scheduler_ ) {
+    if ( scheduler_ == ctx->get_scheduler() ) {
         // local
-        scheduler_->set_ready( ctx);
+        get_scheduler()->schedule( ctx);
     } else {
         // remote
-        ctx->scheduler_->set_remote_ready( ctx);
+        ctx->get_scheduler()->schedule_from_remote( ctx);
     }
+#else
+    BOOST_ASSERT( get_scheduler() == ctx->get_scheduler() );
+    get_scheduler()->schedule( ctx);
+#endif
 }
 
 void *
 context::get_fss_data( void const * vp) const {
-    uintptr_t key( reinterpret_cast< uintptr_t >( vp) );
-    fss_data_t::const_iterator i( fss_data_.find( key) );
+    uintptr_t key = reinterpret_cast< uintptr_t >( vp);
+    fss_data_t::const_iterator i = fss_data_.find( key);
     return fss_data_.end() != i ? i->second.vp : nullptr;
 }
 
@@ -416,8 +300,8 @@ context::set_fss_data( void const * vp,
                        void * data,
                        bool cleanup_existing) {
     BOOST_ASSERT( cleanup_fn);
-    uintptr_t key( reinterpret_cast< uintptr_t >( vp) );
-    fss_data_t::iterator i( fss_data_.find( key) );
+    uintptr_t key = reinterpret_cast< uintptr_t >( vp);
+    fss_data_t::iterator i = fss_data_.find( key);
     if ( fss_data_.end() != i) {
         if( cleanup_existing) {
             i->second.do_cleanup();
@@ -427,7 +311,7 @@ context::set_fss_data( void const * vp,
                     i,
                     std::make_pair(
                         key,
-                        fss_data( data, cleanup_fn) ) );
+                        fss_data{ data, cleanup_fn } ) );
         } else {
             fss_data_.erase( i);
         }
@@ -435,7 +319,7 @@ context::set_fss_data( void const * vp,
         fss_data_.insert(
             std::make_pair(
                 key,
-                fss_data( data, cleanup_fn) ) );
+                fss_data{ data, cleanup_fn } ) );
     }
 }
 
@@ -451,13 +335,13 @@ context::worker_is_linked() const noexcept {
 }
 
 bool
-context::terminated_is_linked() const noexcept {
-    return terminated_hook_.is_linked();
+context::ready_is_linked() const noexcept {
+    return ready_hook_.is_linked();
 }
 
 bool
-context::ready_is_linked() const noexcept {
-    return ready_hook_.is_linked();
+context::remote_ready_is_linked() const noexcept {
+    return remote_ready_hook_.is_linked();
 }
 
 bool
@@ -465,6 +349,11 @@ context::sleep_is_linked() const noexcept {
     return sleep_hook_.is_linked();
 }
 
+bool
+context::terminated_is_linked() const noexcept {
+    return terminated_hook_.is_linked();
+}
+
 bool
 context::wait_is_linked() const noexcept {
     return wait_hook_.is_linked();
@@ -472,34 +361,38 @@ context::wait_is_linked() const noexcept {
 
 void
 context::worker_unlink() noexcept {
+    BOOST_ASSERT( worker_is_linked() );
     worker_hook_.unlink();
 }
 
 void
 context::ready_unlink() noexcept {
+    BOOST_ASSERT( ready_is_linked() );
     ready_hook_.unlink();
 }
 
 void
 context::sleep_unlink() noexcept {
+    BOOST_ASSERT( sleep_is_linked() );
     sleep_hook_.unlink();
 }
 
 void
 context::wait_unlink() noexcept {
+    BOOST_ASSERT( wait_is_linked() );
     wait_hook_.unlink();
 }
 
 void
 context::detach() noexcept {
     BOOST_ASSERT( context::active() != this);
-    scheduler_->detach_worker_context( this);
+    get_scheduler()->detach_worker_context( this);
 }
 
 void
 context::attach( context * ctx) noexcept {
     BOOST_ASSERT( nullptr != ctx);
-    scheduler_->attach_worker_context( ctx);
+    get_scheduler()->attach_worker_context( ctx);
 }
 
 }}