Line data Source code
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/detail/platform_time.hpp>
17 : #include <boost/thread/pthread/pthread_helpers.hpp>
18 :
19 : #if defined BOOST_THREAD_USES_DATETIME
20 : #include <boost/thread/xtime.hpp>
21 : #endif
22 :
23 : #ifdef BOOST_THREAD_USES_CHRONO
24 : #include <boost/chrono/system_clocks.hpp>
25 : #include <boost/chrono/ceil.hpp>
26 : #endif
27 : #include <boost/thread/detail/delete.hpp>
28 : #include <boost/date_time/posix_time/posix_time_duration.hpp>
29 :
30 : #include <algorithm>
31 :
32 : #include <boost/config/abi_prefix.hpp>
33 :
34 : namespace boost
35 : {
36 : class condition_variable
37 : {
38 : private:
39 : //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
40 : pthread_mutex_t internal_mutex;
41 : //#endif
42 : pthread_cond_t cond;
43 :
44 : public:
45 : //private: // used by boost::thread::try_join_until
46 :
47 : bool do_wait_until(
48 : unique_lock<mutex>& lock,
49 : detail::internal_platform_timepoint const &timeout);
50 :
51 : public:
52 : BOOST_THREAD_NO_COPYABLE(condition_variable)
53 : condition_variable()
54 : {
55 : int res;
56 : //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
57 : // Even if it is not used, the internal_mutex exists (see
58 : // above) and must be initialized (etc) in case some
59 : // compilation units provide interruptions and others
60 : // don't.
61 : res=posix::pthread_mutex_init(&internal_mutex);
62 : if(res)
63 : {
64 : boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread_mutex_init"));
65 : }
66 : //#endif
67 : res = posix::pthread_cond_init(&cond);
68 : if (res)
69 : {
70 : //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
71 : // ditto
72 : BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex));
73 : //#endif
74 : boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread_cond_init"));
75 : }
76 : }
77 0 : ~condition_variable()
78 0 : {
79 : //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
80 : // ditto
81 0 : BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex));
82 : //#endif
83 0 : BOOST_VERIFY(!posix::pthread_cond_destroy(&cond));
84 0 : }
85 :
86 : void wait(unique_lock<mutex>& m);
87 :
88 : template<typename predicate_type>
89 0 : void wait(unique_lock<mutex>& m,predicate_type pred)
90 : {
91 0 : while (!pred())
92 : {
93 0 : wait(m);
94 : }
95 0 : }
96 :
97 : #if defined BOOST_THREAD_USES_DATETIME
98 : bool timed_wait(
99 : unique_lock<mutex>& m,
100 : boost::system_time const& abs_time)
101 : {
102 : #if defined BOOST_THREAD_WAIT_BUG
103 : const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG);
104 : #else
105 : const detail::real_platform_timepoint ts(abs_time);
106 : #endif
107 : #if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
108 : // The system time may jump while this function is waiting. To compensate for this and time
109 : // out near the correct time, we could call do_wait_until() in a loop with a short timeout
110 : // and recheck the time remaining each time through the loop. However, because we can't
111 : // check the predicate each time do_wait_until() completes, this introduces the possibility
112 : // of not exiting the function when a notification occurs, since do_wait_until() may report
113 : // that it timed out even though a notification was received. The best this function can do
114 : // is report correctly whether or not it reached the timeout time.
115 : const detail::platform_duration d(ts - detail::real_platform_clock::now());
116 : do_wait_until(m, detail::internal_platform_clock::now() + d);
117 : return ts > detail::real_platform_clock::now();
118 : #else
119 : return do_wait_until(m, ts);
120 : #endif
121 : }
122 : bool timed_wait(
123 : unique_lock<mutex>& m,
124 : ::boost::xtime const& abs_time)
125 : {
126 : return timed_wait(m,system_time(abs_time));
127 : }
128 :
129 : template<typename duration_type>
130 : bool timed_wait(
131 : unique_lock<mutex>& m,
132 : duration_type const& wait_duration)
133 : {
134 : if (wait_duration.is_pos_infinity())
135 : {
136 : wait(m);
137 : return true;
138 : }
139 : if (wait_duration.is_special())
140 : {
141 : return true;
142 : }
143 : detail::platform_duration d(wait_duration);
144 : #if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
145 : // The system time may jump while this function is waiting. To compensate for this and time
146 : // out near the correct time, we could call do_wait_until() in a loop with a short timeout
147 : // and recheck the time remaining each time through the loop. However, because we can't
148 : // check the predicate each time do_wait_until() completes, this introduces the possibility
149 : // of not exiting the function when a notification occurs, since do_wait_until() may report
150 : // that it timed out even though a notification was received. The best this function can do
151 : // is report correctly whether or not it reached the timeout time.
152 : const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
153 : do_wait_until(m, detail::internal_platform_clock::now() + d);
154 : return ts > detail::mono_platform_clock::now();
155 : #else
156 : return do_wait_until(m, detail::internal_platform_clock::now() + d);
157 : #endif
158 : }
159 :
160 : template<typename predicate_type>
161 : bool timed_wait(
162 : unique_lock<mutex>& m,
163 : boost::system_time const& abs_time,predicate_type pred)
164 : {
165 : #if defined BOOST_THREAD_WAIT_BUG
166 : const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG);
167 : #else
168 : const detail::real_platform_timepoint ts(abs_time);
169 : #endif
170 : while (!pred())
171 : {
172 : #if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
173 : // The system time may jump while this function is waiting. To compensate for this
174 : // and time out near the correct time, we call do_wait_until() in a loop with a
175 : // short timeout and recheck the time remaining each time through the loop.
176 : detail::platform_duration d(ts - detail::real_platform_clock::now());
177 : if (d <= detail::platform_duration::zero()) break; // timeout occurred
178 : d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
179 : do_wait_until(m, detail::internal_platform_clock::now() + d);
180 : #else
181 : if (!do_wait_until(m, ts)) break; // timeout occurred
182 : #endif
183 : }
184 : return pred();
185 : }
186 :
187 : template<typename predicate_type>
188 : bool timed_wait(
189 : unique_lock<mutex>& m,
190 : ::boost::xtime const& abs_time,predicate_type pred)
191 : {
192 : return timed_wait(m,system_time(abs_time),pred);
193 : }
194 :
195 : template<typename duration_type,typename predicate_type>
196 : bool timed_wait(
197 : unique_lock<mutex>& m,
198 : duration_type const& wait_duration,predicate_type pred)
199 : {
200 : if (wait_duration.is_pos_infinity())
201 : {
202 : while (!pred())
203 : {
204 : wait(m);
205 : }
206 : return true;
207 : }
208 : if (wait_duration.is_special())
209 : {
210 : return pred();
211 : }
212 : detail::platform_duration d(wait_duration);
213 : #if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
214 : // The system time may jump while this function is waiting. To compensate for this
215 : // and time out near the correct time, we call do_wait_until() in a loop with a
216 : // short timeout and recheck the time remaining each time through the loop.
217 : const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
218 : while (!pred())
219 : {
220 : if (d <= detail::platform_duration::zero()) break; // timeout occurred
221 : d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
222 : do_wait_until(m, detail::internal_platform_clock::now() + d);
223 : d = ts - detail::mono_platform_clock::now();
224 : }
225 : #else
226 : const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
227 : while (!pred())
228 : {
229 : if (!do_wait_until(m, ts)) break; // timeout occurred
230 : }
231 : #endif
232 : return pred();
233 : }
234 : #endif
235 :
236 : #ifdef BOOST_THREAD_USES_CHRONO
237 :
238 : template <class Duration>
239 : cv_status
240 : wait_until(
241 : unique_lock<mutex>& lock,
242 : const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
243 : {
244 : const detail::internal_platform_timepoint ts(t);
245 : if (do_wait_until(lock, ts)) return cv_status::no_timeout;
246 : else return cv_status::timeout;
247 : }
248 :
249 : template <class Clock, class Duration>
250 : cv_status
251 : wait_until(
252 : unique_lock<mutex>& lock,
253 : const chrono::time_point<Clock, Duration>& t)
254 : {
255 : // The system time may jump while this function is waiting. To compensate for this and time
256 : // out near the correct time, we could call do_wait_until() in a loop with a short timeout
257 : // and recheck the time remaining each time through the loop. However, because we can't
258 : // check the predicate each time do_wait_until() completes, this introduces the possibility
259 : // of not exiting the function when a notification occurs, since do_wait_until() may report
260 : // that it timed out even though a notification was received. The best this function can do
261 : // is report correctly whether or not it reached the timeout time.
262 : typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
263 : common_duration d(t - Clock::now());
264 : do_wait_until(lock, detail::internal_chrono_clock::now() + d);
265 : if (t > Clock::now()) return cv_status::no_timeout;
266 : else return cv_status::timeout;
267 : }
268 :
269 : template <class Rep, class Period>
270 : cv_status
271 : wait_for(
272 : unique_lock<mutex>& lock,
273 : const chrono::duration<Rep, Period>& d)
274 : {
275 : return wait_until(lock, chrono::steady_clock::now() + d);
276 : }
277 :
278 : template <class Duration, class Predicate>
279 : bool
280 : wait_until(
281 : unique_lock<mutex>& lock,
282 : const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
283 : Predicate pred)
284 : {
285 : const detail::internal_platform_timepoint ts(t);
286 : while (!pred())
287 : {
288 : if (!do_wait_until(lock, ts)) break; // timeout occurred
289 : }
290 : return pred();
291 : }
292 :
293 : template <class Clock, class Duration, class Predicate>
294 : bool
295 : wait_until(
296 : unique_lock<mutex>& lock,
297 : const chrono::time_point<Clock, Duration>& t,
298 : Predicate pred)
299 : {
300 : // The system time may jump while this function is waiting. To compensate for this
301 : // and time out near the correct time, we call do_wait_until() in a loop with a
302 : // short timeout and recheck the time remaining each time through the loop.
303 : typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
304 : while (!pred())
305 : {
306 : common_duration d(t - Clock::now());
307 : if (d <= common_duration::zero()) break; // timeout occurred
308 : d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
309 : do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
310 : }
311 : return pred();
312 : }
313 :
314 : template <class Rep, class Period, class Predicate>
315 : bool
316 : wait_for(
317 : unique_lock<mutex>& lock,
318 : const chrono::duration<Rep, Period>& d,
319 : Predicate pred)
320 : {
321 : return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
322 : }
323 : #endif
324 :
325 : #define BOOST_THREAD_DEFINES_CONDITION_VARIABLE_NATIVE_HANDLE
326 : typedef pthread_cond_t* native_handle_type;
327 : native_handle_type native_handle()
328 : {
329 : return &cond;
330 : }
331 :
332 : void notify_one() BOOST_NOEXCEPT;
333 : void notify_all() BOOST_NOEXCEPT;
334 : };
335 :
336 : BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
337 : }
338 :
339 : #include <boost/config/abi_suffix.hpp>
340 :
341 : #endif
|