Chris@16
|
1 #ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
|
Chris@16
|
2 #define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
|
Chris@16
|
3 // (C) Copyright 2007-8 Anthony Williams
|
Chris@16
|
4 // (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
Chris@16
|
5 // Distributed under the Boost Software License, Version 1.0. (See
|
Chris@16
|
6 // accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
7 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
8
|
Chris@16
|
9 #include <pthread.h>
|
Chris@16
|
10 #include <boost/throw_exception.hpp>
|
Chris@16
|
11 #include <boost/thread/exceptions.hpp>
|
Chris@16
|
12 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
Chris@16
|
13 #include <boost/thread/lock_types.hpp>
|
Chris@16
|
14 #endif
|
Chris@16
|
15 #include <boost/thread/thread_time.hpp>
|
Chris@16
|
16 #include <boost/assert.hpp>
|
Chris@16
|
17 #ifndef _WIN32
|
Chris@16
|
18 #include <unistd.h>
|
Chris@16
|
19 #endif
|
Chris@16
|
20 #include <boost/date_time/posix_time/conversion.hpp>
|
Chris@16
|
21 #include <errno.h>
|
Chris@16
|
22 #include <boost/thread/pthread/timespec.hpp>
|
Chris@16
|
23 #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
Chris@16
|
24 #ifdef BOOST_THREAD_USES_CHRONO
|
Chris@16
|
25 #include <boost/chrono/system_clocks.hpp>
|
Chris@16
|
26 #include <boost/chrono/ceil.hpp>
|
Chris@16
|
27 #endif
|
Chris@16
|
28 #include <boost/thread/detail/delete.hpp>
|
Chris@16
|
29
|
Chris@16
|
30 #ifdef _POSIX_TIMEOUTS
|
Chris@16
|
31 #if _POSIX_TIMEOUTS >= 0 && _POSIX_TIMEOUTS>=200112L
|
Chris@16
|
32 #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
Chris@16
|
33 #define BOOST_PTHREAD_HAS_TIMEDLOCK
|
Chris@16
|
34 #endif
|
Chris@16
|
35 #endif
|
Chris@16
|
36 #endif
|
Chris@16
|
37
|
Chris@16
|
38
|
Chris@16
|
39 #if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) && defined(BOOST_PTHREAD_HAS_TIMEDLOCK)
|
Chris@16
|
40 #define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
Chris@16
|
41 #endif
|
Chris@16
|
42
|
Chris@16
|
43 #include <boost/config/abi_prefix.hpp>
|
Chris@16
|
44
|
Chris@16
|
45 namespace boost
|
Chris@16
|
46 {
|
Chris@16
|
47 class recursive_mutex
|
Chris@16
|
48 {
|
Chris@16
|
49 private:
|
Chris@16
|
50 pthread_mutex_t m;
|
Chris@16
|
51 #ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
Chris@16
|
52 pthread_cond_t cond;
|
Chris@16
|
53 bool is_locked;
|
Chris@16
|
54 pthread_t owner;
|
Chris@16
|
55 unsigned count;
|
Chris@16
|
56 #endif
|
Chris@16
|
57 public:
|
Chris@16
|
58 BOOST_THREAD_NO_COPYABLE(recursive_mutex)
|
Chris@16
|
59 recursive_mutex()
|
Chris@16
|
60 {
|
Chris@16
|
61 #ifdef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
Chris@16
|
62 pthread_mutexattr_t attr;
|
Chris@16
|
63
|
Chris@16
|
64 int const init_attr_res=pthread_mutexattr_init(&attr);
|
Chris@16
|
65 if(init_attr_res)
|
Chris@16
|
66 {
|
Chris@16
|
67 boost::throw_exception(thread_resource_error(init_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_init"));
|
Chris@16
|
68 }
|
Chris@16
|
69 int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
|
Chris@16
|
70 if(set_attr_res)
|
Chris@16
|
71 {
|
Chris@16
|
72 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
Chris@16
|
73 boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_settype"));
|
Chris@16
|
74 }
|
Chris@16
|
75
|
Chris@16
|
76 int const res=pthread_mutex_init(&m,&attr);
|
Chris@16
|
77 if(res)
|
Chris@16
|
78 {
|
Chris@16
|
79 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
Chris@16
|
80 boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init"));
|
Chris@16
|
81 }
|
Chris@16
|
82 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
Chris@16
|
83 #else
|
Chris@16
|
84 int const res=pthread_mutex_init(&m,NULL);
|
Chris@16
|
85 if(res)
|
Chris@16
|
86 {
|
Chris@16
|
87 boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init"));
|
Chris@16
|
88 }
|
Chris@16
|
89 int const res2=pthread_cond_init(&cond,NULL);
|
Chris@16
|
90 if(res2)
|
Chris@16
|
91 {
|
Chris@16
|
92 BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
Chris@16
|
93 boost::throw_exception(thread_resource_error(res2, "boost:: recursive_mutex constructor failed in pthread_cond_init"));
|
Chris@16
|
94 }
|
Chris@16
|
95 is_locked=false;
|
Chris@16
|
96 count=0;
|
Chris@16
|
97 #endif
|
Chris@16
|
98 }
|
Chris@16
|
99 ~recursive_mutex()
|
Chris@16
|
100 {
|
Chris@16
|
101 BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
Chris@16
|
102 #ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
Chris@16
|
103 BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
Chris@16
|
104 #endif
|
Chris@16
|
105 }
|
Chris@16
|
106
|
Chris@16
|
107 #ifdef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
Chris@16
|
108 void lock()
|
Chris@16
|
109 {
|
Chris@16
|
110 BOOST_VERIFY(!pthread_mutex_lock(&m));
|
Chris@16
|
111 }
|
Chris@16
|
112
|
Chris@16
|
113 void unlock()
|
Chris@16
|
114 {
|
Chris@16
|
115 BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
Chris@16
|
116 }
|
Chris@16
|
117
|
Chris@16
|
118 bool try_lock() BOOST_NOEXCEPT
|
Chris@16
|
119 {
|
Chris@16
|
120 int const res=pthread_mutex_trylock(&m);
|
Chris@16
|
121 BOOST_ASSERT(!res || res==EBUSY);
|
Chris@16
|
122 return !res;
|
Chris@16
|
123 }
|
Chris@16
|
124 #define BOOST_THREAD_DEFINES_RECURSIVE_MUTEX_NATIVE_HANDLE
|
Chris@16
|
125 typedef pthread_mutex_t* native_handle_type;
|
Chris@16
|
126 native_handle_type native_handle()
|
Chris@16
|
127 {
|
Chris@16
|
128 return &m;
|
Chris@16
|
129 }
|
Chris@16
|
130
|
Chris@16
|
131 #else
|
Chris@16
|
132 void lock()
|
Chris@16
|
133 {
|
Chris@16
|
134 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
Chris@16
|
135 if(is_locked && pthread_equal(owner,pthread_self()))
|
Chris@16
|
136 {
|
Chris@16
|
137 ++count;
|
Chris@16
|
138 return;
|
Chris@16
|
139 }
|
Chris@16
|
140
|
Chris@16
|
141 while(is_locked)
|
Chris@16
|
142 {
|
Chris@16
|
143 BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
|
Chris@16
|
144 }
|
Chris@16
|
145 is_locked=true;
|
Chris@16
|
146 ++count;
|
Chris@16
|
147 owner=pthread_self();
|
Chris@16
|
148 }
|
Chris@16
|
149
|
Chris@16
|
150 void unlock()
|
Chris@16
|
151 {
|
Chris@16
|
152 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
Chris@16
|
153 if(!--count)
|
Chris@16
|
154 {
|
Chris@16
|
155 is_locked=false;
|
Chris@16
|
156 }
|
Chris@16
|
157 BOOST_VERIFY(!pthread_cond_signal(&cond));
|
Chris@16
|
158 }
|
Chris@16
|
159
|
Chris@16
|
160 bool try_lock()
|
Chris@16
|
161 {
|
Chris@16
|
162 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
Chris@16
|
163 if(is_locked && !pthread_equal(owner,pthread_self()))
|
Chris@16
|
164 {
|
Chris@16
|
165 return false;
|
Chris@16
|
166 }
|
Chris@16
|
167 is_locked=true;
|
Chris@16
|
168 ++count;
|
Chris@16
|
169 owner=pthread_self();
|
Chris@16
|
170 return true;
|
Chris@16
|
171 }
|
Chris@16
|
172
|
Chris@16
|
173 #endif
|
Chris@16
|
174
|
Chris@16
|
175 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
Chris@16
|
176 typedef unique_lock<recursive_mutex> scoped_lock;
|
Chris@16
|
177 typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock;
|
Chris@16
|
178 #endif
|
Chris@16
|
179 };
|
Chris@16
|
180
|
Chris@16
|
181 typedef recursive_mutex recursive_try_mutex;
|
Chris@16
|
182
|
Chris@16
|
183 class recursive_timed_mutex
|
Chris@16
|
184 {
|
Chris@16
|
185 private:
|
Chris@16
|
186 pthread_mutex_t m;
|
Chris@16
|
187 #ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
Chris@16
|
188 pthread_cond_t cond;
|
Chris@16
|
189 bool is_locked;
|
Chris@16
|
190 pthread_t owner;
|
Chris@16
|
191 unsigned count;
|
Chris@16
|
192 #endif
|
Chris@16
|
193 public:
|
Chris@16
|
194 BOOST_THREAD_NO_COPYABLE(recursive_timed_mutex)
|
Chris@16
|
195 recursive_timed_mutex()
|
Chris@16
|
196 {
|
Chris@16
|
197 #ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
Chris@16
|
198 pthread_mutexattr_t attr;
|
Chris@16
|
199
|
Chris@16
|
200 int const init_attr_res=pthread_mutexattr_init(&attr);
|
Chris@16
|
201 if(init_attr_res)
|
Chris@16
|
202 {
|
Chris@16
|
203 boost::throw_exception(thread_resource_error(init_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_init"));
|
Chris@16
|
204 }
|
Chris@16
|
205 int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
|
Chris@16
|
206 if(set_attr_res)
|
Chris@16
|
207 {
|
Chris@16
|
208 boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_settype"));
|
Chris@16
|
209 }
|
Chris@16
|
210
|
Chris@16
|
211 int const res=pthread_mutex_init(&m,&attr);
|
Chris@16
|
212 if(res)
|
Chris@16
|
213 {
|
Chris@16
|
214 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
Chris@16
|
215 boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init"));
|
Chris@16
|
216 }
|
Chris@16
|
217 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
Chris@16
|
218 #else
|
Chris@16
|
219 int const res=pthread_mutex_init(&m,NULL);
|
Chris@16
|
220 if(res)
|
Chris@16
|
221 {
|
Chris@16
|
222 boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init"));
|
Chris@16
|
223 }
|
Chris@16
|
224 int const res2=pthread_cond_init(&cond,NULL);
|
Chris@16
|
225 if(res2)
|
Chris@16
|
226 {
|
Chris@16
|
227 BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
Chris@16
|
228 boost::throw_exception(thread_resource_error(res2, "boost:: recursive_timed_mutex constructor failed in pthread_cond_init"));
|
Chris@16
|
229 }
|
Chris@16
|
230 is_locked=false;
|
Chris@16
|
231 count=0;
|
Chris@16
|
232 #endif
|
Chris@16
|
233 }
|
Chris@16
|
234 ~recursive_timed_mutex()
|
Chris@16
|
235 {
|
Chris@16
|
236 BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
Chris@16
|
237 #ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
Chris@16
|
238 BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
Chris@16
|
239 #endif
|
Chris@16
|
240 }
|
Chris@16
|
241
|
Chris@16
|
242 #if defined BOOST_THREAD_USES_DATETIME
|
Chris@16
|
243 template<typename TimeDuration>
|
Chris@16
|
244 bool timed_lock(TimeDuration const & relative_time)
|
Chris@16
|
245 {
|
Chris@16
|
246 return timed_lock(get_system_time()+relative_time);
|
Chris@16
|
247 }
|
Chris@16
|
248 #endif
|
Chris@16
|
249
|
Chris@16
|
250 #ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
Chris@16
|
251 void lock()
|
Chris@16
|
252 {
|
Chris@16
|
253 BOOST_VERIFY(!pthread_mutex_lock(&m));
|
Chris@16
|
254 }
|
Chris@16
|
255
|
Chris@16
|
256 void unlock()
|
Chris@16
|
257 {
|
Chris@16
|
258 BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
Chris@16
|
259 }
|
Chris@16
|
260
|
Chris@16
|
261 bool try_lock()
|
Chris@16
|
262 {
|
Chris@16
|
263 int const res=pthread_mutex_trylock(&m);
|
Chris@16
|
264 BOOST_ASSERT(!res || res==EBUSY);
|
Chris@16
|
265 return !res;
|
Chris@16
|
266 }
|
Chris@16
|
267 private:
|
Chris@16
|
268 bool do_try_lock_until(struct timespec const &timeout)
|
Chris@16
|
269 {
|
Chris@16
|
270 int const res=pthread_mutex_timedlock(&m,&timeout);
|
Chris@16
|
271 BOOST_ASSERT(!res || res==ETIMEDOUT);
|
Chris@16
|
272 return !res;
|
Chris@16
|
273 }
|
Chris@16
|
274
|
Chris@16
|
275 public:
|
Chris@16
|
276
|
Chris@16
|
277 #else
|
Chris@16
|
278 void lock()
|
Chris@16
|
279 {
|
Chris@16
|
280 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
Chris@16
|
281 if(is_locked && pthread_equal(owner,pthread_self()))
|
Chris@16
|
282 {
|
Chris@16
|
283 ++count;
|
Chris@16
|
284 return;
|
Chris@16
|
285 }
|
Chris@16
|
286
|
Chris@16
|
287 while(is_locked)
|
Chris@16
|
288 {
|
Chris@16
|
289 BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
|
Chris@16
|
290 }
|
Chris@16
|
291 is_locked=true;
|
Chris@16
|
292 ++count;
|
Chris@16
|
293 owner=pthread_self();
|
Chris@16
|
294 }
|
Chris@16
|
295
|
Chris@16
|
296 void unlock()
|
Chris@16
|
297 {
|
Chris@16
|
298 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
Chris@16
|
299 if(!--count)
|
Chris@16
|
300 {
|
Chris@16
|
301 is_locked=false;
|
Chris@16
|
302 }
|
Chris@16
|
303 BOOST_VERIFY(!pthread_cond_signal(&cond));
|
Chris@16
|
304 }
|
Chris@16
|
305
|
Chris@16
|
306 bool try_lock() BOOST_NOEXCEPT
|
Chris@16
|
307 {
|
Chris@16
|
308 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
Chris@16
|
309 if(is_locked && !pthread_equal(owner,pthread_self()))
|
Chris@16
|
310 {
|
Chris@16
|
311 return false;
|
Chris@16
|
312 }
|
Chris@16
|
313 is_locked=true;
|
Chris@16
|
314 ++count;
|
Chris@16
|
315 owner=pthread_self();
|
Chris@16
|
316 return true;
|
Chris@16
|
317 }
|
Chris@16
|
318
|
Chris@16
|
319 private:
|
Chris@16
|
320 bool do_try_lock_until(struct timespec const &timeout)
|
Chris@16
|
321 {
|
Chris@16
|
322 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
Chris@16
|
323 if(is_locked && pthread_equal(owner,pthread_self()))
|
Chris@16
|
324 {
|
Chris@16
|
325 ++count;
|
Chris@16
|
326 return true;
|
Chris@16
|
327 }
|
Chris@16
|
328 while(is_locked)
|
Chris@16
|
329 {
|
Chris@16
|
330 int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
|
Chris@16
|
331 if(cond_res==ETIMEDOUT)
|
Chris@16
|
332 {
|
Chris@16
|
333 return false;
|
Chris@16
|
334 }
|
Chris@16
|
335 BOOST_ASSERT(!cond_res);
|
Chris@16
|
336 }
|
Chris@16
|
337 is_locked=true;
|
Chris@16
|
338 ++count;
|
Chris@16
|
339 owner=pthread_self();
|
Chris@16
|
340 return true;
|
Chris@16
|
341 }
|
Chris@16
|
342 public:
|
Chris@16
|
343
|
Chris@16
|
344 #endif
|
Chris@16
|
345
|
Chris@16
|
346 #if defined BOOST_THREAD_USES_DATETIME
|
Chris@16
|
347 bool timed_lock(system_time const & abs_time)
|
Chris@16
|
348 {
|
Chris@16
|
349 struct timespec const ts=detail::to_timespec(abs_time);
|
Chris@16
|
350 return do_try_lock_until(ts);
|
Chris@16
|
351 }
|
Chris@16
|
352 #endif
|
Chris@16
|
353 #ifdef BOOST_THREAD_USES_CHRONO
|
Chris@16
|
354 template <class Rep, class Period>
|
Chris@16
|
355 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
Chris@16
|
356 {
|
Chris@16
|
357 return try_lock_until(chrono::steady_clock::now() + rel_time);
|
Chris@16
|
358 }
|
Chris@16
|
359 template <class Clock, class Duration>
|
Chris@16
|
360 bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
|
Chris@16
|
361 {
|
Chris@16
|
362 using namespace chrono;
|
Chris@16
|
363 system_clock::time_point s_now = system_clock::now();
|
Chris@16
|
364 typename Clock::time_point c_now = Clock::now();
|
Chris@16
|
365 return try_lock_until(s_now + ceil<nanoseconds>(t - c_now));
|
Chris@16
|
366 }
|
Chris@16
|
367 template <class Duration>
|
Chris@16
|
368 bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
|
Chris@16
|
369 {
|
Chris@16
|
370 using namespace chrono;
|
Chris@16
|
371 typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
|
Chris@16
|
372 return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
|
Chris@16
|
373 }
|
Chris@16
|
374 bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
|
Chris@16
|
375 {
|
Chris@16
|
376 //using namespace chrono;
|
Chris@16
|
377 chrono::nanoseconds d = tp.time_since_epoch();
|
Chris@16
|
378 timespec ts = boost::detail::to_timespec(d);
|
Chris@16
|
379 return do_try_lock_until(ts);
|
Chris@16
|
380 }
|
Chris@16
|
381 #endif
|
Chris@16
|
382
|
Chris@16
|
383 #define BOOST_THREAD_DEFINES_RECURSIVE_TIMED_MUTEX_NATIVE_HANDLE
|
Chris@16
|
384 typedef pthread_mutex_t* native_handle_type;
|
Chris@16
|
385 native_handle_type native_handle()
|
Chris@16
|
386 {
|
Chris@16
|
387 return &m;
|
Chris@16
|
388 }
|
Chris@16
|
389
|
Chris@16
|
390 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
Chris@16
|
391 typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
|
Chris@16
|
392 typedef detail::try_lock_wrapper<recursive_timed_mutex> scoped_try_lock;
|
Chris@16
|
393 typedef scoped_timed_lock scoped_lock;
|
Chris@16
|
394 #endif
|
Chris@16
|
395 };
|
Chris@16
|
396
|
Chris@16
|
397 }
|
Chris@16
|
398
|
Chris@16
|
399 #include <boost/config/abi_suffix.hpp>
|
Chris@16
|
400
|
Chris@16
|
401 #endif
|