File indexing completed on 2025-07-05 08:35:56
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/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>(ustime(0u), *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>(ustime(0u), *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 typedef typename microsec_clock<TimePoint>::time_point time_point;
0172 time_point now = get_now<TimePoint>(bool_<TimeoutEnabled>());
0173
0174 if(now >= abs_time){
0175
0176
0177 timed_out = m_enter_mut.try_lock();
0178
0179
0180
0181 if(!timed_out){
0182
0183 continue;
0184 }
0185
0186
0187
0188 break;
0189 }
0190 }
0191 }
0192
0193
0194 if(TimeoutEnabled && timed_out){
0195
0196 atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters));
0197 unlock_enter_mut = true;
0198 break;
0199 }
0200 else{
0201 boost::uint32_t result = atomic_cas32
0202 (const_cast<boost::uint32_t*>(&m_command), SLEEP, NOTIFY_ONE);
0203 if(result == SLEEP){
0204
0205
0206 continue;
0207 }
0208 else if(result == NOTIFY_ONE){
0209
0210
0211
0212
0213 unlock_enter_mut = true;
0214 atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters));
0215 break;
0216 }
0217 else{
0218
0219
0220 unlock_enter_mut = 1 == atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters));
0221
0222
0223 if(unlock_enter_mut){
0224 atomic_cas32(const_cast<boost::uint32_t*>(&m_command), SLEEP, NOTIFY_ALL);
0225 }
0226 break;
0227 }
0228 }
0229 }
0230
0231
0232
0233 if(unlock_enter_mut){
0234 m_enter_mut.unlock();
0235 }
0236
0237
0238 mut.lock();
0239 return !timed_out;
0240 }
0241
0242 template <class TimePoint>
0243 static typename microsec_clock<TimePoint>::time_point get_now(bool_<true>)
0244 { return microsec_clock<TimePoint>::universal_time(); }
0245
0246 template <class TimePoint>
0247 static typename microsec_clock<TimePoint>::time_point get_now(bool_<false>)
0248 { return typename microsec_clock<TimePoint>::time_point(); }
0249
0250 template <class Mutex, class Lock, class TimePoint>
0251 static void get_lock(bool_<true>, Mutex &m, Lock &lck, const TimePoint &abs_time)
0252 {
0253 Lock dummy(m, abs_time);
0254 lck = boost::move(dummy);
0255 }
0256
0257 template <class Mutex, class Lock, class TimePoint>
0258 static void get_lock(bool_<false>, Mutex &m, Lock &lck, const TimePoint &)
0259 {
0260 Lock dummy(m);
0261 lck = boost::move(dummy);
0262 }
0263
0264 void notify(boost::uint32_t command)
0265 {
0266
0267
0268
0269
0270
0271 m_enter_mut.lock();
0272
0273
0274 if(!atomic_read32(&m_num_waiters)) {
0275 m_enter_mut.unlock();
0276 return;
0277 }
0278
0279
0280 spin_wait swait;
0281 while(SLEEP != atomic_cas32(const_cast<boost::uint32_t*>(&m_command), command, SLEEP)){
0282 swait.yield();
0283 }
0284
0285 }
0286
0287 enum { SLEEP = 0, NOTIFY_ONE, NOTIFY_ALL };
0288 spin_mutex m_enter_mut;
0289 volatile boost::uint32_t m_command;
0290 volatile boost::uint32_t m_num_waiters;
0291 };
0292
0293 }
0294 }
0295 }
0296
0297 #include <boost/interprocess/detail/config_end.hpp>
0298
0299 #endif