Back to home page

EIC code displayed by LXR

 
 

    


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 // Distributed under the Boost Software License, Version 1.0. (See
0004 // accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 // (C) Copyright 2007-10 Anthony Williams
0007 // (C) Copyright 2011-2012 Vicente J. Botet Escriba
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     // When this function returns true:
0097     // * A notification (or sometimes a spurious OS signal) has been received
0098     // * Do not assume that the timeout has not been reached
0099     // * Do not assume that the predicate has been changed
0100     //
0101     // When this function returns false:
0102     // * The timeout has been reached
0103     // * Do not assume that a notification has not been received
0104     // * Do not assume that the predicate has not been changed
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             // The system time may jump while this function is waiting. To compensate for this and time
0232             // out near the correct time, we could call do_wait_until() in a loop with a short timeout
0233             // and recheck the time remaining each time through the loop. However, because we can't
0234             // check the predicate each time do_wait_until() completes, this introduces the possibility
0235             // of not exiting the function when a notification occurs, since do_wait_until() may report
0236             // that it timed out even though a notification was received. The best this function can do
0237             // is report correctly whether or not it reached the timeout time.
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             // The system time may jump while this function is waiting. To compensate for this and time
0266             // out near the correct time, we could call do_wait_until() in a loop with a short timeout
0267             // and recheck the time remaining each time through the loop. However, because we can't
0268             // check the predicate each time do_wait_until() completes, this introduces the possibility
0269             // of not exiting the function when a notification occurs, since do_wait_until() may report
0270             // that it timed out even though a notification was received. The best this function can do
0271             // is report correctly whether or not it reached the timeout time.
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                 // The system time may jump while this function is waiting. To compensate for this
0292                 // and time out near the correct time, we call do_wait_until() in a loop with a
0293                 // short timeout and recheck the time remaining each time through the loop.
0294                 detail::platform_duration d(ts - detail::real_platform_clock::now());
0295                 if (d <= detail::platform_duration::zero()) break; // timeout occurred
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; // timeout occurred
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             // The system time may jump while this function is waiting. To compensate for this
0329             // and time out near the correct time, we call do_wait_until() in a loop with a
0330             // short timeout and recheck the time remaining each time through the loop.
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; // timeout occurred
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; // timeout occurred
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             // The system time may jump while this function is waiting. To compensate for this and time
0369             // out near the correct time, we could call do_wait_until() in a loop with a short timeout
0370             // and recheck the time remaining each time through the loop. However, because we can't
0371             // check the predicate each time do_wait_until() completes, this introduces the possibility
0372             // of not exiting the function when a notification occurs, since do_wait_until() may report
0373             // that it timed out even though a notification was received. The best this function can do
0374             // is report correctly whether or not it reached the timeout time.
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; // timeout occurred
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             // The system time may jump while this function is waiting. To compensate for this
0414             // and time out near the correct time, we call do_wait_until() in a loop with a
0415             // short timeout and recheck the time remaining each time through the loop.
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; // timeout occurred
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         // When this function returns true:
0452         // * A notification (or sometimes a spurious OS signal) has been received
0453         // * Do not assume that the timeout has not been reached
0454         // * Do not assume that the predicate has been changed
0455         //
0456         // When this function returns false:
0457         // * The timeout has been reached
0458         // * Do not assume that a notification has not been received
0459         // * Do not assume that the predicate has not been changed
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