1#ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP
2#define BOOST_THREAD_PTHREAD_MUTEX_HPP
3// (C) Copyright 2007-8 Anthony Williams
4// (C) Copyright 2011,2012,2015 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 <boost/thread/detail/config.hpp>
10#include <boost/assert.hpp>
11#include <pthread.h>
12#include <boost/throw_exception.hpp>
13#include <boost/core/ignore_unused.hpp>
14#include <boost/thread/exceptions.hpp>
15#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
16#include <boost/thread/lock_types.hpp>
17#endif
18#include <boost/thread/thread_time.hpp>
19#include <boost/thread/xtime.hpp>
20#include <boost/assert.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
38#include <boost/config/abi_prefix.hpp>
39
40#ifndef BOOST_THREAD_HAS_NO_EINTR_BUG
41#define BOOST_THREAD_HAS_EINTR_BUG
42#endif
43
44namespace boost
45{
46 namespace posix {
47#ifdef BOOST_THREAD_HAS_EINTR_BUG
48 BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
49 {
50 int ret;
51 do
52 {
53 ret = ::pthread_mutex_destroy(m);
54 } while (ret == EINTR);
55 return ret;
56 }
57 BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
58 {
59 int ret;
60 do
61 {
62 ret = ::pthread_mutex_lock(m);
63 } while (ret == EINTR);
64 return ret;
65 }
66 BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
67 {
68 int ret;
69 do
70 {
71 ret = ::pthread_mutex_unlock(m);
72 } while (ret == EINTR);
73 return ret;
74 }
75#else
76 BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
77 {
78 return ::pthread_mutex_destroy(m);
79 }
80 BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
81 {
82 return ::pthread_mutex_lock(m);
83 }
84 BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
85 {
86 return ::pthread_mutex_unlock(m);
87 }
88
89#endif
90
91 }
92 class mutex
93 {
94 private:
95 pthread_mutex_t m;
96 public:
97 BOOST_THREAD_NO_COPYABLE(mutex)
98
99 mutex()
100 {
101 int const res=pthread_mutex_init(&m,NULL);
102 if(res)
103 {
104 boost::throw_exception(thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init"));
105 }
106 }
107 ~mutex()
108 {
109 int const res = posix::pthread_mutex_destroy(&m);
110 boost::ignore_unused(res);
111 BOOST_ASSERT(!res);
112 }
113
114 void lock()
115 {
116 int res = posix::pthread_mutex_lock(&m);
117 if (res)
118 {
119 boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
120 }
121 }
122
123 void unlock()
124 {
125 int res = posix::pthread_mutex_unlock(&m);
126 (void)res;
127 BOOST_ASSERT(res == 0);
128// if (res)
129// {
130// boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
131// }
132 }
133
134 bool try_lock()
135 {
136 int res;
137 do
138 {
139 res = pthread_mutex_trylock(&m);
140 } while (res == EINTR);
141 if (res==EBUSY)
142 {
143 return false;
144 }
145
146 return !res;
147 }
148
149#define BOOST_THREAD_DEFINES_MUTEX_NATIVE_HANDLE
150 typedef pthread_mutex_t* native_handle_type;
151 native_handle_type native_handle()
152 {
153 return &m;
154 }
155
156#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
157 typedef unique_lock<mutex> scoped_lock;
158 typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
159#endif
160 };
161
162 typedef mutex try_mutex;
163
164 class timed_mutex
165 {
166 private:
167 pthread_mutex_t m;
168#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
169 pthread_cond_t cond;
170 bool is_locked;
171#endif
172 public:
173 BOOST_THREAD_NO_COPYABLE(timed_mutex)
174 timed_mutex()
175 {
176 int const res=pthread_mutex_init(&m,NULL);
177 if(res)
178 {
179 boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init"));
180 }
181#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
182 int const res2=pthread_cond_init(&cond,NULL);
183 if(res2)
184 {
185 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
186 //BOOST_VERIFY(!pthread_mutex_destroy(&m));
187 boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init"));
188 }
189 is_locked=false;
190#endif
191 }
192 ~timed_mutex()
193 {
194 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
195#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
196 BOOST_VERIFY(!pthread_cond_destroy(&cond));
197#endif
198 }
199
200#if defined BOOST_THREAD_USES_DATETIME
201 template<typename TimeDuration>
202 bool timed_lock(TimeDuration const & relative_time)
203 {
204 return timed_lock(get_system_time()+relative_time);
205 }
206 bool timed_lock(boost::xtime const & absolute_time)
207 {
208 return timed_lock(system_time(absolute_time));
209 }
210#endif
211#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
212 void lock()
213 {
214 int res = posix::pthread_mutex_lock(&m);
215 if (res)
216 {
217 boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
218 }
219 }
220
221 void unlock()
222 {
223 int res = posix::pthread_mutex_unlock(&m);
224 (void)res;
225 BOOST_ASSERT(res == 0);
226// if (res)
227// {
228// boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
229// }
230 }
231
232 bool try_lock()
233 {
234 int res;
235 do
236 {
237 res = pthread_mutex_trylock(&m);
238 } while (res == EINTR);
239 if (res==EBUSY)
240 {
241 return false;
242 }
243
244 return !res;
245 }
246
247
248 private:
249 bool do_try_lock_until(struct timespec const &timeout)
250 {
251 int const res=pthread_mutex_timedlock(&m,&timeout);
252 BOOST_ASSERT(!res || res==ETIMEDOUT);
253 return !res;
254 }
255 public:
256
257#else
258 void lock()
259 {
260 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
261 while(is_locked)
262 {
263 BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
264 }
265 is_locked=true;
266 }
267
268 void unlock()
269 {
270 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
271 is_locked=false;
272 BOOST_VERIFY(!pthread_cond_signal(&cond));
273 }
274
275 bool try_lock()
276 {
277 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
278 if(is_locked)
279 {
280 return false;
281 }
282 is_locked=true;
283 return true;
284 }
285
286 private:
287 bool do_try_lock_until(struct timespec const &timeout)
288 {
289 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
290 while(is_locked)
291 {
292 int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
293 if(cond_res==ETIMEDOUT)
294 {
295 return false;
296 }
297 BOOST_ASSERT(!cond_res);
298 }
299 is_locked=true;
300 return true;
301 }
302 public:
303#endif
304
305#if defined BOOST_THREAD_USES_DATETIME
306 bool timed_lock(system_time const & abs_time)
307 {
308 struct timespec const ts=boost::detail::to_timespec(abs_time);
309 return do_try_lock_until(ts);
310 }
311#endif
312#ifdef BOOST_THREAD_USES_CHRONO
313 template <class Rep, class Period>
314 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
315 {
316 return try_lock_until(chrono::steady_clock::now() + rel_time);
317 }
318 template <class Clock, class Duration>
319 bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
320 {
321 using namespace chrono;
322 system_clock::time_point s_now = system_clock::now();
323 typename Clock::time_point c_now = Clock::now();
324 return try_lock_until(s_now + ceil<nanoseconds>(t - c_now));
325 }
326 template <class Duration>
327 bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
328 {
329 using namespace chrono;
330 typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
331 return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
332 }
333 bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
334 {
335 //using namespace chrono;
336 chrono::nanoseconds d = tp.time_since_epoch();
337 timespec ts = boost::detail::to_timespec(d);
338 return do_try_lock_until(ts);
339 }
340#endif
341
342#define BOOST_THREAD_DEFINES_TIMED_MUTEX_NATIVE_HANDLE
343 typedef pthread_mutex_t* native_handle_type;
344 native_handle_type native_handle()
345 {
346 return &m;
347 }
348
349#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
350 typedef unique_lock<timed_mutex> scoped_timed_lock;
351 typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
352 typedef scoped_timed_lock scoped_lock;
353#endif
354 };
355
356}
357
358#include <boost/config/abi_suffix.hpp>
359
360
361#endif
362