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