1 #ifndef BOOST_BASIC_TIMED_MUTEX_WIN32_HPP 2 #define BOOST_BASIC_TIMED_MUTEX_WIN32_HPP 3 4 // basic_timed_mutex_win32.hpp 5 // 6 // (C) Copyright 2006-8 Anthony Williams 7 // (C) Copyright 2011-2012 Vicente J. Botet Escriba 8 // 9 // Distributed under the Boost Software License, Version 1.0. (See 10 // accompanying file LICENSE_1_0.txt or copy at 11 // http://www.boost.org/LICENSE_1_0.txt) 12 13 #include <boost/assert.hpp> 14 #include <boost/thread/win32/thread_primitives.hpp> 15 #include <boost/thread/win32/interlocked_read.hpp> 16 #include <boost/thread/thread_time.hpp> 17 #if defined BOOST_THREAD_USES_DATETIME 18 #include <boost/thread/xtime.hpp> 19 #endif 20 #include <boost/detail/interlocked.hpp> 21 #ifdef BOOST_THREAD_USES_CHRONO 22 #include <boost/chrono/system_clocks.hpp> 23 #include <boost/chrono/ceil.hpp> 24 #endif 25 #include <boost/config/abi_prefix.hpp> 26 27 namespace boost 28 { 29 namespace detail 30 { 31 struct basic_timed_mutex 32 { 33 BOOST_STATIC_CONSTANT(unsigned char,lock_flag_bit=31); 34 BOOST_STATIC_CONSTANT(unsigned char,event_set_flag_bit=30); 35 BOOST_STATIC_CONSTANT(long,lock_flag_value=1<<lock_flag_bit); 36 BOOST_STATIC_CONSTANT(long,event_set_flag_value=1<<event_set_flag_bit); 37 long active_count; 38 void* event; 39 initializeboost::detail::basic_timed_mutex40 void initialize() 41 { 42 active_count=0; 43 event=0; 44 } 45 destroyboost::detail::basic_timed_mutex46 void destroy() 47 { 48 #ifdef BOOST_MSVC 49 #pragma warning(push) 50 #pragma warning(disable:4312) 51 #endif 52 void* const old_event=BOOST_INTERLOCKED_EXCHANGE_POINTER(&event,0); 53 #ifdef BOOST_MSVC 54 #pragma warning(pop) 55 #endif 56 if(old_event) 57 { 58 win32::CloseHandle(old_event); 59 } 60 } 61 62 try_lockboost::detail::basic_timed_mutex63 bool try_lock() BOOST_NOEXCEPT 64 { 65 return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit); 66 } 67 lockboost::detail::basic_timed_mutex68 void lock() 69 { 70 if(try_lock()) 71 { 72 return; 73 } 74 long old_count=active_count; 75 mark_waiting_and_try_lock(old_count); 76 77 if(old_count&lock_flag_value) 78 { 79 bool lock_acquired=false; 80 void* const sem=get_event(); 81 82 do 83 { 84 unsigned const retval(win32::WaitForSingleObjectEx(sem, ::boost::detail::win32::infinite,0)); 85 BOOST_VERIFY(0 == retval || ::boost::detail::win32::wait_abandoned == retval); 86 // BOOST_VERIFY(win32::WaitForSingleObject( 87 // sem,::boost::detail::win32::infinite)==0); 88 clear_waiting_and_try_lock(old_count); 89 lock_acquired=!(old_count&lock_flag_value); 90 } 91 while(!lock_acquired); 92 } 93 } mark_waiting_and_try_lockboost::detail::basic_timed_mutex94 void mark_waiting_and_try_lock(long& old_count) 95 { 96 for(;;) 97 { 98 bool const was_locked=(old_count&lock_flag_value) ? true : false; 99 long const new_count=was_locked?(old_count+1):(old_count|lock_flag_value); 100 long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count); 101 if(current==old_count) 102 { 103 if(was_locked) 104 old_count=new_count; 105 break; 106 } 107 old_count=current; 108 } 109 } 110 clear_waiting_and_try_lockboost::detail::basic_timed_mutex111 void clear_waiting_and_try_lock(long& old_count) 112 { 113 old_count&=~lock_flag_value; 114 old_count|=event_set_flag_value; 115 for(;;) 116 { 117 long const new_count=((old_count&lock_flag_value)?old_count:((old_count-1)|lock_flag_value))&~event_set_flag_value; 118 long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count); 119 if(current==old_count) 120 { 121 break; 122 } 123 old_count=current; 124 } 125 } 126 127 128 #if defined BOOST_THREAD_USES_DATETIME timed_lockboost::detail::basic_timed_mutex129 bool timed_lock(::boost::system_time const& wait_until) 130 { 131 if(try_lock()) 132 { 133 return true; 134 } 135 long old_count=active_count; 136 mark_waiting_and_try_lock(old_count); 137 138 if(old_count&lock_flag_value) 139 { 140 bool lock_acquired=false; 141 void* const sem=get_event(); 142 143 do 144 { 145 if(win32::WaitForSingleObjectEx(sem,::boost::detail::get_milliseconds_until(wait_until),0)!=0) 146 { 147 BOOST_INTERLOCKED_DECREMENT(&active_count); 148 return false; 149 } 150 clear_waiting_and_try_lock(old_count); 151 lock_acquired=!(old_count&lock_flag_value); 152 } 153 while(!lock_acquired); 154 } 155 return true; 156 } 157 158 template<typename Duration> timed_lockboost::detail::basic_timed_mutex159 bool timed_lock(Duration const& timeout) 160 { 161 return timed_lock(get_system_time()+timeout); 162 } 163 timed_lockboost::detail::basic_timed_mutex164 bool timed_lock(boost::xtime const& timeout) 165 { 166 return timed_lock(system_time(timeout)); 167 } 168 #endif 169 #ifdef BOOST_THREAD_USES_CHRONO 170 template <class Rep, class Period> try_lock_forboost::detail::basic_timed_mutex171 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) 172 { 173 return try_lock_until(chrono::steady_clock::now() + rel_time); 174 } 175 template <class Clock, class Duration> try_lock_untilboost::detail::basic_timed_mutex176 bool try_lock_until(const chrono::time_point<Clock, Duration>& t) 177 { 178 using namespace chrono; 179 system_clock::time_point s_now = system_clock::now(); 180 typename Clock::time_point c_now = Clock::now(); 181 return try_lock_until(s_now + ceil<system_clock::duration>(t - c_now)); 182 } 183 template <class Duration> try_lock_untilboost::detail::basic_timed_mutex184 bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t) 185 { 186 using namespace chrono; 187 typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt; 188 return try_lock_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch()))); 189 } try_lock_untilboost::detail::basic_timed_mutex190 bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp) 191 { 192 if(try_lock()) 193 { 194 return true; 195 } 196 long old_count=active_count; 197 mark_waiting_and_try_lock(old_count); 198 199 if(old_count&lock_flag_value) 200 { 201 bool lock_acquired=false; 202 void* const sem=get_event(); 203 204 do 205 { 206 chrono::time_point<chrono::system_clock, chrono::system_clock::duration> now = chrono::system_clock::now(); 207 if (tp<=now) { 208 BOOST_INTERLOCKED_DECREMENT(&active_count); 209 return false; 210 } 211 chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-now); 212 213 if(win32::WaitForSingleObjectEx(sem,static_cast<unsigned long>(rel_time.count()),0)!=0) 214 { 215 BOOST_INTERLOCKED_DECREMENT(&active_count); 216 return false; 217 } 218 clear_waiting_and_try_lock(old_count); 219 lock_acquired=!(old_count&lock_flag_value); 220 } 221 while(!lock_acquired); 222 } 223 return true; 224 } 225 #endif 226 unlockboost::detail::basic_timed_mutex227 void unlock() 228 { 229 long const offset=lock_flag_value; 230 long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value); 231 if(!(old_count&event_set_flag_value) && (old_count>offset)) 232 { 233 if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit)) 234 { 235 win32::SetEvent(get_event()); 236 } 237 } 238 } 239 240 private: get_eventboost::detail::basic_timed_mutex241 void* get_event() 242 { 243 void* current_event=::boost::detail::interlocked_read_acquire(&event); 244 245 if(!current_event) 246 { 247 void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset); 248 #ifdef BOOST_MSVC 249 #pragma warning(push) 250 #pragma warning(disable:4311) 251 #pragma warning(disable:4312) 252 #endif 253 void* const old_event=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&event,new_event,0); 254 #ifdef BOOST_MSVC 255 #pragma warning(pop) 256 #endif 257 if(old_event!=0) 258 { 259 win32::CloseHandle(new_event); 260 return old_event; 261 } 262 else 263 { 264 return new_event; 265 } 266 } 267 return current_event; 268 } 269 270 }; 271 272 } 273 } 274 275 #define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0} 276 277 #include <boost/config/abi_suffix.hpp> 278 279 #endif 280