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