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 | #if defined BOOST_THREAD_USES_DATETIME |
20 | #include <boost/thread/xtime.hpp> |
21 | #endif |
22 | #include <boost/assert.hpp> |
23 | #include <errno.h> |
24 | #include <boost/thread/detail/platform_time.hpp> |
25 | #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> |
26 | #include <boost/thread/pthread/pthread_helpers.hpp> |
27 | #ifdef BOOST_THREAD_USES_CHRONO |
28 | #include <boost/chrono/system_clocks.hpp> |
29 | #include <boost/chrono/ceil.hpp> |
30 | #endif |
31 | #include <boost/thread/detail/delete.hpp> |
32 | |
33 | |
34 | #include <boost/config/abi_prefix.hpp> |
35 | |
36 | namespace boost |
37 | { |
38 | |
39 | class BOOST_THREAD_CAPABILITY("mutex" ) mutex |
40 | { |
41 | private: |
42 | pthread_mutex_t m; |
43 | public: |
44 | BOOST_THREAD_NO_COPYABLE(mutex) |
45 | |
46 | mutex() |
47 | { |
48 | int const res=posix::pthread_mutex_init(m: &m); |
49 | if(res) |
50 | { |
51 | boost::throw_exception(e: thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init" )); |
52 | } |
53 | } |
54 | ~mutex() |
55 | { |
56 | BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); |
57 | } |
58 | |
59 | void lock() BOOST_THREAD_ACQUIRE() |
60 | { |
61 | int res = posix::pthread_mutex_lock(m: &m); |
62 | if (res) |
63 | { |
64 | boost::throw_exception(e: lock_error(res,"boost: mutex lock failed in pthread_mutex_lock" )); |
65 | } |
66 | } |
67 | |
68 | void unlock() BOOST_THREAD_RELEASE() |
69 | { |
70 | BOOST_VERIFY(!posix::pthread_mutex_unlock(&m)); |
71 | } |
72 | |
73 | bool try_lock() BOOST_THREAD_TRY_ACQUIRE(true) |
74 | { |
75 | int res = posix::pthread_mutex_trylock(m: &m); |
76 | if (res==EBUSY) |
77 | { |
78 | return false; |
79 | } |
80 | |
81 | return !res; |
82 | } |
83 | |
84 | #define BOOST_THREAD_DEFINES_MUTEX_NATIVE_HANDLE |
85 | typedef pthread_mutex_t* native_handle_type; |
86 | native_handle_type native_handle() |
87 | { |
88 | return &m; |
89 | } |
90 | |
91 | #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS |
92 | typedef unique_lock<mutex> scoped_lock; |
93 | typedef detail::try_lock_wrapper<mutex> scoped_try_lock; |
94 | #endif |
95 | }; |
96 | |
97 | typedef mutex try_mutex; |
98 | |
99 | class timed_mutex |
100 | { |
101 | private: |
102 | pthread_mutex_t m; |
103 | #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK |
104 | pthread_cond_t cond; |
105 | bool is_locked; |
106 | #endif |
107 | public: |
108 | BOOST_THREAD_NO_COPYABLE(timed_mutex) |
109 | timed_mutex() |
110 | { |
111 | int const res=posix::pthread_mutex_init(m: &m); |
112 | if(res) |
113 | { |
114 | boost::throw_exception(e: thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init" )); |
115 | } |
116 | #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK |
117 | int const res2=posix::pthread_cond_init(c: &cond); |
118 | if(res2) |
119 | { |
120 | BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); |
121 | boost::throw_exception(e: thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init" )); |
122 | } |
123 | is_locked=false; |
124 | #endif |
125 | } |
126 | ~timed_mutex() |
127 | { |
128 | BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); |
129 | #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK |
130 | BOOST_VERIFY(!posix::pthread_cond_destroy(&cond)); |
131 | #endif |
132 | } |
133 | |
134 | #if defined BOOST_THREAD_USES_DATETIME |
135 | template<typename TimeDuration> |
136 | bool timed_lock(TimeDuration const & relative_time) |
137 | { |
138 | if (relative_time.is_pos_infinity()) |
139 | { |
140 | lock(); |
141 | return true; |
142 | } |
143 | if (relative_time.is_special()) |
144 | { |
145 | return true; |
146 | } |
147 | detail::platform_duration d(relative_time); |
148 | #if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) |
149 | const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); |
150 | d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); |
151 | while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) ) |
152 | { |
153 | d = ts - detail::mono_platform_clock::now(); |
154 | if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred |
155 | d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); |
156 | } |
157 | return true; |
158 | #else |
159 | return do_try_lock_until(timeout: detail::internal_platform_clock::now() + d); |
160 | #endif |
161 | } |
162 | bool timed_lock(boost::xtime const & absolute_time) |
163 | { |
164 | return timed_lock(abs_time: system_time(absolute_time)); |
165 | } |
166 | #endif |
167 | #ifdef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK |
168 | void lock() |
169 | { |
170 | int res = posix::pthread_mutex_lock(&m); |
171 | if (res) |
172 | { |
173 | boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock" )); |
174 | } |
175 | } |
176 | |
177 | void unlock() |
178 | { |
179 | BOOST_VERIFY(!posix::pthread_mutex_unlock(&m)); |
180 | } |
181 | |
182 | bool try_lock() |
183 | { |
184 | int res = posix::pthread_mutex_trylock(&m); |
185 | if (res==EBUSY) |
186 | { |
187 | return false; |
188 | } |
189 | |
190 | return !res; |
191 | } |
192 | |
193 | |
194 | private: |
195 | bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) |
196 | { |
197 | int const res=pthread_mutex_timedlock(&m,&timeout.getTs()); |
198 | BOOST_ASSERT(!res || res==ETIMEDOUT); |
199 | return !res; |
200 | } |
201 | public: |
202 | |
203 | #else |
204 | void lock() |
205 | { |
206 | boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); |
207 | while(is_locked) |
208 | { |
209 | BOOST_VERIFY(!posix::pthread_cond_wait(&cond,&m)); |
210 | } |
211 | is_locked=true; |
212 | } |
213 | |
214 | void unlock() |
215 | { |
216 | boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); |
217 | is_locked=false; |
218 | BOOST_VERIFY(!posix::pthread_cond_signal(&cond)); |
219 | } |
220 | |
221 | bool try_lock() |
222 | { |
223 | boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); |
224 | if(is_locked) |
225 | { |
226 | return false; |
227 | } |
228 | is_locked=true; |
229 | return true; |
230 | } |
231 | |
232 | private: |
233 | bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) |
234 | { |
235 | boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); |
236 | while(is_locked) |
237 | { |
238 | int const cond_res=posix::pthread_cond_timedwait(c: &cond,m: &m,t: &timeout.getTs()); |
239 | if(cond_res==ETIMEDOUT) |
240 | { |
241 | break; |
242 | } |
243 | BOOST_ASSERT(!cond_res); |
244 | } |
245 | if(is_locked) |
246 | { |
247 | return false; |
248 | } |
249 | is_locked=true; |
250 | return true; |
251 | } |
252 | public: |
253 | #endif |
254 | |
255 | #if defined BOOST_THREAD_USES_DATETIME |
256 | bool timed_lock(system_time const & abs_time) |
257 | { |
258 | const detail::real_platform_timepoint ts(abs_time); |
259 | #if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO |
260 | detail::platform_duration d(ts - detail::real_platform_clock::now()); |
261 | d = (std::min)(a: d, b: detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); |
262 | while ( ! do_try_lock_until(timeout: detail::internal_platform_clock::now() + d) ) |
263 | { |
264 | d = ts - detail::real_platform_clock::now(); |
265 | if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred |
266 | d = (std::min)(a: d, b: detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); |
267 | } |
268 | return true; |
269 | #else |
270 | return do_try_lock_until(ts); |
271 | #endif |
272 | } |
273 | #endif |
274 | #ifdef BOOST_THREAD_USES_CHRONO |
275 | template <class Rep, class Period> |
276 | bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) |
277 | { |
278 | return try_lock_until(chrono::steady_clock::now() + rel_time); |
279 | } |
280 | template <class Clock, class Duration> |
281 | bool try_lock_until(const chrono::time_point<Clock, Duration>& t) |
282 | { |
283 | typedef typename common_type<Duration, typename Clock::duration>::type common_duration; |
284 | common_duration d(t - Clock::now()); |
285 | d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); |
286 | while ( ! try_lock_until(detail::internal_chrono_clock::now() + d)) |
287 | { |
288 | d = t - Clock::now(); |
289 | if ( d <= common_duration::zero() ) return false; // timeout occurred |
290 | d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); |
291 | } |
292 | return true; |
293 | } |
294 | template <class Duration> |
295 | bool try_lock_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t) |
296 | { |
297 | detail::internal_platform_timepoint ts(t); |
298 | return do_try_lock_until(timeout: ts); |
299 | } |
300 | #endif |
301 | |
302 | #define BOOST_THREAD_DEFINES_TIMED_MUTEX_NATIVE_HANDLE |
303 | typedef pthread_mutex_t* native_handle_type; |
304 | native_handle_type native_handle() |
305 | { |
306 | return &m; |
307 | } |
308 | |
309 | #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS |
310 | typedef unique_lock<timed_mutex> scoped_timed_lock; |
311 | typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock; |
312 | typedef scoped_timed_lock scoped_lock; |
313 | #endif |
314 | }; |
315 | } |
316 | |
317 | #include <boost/config/abi_suffix.hpp> |
318 | |
319 | |
320 | #endif |
321 | |