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 // 8 // Distributed under the Boost Software License, Version 1.0. (See 9 // accompanying file LICENSE_1_0.txt or copy at 10 // http://www.boost.org/LICENSE_1_0.txt) 11 12 #include <boost/assert.hpp> 13 #include "thread_primitives.hpp" 14 #include "interlocked_read.hpp" 15 #include <boost/thread/thread_time.hpp> 16 #include <boost/thread/xtime.hpp> 17 #include <boost/detail/interlocked.hpp> 18 19 #include <boost/config/abi_prefix.hpp> 20 21 namespace boost 22 { 23 namespace detail 24 { 25 struct basic_timed_mutex 26 { 27 BOOST_STATIC_CONSTANT(unsigned char,lock_flag_bit=31); 28 BOOST_STATIC_CONSTANT(unsigned char,event_set_flag_bit=30); 29 BOOST_STATIC_CONSTANT(long,lock_flag_value=1<<lock_flag_bit); 30 BOOST_STATIC_CONSTANT(long,event_set_flag_value=1<<event_set_flag_bit); 31 long active_count; 32 void* event; 33 initializeboost::detail::basic_timed_mutex34 void initialize() 35 { 36 active_count=0; 37 event=0; 38 } 39 destroyboost::detail::basic_timed_mutex40 void destroy() 41 { 42 #ifdef BOOST_MSVC 43 #pragma warning(push) 44 #pragma warning(disable:4312) 45 #endif 46 void* const old_event=BOOST_INTERLOCKED_EXCHANGE_POINTER(&event,0); 47 #ifdef BOOST_MSVC 48 #pragma warning(pop) 49 #endif 50 if(old_event) 51 { 52 win32::CloseHandle(old_event); 53 } 54 } 55 56 try_lockboost::detail::basic_timed_mutex57 bool try_lock() 58 { 59 return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit); 60 } 61 lockboost::detail::basic_timed_mutex62 void lock() 63 { 64 if(try_lock()) 65 { 66 return; 67 } 68 long old_count=active_count; 69 mark_waiting_and_try_lock(old_count); 70 71 if(old_count&lock_flag_value) 72 { 73 bool lock_acquired=false; 74 void* const sem=get_event(); 75 76 do 77 { 78 BOOST_VERIFY(win32::WaitForSingleObject( 79 sem,::boost::detail::win32::infinite)==0); 80 clear_waiting_and_try_lock(old_count); 81 lock_acquired=!(old_count&lock_flag_value); 82 } 83 while(!lock_acquired); 84 } 85 } mark_waiting_and_try_lockboost::detail::basic_timed_mutex86 void mark_waiting_and_try_lock(long& old_count) 87 { 88 for(;;) 89 { 90 long const new_count=(old_count&lock_flag_value)?(old_count+1):(old_count|lock_flag_value); 91 long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count); 92 if(current==old_count) 93 { 94 break; 95 } 96 old_count=current; 97 } 98 } 99 clear_waiting_and_try_lockboost::detail::basic_timed_mutex100 void clear_waiting_and_try_lock(long& old_count) 101 { 102 old_count&=~lock_flag_value; 103 old_count|=event_set_flag_value; 104 for(;;) 105 { 106 long const new_count=((old_count&lock_flag_value)?old_count:((old_count-1)|lock_flag_value))&~event_set_flag_value; 107 long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count); 108 if(current==old_count) 109 { 110 break; 111 } 112 old_count=current; 113 } 114 } 115 116 timed_lockboost::detail::basic_timed_mutex117 bool timed_lock(::boost::system_time const& wait_until) 118 { 119 if(try_lock()) 120 { 121 return true; 122 } 123 long old_count=active_count; 124 mark_waiting_and_try_lock(old_count); 125 126 if(old_count&lock_flag_value) 127 { 128 bool lock_acquired=false; 129 void* const sem=get_event(); 130 131 do 132 { 133 if(win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until(wait_until))!=0) 134 { 135 BOOST_INTERLOCKED_DECREMENT(&active_count); 136 return false; 137 } 138 clear_waiting_and_try_lock(old_count); 139 lock_acquired=!(old_count&lock_flag_value); 140 } 141 while(!lock_acquired); 142 } 143 return true; 144 } 145 146 template<typename Duration> timed_lockboost::detail::basic_timed_mutex147 bool timed_lock(Duration const& timeout) 148 { 149 return timed_lock(get_system_time()+timeout); 150 } 151 timed_lockboost::detail::basic_timed_mutex152 bool timed_lock(boost::xtime const& timeout) 153 { 154 return timed_lock(system_time(timeout)); 155 } 156 unlockboost::detail::basic_timed_mutex157 void unlock() 158 { 159 long const offset=lock_flag_value; 160 long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value); 161 if(!(old_count&event_set_flag_value) && (old_count>offset)) 162 { 163 if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit)) 164 { 165 win32::SetEvent(get_event()); 166 } 167 } 168 } 169 170 private: get_eventboost::detail::basic_timed_mutex171 void* get_event() 172 { 173 void* current_event=::boost::detail::interlocked_read_acquire(&event); 174 175 if(!current_event) 176 { 177 void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset); 178 #ifdef BOOST_MSVC 179 #pragma warning(push) 180 #pragma warning(disable:4311) 181 #pragma warning(disable:4312) 182 #endif 183 void* const old_event=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&event,new_event,0); 184 #ifdef BOOST_MSVC 185 #pragma warning(pop) 186 #endif 187 if(old_event!=0) 188 { 189 win32::CloseHandle(new_event); 190 return old_event; 191 } 192 else 193 { 194 return new_event; 195 } 196 } 197 return current_event; 198 } 199 200 }; 201 202 } 203 } 204 205 #define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0} 206 207 #include <boost/config/abi_suffix.hpp> 208 209 #endif 210