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