1 | #ifndef BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP |
2 | #define BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP |
3 | // Distributed under the Boost Software License, Version 1.0. (See |
4 | // accompanying file LICENSE_1_0.txt or copy at |
5 | // http://www.boost.org/LICENSE_1_0.txt) |
6 | // (C) Copyright 2007-8 Anthony Williams |
7 | // (C) Copyright 2011-2012 Vicente J. Botet Escriba |
8 | |
9 | #include <boost/assert.hpp> |
10 | #include <boost/throw_exception.hpp> |
11 | #include <pthread.h> |
12 | #include <boost/thread/cv_status.hpp> |
13 | #include <boost/thread/mutex.hpp> |
14 | #include <boost/thread/lock_types.hpp> |
15 | #include <boost/thread/thread_time.hpp> |
16 | #include <boost/thread/pthread/timespec.hpp> |
17 | #if defined BOOST_THREAD_USES_DATETIME |
18 | #include <boost/thread/xtime.hpp> |
19 | #endif |
20 | #ifdef BOOST_THREAD_USES_CHRONO |
21 | #include <boost/chrono/system_clocks.hpp> |
22 | #include <boost/chrono/ceil.hpp> |
23 | #endif |
24 | #include <boost/thread/detail/delete.hpp> |
25 | #include <boost/date_time/posix_time/posix_time_duration.hpp> |
26 | |
27 | #include <boost/config/abi_prefix.hpp> |
28 | |
29 | namespace boost |
30 | { |
31 | namespace detail { |
32 | inline int monotonic_pthread_cond_init(pthread_cond_t& cond) { |
33 | |
34 | #ifdef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC |
35 | pthread_condattr_t attr; |
36 | int res = pthread_condattr_init(&attr); |
37 | if (res) |
38 | { |
39 | return res; |
40 | } |
41 | pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); |
42 | res=pthread_cond_init(&cond,&attr); |
43 | pthread_condattr_destroy(&attr); |
44 | return res; |
45 | #else |
46 | return pthread_cond_init(&cond,NULL); |
47 | #endif |
48 | |
49 | } |
50 | } |
51 | |
52 | class condition_variable |
53 | { |
54 | private: |
55 | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS |
56 | pthread_mutex_t internal_mutex; |
57 | #endif |
58 | pthread_cond_t cond; |
59 | |
60 | public: |
61 | //private: // used by boost::thread::try_join_until |
62 | |
63 | inline bool do_wait_until( |
64 | unique_lock<mutex>& lock, |
65 | struct timespec const &timeout); |
66 | |
67 | bool do_wait_for( |
68 | unique_lock<mutex>& lock, |
69 | struct timespec const &timeout) |
70 | { |
71 | return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now())); |
72 | } |
73 | |
74 | public: |
75 | BOOST_THREAD_NO_COPYABLE(condition_variable) |
76 | condition_variable() |
77 | { |
78 | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS |
79 | int res=pthread_mutex_init(&internal_mutex,NULL); |
80 | if(res) |
81 | { |
82 | boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread_mutex_init" )); |
83 | } |
84 | #endif |
85 | res = detail::monotonic_pthread_cond_init(cond); |
86 | if (res) |
87 | { |
88 | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS |
89 | BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); |
90 | #endif |
91 | boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in detail::monotonic_pthread_cond_init" )); |
92 | } |
93 | } |
94 | ~condition_variable() |
95 | { |
96 | int ret; |
97 | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS |
98 | do { |
99 | ret = pthread_mutex_destroy(&internal_mutex); |
100 | } while (ret == EINTR); |
101 | BOOST_ASSERT(!ret); |
102 | #endif |
103 | do { |
104 | ret = pthread_cond_destroy(&cond); |
105 | } while (ret == EINTR); |
106 | BOOST_ASSERT(!ret); |
107 | } |
108 | |
109 | void wait(unique_lock<mutex>& m); |
110 | |
111 | template<typename predicate_type> |
112 | void wait(unique_lock<mutex>& m,predicate_type pred) |
113 | { |
114 | while(!pred()) wait(m); |
115 | } |
116 | |
117 | #if defined BOOST_THREAD_USES_DATETIME |
118 | inline bool timed_wait( |
119 | unique_lock<mutex>& m, |
120 | boost::system_time const& abs_time) |
121 | { |
122 | #if defined BOOST_THREAD_WAIT_BUG |
123 | struct timespec const timeout=detail::to_timespec(abs_time + BOOST_THREAD_WAIT_BUG); |
124 | return do_wait_until(m, timeout); |
125 | #else |
126 | struct timespec const timeout=detail::to_timespec(abs_time); |
127 | return do_wait_until(m, timeout); |
128 | #endif |
129 | } |
130 | bool timed_wait( |
131 | unique_lock<mutex>& m, |
132 | xtime const& abs_time) |
133 | { |
134 | return timed_wait(m,system_time(abs_time)); |
135 | } |
136 | |
137 | template<typename duration_type> |
138 | bool timed_wait( |
139 | unique_lock<mutex>& m, |
140 | duration_type const& wait_duration) |
141 | { |
142 | if (wait_duration.is_pos_infinity()) |
143 | { |
144 | wait(m); // or do_wait(m,detail::timeout::sentinel()); |
145 | return true; |
146 | } |
147 | if (wait_duration.is_special()) |
148 | { |
149 | return true; |
150 | } |
151 | return timed_wait(m,get_system_time()+wait_duration); |
152 | } |
153 | |
154 | template<typename predicate_type> |
155 | bool timed_wait( |
156 | unique_lock<mutex>& m, |
157 | boost::system_time const& abs_time,predicate_type pred) |
158 | { |
159 | while (!pred()) |
160 | { |
161 | if(!timed_wait(m, abs_time)) |
162 | return pred(); |
163 | } |
164 | return true; |
165 | } |
166 | |
167 | template<typename predicate_type> |
168 | bool timed_wait( |
169 | unique_lock<mutex>& m, |
170 | xtime const& abs_time,predicate_type pred) |
171 | { |
172 | return timed_wait(m,system_time(abs_time),pred); |
173 | } |
174 | |
175 | template<typename duration_type,typename predicate_type> |
176 | bool timed_wait( |
177 | unique_lock<mutex>& m, |
178 | duration_type const& wait_duration,predicate_type pred) |
179 | { |
180 | if (wait_duration.is_pos_infinity()) |
181 | { |
182 | while (!pred()) |
183 | { |
184 | wait(m); // or do_wait(m,detail::timeout::sentinel()); |
185 | } |
186 | return true; |
187 | } |
188 | if (wait_duration.is_special()) |
189 | { |
190 | return pred(); |
191 | } |
192 | return timed_wait(m,get_system_time()+wait_duration,pred); |
193 | } |
194 | #endif |
195 | |
196 | #ifndef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC |
197 | |
198 | #ifdef BOOST_THREAD_USES_CHRONO |
199 | |
200 | template <class Duration> |
201 | cv_status |
202 | wait_until( |
203 | unique_lock<mutex>& lock, |
204 | const chrono::time_point<chrono::system_clock, Duration>& t) |
205 | { |
206 | using namespace chrono; |
207 | typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; |
208 | wait_until(lock, |
209 | nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); |
210 | return system_clock::now() < t ? cv_status::no_timeout : |
211 | cv_status::timeout; |
212 | } |
213 | |
214 | template <class Clock, class Duration> |
215 | cv_status |
216 | wait_until( |
217 | unique_lock<mutex>& lock, |
218 | const chrono::time_point<Clock, Duration>& t) |
219 | { |
220 | using namespace chrono; |
221 | system_clock::time_point s_now = system_clock::now(); |
222 | typename Clock::time_point c_now = Clock::now(); |
223 | wait_until(lock, s_now + ceil<nanoseconds>(t - c_now)); |
224 | return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout; |
225 | } |
226 | |
227 | |
228 | |
229 | template <class Rep, class Period> |
230 | cv_status |
231 | wait_for( |
232 | unique_lock<mutex>& lock, |
233 | const chrono::duration<Rep, Period>& d) |
234 | { |
235 | using namespace chrono; |
236 | system_clock::time_point s_now = system_clock::now(); |
237 | steady_clock::time_point c_now = steady_clock::now(); |
238 | wait_until(lock, s_now + ceil<nanoseconds>(d)); |
239 | return steady_clock::now() - c_now < d ? cv_status::no_timeout : |
240 | cv_status::timeout; |
241 | |
242 | } |
243 | |
244 | inline cv_status wait_until( |
245 | unique_lock<mutex>& lk, |
246 | chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp) |
247 | { |
248 | using namespace chrono; |
249 | nanoseconds d = tp.time_since_epoch(); |
250 | timespec ts = boost::detail::to_timespec(d); |
251 | if (do_wait_until(lk, ts)) return cv_status::no_timeout; |
252 | else return cv_status::timeout; |
253 | } |
254 | #endif |
255 | |
256 | #else // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC |
257 | #ifdef BOOST_THREAD_USES_CHRONO |
258 | |
259 | template <class Duration> |
260 | cv_status |
261 | wait_until( |
262 | unique_lock<mutex>& lock, |
263 | const chrono::time_point<chrono::steady_clock, Duration>& t) |
264 | { |
265 | using namespace chrono; |
266 | typedef time_point<steady_clock, nanoseconds> nano_sys_tmpt; |
267 | wait_until(lock, |
268 | nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); |
269 | return steady_clock::now() < t ? cv_status::no_timeout : |
270 | cv_status::timeout; |
271 | } |
272 | |
273 | template <class Clock, class Duration> |
274 | cv_status |
275 | wait_until( |
276 | unique_lock<mutex>& lock, |
277 | const chrono::time_point<Clock, Duration>& t) |
278 | { |
279 | using namespace chrono; |
280 | steady_clock::time_point s_now = steady_clock::now(); |
281 | typename Clock::time_point c_now = Clock::now(); |
282 | wait_until(lock, s_now + ceil<nanoseconds>(t - c_now)); |
283 | return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout; |
284 | } |
285 | |
286 | template <class Rep, class Period> |
287 | cv_status |
288 | wait_for( |
289 | unique_lock<mutex>& lock, |
290 | const chrono::duration<Rep, Period>& d) |
291 | { |
292 | using namespace chrono; |
293 | steady_clock::time_point c_now = steady_clock::now(); |
294 | wait_until(lock, c_now + ceil<nanoseconds>(d)); |
295 | return steady_clock::now() - c_now < d ? cv_status::no_timeout : |
296 | cv_status::timeout; |
297 | } |
298 | |
299 | inline cv_status wait_until( |
300 | unique_lock<mutex>& lk, |
301 | chrono::time_point<chrono::steady_clock, chrono::nanoseconds> tp) |
302 | { |
303 | using namespace chrono; |
304 | nanoseconds d = tp.time_since_epoch(); |
305 | timespec ts = boost::detail::to_timespec(d); |
306 | if (do_wait_until(lk, ts)) return cv_status::no_timeout; |
307 | else return cv_status::timeout; |
308 | } |
309 | #endif |
310 | |
311 | #endif // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC |
312 | |
313 | #ifdef BOOST_THREAD_USES_CHRONO |
314 | template <class Clock, class Duration, class Predicate> |
315 | bool |
316 | wait_until( |
317 | unique_lock<mutex>& lock, |
318 | const chrono::time_point<Clock, Duration>& t, |
319 | Predicate pred) |
320 | { |
321 | while (!pred()) |
322 | { |
323 | if (wait_until(lock, t) == cv_status::timeout) |
324 | return pred(); |
325 | } |
326 | return true; |
327 | } |
328 | |
329 | template <class Rep, class Period, class Predicate> |
330 | bool |
331 | wait_for( |
332 | unique_lock<mutex>& lock, |
333 | const chrono::duration<Rep, Period>& d, |
334 | Predicate pred) |
335 | { |
336 | return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); |
337 | } |
338 | #endif |
339 | |
340 | #define BOOST_THREAD_DEFINES_CONDITION_VARIABLE_NATIVE_HANDLE |
341 | typedef pthread_cond_t* native_handle_type; |
342 | native_handle_type native_handle() |
343 | { |
344 | return &cond; |
345 | } |
346 | |
347 | void notify_one() BOOST_NOEXCEPT; |
348 | void notify_all() BOOST_NOEXCEPT; |
349 | |
350 | |
351 | }; |
352 | |
353 | BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk); |
354 | |
355 | } |
356 | |
357 | |
358 | #include <boost/config/abi_suffix.hpp> |
359 | |
360 | #endif |
361 | |