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