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_CONDITION_VARIABLE_H
0008 #define BOOST_FIBERS_CONDITION_VARIABLE_H
0009 
0010 #include <algorithm>
0011 #include <atomic>
0012 #include <chrono>
0013 #include <functional>
0014 #include <mutex>
0015 
0016 #include <boost/assert.hpp>
0017 #include <boost/config.hpp>
0018 #include <boost/context/detail/config.hpp>
0019 
0020 #include <boost/fiber/context.hpp>
0021 #include <boost/fiber/detail/config.hpp>
0022 #include <boost/fiber/detail/convert.hpp>
0023 #include <boost/fiber/detail/spinlock.hpp>
0024 #include <boost/fiber/exceptions.hpp>
0025 #include <boost/fiber/mutex.hpp>
0026 #include <boost/fiber/operations.hpp>
0027 #include <boost/fiber/waker.hpp>
0028 
0029 #ifdef BOOST_HAS_ABI_HEADERS
0030 #  include BOOST_ABI_PREFIX
0031 #endif
0032 
0033 #ifdef _MSC_VER
0034 # pragma warning(push)
0035 //# pragma warning(disable:4251)
0036 #endif
0037 
0038 namespace boost {
0039 namespace fibers {
0040 
0041 enum class cv_status {
0042     no_timeout = 1,
0043     timeout
0044 };
0045 
0046 class BOOST_FIBERS_DECL condition_variable_any {
0047 private:
0048     detail::spinlock    wait_queue_splk_{};
0049     wait_queue          wait_queue_{};
0050 
0051 public:
0052     condition_variable_any() = default;
0053 
0054     ~condition_variable_any() {
0055         BOOST_ASSERT( wait_queue_.empty() );
0056     }
0057 
0058     condition_variable_any( condition_variable_any const&) = delete;
0059     condition_variable_any & operator=( condition_variable_any const&) = delete;
0060 
0061     void notify_one() noexcept;
0062 
0063     void notify_all() noexcept;
0064 
0065     template< typename LockType >
0066     void wait( LockType & lt) {
0067         context * active_ctx = context::active();
0068         // atomically call lt.unlock() and block on *this
0069         // store this fiber in waiting-queue
0070         detail::spinlock_lock lk{ wait_queue_splk_ };
0071         lt.unlock();
0072         wait_queue_.suspend_and_wait( lk, active_ctx);
0073 
0074         // relock external again before returning
0075         try {
0076             lt.lock();
0077 #if defined(BOOST_CONTEXT_HAS_CXXABI_H)
0078         } catch ( abi::__forced_unwind const&) {
0079             throw;
0080 #endif
0081         } catch (...) {
0082             std::terminate();
0083         }
0084     }
0085 
0086     template< typename LockType, typename Pred >
0087     void wait( LockType & lt, Pred pred) {
0088         while ( ! pred() ) {
0089             wait( lt);
0090         }
0091     }
0092 
0093     template< typename LockType, typename Clock, typename Duration >
0094     cv_status wait_until( LockType & lt, std::chrono::time_point< Clock, Duration > const& timeout_time_) {
0095         context * active_ctx = context::active();
0096         cv_status status = cv_status::no_timeout;
0097         std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_);
0098         // atomically call lt.unlock() and block on *this
0099         // store this fiber in waiting-queue
0100         detail::spinlock_lock lk{ wait_queue_splk_ };
0101         // unlock external lt
0102         lt.unlock();
0103         if ( ! wait_queue_.suspend_and_wait_until( lk, active_ctx, timeout_time)) {
0104             status = cv_status::timeout;
0105         }
0106         // relock external again before returning
0107         try {
0108             lt.lock();
0109 #if defined(BOOST_CONTEXT_HAS_CXXABI_H)
0110         } catch ( abi::__forced_unwind const&) {
0111             throw;
0112 #endif
0113         } catch (...) {
0114             std::terminate();
0115         }
0116         return status;
0117     }
0118 
0119     template< typename LockType, typename Clock, typename Duration, typename Pred >
0120     bool wait_until( LockType & lt,
0121                      std::chrono::time_point< Clock, Duration > const& timeout_time, Pred pred) {
0122         while ( ! pred() ) {
0123             if ( cv_status::timeout == wait_until( lt, timeout_time) ) {
0124                 return pred();
0125             }
0126         }
0127         return true;
0128     }
0129 
0130     template< typename LockType, typename Rep, typename Period >
0131     cv_status wait_for( LockType & lt, std::chrono::duration< Rep, Period > const& timeout_duration) {
0132         return wait_until( lt,
0133                            std::chrono::steady_clock::now() + timeout_duration);
0134     }
0135 
0136     template< typename LockType, typename Rep, typename Period, typename Pred >
0137     bool wait_for( LockType & lt, std::chrono::duration< Rep, Period > const& timeout_duration, Pred pred) {
0138         return wait_until( lt,
0139                            std::chrono::steady_clock::now() + timeout_duration,
0140                            pred);
0141     }
0142 };
0143 
0144 class BOOST_FIBERS_DECL condition_variable {
0145 private:
0146     condition_variable_any      cnd_;
0147 
0148 public:
0149     condition_variable() = default;
0150 
0151     condition_variable( condition_variable const&) = delete;
0152     condition_variable & operator=( condition_variable const&) = delete;
0153 
0154     void notify_one() noexcept {
0155         cnd_.notify_one();
0156     }
0157 
0158     void notify_all() noexcept {
0159         cnd_.notify_all();
0160     }
0161 
0162     void wait( std::unique_lock< mutex > & lt) {
0163         // pre-condition
0164         BOOST_ASSERT( lt.owns_lock() );
0165         BOOST_ASSERT( context::active() == lt.mutex()->owner_);
0166         cnd_.wait( lt);
0167         // post-condition
0168         BOOST_ASSERT( lt.owns_lock() );
0169         BOOST_ASSERT( context::active() == lt.mutex()->owner_);
0170     }
0171 
0172     template< typename Pred >
0173     void wait( std::unique_lock< mutex > & lt, Pred pred) {
0174         // pre-condition
0175         BOOST_ASSERT( lt.owns_lock() );
0176         BOOST_ASSERT( context::active() == lt.mutex()->owner_);
0177         cnd_.wait( lt, pred);
0178         // post-condition
0179         BOOST_ASSERT( lt.owns_lock() );
0180         BOOST_ASSERT( context::active() == lt.mutex()->owner_);
0181     }
0182 
0183     template< typename Clock, typename Duration >
0184     cv_status wait_until( std::unique_lock< mutex > & lt,
0185                           std::chrono::time_point< Clock, Duration > const& timeout_time) {
0186         // pre-condition
0187         BOOST_ASSERT( lt.owns_lock() );
0188         BOOST_ASSERT( context::active() == lt.mutex()->owner_);
0189         cv_status result = cnd_.wait_until( lt, timeout_time);
0190         // post-condition
0191         BOOST_ASSERT( lt.owns_lock() );
0192         BOOST_ASSERT( context::active() == lt.mutex()->owner_);
0193         return result;
0194     }
0195 
0196     template< typename Clock, typename Duration, typename Pred >
0197     bool wait_until( std::unique_lock< mutex > & lt,
0198                      std::chrono::time_point< Clock, Duration > const& timeout_time, Pred pred) {
0199         // pre-condition
0200         BOOST_ASSERT( lt.owns_lock() );
0201         BOOST_ASSERT( context::active() == lt.mutex()->owner_);
0202         bool result = cnd_.wait_until( lt, timeout_time, pred);
0203         // post-condition
0204         BOOST_ASSERT( lt.owns_lock() );
0205         BOOST_ASSERT( context::active() == lt.mutex()->owner_);
0206         return result;
0207     }
0208 
0209     template< typename Rep, typename Period >
0210     cv_status wait_for( std::unique_lock< mutex > & lt,
0211                         std::chrono::duration< Rep, Period > const& timeout_duration) {
0212         // pre-condition
0213         BOOST_ASSERT( lt.owns_lock() );
0214         BOOST_ASSERT( context::active() == lt.mutex()->owner_);
0215         cv_status result = cnd_.wait_for( lt, timeout_duration);
0216         // post-condition
0217         BOOST_ASSERT( lt.owns_lock() );
0218         BOOST_ASSERT( context::active() == lt.mutex()->owner_);
0219         return result;
0220     }
0221 
0222     template< typename Rep, typename Period, typename Pred >
0223     bool wait_for( std::unique_lock< mutex > & lt,
0224                    std::chrono::duration< Rep, Period > const& timeout_duration, Pred pred) {
0225         // pre-condition
0226         BOOST_ASSERT( lt.owns_lock() );
0227         BOOST_ASSERT( context::active() == lt.mutex()->owner_);
0228         bool result = cnd_.wait_for( lt, timeout_duration, pred);
0229         // post-condition
0230         BOOST_ASSERT( lt.owns_lock() );
0231         BOOST_ASSERT( context::active() == lt.mutex()->owner_);
0232         return result;
0233     }
0234 };
0235 
0236 }}
0237 
0238 #ifdef _MSC_VER
0239 # pragma warning(pop)
0240 #endif
0241 
0242 #ifdef BOOST_HAS_ABI_HEADERS
0243 #  include BOOST_ABI_SUFFIX
0244 #endif
0245 
0246 #endif // BOOST_FIBERS_CONDITION_VARIABLE_H