File indexing completed on 2025-12-16 10:10:03
0001 #ifndef BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
0002 #define BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <boost/assert.hpp>
0014 #include <boost/thread/win32/thread_primitives.hpp>
0015 #include <boost/thread/win32/interlocked_read.hpp>
0016 #include <boost/thread/thread_time.hpp>
0017 #if defined BOOST_THREAD_USES_DATETIME
0018 #include <boost/thread/xtime.hpp>
0019 #endif
0020 #include <boost/detail/interlocked.hpp>
0021 #ifdef BOOST_THREAD_USES_CHRONO
0022 #include <boost/chrono/system_clocks.hpp>
0023 #include <boost/chrono/ceil.hpp>
0024 #endif
0025 #include <boost/thread/detail/platform_time.hpp>
0026
0027 #include <boost/config/abi_prefix.hpp>
0028
0029 namespace boost
0030 {
0031 namespace detail
0032 {
0033 struct BOOST_THREAD_CAPABILITY("mutex") basic_timed_mutex
0034 {
0035 BOOST_STATIC_CONSTANT(unsigned char,lock_flag_bit=31);
0036 BOOST_STATIC_CONSTANT(unsigned char,event_set_flag_bit=30);
0037 BOOST_STATIC_CONSTANT(long,lock_flag_value=1<<lock_flag_bit);
0038 BOOST_STATIC_CONSTANT(long,event_set_flag_value=1<<event_set_flag_bit);
0039 long active_count;
0040 void* event;
0041
0042 void initialize()
0043 {
0044 active_count=0;
0045 event=0;
0046 }
0047
0048 void destroy()
0049 {
0050 #ifdef BOOST_MSVC
0051 #pragma warning(push)
0052 #pragma warning(disable:4312)
0053 #endif
0054 void* const old_event=BOOST_INTERLOCKED_EXCHANGE_POINTER(&event,0);
0055 #ifdef BOOST_MSVC
0056 #pragma warning(pop)
0057 #endif
0058 if(old_event)
0059 {
0060 winapi::CloseHandle(old_event);
0061 }
0062 }
0063
0064
0065 bool try_lock() BOOST_NOEXCEPT BOOST_THREAD_TRY_ACQUIRE(true)
0066 {
0067 return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit);
0068 }
0069
0070 void lock() BOOST_THREAD_ACQUIRE()
0071 {
0072 if(try_lock())
0073 {
0074 return;
0075 }
0076 long old_count=active_count;
0077 mark_waiting_and_try_lock(old_count);
0078
0079 if(old_count&lock_flag_value)
0080 {
0081 void* const sem=get_event();
0082
0083 do
0084 {
0085 if(winapi::WaitForSingleObjectEx(sem,::boost::detail::win32::infinite,0)==0)
0086 {
0087 clear_waiting_and_try_lock(old_count);
0088 }
0089 }
0090 while(old_count&lock_flag_value);
0091 }
0092 }
0093
0094
0095
0096 void mark_waiting_and_try_lock(long& old_count) BOOST_THREAD_TRY_ACQUIRE(true)
0097 {
0098 for(;;)
0099 {
0100 bool const was_locked=(old_count&lock_flag_value) ? true : false;
0101 long const new_count=was_locked?(old_count+1):(old_count|lock_flag_value);
0102 long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
0103 if(current==old_count)
0104 {
0105 if(was_locked)
0106 old_count=new_count;
0107
0108
0109
0110 break;
0111 }
0112 old_count=current;
0113 }
0114 }
0115
0116
0117
0118
0119
0120 void clear_waiting_and_try_lock(long& old_count) BOOST_THREAD_TRY_ACQUIRE(true)
0121 {
0122 old_count&=~lock_flag_value;
0123 old_count|=event_set_flag_value;
0124 for(;;)
0125 {
0126 long const new_count=((old_count&lock_flag_value)?old_count:((old_count-1)|lock_flag_value))&~event_set_flag_value;
0127 long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
0128 if(current==old_count)
0129 {
0130
0131
0132
0133
0134
0135
0136 break;
0137 }
0138 old_count=current;
0139 }
0140 }
0141
0142 private:
0143 unsigned long getMs(detail::platform_duration const& d)
0144 {
0145 return static_cast<unsigned long>(d.getMs());
0146 }
0147
0148 template <typename Duration>
0149 unsigned long getMs(Duration const& d)
0150 {
0151 return static_cast<unsigned long>(chrono::ceil<chrono::milliseconds>(d).count());
0152 }
0153
0154 template <typename Clock, typename Timepoint, typename Duration>
0155 bool do_lock_until(Timepoint const& t, Duration const& max) BOOST_THREAD_TRY_ACQUIRE(true)
0156 {
0157 if(try_lock())
0158 {
0159 return true;
0160 }
0161
0162 long old_count=active_count;
0163 mark_waiting_and_try_lock(old_count);
0164
0165 if(old_count&lock_flag_value)
0166 {
0167 void* const sem=get_event();
0168
0169
0170
0171
0172
0173 do
0174 {
0175 Duration d(t - Clock::now());
0176 if(d <= Duration::zero())
0177 {
0178 BOOST_INTERLOCKED_DECREMENT(&active_count);
0179 return false;
0180 }
0181 if(max != Duration::zero())
0182 {
0183 d = (std::min)(d, max);
0184 }
0185 if(winapi::WaitForSingleObjectEx(sem,getMs(d),0)==0)
0186 {
0187 clear_waiting_and_try_lock(old_count);
0188 }
0189 }
0190 while(old_count&lock_flag_value);
0191 }
0192 return true;
0193 }
0194 public:
0195
0196 #if defined BOOST_THREAD_USES_DATETIME
0197 bool timed_lock(::boost::system_time const& wait_until)
0198 {
0199 const detail::real_platform_timepoint t(wait_until);
0200 return do_lock_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
0201 }
0202
0203 template<typename Duration>
0204 bool timed_lock(Duration const& timeout)
0205 {
0206 const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(timeout));
0207
0208 return do_lock_until<detail::mono_platform_clock>(t, detail::platform_duration::zero());
0209 }
0210
0211 bool timed_lock(boost::xtime const& timeout)
0212 {
0213 return timed_lock(boost::system_time(timeout));
0214 }
0215 #endif
0216 #ifdef BOOST_THREAD_USES_CHRONO
0217 template <class Rep, class Period>
0218 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
0219 {
0220 const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time);
0221 typedef typename chrono::duration<Rep, Period> Duration;
0222 typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
0223
0224 return do_lock_until<chrono::steady_clock>(t, common_duration::zero());
0225 }
0226 template <class Duration>
0227 bool try_lock_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
0228 {
0229 typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
0230
0231 return do_lock_until<chrono::steady_clock>(t, common_duration::zero());
0232 }
0233 template <class Clock, class Duration>
0234 bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
0235 {
0236 typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
0237 return do_lock_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
0238 }
0239 #endif
0240
0241 void unlock() BOOST_THREAD_RELEASE()
0242 {
0243
0244 long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value);
0245
0246
0247 if(!(old_count&event_set_flag_value) && (old_count>lock_flag_value))
0248 {
0249 if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit))
0250 {
0251 winapi::SetEvent(get_event());
0252 }
0253 }
0254 }
0255
0256 private:
0257
0258
0259 void* get_event()
0260 {
0261 void* current_event=::boost::detail::interlocked_read_acquire(&event);
0262
0263 if(!current_event)
0264 {
0265 void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset);
0266 #ifdef BOOST_MSVC
0267 #pragma warning(push)
0268 #pragma warning(disable:4311)
0269 #pragma warning(disable:4312)
0270 #endif
0271 void* const old_event=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&event,new_event,0);
0272 #ifdef BOOST_MSVC
0273 #pragma warning(pop)
0274 #endif
0275 if(old_event!=0)
0276 {
0277 winapi::CloseHandle(new_event);
0278 return old_event;
0279 }
0280 else
0281 {
0282 return new_event;
0283 }
0284 }
0285 return current_event;
0286 }
0287
0288 };
0289
0290 }
0291 }
0292
0293 #define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0}
0294
0295 #include <boost/config/abi_suffix.hpp>
0296
0297 #endif