File indexing completed on 2025-01-18 09:38:32
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_INTERPROCESS_DETAIL_SPIN_CONDITION_HPP
0012 #define BOOST_INTERPROCESS_DETAIL_SPIN_CONDITION_HPP
0013
0014 #ifndef BOOST_CONFIG_HPP
0015 # include <boost/config.hpp>
0016 #endif
0017 #
0018 #if defined(BOOST_HAS_PRAGMA_ONCE)
0019 # pragma once
0020 #endif
0021
0022 #include <boost/interprocess/detail/config_begin.hpp>
0023 #include <boost/interprocess/detail/workaround.hpp>
0024
0025 #include <boost/interprocess/sync/cv_status.hpp>
0026 #include <boost/interprocess/sync/spin/mutex.hpp>
0027 #include <boost/interprocess/detail/atomic.hpp>
0028 #include <boost/interprocess/sync/scoped_lock.hpp>
0029 #include <boost/interprocess/exceptions.hpp>
0030 #include <boost/interprocess/detail/os_thread_functions.hpp>
0031 #include <boost/interprocess/detail/timed_utils.hpp>
0032 #include <boost/interprocess/sync/spin/wait.hpp>
0033 #include <boost/move/utility_core.hpp>
0034 #include <boost/cstdint.hpp>
0035
0036 namespace boost {
0037 namespace interprocess {
0038 namespace ipcdetail {
0039
0040 class spin_condition
0041 {
0042 spin_condition(const spin_condition &);
0043 spin_condition &operator=(const spin_condition &);
0044
0045 public:
0046 spin_condition()
0047 {
0048
0049
0050
0051 m_command = SLEEP;
0052 m_num_waiters = 0;
0053 }
0054
0055 ~spin_condition()
0056 {
0057
0058
0059 this->notify_all();
0060 }
0061
0062 void notify_one()
0063 { this->notify(NOTIFY_ONE); }
0064
0065 void notify_all()
0066 { this->notify(NOTIFY_ALL); }
0067
0068 template <typename L>
0069 void wait(L& lock)
0070 {
0071 if (!lock)
0072 throw lock_exception();
0073 this->do_timed_wait_impl<false>(0, *lock.mutex());
0074 }
0075
0076 template <typename L, typename Pr>
0077 void wait(L& lock, Pr pred)
0078 {
0079 if (!lock)
0080 throw lock_exception();
0081
0082 while (!pred())
0083 this->do_timed_wait_impl<false>(0, *lock.mutex());
0084 }
0085
0086 template <typename L, typename TimePoint>
0087 bool timed_wait(L& lock, const TimePoint &abs_time)
0088 {
0089 if (!lock)
0090 throw lock_exception();
0091
0092 if(is_pos_infinity(abs_time)){
0093 this->wait(lock);
0094 return true;
0095 }
0096 return this->do_timed_wait_impl<true>(abs_time, *lock.mutex());
0097 }
0098
0099 template <typename L, typename TimePoint, typename Pr>
0100 bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred)
0101 {
0102 if (!lock)
0103 throw lock_exception();
0104
0105 if(is_pos_infinity(abs_time)){
0106 this->wait(lock, pred);
0107 return true;
0108 }
0109 while (!pred()){
0110 if (!this->do_timed_wait_impl<true>(abs_time, *lock.mutex()))
0111 return pred();
0112 }
0113 return true;
0114 }
0115
0116 template <typename L, class TimePoint>
0117 cv_status wait_until(L& lock, const TimePoint &abs_time)
0118 { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; }
0119
0120 template <typename L, class TimePoint, typename Pr>
0121 bool wait_until(L& lock, const TimePoint &abs_time, Pr pred)
0122 { return this->timed_wait(lock, abs_time, pred); }
0123
0124 template <typename L, class Duration>
0125 cv_status wait_for(L& lock, const Duration &dur)
0126 { return this->wait_until(lock, duration_to_ustime(dur)); }
0127
0128 template <typename L, class Duration, typename Pr>
0129 bool wait_for(L& lock, const Duration &dur, Pr pred)
0130 { return this->wait_until(lock, duration_to_ustime(dur), pred); }
0131
0132 private:
0133
0134 template<bool TimeoutEnabled, class InterprocessMutex, class TimePoint>
0135 bool do_timed_wait_impl(const TimePoint &abs_time, InterprocessMutex &mut)
0136 {
0137 typedef boost::interprocess::scoped_lock<spin_mutex> InternalLock;
0138
0139
0140 {
0141
0142 InternalLock lock;
0143 get_lock(bool_<TimeoutEnabled>(), m_enter_mut, lock, abs_time);
0144
0145 if(!lock)
0146 return false;
0147
0148
0149
0150
0151 atomic_inc32(const_cast<boost::uint32_t*>(&m_num_waiters));
0152
0153
0154 mut.unlock();
0155 }
0156
0157
0158 bool timed_out = false, unlock_enter_mut= false;
0159
0160
0161
0162 while(1){
0163
0164
0165 spin_wait swait;
0166 while(atomic_read32(&m_command) == SLEEP){
0167 swait.yield();
0168
0169
0170 if(TimeoutEnabled){
0171 TimePoint now = get_now<TimePoint>(bool_<TimeoutEnabled>());
0172
0173 if(now >= abs_time){
0174
0175
0176 timed_out = m_enter_mut.try_lock();
0177
0178
0179
0180 if(!timed_out){
0181
0182 continue;
0183 }
0184
0185
0186
0187 break;
0188 }
0189 }
0190 }
0191
0192
0193 if(TimeoutEnabled && timed_out){
0194
0195 atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters));
0196 unlock_enter_mut = true;
0197 break;
0198 }
0199 else{
0200 boost::uint32_t result = atomic_cas32
0201 (const_cast<boost::uint32_t*>(&m_command), SLEEP, NOTIFY_ONE);
0202 if(result == SLEEP){
0203
0204
0205 continue;
0206 }
0207 else if(result == NOTIFY_ONE){
0208
0209
0210
0211
0212 unlock_enter_mut = true;
0213 atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters));
0214 break;
0215 }
0216 else{
0217
0218
0219 unlock_enter_mut = 1 == atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters));
0220
0221
0222 if(unlock_enter_mut){
0223 atomic_cas32(const_cast<boost::uint32_t*>(&m_command), SLEEP, NOTIFY_ALL);
0224 }
0225 break;
0226 }
0227 }
0228 }
0229
0230
0231
0232 if(unlock_enter_mut){
0233 m_enter_mut.unlock();
0234 }
0235
0236
0237 mut.lock();
0238 return !timed_out;
0239 }
0240
0241 template <class TimePoint>
0242 static TimePoint get_now(bool_<true>)
0243 { return microsec_clock<TimePoint>::universal_time(); }
0244
0245 template <class TimePoint>
0246 static TimePoint get_now(bool_<false>)
0247 { return TimePoint(); }
0248
0249 template <class Mutex, class Lock, class TimePoint>
0250 static void get_lock(bool_<true>, Mutex &m, Lock &lck, const TimePoint &abs_time)
0251 {
0252 Lock dummy(m, abs_time);
0253 lck = boost::move(dummy);
0254 }
0255
0256 template <class Mutex, class Lock, class TimePoint>
0257 static void get_lock(bool_<false>, Mutex &m, Lock &lck, const TimePoint &)
0258 {
0259 Lock dummy(m);
0260 lck = boost::move(dummy);
0261 }
0262
0263 void notify(boost::uint32_t command)
0264 {
0265
0266
0267
0268
0269
0270 m_enter_mut.lock();
0271
0272
0273 if(!atomic_read32(&m_num_waiters)) {
0274 m_enter_mut.unlock();
0275 return;
0276 }
0277
0278
0279 spin_wait swait;
0280 while(SLEEP != atomic_cas32(const_cast<boost::uint32_t*>(&m_command), command, SLEEP)){
0281 swait.yield();
0282 }
0283
0284 }
0285
0286 enum { SLEEP = 0, NOTIFY_ONE, NOTIFY_ALL };
0287 spin_mutex m_enter_mut;
0288 volatile boost::uint32_t m_command;
0289 volatile boost::uint32_t m_num_waiters;
0290 };
0291
0292 }
0293 }
0294 }
0295
0296 #include <boost/interprocess/detail/config_end.hpp>
0297
0298 #endif