• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
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         }
~condition_variable()77         ~condition_variable()
78         {
79 //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
80             // ditto
81             BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex));
82 //#endif
83             BOOST_VERIFY(!posix::pthread_cond_destroy(&cond));
84         }
85 
86         void wait(unique_lock<mutex>& m);
87 
88         template<typename predicate_type>
wait(unique_lock<mutex> & m,predicate_type pred)89         void wait(unique_lock<mutex>& m,predicate_type pred)
90         {
91             while (!pred())
92             {
93                 wait(m);
94             }
95         }
96 
97 #if defined BOOST_THREAD_USES_DATETIME
timed_wait(unique_lock<mutex> & m,boost::system_time const & abs_time)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         }
timed_wait(unique_lock<mutex> & m,::boost::xtime const & abs_time)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>
timed_wait(unique_lock<mutex> & m,duration_type const & wait_duration)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>
timed_wait(unique_lock<mutex> & m,boost::system_time const & abs_time,predicate_type pred)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>
timed_wait(unique_lock<mutex> & m,::boost::xtime const & abs_time,predicate_type pred)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>
timed_wait(unique_lock<mutex> & m,duration_type const & wait_duration,predicate_type pred)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
wait_until(unique_lock<mutex> & lock,const chrono::time_point<detail::internal_chrono_clock,Duration> & t)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
wait_until(unique_lock<mutex> & lock,const chrono::time_point<Clock,Duration> & t)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
wait_for(unique_lock<mutex> & lock,const chrono::duration<Rep,Period> & d)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
wait_until(unique_lock<mutex> & lock,const chrono::time_point<detail::internal_chrono_clock,Duration> & t,Predicate pred)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
wait_until(unique_lock<mutex> & lock,const chrono::time_point<Clock,Duration> & t,Predicate pred)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
wait_for(unique_lock<mutex> & lock,const chrono::duration<Rep,Period> & d,Predicate pred)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;
native_handle()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
342