]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 |