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
30namespace 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