Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-31 09:37:22

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_DETAIL_SHARED_STATE_H
0008 #define BOOST_FIBERS_DETAIL_SHARED_STATE_H
0009 
0010 #include <algorithm>
0011 #include <atomic>
0012 #include <chrono>
0013 #include <cstddef>
0014 #include <exception>
0015 #include <memory>
0016 #include <mutex>
0017 #include <type_traits>
0018 
0019 #include <boost/assert.hpp>
0020 #include <boost/config.hpp>
0021 #include <boost/intrusive_ptr.hpp>
0022 
0023 #include <boost/fiber/detail/config.hpp>
0024 #include <boost/fiber/future/future_status.hpp>
0025 #include <boost/fiber/condition_variable.hpp>
0026 #include <boost/fiber/exceptions.hpp>
0027 #include <boost/fiber/mutex.hpp>
0028 
0029 #ifdef BOOST_HAS_ABI_HEADERS
0030 #  include BOOST_ABI_PREFIX
0031 #endif
0032 
0033 namespace boost {
0034 namespace fibers {
0035 namespace detail {
0036 
0037 class shared_state_base {
0038 private:
0039     std::atomic< std::size_t >  use_count_{ 0 };
0040     mutable condition_variable  waiters_{};
0041 
0042 protected:
0043     mutable mutex       mtx_{};
0044     bool                ready_{ false };
0045     std::exception_ptr  except_{};
0046 
0047     void mark_ready_and_notify_( std::unique_lock< mutex > & lk) noexcept {
0048         BOOST_ASSERT( lk.owns_lock() );
0049         ready_ = true;
0050         lk.unlock();
0051         waiters_.notify_all();
0052     }
0053 
0054     void owner_destroyed_( std::unique_lock< mutex > & lk) {
0055         BOOST_ASSERT( lk.owns_lock() );
0056         if ( ! ready_) {
0057             set_exception_(
0058                     std::make_exception_ptr( broken_promise() ),
0059                     lk);
0060         }
0061     }
0062 
0063     void set_exception_( std::exception_ptr except, std::unique_lock< mutex > & lk) {
0064         BOOST_ASSERT( lk.owns_lock() );
0065         if ( BOOST_UNLIKELY( ready_) ) {
0066             throw promise_already_satisfied();
0067         }
0068         except_ = except;
0069         mark_ready_and_notify_( lk);
0070     }
0071 
0072     std::exception_ptr get_exception_ptr_( std::unique_lock< mutex > & lk) {
0073         BOOST_ASSERT( lk.owns_lock() );
0074         wait_( lk);
0075         return except_;
0076     }
0077 
0078     void wait_( std::unique_lock< mutex > & lk) const {
0079         BOOST_ASSERT( lk.owns_lock() );
0080         waiters_.wait( lk, [this](){ return ready_; });
0081     }
0082 
0083     template< typename Rep, typename Period >
0084     future_status wait_for_( std::unique_lock< mutex > & lk,
0085                              std::chrono::duration< Rep, Period > const& timeout_duration) const {
0086         BOOST_ASSERT( lk.owns_lock() );
0087         return waiters_.wait_for( lk, timeout_duration, [this](){ return ready_; })
0088                     ? future_status::ready
0089                     : future_status::timeout;
0090     }
0091 
0092     template< typename Clock, typename Duration >
0093     future_status wait_until_( std::unique_lock< mutex > & lk,
0094                                std::chrono::time_point< Clock, Duration > const& timeout_time) const {
0095         BOOST_ASSERT( lk.owns_lock() );
0096         return waiters_.wait_until( lk, timeout_time, [this](){ return ready_; })
0097                     ? future_status::ready
0098                     : future_status::timeout;
0099     }
0100 
0101     virtual void deallocate_future() noexcept = 0;
0102 
0103 public:
0104     shared_state_base() = default;
0105 
0106     virtual ~shared_state_base() = default;
0107 
0108     shared_state_base( shared_state_base const&) = delete;
0109     shared_state_base & operator=( shared_state_base const&) = delete;
0110 
0111     void owner_destroyed() {
0112         std::unique_lock< mutex > lk{ mtx_ };
0113         owner_destroyed_( lk);
0114     }
0115 
0116     void set_exception( std::exception_ptr except) {
0117         std::unique_lock< mutex > lk{ mtx_ };
0118         set_exception_( except, lk);
0119     }
0120 
0121     std::exception_ptr get_exception_ptr() {
0122         std::unique_lock< mutex > lk{ mtx_ };
0123         return get_exception_ptr_( lk);
0124     }
0125 
0126     void wait() const {
0127         std::unique_lock< mutex > lk{ mtx_ };
0128         wait_( lk);
0129     }
0130 
0131     template< typename Rep, typename Period >
0132     future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const {
0133         std::unique_lock< mutex > lk{ mtx_ };
0134         return wait_for_( lk, timeout_duration);
0135     }
0136 
0137     template< typename Clock, typename Duration >
0138     future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const {
0139         std::unique_lock< mutex > lk{ mtx_ };
0140         return wait_until_( lk, timeout_time);
0141     }
0142 
0143     friend inline
0144     void intrusive_ptr_add_ref( shared_state_base * p) noexcept {
0145         p->use_count_.fetch_add( 1, std::memory_order_relaxed);
0146     }
0147 
0148     friend inline
0149     void intrusive_ptr_release( shared_state_base * p) noexcept {
0150         if ( 1 == p->use_count_.fetch_sub( 1, std::memory_order_release) ) {
0151             std::atomic_thread_fence( std::memory_order_acquire);
0152             p->deallocate_future();
0153         }
0154     }
0155 };
0156 
0157 template< typename R >
0158 class shared_state : public shared_state_base {
0159 private:
0160     typename std::aligned_storage< sizeof( R), alignof( R) >::type  storage_{};
0161 
0162     void set_value_( R const& value, std::unique_lock< mutex > & lk) {
0163         BOOST_ASSERT( lk.owns_lock() );
0164         if ( BOOST_UNLIKELY( ready_) ) {
0165             throw promise_already_satisfied{};
0166         }
0167         ::new ( static_cast< void * >( std::addressof( storage_) ) ) R( value );
0168         mark_ready_and_notify_( lk);
0169     }
0170 
0171     void set_value_( R && value, std::unique_lock< mutex > & lk) {
0172         BOOST_ASSERT( lk.owns_lock() );
0173         if ( BOOST_UNLIKELY( ready_) ) {
0174             throw promise_already_satisfied{};
0175         }
0176         ::new ( static_cast< void * >( std::addressof( storage_) ) ) R( std::move( value) );
0177         mark_ready_and_notify_( lk);
0178     }
0179 
0180     R & get_( std::unique_lock< mutex > & lk) {
0181         BOOST_ASSERT( lk.owns_lock() );
0182         wait_( lk);
0183         if ( except_) {
0184             std::rethrow_exception( except_);
0185         }
0186         return * reinterpret_cast< R * >( std::addressof( storage_) );
0187     }
0188 
0189 public:
0190     typedef intrusive_ptr< shared_state >    ptr_type;
0191 
0192     shared_state() = default;
0193 
0194     virtual ~shared_state() {
0195         if ( ready_ && ! except_) {
0196             reinterpret_cast< R * >( std::addressof( storage_) )->~R();
0197         }
0198     }
0199 
0200     shared_state( shared_state const&) = delete;
0201     shared_state & operator=( shared_state const&) = delete;
0202 
0203     void set_value( R const& value) {
0204         std::unique_lock< mutex > lk{ mtx_ };
0205         set_value_( value, lk);
0206     }
0207 
0208     void set_value( R && value) {
0209         std::unique_lock< mutex > lk{ mtx_ };
0210         set_value_( std::move( value), lk);
0211     }
0212 
0213     R & get() {
0214         std::unique_lock< mutex > lk{ mtx_ };
0215         return get_( lk);
0216     }
0217 };
0218 
0219 template< typename R >
0220 class shared_state< R & > : public shared_state_base {
0221 private:
0222     R   *   value_{ nullptr };
0223 
0224     void set_value_( R & value, std::unique_lock< mutex > & lk) {
0225         BOOST_ASSERT( lk.owns_lock() );
0226         if ( BOOST_UNLIKELY( ready_) ) {
0227             throw promise_already_satisfied();
0228         }
0229         value_ = std::addressof( value);
0230         mark_ready_and_notify_( lk);
0231     }
0232 
0233     R & get_( std::unique_lock< mutex > & lk) {
0234         BOOST_ASSERT( lk.owns_lock() );
0235         wait_( lk);
0236         if ( except_) {
0237             std::rethrow_exception( except_);
0238         }
0239         return * value_;
0240     }
0241 
0242 public:
0243     typedef intrusive_ptr< shared_state >    ptr_type;
0244 
0245     shared_state() = default;
0246 
0247     virtual ~shared_state() = default;
0248 
0249     shared_state( shared_state const&) = delete;
0250     shared_state & operator=( shared_state const&) = delete;
0251 
0252     void set_value( R & value) {
0253         std::unique_lock< mutex > lk{ mtx_ };
0254         set_value_( value, lk);
0255     }
0256 
0257     R & get() {
0258         std::unique_lock< mutex > lk{ mtx_ };
0259         return get_( lk);
0260     }
0261 };
0262 
0263 template<>
0264 class shared_state< void > : public shared_state_base {
0265 private:
0266     inline
0267     void set_value_( std::unique_lock< mutex > & lk) {
0268         BOOST_ASSERT( lk.owns_lock() );
0269         if ( BOOST_UNLIKELY( ready_) ) {
0270             throw promise_already_satisfied();
0271         }
0272         mark_ready_and_notify_( lk);
0273     }
0274 
0275     inline
0276     void get_( std::unique_lock< mutex > & lk) {
0277         BOOST_ASSERT( lk.owns_lock() );
0278         wait_( lk);
0279         if ( except_) {
0280             std::rethrow_exception( except_);
0281         }
0282     }
0283 
0284 public:
0285     typedef intrusive_ptr< shared_state >    ptr_type;
0286 
0287     shared_state() = default;
0288 
0289     virtual ~shared_state() = default;
0290 
0291     shared_state( shared_state const&) = delete;
0292     shared_state & operator=( shared_state const&) = delete;
0293 
0294     inline
0295     void set_value() {
0296         std::unique_lock< mutex > lk{ mtx_ };
0297         set_value_( lk);
0298     }
0299 
0300     inline
0301     void get() {
0302         std::unique_lock< mutex > lk{ mtx_ };
0303         get_( lk);
0304     }
0305 };
0306 
0307 }}}
0308 
0309 #ifdef BOOST_HAS_ABI_HEADERS
0310 #  include BOOST_ABI_SUFFIX
0311 #endif
0312 
0313 #endif // BOOST_FIBERS_DETAIL_SHARED_STATE_H