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