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 | |
44 | namespace 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 | |