LCOV - code coverage report
Current view: top level - usr/include/boost/thread/pthread - condition_variable.hpp (source / functions) Hit Total Coverage
Test: ROSE Lines: 0 45 0.0 %
Date: 2022-12-08 13:48:47 Functions: 0 4 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #ifndef BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP
       2             : #define BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_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-10 Anthony Williams
       7             : // (C) Copyright 2011-2012 Vicente J. Botet Escriba
       8             : 
       9             : #include <boost/thread/detail/platform_time.hpp>
      10             : #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
      11             : #include <boost/thread/pthread/pthread_helpers.hpp>
      12             : 
      13             : #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
      14             : #include <boost/thread/interruption.hpp>
      15             : #include <boost/thread/pthread/thread_data.hpp>
      16             : #endif
      17             : #include <boost/thread/pthread/condition_variable_fwd.hpp>
      18             : #ifdef BOOST_THREAD_USES_CHRONO
      19             : #include <boost/chrono/system_clocks.hpp>
      20             : #include <boost/chrono/ceil.hpp>
      21             : #endif
      22             : #include <boost/thread/detail/delete.hpp>
      23             : 
      24             : #include <algorithm>
      25             : 
      26             : #include <boost/config/abi_prefix.hpp>
      27             : 
      28             : namespace boost
      29             : {
      30             :     namespace thread_cv_detail
      31             :     {
      32             :         template<typename MutexType>
      33             :         struct lock_on_exit
      34             :         {
      35             :             MutexType* m;
      36             : 
      37           0 :             lock_on_exit():
      38           0 :                 m(0)
      39             :             {}
      40             : 
      41           0 :             void activate(MutexType& m_)
      42             :             {
      43           0 :                 m_.unlock();
      44           0 :                 m=&m_;
      45             :             }
      46           0 :             void deactivate()
      47             :             {
      48             :                 if (m)
      49             :                 {
      50           0 :                     m->lock();
      51             :                 }
      52           0 :                 m = 0;
      53             :             }
      54           0 :             ~lock_on_exit() BOOST_NOEXCEPT_IF(false)
      55             :             {
      56           0 :                 if (m)
      57             :                 {
      58           0 :                     m->lock();
      59             :                 }
      60           0 :            }
      61             :         };
      62             :     }
      63             : 
      64           0 :     inline void condition_variable::wait(unique_lock<mutex>& m)
      65             :     {
      66             : #if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
      67             :         if(! m.owns_lock())
      68             :         {
      69             :             boost::throw_exception(condition_error(-1, "boost::condition_variable::wait() failed precondition mutex not owned"));
      70             :         }
      71             : #endif
      72           0 :         int res=0;
      73           0 :         {
      74             : #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
      75           0 :             thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
      76           0 :             detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
      77           0 :             pthread_mutex_t* the_mutex = &internal_mutex;
      78           0 :             guard.activate(m);
      79           0 :             res = posix::pthread_cond_wait(&cond,the_mutex);
      80           0 :             check_for_interruption.unlock_if_locked();
      81           0 :             guard.deactivate();
      82             : #else
      83             :             pthread_mutex_t* the_mutex = m.mutex()->native_handle();
      84             :             res = posix::pthread_cond_wait(&cond,the_mutex);
      85             : #endif
      86             :         }
      87             : #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
      88           0 :         this_thread::interruption_point();
      89             : #endif
      90           0 :         if(res)
      91             :         {
      92           0 :             boost::throw_exception(condition_error(res, "boost::condition_variable::wait failed in pthread_cond_wait"));
      93             :         }
      94           0 :     }
      95             : 
      96             :     // When this function returns true:
      97             :     // * A notification (or sometimes a spurious OS signal) has been received
      98             :     // * Do not assume that the timeout has not been reached
      99             :     // * Do not assume that the predicate has been changed
     100             :     //
     101             :     // When this function returns false:
     102             :     // * The timeout has been reached
     103             :     // * Do not assume that a notification has not been received
     104             :     // * Do not assume that the predicate has not been changed
     105             :     inline bool condition_variable::do_wait_until(
     106             :                 unique_lock<mutex>& m,
     107             :                 detail::internal_platform_timepoint const &timeout)
     108             :     {
     109             : #if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
     110             :         if (!m.owns_lock())
     111             :         {
     112             :             boost::throw_exception(condition_error(EPERM, "boost::condition_variable::do_wait_until() failed precondition mutex not owned"));
     113             :         }
     114             : #endif
     115             :         int cond_res;
     116             :         {
     117             : #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
     118             :             thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
     119             :             detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
     120             :             pthread_mutex_t* the_mutex = &internal_mutex;
     121             :             guard.activate(m);
     122             :             cond_res=posix::pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs());
     123             :             check_for_interruption.unlock_if_locked();
     124             :             guard.deactivate();
     125             : #else
     126             :             pthread_mutex_t* the_mutex = m.mutex()->native_handle();
     127             :             cond_res=posix::pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs());
     128             : #endif
     129             :         }
     130             : #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
     131             :         this_thread::interruption_point();
     132             : #endif
     133             :         if(cond_res==ETIMEDOUT)
     134             :         {
     135             :             return false;
     136             :         }
     137             :         if(cond_res)
     138             :         {
     139             :             boost::throw_exception(condition_error(cond_res, "boost::condition_variable::do_wait_until failed in pthread_cond_timedwait"));
     140             :         }
     141             :         return true;
     142             :     }
     143             : 
     144             :     inline void condition_variable::notify_one() BOOST_NOEXCEPT
     145             :     {
     146             : #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
     147             :         boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
     148             : #endif
     149             :         BOOST_VERIFY(!posix::pthread_cond_signal(&cond));
     150             :     }
     151             : 
     152             :     inline void condition_variable::notify_all() BOOST_NOEXCEPT
     153             :     {
     154             : #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
     155             :         boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
     156             : #endif
     157             :         BOOST_VERIFY(!posix::pthread_cond_broadcast(&cond));
     158             :     }
     159             : 
     160             :     class condition_variable_any
     161             :     {
     162             :         pthread_mutex_t internal_mutex;
     163             :         pthread_cond_t cond;
     164             : 
     165             :     public:
     166             :         BOOST_THREAD_NO_COPYABLE(condition_variable_any)
     167           0 :         condition_variable_any()
     168           0 :         {
     169           0 :             int const res=posix::pthread_mutex_init(&internal_mutex);
     170           0 :             if(res)
     171             :             {
     172           0 :                 boost::throw_exception(thread_resource_error(res, "boost::condition_variable_any::condition_variable_any() failed in pthread_mutex_init"));
     173             :             }
     174           0 :             int const res2 = posix::pthread_cond_init(&cond);
     175           0 :             if(res2)
     176             :             {
     177           0 :                 BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex));
     178           0 :                 boost::throw_exception(thread_resource_error(res2, "boost::condition_variable_any::condition_variable_any() failed in pthread_cond_init"));
     179             :             }
     180           0 :         }
     181           0 :         ~condition_variable_any()
     182           0 :         {
     183           0 :             BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex));
     184           0 :             BOOST_VERIFY(!posix::pthread_cond_destroy(&cond));
     185           0 :         }
     186             : 
     187             :         template<typename lock_type>
     188             :         void wait(lock_type& m)
     189             :         {
     190             :             int res=0;
     191             :             {
     192             :                 thread_cv_detail::lock_on_exit<lock_type> guard;
     193             : #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
     194             :                 detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
     195             : #else
     196             :                 boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
     197             : #endif
     198             :                 guard.activate(m);
     199             :                 res=posix::pthread_cond_wait(&cond,&internal_mutex);
     200             :                 check_for_interruption.unlock_if_locked();
     201             :                 guard.deactivate();
     202             :             }
     203             : #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
     204             :             this_thread::interruption_point();
     205             : #endif
     206             :             if(res)
     207             :             {
     208             :                 boost::throw_exception(condition_error(res, "boost::condition_variable_any::wait() failed in pthread_cond_wait"));
     209             :             }
     210             :         }
     211             : 
     212             :         template<typename lock_type,typename predicate_type>
     213             :         void wait(lock_type& m,predicate_type pred)
     214             :         {
     215             :             while (!pred())
     216             :             {
     217             :                 wait(m);
     218             :             }
     219             :         }
     220             : 
     221             : #if defined BOOST_THREAD_USES_DATETIME
     222             :         template<typename lock_type>
     223             :         bool timed_wait(lock_type& m,boost::system_time const& abs_time)
     224             :         {
     225             : #if defined BOOST_THREAD_WAIT_BUG
     226             :             const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG);
     227             : #else
     228             :             const detail::real_platform_timepoint ts(abs_time);
     229             : #endif
     230             : #if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
     231             :             // The system time may jump while this function is waiting. To compensate for this and time
     232             :             // out near the correct time, we could call do_wait_until() in a loop with a short timeout
     233             :             // and recheck the time remaining each time through the loop. However, because we can't
     234             :             // check the predicate each time do_wait_until() completes, this introduces the possibility
     235             :             // of not exiting the function when a notification occurs, since do_wait_until() may report
     236             :             // that it timed out even though a notification was received. The best this function can do
     237             :             // is report correctly whether or not it reached the timeout time.
     238             :             const detail::platform_duration d(ts - detail::real_platform_clock::now());
     239             :             do_wait_until(m, detail::internal_platform_clock::now() + d);
     240             :             return ts > detail::real_platform_clock::now();
     241             : #else
     242             :             return do_wait_until(m, ts);
     243             : #endif
     244             :         }
     245             :         template<typename lock_type>
     246             :         bool timed_wait(lock_type& m,::boost::xtime const& abs_time)
     247             :         {
     248             :             return timed_wait(m,system_time(abs_time));
     249             :         }
     250             : 
     251             :         template<typename lock_type,typename duration_type>
     252             :         bool timed_wait(lock_type& m,duration_type const& wait_duration)
     253             :         {
     254             :             if (wait_duration.is_pos_infinity())
     255             :             {
     256             :                 wait(m);
     257             :                 return true;
     258             :             }
     259             :             if (wait_duration.is_special())
     260             :             {
     261             :                 return true;
     262             :             }
     263             :             detail::platform_duration d(wait_duration);
     264             : #if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
     265             :             // The system time may jump while this function is waiting. To compensate for this and time
     266             :             // out near the correct time, we could call do_wait_until() in a loop with a short timeout
     267             :             // and recheck the time remaining each time through the loop. However, because we can't
     268             :             // check the predicate each time do_wait_until() completes, this introduces the possibility
     269             :             // of not exiting the function when a notification occurs, since do_wait_until() may report
     270             :             // that it timed out even though a notification was received. The best this function can do
     271             :             // is report correctly whether or not it reached the timeout time.
     272             :             const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
     273             :             do_wait_until(m, detail::internal_platform_clock::now() + d);
     274             :             return ts > detail::mono_platform_clock::now();
     275             : #else
     276             :             return do_wait_until(m, detail::internal_platform_clock::now() + d);
     277             : #endif
     278             :         }
     279             : 
     280             :         template<typename lock_type,typename predicate_type>
     281             :         bool timed_wait(lock_type& m,boost::system_time const& abs_time, predicate_type pred)
     282             :         {
     283             : #if defined BOOST_THREAD_WAIT_BUG
     284             :             const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG);
     285             : #else
     286             :             const detail::real_platform_timepoint ts(abs_time);
     287             : #endif
     288             :             while (!pred())
     289             :             {
     290             : #if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
     291             :                 // The system time may jump while this function is waiting. To compensate for this
     292             :                 // and time out near the correct time, we call do_wait_until() in a loop with a
     293             :                 // short timeout and recheck the time remaining each time through the loop.
     294             :                 detail::platform_duration d(ts - detail::real_platform_clock::now());
     295             :                 if (d <= detail::platform_duration::zero()) break; // timeout occurred
     296             :                 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
     297             :                 do_wait_until(m, detail::internal_platform_clock::now() + d);
     298             : #else
     299             :                 if (!do_wait_until(m, ts)) break; // timeout occurred
     300             : #endif
     301             :             }
     302             :             return pred();
     303             :         }
     304             : 
     305             :         template<typename lock_type,typename predicate_type>
     306             :         bool timed_wait(lock_type& m,::boost::xtime const& abs_time, predicate_type pred)
     307             :         {
     308             :             return timed_wait(m,system_time(abs_time),pred);
     309             :         }
     310             : 
     311             :         template<typename lock_type,typename duration_type,typename predicate_type>
     312             :         bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
     313             :         {
     314             :             if (wait_duration.is_pos_infinity())
     315             :             {
     316             :                 while (!pred())
     317             :                 {
     318             :                     wait(m);
     319             :                 }
     320             :                 return true;
     321             :             }
     322             :             if (wait_duration.is_special())
     323             :             {
     324             :                 return pred();
     325             :             }
     326             :             detail::platform_duration d(wait_duration);
     327             : #if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
     328             :             // The system time may jump while this function is waiting. To compensate for this
     329             :             // and time out near the correct time, we call do_wait_until() in a loop with a
     330             :             // short timeout and recheck the time remaining each time through the loop.
     331             :             const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
     332             :             while (!pred())
     333             :             {
     334             :                 if (d <= detail::platform_duration::zero()) break; // timeout occurred
     335             :                 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
     336             :                 do_wait_until(m, detail::internal_platform_clock::now() + d);
     337             :                 d = ts - detail::mono_platform_clock::now();
     338             :             }
     339             : #else
     340             :             const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
     341             :             while (!pred())
     342             :             {
     343             :                 if (!do_wait_until(m, ts)) break; // timeout occurred
     344             :             }
     345             : #endif
     346             :             return pred();
     347             :         }
     348             : #endif
     349             : 
     350             : #ifdef BOOST_THREAD_USES_CHRONO
     351             :         template <class lock_type,class Duration>
     352             :         cv_status
     353             :         wait_until(
     354             :                 lock_type& lock,
     355             :                 const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
     356             :         {
     357             :             const boost::detail::internal_platform_timepoint ts(t);
     358             :             if (do_wait_until(lock, ts)) return cv_status::no_timeout;
     359             :             else return cv_status::timeout;
     360             :         }
     361             : 
     362             :         template <class lock_type, class Clock, class Duration>
     363             :         cv_status
     364             :         wait_until(
     365             :                 lock_type& lock,
     366             :                 const chrono::time_point<Clock, Duration>& t)
     367             :         {
     368             :             // The system time may jump while this function is waiting. To compensate for this and time
     369             :             // out near the correct time, we could call do_wait_until() in a loop with a short timeout
     370             :             // and recheck the time remaining each time through the loop. However, because we can't
     371             :             // check the predicate each time do_wait_until() completes, this introduces the possibility
     372             :             // of not exiting the function when a notification occurs, since do_wait_until() may report
     373             :             // that it timed out even though a notification was received. The best this function can do
     374             :             // is report correctly whether or not it reached the timeout time.
     375             :             typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
     376             :             common_duration d(t - Clock::now());
     377             :             do_wait_until(lock, detail::internal_chrono_clock::now() + d);
     378             :             if (t > Clock::now()) return cv_status::no_timeout;
     379             :             else return cv_status::timeout;
     380             :         }
     381             : 
     382             :         template <class lock_type, class Rep, class Period>
     383             :         cv_status
     384             :         wait_for(
     385             :                 lock_type& lock,
     386             :                 const chrono::duration<Rep, Period>& d)
     387             :         {
     388             :             return wait_until(lock, chrono::steady_clock::now() + d);
     389             :         }
     390             : 
     391             :         template <class lock_type, class Duration, class Predicate>
     392             :         bool
     393             :         wait_until(
     394             :                 lock_type& lock,
     395             :                 const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
     396             :                 Predicate pred)
     397             :         {
     398             :             const detail::internal_platform_timepoint ts(t);
     399             :             while (!pred())
     400             :             {
     401             :                 if (!do_wait_until(lock, ts)) break; // timeout occurred
     402             :             }
     403             :             return pred();
     404             :         }
     405             : 
     406             :         template <class lock_type, class Clock, class Duration, class Predicate>
     407             :         bool
     408             :         wait_until(
     409             :                 lock_type& lock,
     410             :                 const chrono::time_point<Clock, Duration>& t,
     411             :                 Predicate pred)
     412             :         {
     413             :             // The system time may jump while this function is waiting. To compensate for this
     414             :             // and time out near the correct time, we call do_wait_until() in a loop with a
     415             :             // short timeout and recheck the time remaining each time through the loop.
     416             :             typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
     417             :             while (!pred())
     418             :             {
     419             :                 common_duration d(t - Clock::now());
     420             :                 if (d <= common_duration::zero()) break; // timeout occurred
     421             :                 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
     422             :                 do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
     423             :             }
     424             :             return pred();
     425             :         }
     426             : 
     427             :         template <class lock_type, class Rep, class Period, class Predicate>
     428             :         bool
     429             :         wait_for(
     430             :                 lock_type& lock,
     431             :                 const chrono::duration<Rep, Period>& d,
     432             :                 Predicate pred)
     433             :         {
     434             :             return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
     435             :         }
     436             : #endif
     437             : 
     438             :         void notify_one() BOOST_NOEXCEPT
     439             :         {
     440             :             boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
     441             :             BOOST_VERIFY(!posix::pthread_cond_signal(&cond));
     442             :         }
     443             : 
     444           0 :         void notify_all() BOOST_NOEXCEPT
     445             :         {
     446           0 :             boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
     447           0 :             BOOST_VERIFY(!posix::pthread_cond_broadcast(&cond));
     448           0 :         }
     449             :     private:
     450             : 
     451             :         // When this function returns true:
     452             :         // * A notification (or sometimes a spurious OS signal) has been received
     453             :         // * Do not assume that the timeout has not been reached
     454             :         // * Do not assume that the predicate has been changed
     455             :         //
     456             :         // When this function returns false:
     457             :         // * The timeout has been reached
     458             :         // * Do not assume that a notification has not been received
     459             :         // * Do not assume that the predicate has not been changed
     460             :         template <class lock_type>
     461             :         bool do_wait_until(
     462             :           lock_type& m,
     463             :           detail::internal_platform_timepoint const &timeout)
     464             :         {
     465             :           int res=0;
     466             :           {
     467             :               thread_cv_detail::lock_on_exit<lock_type> guard;
     468             : #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
     469             :               detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
     470             : #else
     471             :               boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
     472             : #endif
     473             :               guard.activate(m);
     474             :               res=posix::pthread_cond_timedwait(&cond,&internal_mutex,&timeout.getTs());
     475             :               check_for_interruption.unlock_if_locked();
     476             :               guard.deactivate();
     477             :           }
     478             : #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
     479             :           this_thread::interruption_point();
     480             : #endif
     481             :           if(res==ETIMEDOUT)
     482             :           {
     483             :               return false;
     484             :           }
     485             :           if(res)
     486             :           {
     487             :               boost::throw_exception(condition_error(res, "boost::condition_variable_any::do_wait_until() failed in pthread_cond_timedwait"));
     488             :           }
     489             :           return true;
     490             :         }
     491             :     };
     492             : }
     493             : 
     494             : #include <boost/config/abi_suffix.hpp>
     495             : 
     496             : #endif

Generated by: LCOV version 1.14