File indexing completed on 2024-11-15 09:05:26
0001
0002
0003
0004
0005
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
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
0069
0070 detail::spinlock_lock lk{ wait_queue_splk_ };
0071 lt.unlock();
0072 wait_queue_.suspend_and_wait( lk, active_ctx);
0073
0074
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
0099
0100 detail::spinlock_lock lk{ wait_queue_splk_ };
0101
0102 lt.unlock();
0103 if ( ! wait_queue_.suspend_and_wait_until( lk, active_ctx, timeout_time)) {
0104 status = cv_status::timeout;
0105 }
0106
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
0164 BOOST_ASSERT( lt.owns_lock() );
0165 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
0166 cnd_.wait( lt);
0167
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
0175 BOOST_ASSERT( lt.owns_lock() );
0176 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
0177 cnd_.wait( lt, pred);
0178
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
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
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
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
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
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
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
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
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