]>
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> | |
11fdf7f2 | 19 | #if defined BOOST_THREAD_USES_DATETIME |
7c673cae | 20 | #include <boost/thread/xtime.hpp> |
11fdf7f2 | 21 | #endif |
7c673cae FG |
22 | #include <boost/assert.hpp> |
23 | #include <errno.h> | |
11fdf7f2 | 24 | #include <boost/thread/detail/platform_time.hpp> |
7c673cae | 25 | #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> |
11fdf7f2 | 26 | #include <boost/thread/pthread/pthread_helpers.hpp> |
7c673cae FG |
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 | ||
7c673cae FG |
33 | |
34 | #include <boost/config/abi_prefix.hpp> | |
35 | ||
7c673cae FG |
36 | namespace boost |
37 | { | |
7c673cae | 38 | |
92f5a8d4 | 39 | class BOOST_THREAD_CAPABILITY("mutex") mutex |
7c673cae FG |
40 | { |
41 | private: | |
42 | pthread_mutex_t m; | |
43 | public: | |
44 | BOOST_THREAD_NO_COPYABLE(mutex) | |
45 | ||
46 | mutex() | |
47 | { | |
92f5a8d4 | 48 | int const res=posix::pthread_mutex_init(&m); |
7c673cae FG |
49 | if(res) |
50 | { | |
51 | boost::throw_exception(thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init")); | |
52 | } | |
53 | } | |
54 | ~mutex() | |
55 | { | |
92f5a8d4 | 56 | BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); |
7c673cae FG |
57 | } |
58 | ||
92f5a8d4 | 59 | void lock() BOOST_THREAD_ACQUIRE() |
7c673cae FG |
60 | { |
61 | int res = posix::pthread_mutex_lock(&m); | |
62 | if (res) | |
63 | { | |
64 | boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock")); | |
65 | } | |
66 | } | |
67 | ||
92f5a8d4 | 68 | void unlock() BOOST_THREAD_RELEASE() |
7c673cae | 69 | { |
92f5a8d4 | 70 | BOOST_VERIFY(!posix::pthread_mutex_unlock(&m)); |
7c673cae FG |
71 | } |
72 | ||
92f5a8d4 | 73 | bool try_lock() BOOST_THREAD_TRY_ACQUIRE(true) |
7c673cae | 74 | { |
92f5a8d4 | 75 | int res = posix::pthread_mutex_trylock(&m); |
7c673cae FG |
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; | |
11fdf7f2 | 103 | #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK |
7c673cae FG |
104 | pthread_cond_t cond; |
105 | bool is_locked; | |
106 | #endif | |
107 | public: | |
108 | BOOST_THREAD_NO_COPYABLE(timed_mutex) | |
109 | timed_mutex() | |
110 | { | |
92f5a8d4 | 111 | int const res=posix::pthread_mutex_init(&m); |
7c673cae FG |
112 | if(res) |
113 | { | |
114 | boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init")); | |
115 | } | |
11fdf7f2 | 116 | #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK |
92f5a8d4 | 117 | int const res2=posix::pthread_cond_init(&cond); |
7c673cae FG |
118 | if(res2) |
119 | { | |
120 | BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); | |
92f5a8d4 | 121 | boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init")); |
7c673cae FG |
122 | } |
123 | is_locked=false; | |
124 | #endif | |
125 | } | |
126 | ~timed_mutex() | |
127 | { | |
128 | BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); | |
11fdf7f2 | 129 | #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK |
92f5a8d4 | 130 | BOOST_VERIFY(!posix::pthread_cond_destroy(&cond)); |
7c673cae FG |
131 | #endif |
132 | } | |
133 | ||
134 | #if defined BOOST_THREAD_USES_DATETIME | |
135 | template<typename TimeDuration> | |
136 | bool timed_lock(TimeDuration const & relative_time) | |
137 | { | |
11fdf7f2 TL |
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(detail::internal_platform_clock::now() + d); | |
160 | #endif | |
7c673cae FG |
161 | } |
162 | bool timed_lock(boost::xtime const & absolute_time) | |
163 | { | |
164 | return timed_lock(system_time(absolute_time)); | |
165 | } | |
166 | #endif | |
11fdf7f2 | 167 | #ifdef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK |
7c673cae FG |
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 | { | |
92f5a8d4 | 179 | BOOST_VERIFY(!posix::pthread_mutex_unlock(&m)); |
7c673cae FG |
180 | } |
181 | ||
182 | bool try_lock() | |
183 | { | |
92f5a8d4 | 184 | int res = posix::pthread_mutex_trylock(&m); |
7c673cae FG |
185 | if (res==EBUSY) |
186 | { | |
187 | return false; | |
188 | } | |
189 | ||
190 | return !res; | |
191 | } | |
192 | ||
193 | ||
194 | private: | |
11fdf7f2 | 195 | bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) |
7c673cae | 196 | { |
11fdf7f2 | 197 | int const res=pthread_mutex_timedlock(&m,&timeout.getTs()); |
7c673cae FG |
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 | { | |
92f5a8d4 | 209 | BOOST_VERIFY(!posix::pthread_cond_wait(&cond,&m)); |
7c673cae FG |
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; | |
92f5a8d4 | 218 | BOOST_VERIFY(!posix::pthread_cond_signal(&cond)); |
7c673cae FG |
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: | |
11fdf7f2 | 233 | bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) |
7c673cae FG |
234 | { |
235 | boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); | |
236 | while(is_locked) | |
237 | { | |
92f5a8d4 | 238 | int const cond_res=posix::pthread_cond_timedwait(&cond,&m,&timeout.getTs()); |
7c673cae FG |
239 | if(cond_res==ETIMEDOUT) |
240 | { | |
11fdf7f2 | 241 | break; |
7c673cae FG |
242 | } |
243 | BOOST_ASSERT(!cond_res); | |
244 | } | |
11fdf7f2 TL |
245 | if(is_locked) |
246 | { | |
247 | return false; | |
248 | } | |
7c673cae FG |
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 | { | |
11fdf7f2 TL |
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)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); | |
262 | while ( ! do_try_lock_until(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)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); | |
267 | } | |
268 | return true; | |
269 | #else | |
7c673cae | 270 | return do_try_lock_until(ts); |
11fdf7f2 | 271 | #endif |
7c673cae FG |
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 | { | |
11fdf7f2 TL |
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; | |
7c673cae FG |
293 | } |
294 | template <class Duration> | |
11fdf7f2 | 295 | bool try_lock_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t) |
7c673cae | 296 | { |
11fdf7f2 | 297 | detail::internal_platform_timepoint ts(t); |
7c673cae FG |
298 | return do_try_lock_until(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 | }; | |
7c673cae FG |
315 | } |
316 | ||
317 | #include <boost/config/abi_suffix.hpp> | |
318 | ||
319 | ||
320 | #endif |