Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:37:39

0001 
0002 //          Copyright Oliver Kowalke 2013.
0003 // Distributed under the Boost Software License, Version 1.0.
0004 //    (See accompanying file LICENSE_1_0.txt or copy at
0005 //          http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 #ifndef BOOST_FIBERS_CONTEXT_H
0008 #define BOOST_FIBERS_CONTEXT_H
0009 
0010 #include <atomic>
0011 #include <chrono>
0012 #include <cstdint>
0013 #include <exception>
0014 #include <functional>
0015 #include <iostream>
0016 #include <map>
0017 #include <memory>
0018 #include <tuple>
0019 #include <type_traits>
0020 #include <utility>
0021 
0022 #include <boost/assert.hpp>
0023 #include <boost/config.hpp>
0024 #include <boost/core/ignore_unused.hpp>
0025 #if defined(BOOST_NO_CXX17_STD_APPLY)
0026 #include <boost/context/detail/apply.hpp>
0027 #endif
0028 #include <boost/context/fiber.hpp>
0029 #include <boost/context/stack_context.hpp>
0030 #include <boost/intrusive/list.hpp>
0031 #include <boost/intrusive/parent_from_member.hpp>
0032 #include <boost/intrusive_ptr.hpp>
0033 #include <boost/intrusive/set.hpp>
0034 #include <boost/intrusive/slist.hpp>
0035 
0036 #include <boost/fiber/detail/config.hpp>
0037 #include <boost/fiber/detail/data.hpp>
0038 #include <boost/fiber/detail/decay_copy.hpp>
0039 #include <boost/fiber/detail/fss.hpp>
0040 #include <boost/fiber/detail/spinlock.hpp>
0041 #include <boost/fiber/exceptions.hpp>
0042 #include <boost/fiber/fixedsize_stack.hpp>
0043 #include <boost/fiber/policy.hpp>
0044 #include <boost/fiber/properties.hpp>
0045 #include <boost/fiber/segmented_stack.hpp>
0046 #include <boost/fiber/type.hpp>
0047 #include <boost/fiber/waker.hpp>
0048 #include <boost/fiber/stack_allocator_wrapper.hpp>
0049 #include <boost/fiber/algo/algorithm.hpp>
0050 
0051 #ifdef BOOST_HAS_ABI_HEADERS
0052 #  include BOOST_ABI_PREFIX
0053 #endif
0054 
0055 #ifdef _MSC_VER
0056 # pragma warning(push)
0057 # pragma warning(disable:4251)
0058 #endif
0059 
0060 namespace boost {
0061 namespace fibers {
0062 
0063 class context;
0064 class fiber;
0065 class scheduler;
0066 
0067 namespace detail {
0068 
0069 struct ready_tag;
0070 typedef intrusive::list_member_hook<
0071     intrusive::tag< ready_tag >,
0072     intrusive::link_mode<
0073         intrusive::auto_unlink
0074     >
0075 >                                       ready_hook;
0076 
0077 struct sleep_tag;
0078 typedef intrusive::set_member_hook<
0079     intrusive::tag< sleep_tag >,
0080     intrusive::link_mode<
0081         intrusive::auto_unlink
0082     >
0083 >                                       sleep_hook;
0084 
0085 struct worker_tag;
0086 typedef intrusive::list_member_hook<
0087     intrusive::tag< worker_tag >,
0088     intrusive::link_mode<
0089         intrusive::auto_unlink
0090     >
0091 >                                       worker_hook;
0092 
0093 struct terminated_tag;
0094 typedef intrusive::slist_member_hook<
0095     intrusive::tag< terminated_tag >,
0096     intrusive::link_mode<
0097         intrusive::safe_link
0098     >
0099 >                                       terminated_hook;
0100 
0101 struct remote_ready_tag;
0102 typedef intrusive::slist_member_hook<
0103     intrusive::tag< remote_ready_tag >,
0104     intrusive::link_mode<
0105         intrusive::safe_link
0106     >
0107 >                                       remote_ready_hook;
0108 
0109 }
0110 
0111 class BOOST_FIBERS_DECL context {
0112 private:
0113     friend class dispatcher_context;
0114     friend class main_context;
0115     template< typename Fn, typename ... Arg > friend class worker_context;
0116     friend class scheduler;
0117 
0118     struct fss_data {
0119         void                                *   vp{ nullptr };
0120         detail::fss_cleanup_function::ptr_t     cleanup_function{};
0121 
0122         fss_data() = default;
0123 
0124         fss_data( void * vp_,
0125                   detail::fss_cleanup_function::ptr_t fn) noexcept :
0126             vp( vp_),
0127             cleanup_function(std::move( fn)) {
0128             BOOST_ASSERT( cleanup_function);
0129         }
0130 
0131         void do_cleanup() {
0132             ( * cleanup_function)( vp);
0133         }
0134     };
0135 
0136     typedef std::map< uintptr_t, fss_data >             fss_data_t;
0137 
0138 #if ! defined(BOOST_FIBERS_NO_ATOMICS)
0139     std::atomic< std::size_t >                          use_count_;
0140 #else
0141     std::size_t                                         use_count_;
0142 #endif
0143 #if ! defined(BOOST_FIBERS_NO_ATOMICS)
0144     detail::remote_ready_hook                           remote_ready_hook_{};
0145 #endif
0146     detail::spinlock                                    splk_{};
0147     bool                                                terminated_{ false };
0148     wait_queue                                          wait_queue_{};
0149 public:
0150 #if ! defined(BOOST_FIBERS_NO_ATOMICS)
0151     std::atomic<size_t>                                 waker_epoch_{ 0 };
0152 #endif
0153 private:
0154     scheduler                                       *   scheduler_{ nullptr };
0155     fss_data_t                                          fss_data_{};
0156     detail::sleep_hook                                  sleep_hook_{};
0157     waker                                               sleep_waker_{};
0158     detail::ready_hook                                  ready_hook_{};
0159     detail::terminated_hook                             terminated_hook_{};
0160     detail::worker_hook                                 worker_hook_{};
0161     fiber_properties                                *   properties_{ nullptr };
0162     boost::context::fiber                               c_{};
0163     std::chrono::steady_clock::time_point               tp_;
0164     type                                                type_;
0165     launch                                              policy_;
0166 
0167     context( std::size_t initial_count, type t, launch policy) noexcept :
0168         use_count_{ initial_count },
0169         tp_{ (std::chrono::steady_clock::time_point::max)() },
0170         type_{ t },
0171         policy_{ policy } {
0172     }
0173 
0174 public:
0175     class id {
0176     private:
0177         friend std::hash<id>;
0178         context  *   impl_{ nullptr };
0179 
0180     public:
0181         id() = default;
0182 
0183         explicit id( context * impl) noexcept :
0184             impl_{ impl } {
0185         }
0186 
0187         bool operator==( id const& other) const noexcept {
0188             return impl_ == other.impl_;
0189         }
0190 
0191         bool operator!=( id const& other) const noexcept {
0192             return impl_ != other.impl_;
0193         }
0194 
0195         bool operator<( id const& other) const noexcept {
0196             return impl_ < other.impl_;
0197         }
0198 
0199         bool operator>( id const& other) const noexcept {
0200             return other.impl_ < impl_;
0201         }
0202 
0203         bool operator<=( id const& other) const noexcept {
0204             return ! ( * this > other);
0205         }
0206 
0207         bool operator>=( id const& other) const noexcept {
0208             return ! ( * this < other);
0209         }
0210 
0211         template< typename charT, class traitsT >
0212         friend std::basic_ostream< charT, traitsT > &
0213         operator<<( std::basic_ostream< charT, traitsT > & os, id const& other) {
0214             if ( nullptr != other.impl_) {
0215                 return os << other.impl_;
0216             }
0217             return os << "{not-valid}";
0218         }
0219 
0220         explicit operator bool() const noexcept {
0221             return nullptr != impl_;
0222         }
0223 
0224         bool operator!() const noexcept {
0225             return nullptr == impl_;
0226         }
0227     };
0228 
0229     // Returns true if the thread could be initialize, false otherwise (it was already initialized previously).
0230     static bool initialize_thread(algo::algorithm::ptr_t algo, stack_allocator_wrapper&& salloc) noexcept;
0231 
0232     static context * active() noexcept;
0233 
0234     static void reset_active() noexcept;
0235 
0236     context( context const&) = delete;
0237     context( context &&) = delete;
0238     context & operator=( context const&) = delete;
0239     context & operator=( context &&) = delete;
0240 
0241     #if !defined(BOOST_EMBTC)
0242   
0243     friend bool
0244     operator==( context const& lhs, context const& rhs) noexcept {
0245         return & lhs == & rhs;
0246     }
0247 
0248     #else
0249   
0250     friend bool
0251     operator==( context const& lhs, context const& rhs) noexcept;
0252 
0253     #endif
0254       
0255     virtual ~context();
0256 
0257     scheduler * get_scheduler() const noexcept {
0258         return scheduler_;
0259     }
0260 
0261     id get_id() const noexcept;
0262 
0263     bool is_resumable() const noexcept {
0264         return static_cast<bool>(c_);
0265     }
0266 
0267     void resume() noexcept;
0268     void resume( detail::spinlock_lock &) noexcept;
0269     void resume( context *) noexcept;
0270 
0271     void suspend() noexcept;
0272     void suspend( detail::spinlock_lock &) noexcept;
0273 
0274     boost::context::fiber suspend_with_cc() noexcept;
0275     boost::context::fiber terminate() noexcept;
0276 
0277     void join();
0278 
0279     void yield() noexcept;
0280 
0281     bool wait_until( std::chrono::steady_clock::time_point const&) noexcept;
0282     bool wait_until( std::chrono::steady_clock::time_point const&,
0283                      detail::spinlock_lock &,
0284                      waker &&) noexcept;
0285 
0286     bool wake(const size_t) noexcept;
0287 
0288     waker create_waker() noexcept {
0289         // this operation makes all previously created wakers to be outdated
0290         return { this, ++waker_epoch_ };
0291     }
0292 
0293     void schedule( context *) noexcept;
0294 
0295     bool is_context( type t) const noexcept {
0296         return type::none != ( type_ & t);
0297     }
0298 
0299     void * get_fss_data( void const * vp) const;
0300 
0301     void set_fss_data(
0302         void const * vp,
0303         detail::fss_cleanup_function::ptr_t const& cleanup_fn,
0304         void * data,
0305         bool cleanup_existing);
0306 
0307     void set_properties( fiber_properties * props) noexcept;
0308 
0309     fiber_properties * get_properties() const noexcept {
0310         return properties_;
0311     }
0312 
0313     launch get_policy() const noexcept {
0314         return policy_;
0315     }
0316 
0317     bool worker_is_linked() const noexcept;
0318 
0319     bool ready_is_linked() const noexcept;
0320 
0321     bool remote_ready_is_linked() const noexcept;
0322 
0323     bool sleep_is_linked() const noexcept;
0324 
0325     bool terminated_is_linked() const noexcept;
0326 
0327     template< typename List >
0328     void worker_link( List & lst) noexcept {
0329         static_assert( std::is_same< typename List::value_traits::hook_type, detail::worker_hook >::value, "not a worker-queue");
0330         BOOST_ASSERT( ! worker_is_linked() );
0331         lst.push_back( * this);
0332     }
0333 
0334     template< typename List >
0335     void ready_link( List & lst) noexcept {
0336         static_assert( std::is_same< typename List::value_traits::hook_type, detail::ready_hook >::value, "not a ready-queue");
0337         BOOST_ASSERT( ! ready_is_linked() );
0338         lst.push_back( * this);
0339     }
0340 
0341     template< typename List >
0342     void remote_ready_link( List & lst) noexcept {
0343         static_assert( std::is_same< typename List::value_traits::hook_type, detail::remote_ready_hook >::value, "not a remote-ready-queue");
0344         BOOST_ASSERT( ! remote_ready_is_linked() );
0345         lst.push_back( * this);
0346     }
0347 
0348     template< typename Set >
0349     void sleep_link( Set & set) noexcept {
0350         static_assert( std::is_same< typename Set::value_traits::hook_type,detail::sleep_hook >::value, "not a sleep-queue");
0351         BOOST_ASSERT( ! sleep_is_linked() );
0352         set.insert( * this);
0353     }
0354 
0355     template< typename List >
0356     void terminated_link( List & lst) noexcept {
0357         static_assert( std::is_same< typename List::value_traits::hook_type, detail::terminated_hook >::value, "not a terminated-queue");
0358         BOOST_ASSERT( ! terminated_is_linked() );
0359         lst.push_back( * this);
0360     }
0361 
0362     void worker_unlink() noexcept;
0363 
0364     void ready_unlink() noexcept;
0365 
0366     void sleep_unlink() noexcept;
0367 
0368     void detach() noexcept;
0369 
0370     void attach( context *) noexcept;
0371 
0372     #if !defined(BOOST_EMBTC)
0373       
0374     friend void intrusive_ptr_add_ref( context * ctx) noexcept {
0375         BOOST_ASSERT( nullptr != ctx);
0376         ctx->use_count_.fetch_add( 1, std::memory_order_relaxed);
0377     }
0378 
0379     friend void intrusive_ptr_release( context * ctx) noexcept {
0380         BOOST_ASSERT( nullptr != ctx);
0381         if ( 1 == ctx->use_count_.fetch_sub( 1, std::memory_order_release) ) {
0382             std::atomic_thread_fence( std::memory_order_acquire);
0383             boost::context::fiber c = std::move( ctx->c_);
0384             // destruct context
0385             ctx->~context();
0386             // deallocated stack
0387             std::move( c).resume();
0388         }
0389     }
0390     
0391     #else
0392       
0393     friend void intrusive_ptr_add_ref( context * ctx) noexcept;
0394     friend void intrusive_ptr_release( context * ctx) noexcept;
0395     
0396     #endif
0397       
0398 };
0399 
0400 #if defined(BOOST_EMBTC)
0401 
0402     inline bool
0403     operator==( context const& lhs, context const& rhs) noexcept {
0404         return & lhs == & rhs;
0405     }
0406 
0407     inline void intrusive_ptr_add_ref( context * ctx) noexcept {
0408         BOOST_ASSERT( nullptr != ctx);
0409         ctx->use_count_.fetch_add( 1, std::memory_order_relaxed);
0410     }
0411 
0412     inline void intrusive_ptr_release( context * ctx) noexcept {
0413         BOOST_ASSERT( nullptr != ctx);
0414         if ( 1 == ctx->use_count_.fetch_sub( 1, std::memory_order_release) ) {
0415             std::atomic_thread_fence( std::memory_order_acquire);
0416             boost::context::fiber c = std::move( ctx->c_);
0417             // destruct context
0418             ctx->~context();
0419             // deallocated stack
0420             std::move( c).resume();
0421         }
0422     }
0423     
0424 #endif
0425     
0426 inline
0427 bool operator<( context const& l, context const& r) noexcept {
0428     return l.get_id() < r.get_id();
0429 }
0430 
0431 template< typename Fn, typename ... Arg >
0432 class worker_context final : public context {
0433 private:
0434     typename std::decay< Fn >::type                     fn_;
0435     std::tuple< Arg ... >                               arg_;
0436 
0437     boost::context::fiber
0438     run_( boost::context::fiber && c) {
0439         {
0440             // fn and tpl must be destroyed before calling terminate()
0441             auto fn = std::move( fn_);
0442             auto arg = std::move( arg_);
0443 #if (defined(BOOST_USE_UCONTEXT)||defined(BOOST_USE_WINFIB))
0444             std::move( c).resume();
0445 #else
0446             boost::ignore_unused(c);
0447 #endif
0448 #if defined(BOOST_NO_CXX17_STD_APPLY)
0449            boost::context::detail::apply( std::move( fn), std::move( arg) );
0450 #else
0451            std::apply( std::move( fn), std::move( arg) );
0452 #endif
0453         }
0454         // terminate context
0455         return terminate();
0456     }
0457 
0458 public:
0459     template< typename StackAlloc >
0460     worker_context( launch policy,
0461                     fiber_properties* properties,
0462                     boost::context::preallocated const& palloc, StackAlloc && salloc,
0463                     Fn && fn, Arg ... arg) :
0464             context{ 1, type::worker_context, policy },
0465             fn_( std::forward< Fn >( fn) ),
0466             arg_( std::forward< Arg >( arg) ... ) {
0467         if ( properties != nullptr ) {
0468             set_properties(properties);
0469             properties->set_context(this);
0470         }
0471         c_ = boost::context::fiber{ std::allocator_arg, palloc, std::forward< StackAlloc >( salloc),
0472                                     std::bind( & worker_context::run_, this, std::placeholders::_1) };
0473 #if (defined(BOOST_USE_UCONTEXT)||defined(BOOST_USE_WINFIB))
0474         c_ = std::move( c_).resume();
0475 #endif
0476     }
0477 
0478     template< typename StackAlloc >
0479     worker_context( launch policy,
0480                     boost::context::preallocated const& palloc, StackAlloc && salloc,
0481                     Fn && fn, Arg ... arg) :
0482             worker_context( policy, palloc, salloc, nullptr, std::forward<Fn>( fn ), std::forward<Arg>( arg ) ... ){
0483     }
0484 };
0485 
0486 
0487 template< typename StackAlloc, typename Fn, typename ... Arg >
0488 static intrusive_ptr< context > make_worker_context_with_properties( launch policy,
0489                                                      fiber_properties* properties,
0490                                                      StackAlloc && salloc,
0491                                                      Fn && fn, Arg ... arg) {
0492     typedef worker_context< Fn, Arg ... >   context_t;
0493 
0494     auto sctx = salloc.allocate();
0495     // reserve space for control structure
0496     void * storage = reinterpret_cast< void * >(
0497             ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( context_t) ) )
0498             & ~ static_cast< uintptr_t >( 0xff) );
0499     void * stack_bottom = reinterpret_cast< void * >(
0500             reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) );
0501     const std::size_t size = reinterpret_cast< uintptr_t >( storage) - reinterpret_cast< uintptr_t >( stack_bottom);
0502     // placement new of context on top of fiber's stack
0503     return intrusive_ptr< context >{ 
0504             new ( storage) context_t{
0505                 policy,
0506                 properties,
0507                 boost::context::preallocated{ storage, size, sctx },
0508                 std::forward< StackAlloc >( salloc),
0509                 std::forward< Fn >( fn),
0510                 std::forward< Arg >( arg) ... } };
0511 }
0512 
0513 template< typename StackAlloc, typename Fn, typename ... Arg >
0514 static intrusive_ptr< context > make_worker_context( launch policy,
0515                                                      StackAlloc && salloc,
0516                                                      Fn && fn, Arg ... arg){
0517     return make_worker_context_with_properties( policy, nullptr, std::forward<StackAlloc>(salloc),
0518                                                 std::forward<Fn>( fn ), std::forward<Arg>( arg ) ... );
0519 }
0520 
0521 
0522 }}
0523 
0524 // std::hash specialization
0525 namespace std {
0526 
0527 template <>
0528 struct hash< ::boost::fibers::context::id > {
0529     std::size_t
0530     operator() ( ::boost::fibers::context::id const& id ) const noexcept;
0531 };
0532 
0533 }
0534 
0535 #ifdef _MSC_VER
0536 # pragma warning(pop)
0537 #endif
0538 
0539 #ifdef BOOST_HAS_ABI_HEADERS
0540 #  include BOOST_ABI_SUFFIX
0541 #endif
0542 
0543 #endif // BOOST_FIBERS_CONTEXT_H