File indexing completed on 2025-12-17 10:05:22
0001 #ifndef BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP
0002 #define BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP
0003
0004
0005
0006
0007
0008
0009 #include <boost/thread/detail/platform_time.hpp>
0010 #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
0011 #include <boost/thread/pthread/pthread_helpers.hpp>
0012
0013 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
0014 #include <boost/thread/interruption.hpp>
0015 #include <boost/thread/pthread/thread_data.hpp>
0016 #endif
0017 #include <boost/thread/pthread/condition_variable_fwd.hpp>
0018 #ifdef BOOST_THREAD_USES_CHRONO
0019 #include <boost/chrono/system_clocks.hpp>
0020 #include <boost/chrono/ceil.hpp>
0021 #endif
0022 #include <boost/thread/detail/delete.hpp>
0023
0024 #include <algorithm>
0025
0026 #include <boost/config/abi_prefix.hpp>
0027
0028 namespace boost
0029 {
0030 namespace thread_cv_detail
0031 {
0032 template<typename MutexType>
0033 struct lock_on_exit
0034 {
0035 MutexType* m;
0036
0037 lock_on_exit():
0038 m(0)
0039 {}
0040
0041 void activate(MutexType& m_)
0042 {
0043 m_.unlock();
0044 m=&m_;
0045 }
0046 void deactivate()
0047 {
0048 if (m)
0049 {
0050 m->lock();
0051 }
0052 m = 0;
0053 }
0054 ~lock_on_exit() BOOST_NOEXCEPT_IF(false)
0055 {
0056 if (m)
0057 {
0058 m->lock();
0059 }
0060 }
0061 };
0062 }
0063
0064 inline void condition_variable::wait(unique_lock<mutex>& m)
0065 {
0066 #if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
0067 if(! m.owns_lock())
0068 {
0069 boost::throw_exception(condition_error(-1, "boost::condition_variable::wait() failed precondition mutex not owned"));
0070 }
0071 #endif
0072 int res=0;
0073 {
0074 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
0075 thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
0076 detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
0077 pthread_mutex_t* the_mutex = &internal_mutex;
0078 guard.activate(m);
0079 res = posix::pthread_cond_wait(&cond,the_mutex);
0080 check_for_interruption.unlock_if_locked();
0081 guard.deactivate();
0082 #else
0083 pthread_mutex_t* the_mutex = m.mutex()->native_handle();
0084 res = posix::pthread_cond_wait(&cond,the_mutex);
0085 #endif
0086 }
0087 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
0088 this_thread::interruption_point();
0089 #endif
0090 if(res)
0091 {
0092 boost::throw_exception(condition_error(res, "boost::condition_variable::wait failed in pthread_cond_wait"));
0093 }
0094 }
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105 inline bool condition_variable::do_wait_until(
0106 unique_lock<mutex>& m,
0107 detail::internal_platform_timepoint const &timeout)
0108 {
0109 #if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
0110 if (!m.owns_lock())
0111 {
0112 boost::throw_exception(condition_error(EPERM, "boost::condition_variable::do_wait_until() failed precondition mutex not owned"));
0113 }
0114 #endif
0115 int cond_res;
0116 {
0117 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
0118 thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
0119 detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
0120 pthread_mutex_t* the_mutex = &internal_mutex;
0121 guard.activate(m);
0122 cond_res=posix::pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs());
0123 check_for_interruption.unlock_if_locked();
0124 guard.deactivate();
0125 #else
0126 pthread_mutex_t* the_mutex = m.mutex()->native_handle();
0127 cond_res=posix::pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs());
0128 #endif
0129 }
0130 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
0131 this_thread::interruption_point();
0132 #endif
0133 if(cond_res==ETIMEDOUT)
0134 {
0135 return false;
0136 }
0137 if(cond_res)
0138 {
0139 boost::throw_exception(condition_error(cond_res, "boost::condition_variable::do_wait_until failed in pthread_cond_timedwait"));
0140 }
0141 return true;
0142 }
0143
0144 inline void condition_variable::notify_one() BOOST_NOEXCEPT
0145 {
0146 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
0147 boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
0148 #endif
0149 BOOST_VERIFY(!posix::pthread_cond_signal(&cond));
0150 }
0151
0152 inline void condition_variable::notify_all() BOOST_NOEXCEPT
0153 {
0154 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
0155 boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
0156 #endif
0157 BOOST_VERIFY(!posix::pthread_cond_broadcast(&cond));
0158 }
0159
0160 class condition_variable_any
0161 {
0162 pthread_mutex_t internal_mutex;
0163 pthread_cond_t cond;
0164
0165 public:
0166 BOOST_THREAD_NO_COPYABLE(condition_variable_any)
0167 condition_variable_any()
0168 {
0169 int const res=posix::pthread_mutex_init(&internal_mutex);
0170 if(res)
0171 {
0172 boost::throw_exception(thread_resource_error(res, "boost::condition_variable_any::condition_variable_any() failed in pthread_mutex_init"));
0173 }
0174 int const res2 = posix::pthread_cond_init(&cond);
0175 if(res2)
0176 {
0177 BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex));
0178 boost::throw_exception(thread_resource_error(res2, "boost::condition_variable_any::condition_variable_any() failed in pthread_cond_init"));
0179 }
0180 }
0181 ~condition_variable_any()
0182 {
0183 BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex));
0184 BOOST_VERIFY(!posix::pthread_cond_destroy(&cond));
0185 }
0186
0187 template<typename lock_type>
0188 void wait(lock_type& m)
0189 {
0190 int res=0;
0191 {
0192 thread_cv_detail::lock_on_exit<lock_type> guard;
0193 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
0194 detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
0195 #else
0196 boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
0197 #endif
0198 guard.activate(m);
0199 res=posix::pthread_cond_wait(&cond,&internal_mutex);
0200 check_for_interruption.unlock_if_locked();
0201 guard.deactivate();
0202 }
0203 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
0204 this_thread::interruption_point();
0205 #endif
0206 if(res)
0207 {
0208 boost::throw_exception(condition_error(res, "boost::condition_variable_any::wait() failed in pthread_cond_wait"));
0209 }
0210 }
0211
0212 template<typename lock_type,typename predicate_type>
0213 void wait(lock_type& m,predicate_type pred)
0214 {
0215 while (!pred())
0216 {
0217 wait(m);
0218 }
0219 }
0220
0221 #if defined BOOST_THREAD_USES_DATETIME
0222 template<typename lock_type>
0223 bool timed_wait(lock_type& m,boost::system_time const& abs_time)
0224 {
0225 #if defined BOOST_THREAD_WAIT_BUG
0226 const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG);
0227 #else
0228 const detail::real_platform_timepoint ts(abs_time);
0229 #endif
0230 #if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
0231
0232
0233
0234
0235
0236
0237
0238 const detail::platform_duration d(ts - detail::real_platform_clock::now());
0239 do_wait_until(m, detail::internal_platform_clock::now() + d);
0240 return ts > detail::real_platform_clock::now();
0241 #else
0242 return do_wait_until(m, ts);
0243 #endif
0244 }
0245 template<typename lock_type>
0246 bool timed_wait(lock_type& m,::boost::xtime const& abs_time)
0247 {
0248 return timed_wait(m,system_time(abs_time));
0249 }
0250
0251 template<typename lock_type,typename duration_type>
0252 bool timed_wait(lock_type& m,duration_type const& wait_duration)
0253 {
0254 if (wait_duration.is_pos_infinity())
0255 {
0256 wait(m);
0257 return true;
0258 }
0259 if (wait_duration.is_special())
0260 {
0261 return true;
0262 }
0263 detail::platform_duration d(wait_duration);
0264 #if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
0265
0266
0267
0268
0269
0270
0271
0272 const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
0273 do_wait_until(m, detail::internal_platform_clock::now() + d);
0274 return ts > detail::mono_platform_clock::now();
0275 #else
0276 return do_wait_until(m, detail::internal_platform_clock::now() + d);
0277 #endif
0278 }
0279
0280 template<typename lock_type,typename predicate_type>
0281 bool timed_wait(lock_type& m,boost::system_time const& abs_time, predicate_type pred)
0282 {
0283 #if defined BOOST_THREAD_WAIT_BUG
0284 const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG);
0285 #else
0286 const detail::real_platform_timepoint ts(abs_time);
0287 #endif
0288 while (!pred())
0289 {
0290 #if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
0291
0292
0293
0294 detail::platform_duration d(ts - detail::real_platform_clock::now());
0295 if (d <= detail::platform_duration::zero()) break;
0296 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
0297 do_wait_until(m, detail::internal_platform_clock::now() + d);
0298 #else
0299 if (!do_wait_until(m, ts)) break;
0300 #endif
0301 }
0302 return pred();
0303 }
0304
0305 template<typename lock_type,typename predicate_type>
0306 bool timed_wait(lock_type& m,::boost::xtime const& abs_time, predicate_type pred)
0307 {
0308 return timed_wait(m,system_time(abs_time),pred);
0309 }
0310
0311 template<typename lock_type,typename duration_type,typename predicate_type>
0312 bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
0313 {
0314 if (wait_duration.is_pos_infinity())
0315 {
0316 while (!pred())
0317 {
0318 wait(m);
0319 }
0320 return true;
0321 }
0322 if (wait_duration.is_special())
0323 {
0324 return pred();
0325 }
0326 detail::platform_duration d(wait_duration);
0327 #if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
0328
0329
0330
0331 const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
0332 while (!pred())
0333 {
0334 if (d <= detail::platform_duration::zero()) break;
0335 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
0336 do_wait_until(m, detail::internal_platform_clock::now() + d);
0337 d = ts - detail::mono_platform_clock::now();
0338 }
0339 #else
0340 const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
0341 while (!pred())
0342 {
0343 if (!do_wait_until(m, ts)) break;
0344 }
0345 #endif
0346 return pred();
0347 }
0348 #endif
0349
0350 #ifdef BOOST_THREAD_USES_CHRONO
0351 template <class lock_type,class Duration>
0352 cv_status
0353 wait_until(
0354 lock_type& lock,
0355 const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
0356 {
0357 const boost::detail::internal_platform_timepoint ts(t);
0358 if (do_wait_until(lock, ts)) return cv_status::no_timeout;
0359 else return cv_status::timeout;
0360 }
0361
0362 template <class lock_type, class Clock, class Duration>
0363 cv_status
0364 wait_until(
0365 lock_type& lock,
0366 const chrono::time_point<Clock, Duration>& t)
0367 {
0368
0369
0370
0371
0372
0373
0374
0375 typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
0376 common_duration d(t - Clock::now());
0377 do_wait_until(lock, detail::internal_chrono_clock::now() + d);
0378 if (t > Clock::now()) return cv_status::no_timeout;
0379 else return cv_status::timeout;
0380 }
0381
0382 template <class lock_type, class Rep, class Period>
0383 cv_status
0384 wait_for(
0385 lock_type& lock,
0386 const chrono::duration<Rep, Period>& d)
0387 {
0388 return wait_until(lock, chrono::steady_clock::now() + d);
0389 }
0390
0391 template <class lock_type, class Duration, class Predicate>
0392 bool
0393 wait_until(
0394 lock_type& lock,
0395 const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
0396 Predicate pred)
0397 {
0398 const detail::internal_platform_timepoint ts(t);
0399 while (!pred())
0400 {
0401 if (!do_wait_until(lock, ts)) break;
0402 }
0403 return pred();
0404 }
0405
0406 template <class lock_type, class Clock, class Duration, class Predicate>
0407 bool
0408 wait_until(
0409 lock_type& lock,
0410 const chrono::time_point<Clock, Duration>& t,
0411 Predicate pred)
0412 {
0413
0414
0415
0416 typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
0417 while (!pred())
0418 {
0419 common_duration d(t - Clock::now());
0420 if (d <= common_duration::zero()) break;
0421 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
0422 do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
0423 }
0424 return pred();
0425 }
0426
0427 template <class lock_type, class Rep, class Period, class Predicate>
0428 bool
0429 wait_for(
0430 lock_type& lock,
0431 const chrono::duration<Rep, Period>& d,
0432 Predicate pred)
0433 {
0434 return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
0435 }
0436 #endif
0437
0438 void notify_one() BOOST_NOEXCEPT
0439 {
0440 boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
0441 BOOST_VERIFY(!posix::pthread_cond_signal(&cond));
0442 }
0443
0444 void notify_all() BOOST_NOEXCEPT
0445 {
0446 boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
0447 BOOST_VERIFY(!posix::pthread_cond_broadcast(&cond));
0448 }
0449 private:
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460 template <class lock_type>
0461 bool do_wait_until(
0462 lock_type& m,
0463 detail::internal_platform_timepoint const &timeout)
0464 {
0465 int res=0;
0466 {
0467 thread_cv_detail::lock_on_exit<lock_type> guard;
0468 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
0469 detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
0470 #else
0471 boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
0472 #endif
0473 guard.activate(m);
0474 res=posix::pthread_cond_timedwait(&cond,&internal_mutex,&timeout.getTs());
0475 check_for_interruption.unlock_if_locked();
0476 guard.deactivate();
0477 }
0478 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
0479 this_thread::interruption_point();
0480 #endif
0481 if(res==ETIMEDOUT)
0482 {
0483 return false;
0484 }
0485 if(res)
0486 {
0487 boost::throw_exception(condition_error(res, "boost::condition_variable_any::do_wait_until() failed in pthread_cond_timedwait"));
0488 }
0489 return true;
0490 }
0491 };
0492 }
0493
0494 #include <boost/config/abi_suffix.hpp>
0495
0496 #endif