Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-15 09:05:26

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         context  *   impl_{ nullptr };
0178 
0179     public:
0180         id() = default;
0181 
0182         explicit id( context * impl) noexcept :
0183             impl_{ impl } {
0184         }
0185 
0186         bool operator==( id const& other) const noexcept {
0187             return impl_ == other.impl_;
0188         }
0189 
0190         bool operator!=( id const& other) const noexcept {
0191             return impl_ != other.impl_;
0192         }
0193 
0194         bool operator<( id const& other) const noexcept {
0195             return impl_ < other.impl_;
0196         }
0197 
0198         bool operator>( id const& other) const noexcept {
0199             return other.impl_ < impl_;
0200         }
0201 
0202         bool operator<=( id const& other) const noexcept {
0203             return ! ( * this > other);
0204         }
0205 
0206         bool operator>=( id const& other) const noexcept {
0207             return ! ( * this < other);
0208         }
0209 
0210         template< typename charT, class traitsT >
0211         friend std::basic_ostream< charT, traitsT > &
0212         operator<<( std::basic_ostream< charT, traitsT > & os, id const& other) {
0213             if ( nullptr != other.impl_) {
0214                 return os << other.impl_;
0215             }
0216             return os << "{not-valid}";
0217         }
0218 
0219         explicit operator bool() const noexcept {
0220             return nullptr != impl_;
0221         }
0222 
0223         bool operator!() const noexcept {
0224             return nullptr == impl_;
0225         }
0226     };
0227 
0228     // Returns true if the thread could be initialize, false otherwise (it was already initialized previously).
0229     static bool initialize_thread(algo::algorithm::ptr_t algo, stack_allocator_wrapper&& salloc) noexcept;
0230 
0231     static context * active() noexcept;
0232 
0233     static void reset_active() noexcept;
0234 
0235     context( context const&) = delete;
0236     context( context &&) = delete;
0237     context & operator=( context const&) = delete;
0238     context & operator=( context &&) = delete;
0239 
0240     #if !defined(BOOST_EMBTC)
0241   
0242     friend bool
0243     operator==( context const& lhs, context const& rhs) noexcept {
0244         return & lhs == & rhs;
0245     }
0246 
0247     #else
0248   
0249     friend bool
0250     operator==( context const& lhs, context const& rhs) noexcept;
0251 
0252     #endif
0253       
0254     virtual ~context();
0255 
0256     scheduler * get_scheduler() const noexcept {
0257         return scheduler_;
0258     }
0259 
0260     id get_id() const noexcept;
0261 
0262     bool is_resumable() const noexcept {
0263         return static_cast<bool>(c_);
0264     }
0265 
0266     void resume() noexcept;
0267     void resume( detail::spinlock_lock &) noexcept;
0268     void resume( context *) noexcept;
0269 
0270     void suspend() noexcept;
0271     void suspend( detail::spinlock_lock &) noexcept;
0272 
0273     boost::context::fiber suspend_with_cc() noexcept;
0274     boost::context::fiber terminate() noexcept;
0275 
0276     void join();
0277 
0278     void yield() noexcept;
0279 
0280     bool wait_until( std::chrono::steady_clock::time_point const&) noexcept;
0281     bool wait_until( std::chrono::steady_clock::time_point const&,
0282                      detail::spinlock_lock &,
0283                      waker &&) noexcept;
0284 
0285     bool wake(const size_t) noexcept;
0286 
0287     waker create_waker() noexcept {
0288         // this operation makes all previously created wakers to be outdated
0289         return { this, ++waker_epoch_ };
0290     }
0291 
0292     void schedule( context *) noexcept;
0293 
0294     bool is_context( type t) const noexcept {
0295         return type::none != ( type_ & t);
0296     }
0297 
0298     void * get_fss_data( void const * vp) const;
0299 
0300     void set_fss_data(
0301         void const * vp,
0302         detail::fss_cleanup_function::ptr_t const& cleanup_fn,
0303         void * data,
0304         bool cleanup_existing);
0305 
0306     void set_properties( fiber_properties * props) noexcept;
0307 
0308     fiber_properties * get_properties() const noexcept {
0309         return properties_;
0310     }
0311 
0312     launch get_policy() const noexcept {
0313         return policy_;
0314     }
0315 
0316     bool worker_is_linked() const noexcept;
0317 
0318     bool ready_is_linked() const noexcept;
0319 
0320     bool remote_ready_is_linked() const noexcept;
0321 
0322     bool sleep_is_linked() const noexcept;
0323 
0324     bool terminated_is_linked() const noexcept;
0325 
0326     template< typename List >
0327     void worker_link( List & lst) noexcept {
0328         static_assert( std::is_same< typename List::value_traits::hook_type, detail::worker_hook >::value, "not a worker-queue");
0329         BOOST_ASSERT( ! worker_is_linked() );
0330         lst.push_back( * this);
0331     }
0332 
0333     template< typename List >
0334     void ready_link( List & lst) noexcept {
0335         static_assert( std::is_same< typename List::value_traits::hook_type, detail::ready_hook >::value, "not a ready-queue");
0336         BOOST_ASSERT( ! ready_is_linked() );
0337         lst.push_back( * this);
0338     }
0339 
0340     template< typename List >
0341     void remote_ready_link( List & lst) noexcept {
0342         static_assert( std::is_same< typename List::value_traits::hook_type, detail::remote_ready_hook >::value, "not a remote-ready-queue");
0343         BOOST_ASSERT( ! remote_ready_is_linked() );
0344         lst.push_back( * this);
0345     }
0346 
0347     template< typename Set >
0348     void sleep_link( Set & set) noexcept {
0349         static_assert( std::is_same< typename Set::value_traits::hook_type,detail::sleep_hook >::value, "not a sleep-queue");
0350         BOOST_ASSERT( ! sleep_is_linked() );
0351         set.insert( * this);
0352     }
0353 
0354     template< typename List >
0355     void terminated_link( List & lst) noexcept {
0356         static_assert( std::is_same< typename List::value_traits::hook_type, detail::terminated_hook >::value, "not a terminated-queue");
0357         BOOST_ASSERT( ! terminated_is_linked() );
0358         lst.push_back( * this);
0359     }
0360 
0361     void worker_unlink() noexcept;
0362 
0363     void ready_unlink() noexcept;
0364 
0365     void sleep_unlink() noexcept;
0366 
0367     void detach() noexcept;
0368 
0369     void attach( context *) noexcept;
0370 
0371     #if !defined(BOOST_EMBTC)
0372       
0373     friend void intrusive_ptr_add_ref( context * ctx) noexcept {
0374         BOOST_ASSERT( nullptr != ctx);
0375         ctx->use_count_.fetch_add( 1, std::memory_order_relaxed);
0376     }
0377 
0378     friend void intrusive_ptr_release( context * ctx) noexcept {
0379         BOOST_ASSERT( nullptr != ctx);
0380         if ( 1 == ctx->use_count_.fetch_sub( 1, std::memory_order_release) ) {
0381             std::atomic_thread_fence( std::memory_order_acquire);
0382             boost::context::fiber c = std::move( ctx->c_);
0383             // destruct context
0384             ctx->~context();
0385             // deallocated stack
0386             std::move( c).resume();
0387         }
0388     }
0389     
0390     #else
0391       
0392     friend void intrusive_ptr_add_ref( context * ctx) noexcept;
0393     friend void intrusive_ptr_release( context * ctx) noexcept;
0394     
0395     #endif
0396       
0397 };
0398 
0399 #if defined(BOOST_EMBTC)
0400 
0401     inline bool
0402     operator==( context const& lhs, context const& rhs) noexcept {
0403         return & lhs == & rhs;
0404     }
0405 
0406     inline void intrusive_ptr_add_ref( context * ctx) noexcept {
0407         BOOST_ASSERT( nullptr != ctx);
0408         ctx->use_count_.fetch_add( 1, std::memory_order_relaxed);
0409     }
0410 
0411     inline void intrusive_ptr_release( context * ctx) noexcept {
0412         BOOST_ASSERT( nullptr != ctx);
0413         if ( 1 == ctx->use_count_.fetch_sub( 1, std::memory_order_release) ) {
0414             std::atomic_thread_fence( std::memory_order_acquire);
0415             boost::context::fiber c = std::move( ctx->c_);
0416             // destruct context
0417             ctx->~context();
0418             // deallocated stack
0419             std::move( c).resume();
0420         }
0421     }
0422     
0423 #endif
0424     
0425 inline
0426 bool operator<( context const& l, context const& r) noexcept {
0427     return l.get_id() < r.get_id();
0428 }
0429 
0430 template< typename Fn, typename ... Arg >
0431 class worker_context final : public context {
0432 private:
0433     typename std::decay< Fn >::type                     fn_;
0434     std::tuple< Arg ... >                               arg_;
0435 
0436     boost::context::fiber
0437     run_( boost::context::fiber && c) {
0438         {
0439             // fn and tpl must be destroyed before calling terminate()
0440             auto fn = std::move( fn_);
0441             auto arg = std::move( arg_);
0442 #if (defined(BOOST_USE_UCONTEXT)||defined(BOOST_USE_WINFIB))
0443             std::move( c).resume();
0444 #else
0445             boost::ignore_unused(c);
0446 #endif
0447 #if defined(BOOST_NO_CXX17_STD_APPLY)
0448            boost::context::detail::apply( std::move( fn), std::move( arg) );
0449 #else
0450            std::apply( std::move( fn), std::move( arg) );
0451 #endif
0452         }
0453         // terminate context
0454         return terminate();
0455     }
0456 
0457 public:
0458     template< typename StackAlloc >
0459     worker_context( launch policy,
0460                     fiber_properties* properties,
0461                     boost::context::preallocated const& palloc, StackAlloc && salloc,
0462                     Fn && fn, Arg ... arg) :
0463             context{ 1, type::worker_context, policy },
0464             fn_( std::forward< Fn >( fn) ),
0465             arg_( std::forward< Arg >( arg) ... ) {
0466         if ( properties != nullptr ) {
0467             set_properties(properties);
0468             properties->set_context(this);
0469         }
0470         c_ = boost::context::fiber{ std::allocator_arg, palloc, std::forward< StackAlloc >( salloc),
0471                                     std::bind( & worker_context::run_, this, std::placeholders::_1) };
0472 #if (defined(BOOST_USE_UCONTEXT)||defined(BOOST_USE_WINFIB))
0473         c_ = std::move( c_).resume();
0474 #endif
0475     }
0476 
0477     template< typename StackAlloc >
0478     worker_context( launch policy,
0479                     boost::context::preallocated const& palloc, StackAlloc && salloc,
0480                     Fn && fn, Arg ... arg) :
0481             worker_context( policy, palloc, salloc, nullptr, std::forward<Fn>( fn ), std::forward<Arg>( arg ) ... ){
0482     }
0483 };
0484 
0485 
0486 template< typename StackAlloc, typename Fn, typename ... Arg >
0487 static intrusive_ptr< context > make_worker_context_with_properties( launch policy,
0488                                                      fiber_properties* properties,
0489                                                      StackAlloc && salloc,
0490                                                      Fn && fn, Arg ... arg) {
0491     typedef worker_context< Fn, Arg ... >   context_t;
0492 
0493     auto sctx = salloc.allocate();
0494     // reserve space for control structure
0495     void * storage = reinterpret_cast< void * >(
0496             ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( context_t) ) )
0497             & ~ static_cast< uintptr_t >( 0xff) );
0498     void * stack_bottom = reinterpret_cast< void * >(
0499             reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) );
0500     const std::size_t size = reinterpret_cast< uintptr_t >( storage) - reinterpret_cast< uintptr_t >( stack_bottom);
0501     // placement new of context on top of fiber's stack
0502     return intrusive_ptr< context >{ 
0503             new ( storage) context_t{
0504                 policy,
0505                 properties,
0506                 boost::context::preallocated{ storage, size, sctx },
0507                 std::forward< StackAlloc >( salloc),
0508                 std::forward< Fn >( fn),
0509                 std::forward< Arg >( arg) ... } };
0510 }
0511 
0512 template< typename StackAlloc, typename Fn, typename ... Arg >
0513 static intrusive_ptr< context > make_worker_context( launch policy,
0514                                                      StackAlloc && salloc,
0515                                                      Fn && fn, Arg ... arg){
0516     return make_worker_context_with_properties( policy, nullptr, std::forward<StackAlloc>(salloc),
0517                                                 std::forward<Fn>( fn ), std::forward<Arg>( arg ) ... );
0518 }
0519 
0520 
0521 }}
0522 
0523 #ifdef _MSC_VER
0524 # pragma warning(pop)
0525 #endif
0526 
0527 #ifdef BOOST_HAS_ABI_HEADERS
0528 #  include BOOST_ABI_SUFFIX
0529 #endif
0530 
0531 #endif // BOOST_FIBERS_CONTEXT_H