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