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