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