428 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			428 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | #ifndef BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP | ||
|  | #define BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP | ||
|  | // Distributed under the Boost Software License, Version 1.0. (See | ||
|  | // accompanying file LICENSE_1_0.txt or copy at | ||
|  | // http://www.boost.org/LICENSE_1_0.txt) | ||
|  | // (C) Copyright 2007-10 Anthony Williams | ||
|  | // (C) Copyright 2011-2012 Vicente J. Botet Escriba | ||
|  | 
 | ||
|  | #include <boost/thread/pthread/timespec.hpp> | ||
|  | #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> | ||
|  | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | ||
|  | #include <boost/thread/pthread/thread_data.hpp> | ||
|  | #endif | ||
|  | #include <boost/thread/pthread/condition_variable_fwd.hpp> | ||
|  | #ifdef BOOST_THREAD_USES_CHRONO | ||
|  | #include <boost/chrono/system_clocks.hpp> | ||
|  | #include <boost/chrono/ceil.hpp> | ||
|  | #endif | ||
|  | #include <boost/thread/detail/delete.hpp> | ||
|  | 
 | ||
|  | #include <boost/config/abi_prefix.hpp> | ||
|  | 
 | ||
|  | namespace boost | ||
|  | { | ||
|  | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | ||
|  |     namespace this_thread | ||
|  |     { | ||
|  |         void BOOST_THREAD_DECL interruption_point(); | ||
|  |     } | ||
|  | #endif | ||
|  | 
 | ||
|  |     namespace thread_cv_detail | ||
|  |     { | ||
|  |         template<typename MutexType> | ||
|  |         struct lock_on_exit | ||
|  |         { | ||
|  |             MutexType* m; | ||
|  | 
 | ||
|  |             lock_on_exit(): | ||
|  |                 m(0) | ||
|  |             {} | ||
|  | 
 | ||
|  |             void activate(MutexType& m_) | ||
|  |             { | ||
|  |                 m_.unlock(); | ||
|  |                 m=&m_; | ||
|  |             } | ||
|  |             ~lock_on_exit() | ||
|  |             { | ||
|  |                 if(m) | ||
|  |                 { | ||
|  |                     m->lock(); | ||
|  |                 } | ||
|  |            } | ||
|  |         }; | ||
|  |     } | ||
|  | 
 | ||
|  |     inline void condition_variable::wait(unique_lock<mutex>& m) | ||
|  |     { | ||
|  | #if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED | ||
|  |         if(! m.owns_lock()) | ||
|  |         { | ||
|  |             boost::throw_exception(condition_error(-1, "boost::condition_variable::wait() failed precondition mutex not owned")); | ||
|  |         } | ||
|  | #endif | ||
|  |         int res=0; | ||
|  |         { | ||
|  | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | ||
|  |             thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard; | ||
|  |             detail::interruption_checker check_for_interruption(&internal_mutex,&cond); | ||
|  |             pthread_mutex_t* the_mutex = &internal_mutex; | ||
|  |             guard.activate(m); | ||
|  | #else | ||
|  |             pthread_mutex_t* the_mutex = m.mutex()->native_handle(); | ||
|  | #endif | ||
|  |             res = pthread_cond_wait(&cond,the_mutex); | ||
|  |         } | ||
|  | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | ||
|  |         this_thread::interruption_point(); | ||
|  | #endif | ||
|  |         if(res && res != EINTR) | ||
|  |         { | ||
|  |             boost::throw_exception(condition_error(res, "boost::condition_variable::wait failed in pthread_cond_wait")); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     inline bool condition_variable::do_wait_until( | ||
|  |                 unique_lock<mutex>& m, | ||
|  |                 struct timespec const &timeout) | ||
|  |     { | ||
|  | #if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED | ||
|  |         if (!m.owns_lock()) | ||
|  |         { | ||
|  |             boost::throw_exception(condition_error(EPERM, "boost::condition_variable::do_wait_until() failed precondition mutex not owned")); | ||
|  |         } | ||
|  | #endif | ||
|  |         int cond_res; | ||
|  |         { | ||
|  | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | ||
|  |             thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard; | ||
|  |             detail::interruption_checker check_for_interruption(&internal_mutex,&cond); | ||
|  |             pthread_mutex_t* the_mutex = &internal_mutex; | ||
|  |             guard.activate(m); | ||
|  | #else | ||
|  |             pthread_mutex_t* the_mutex = m.mutex()->native_handle(); | ||
|  | #endif | ||
|  |             cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout); | ||
|  |         } | ||
|  | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | ||
|  |         this_thread::interruption_point(); | ||
|  | #endif | ||
|  |         if(cond_res==ETIMEDOUT) | ||
|  |         { | ||
|  |             return false; | ||
|  |         } | ||
|  |         if(cond_res) | ||
|  |         { | ||
|  |             boost::throw_exception(condition_error(cond_res, "boost::condition_variable::do_wait_until failed in pthread_cond_timedwait")); | ||
|  |         } | ||
|  |         return true; | ||
|  |     } | ||
|  | 
 | ||
|  |     inline void condition_variable::notify_one() BOOST_NOEXCEPT | ||
|  |     { | ||
|  | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | ||
|  |         boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); | ||
|  | #endif | ||
|  |         BOOST_VERIFY(!pthread_cond_signal(&cond)); | ||
|  |     } | ||
|  | 
 | ||
|  |     inline void condition_variable::notify_all() BOOST_NOEXCEPT | ||
|  |     { | ||
|  | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | ||
|  |         boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); | ||
|  | #endif | ||
|  |         BOOST_VERIFY(!pthread_cond_broadcast(&cond)); | ||
|  |     } | ||
|  | 
 | ||
|  |     class condition_variable_any | ||
|  |     { | ||
|  |         pthread_mutex_t internal_mutex; | ||
|  |         pthread_cond_t cond; | ||
|  | 
 | ||
|  |     public: | ||
|  |         BOOST_THREAD_NO_COPYABLE(condition_variable_any) | ||
|  |         condition_variable_any() | ||
|  |         { | ||
|  |             int const res=pthread_mutex_init(&internal_mutex,NULL); | ||
|  |             if(res) | ||
|  |             { | ||
|  |                 boost::throw_exception(thread_resource_error(res, "boost::condition_variable_any::condition_variable_any() failed in pthread_mutex_init")); | ||
|  |             } | ||
|  |             int const res2 = detail::monotonic_pthread_cond_init(cond); | ||
|  |             if(res2) | ||
|  |             { | ||
|  |                 BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); | ||
|  |                 boost::throw_exception(thread_resource_error(res2, "boost::condition_variable_any::condition_variable_any() failed in detail::monotonic_pthread_cond_init")); | ||
|  |             } | ||
|  |         } | ||
|  |         ~condition_variable_any() | ||
|  |         { | ||
|  |             BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); | ||
|  |             BOOST_VERIFY(!pthread_cond_destroy(&cond)); | ||
|  |         } | ||
|  | 
 | ||
|  |         template<typename lock_type> | ||
|  |         void wait(lock_type& m) | ||
|  |         { | ||
|  |             int res=0; | ||
|  |             { | ||
|  |                 thread_cv_detail::lock_on_exit<lock_type> guard; | ||
|  | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | ||
|  |                 detail::interruption_checker check_for_interruption(&internal_mutex,&cond); | ||
|  | #else | ||
|  |                 boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); | ||
|  | #endif | ||
|  |                 guard.activate(m); | ||
|  |                 res=pthread_cond_wait(&cond,&internal_mutex); | ||
|  |             } | ||
|  | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | ||
|  |             this_thread::interruption_point(); | ||
|  | #endif | ||
|  |             if(res) | ||
|  |             { | ||
|  |                 boost::throw_exception(condition_error(res, "boost::condition_variable_any::wait() failed in pthread_cond_wait")); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         template<typename lock_type,typename predicate_type> | ||
|  |         void wait(lock_type& m,predicate_type pred) | ||
|  |         { | ||
|  |             while(!pred()) wait(m); | ||
|  |         } | ||
|  | 
 | ||
|  | #if defined BOOST_THREAD_USES_DATETIME | ||
|  |         template<typename lock_type> | ||
|  |         bool timed_wait(lock_type& m,boost::system_time const& abs_time) | ||
|  |         { | ||
|  |             struct timespec const timeout=detail::to_timespec(abs_time); | ||
|  |             return do_wait_until(m, timeout); | ||
|  |         } | ||
|  |         template<typename lock_type> | ||
|  |         bool timed_wait(lock_type& m,xtime const& abs_time) | ||
|  |         { | ||
|  |             return timed_wait(m,system_time(abs_time)); | ||
|  |         } | ||
|  | 
 | ||
|  |         template<typename lock_type,typename duration_type> | ||
|  |         bool timed_wait(lock_type& m,duration_type const& wait_duration) | ||
|  |         { | ||
|  |             return timed_wait(m,get_system_time()+wait_duration); | ||
|  |         } | ||
|  | 
 | ||
|  |         template<typename lock_type,typename predicate_type> | ||
|  |         bool timed_wait(lock_type& m,boost::system_time const& abs_time, predicate_type pred) | ||
|  |         { | ||
|  |             while (!pred()) | ||
|  |             { | ||
|  |                 if(!timed_wait(m, abs_time)) | ||
|  |                     return pred(); | ||
|  |             } | ||
|  |             return true; | ||
|  |         } | ||
|  | 
 | ||
|  |         template<typename lock_type,typename predicate_type> | ||
|  |         bool timed_wait(lock_type& m,xtime const& abs_time, predicate_type pred) | ||
|  |         { | ||
|  |             return timed_wait(m,system_time(abs_time),pred); | ||
|  |         } | ||
|  | 
 | ||
|  |         template<typename lock_type,typename duration_type,typename predicate_type> | ||
|  |         bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) | ||
|  |         { | ||
|  |             return timed_wait(m,get_system_time()+wait_duration,pred); | ||
|  |         } | ||
|  | #endif | ||
|  | #ifndef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC | ||
|  | 
 | ||
|  | #ifdef BOOST_THREAD_USES_CHRONO | ||
|  |         template <class lock_type,class Duration> | ||
|  |         cv_status | ||
|  |         wait_until( | ||
|  |                 lock_type& lock, | ||
|  |                 const chrono::time_point<chrono::system_clock, Duration>& t) | ||
|  |         { | ||
|  |           using namespace chrono; | ||
|  |           typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; | ||
|  |           wait_until(lock, | ||
|  |                         nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); | ||
|  |           return system_clock::now() < t ? cv_status::no_timeout : | ||
|  |                                              cv_status::timeout; | ||
|  |         } | ||
|  | 
 | ||
|  |         template <class lock_type, class Clock, class Duration> | ||
|  |         cv_status | ||
|  |         wait_until( | ||
|  |                 lock_type& lock, | ||
|  |                 const chrono::time_point<Clock, Duration>& t) | ||
|  |         { | ||
|  |           using namespace chrono; | ||
|  |           system_clock::time_point     s_now = system_clock::now(); | ||
|  |           typename Clock::time_point  c_now = Clock::now(); | ||
|  |           wait_until(lock, s_now + ceil<nanoseconds>(t - c_now)); | ||
|  |           return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout; | ||
|  |         } | ||
|  | 
 | ||
|  |         template <class lock_type, class Rep, class Period> | ||
|  |         cv_status | ||
|  |         wait_for( | ||
|  |                 lock_type& lock, | ||
|  |                 const chrono::duration<Rep, Period>& d) | ||
|  |         { | ||
|  |           using namespace chrono; | ||
|  |           system_clock::time_point s_now = system_clock::now(); | ||
|  |           steady_clock::time_point c_now = steady_clock::now(); | ||
|  |           wait_until(lock, s_now + ceil<nanoseconds>(d)); | ||
|  |           return steady_clock::now() - c_now < d ? cv_status::no_timeout : | ||
|  |                                                    cv_status::timeout; | ||
|  | 
 | ||
|  |         } | ||
|  | 
 | ||
|  |         template <class lock_type> | ||
|  |         cv_status wait_until( | ||
|  |             lock_type& lk, | ||
|  |             chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp) | ||
|  |         { | ||
|  |             using namespace chrono; | ||
|  |             nanoseconds d = tp.time_since_epoch(); | ||
|  |             timespec ts = boost::detail::to_timespec(d); | ||
|  |             if (do_wait_until(lk, ts)) return cv_status::no_timeout; | ||
|  |             else return cv_status::timeout; | ||
|  |         } | ||
|  | #endif | ||
|  | #else // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC | ||
|  | #ifdef BOOST_THREAD_USES_CHRONO | ||
|  | 
 | ||
|  |         template <class lock_type, class Duration> | ||
|  |         cv_status | ||
|  |         wait_until( | ||
|  |             lock_type& lock, | ||
|  |             const chrono::time_point<chrono::steady_clock, Duration>& t) | ||
|  |         { | ||
|  |             using namespace chrono; | ||
|  |             typedef time_point<steady_clock, nanoseconds> nano_sys_tmpt; | ||
|  |             wait_until(lock, | ||
|  |                         nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); | ||
|  |             return steady_clock::now() < t ? cv_status::no_timeout : | ||
|  |                                              cv_status::timeout; | ||
|  |         } | ||
|  | 
 | ||
|  |         template <class lock_type, class Clock, class Duration> | ||
|  |         cv_status | ||
|  |         wait_until( | ||
|  |             lock_type& lock, | ||
|  |             const chrono::time_point<Clock, Duration>& t) | ||
|  |         { | ||
|  |             using namespace chrono; | ||
|  |             steady_clock::time_point     s_now = steady_clock::now(); | ||
|  |             typename Clock::time_point  c_now = Clock::now(); | ||
|  |             wait_until(lock, s_now + ceil<nanoseconds>(t - c_now)); | ||
|  |             return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout; | ||
|  |         } | ||
|  | 
 | ||
|  |         template <class lock_type, class Rep, class Period> | ||
|  |         cv_status | ||
|  |         wait_for( | ||
|  |             lock_type& lock, | ||
|  |             const chrono::duration<Rep, Period>& d) | ||
|  |         { | ||
|  |             using namespace chrono; | ||
|  |             steady_clock::time_point c_now = steady_clock::now(); | ||
|  |             wait_until(lock, c_now + ceil<nanoseconds>(d)); | ||
|  |             return steady_clock::now() - c_now < d ? cv_status::no_timeout : | ||
|  |                                                    cv_status::timeout; | ||
|  |         } | ||
|  | 
 | ||
|  |         template <class lock_type> | ||
|  |         inline cv_status wait_until( | ||
|  |             lock_type& lock, | ||
|  |             chrono::time_point<chrono::steady_clock, chrono::nanoseconds> tp) | ||
|  |         { | ||
|  |             using namespace chrono; | ||
|  |             nanoseconds d = tp.time_since_epoch(); | ||
|  |             timespec ts = boost::detail::to_timespec(d); | ||
|  |             if (do_wait_until(lock, ts)) return cv_status::no_timeout; | ||
|  |             else return cv_status::timeout; | ||
|  |         } | ||
|  | 
 | ||
|  | #endif | ||
|  | #endif // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC | ||
|  | 
 | ||
|  | #ifdef BOOST_THREAD_USES_CHRONO | ||
|  |         template <class lock_type, class Clock, class Duration, class Predicate> | ||
|  |         bool | ||
|  |         wait_until( | ||
|  |                 lock_type& lock, | ||
|  |                 const chrono::time_point<Clock, Duration>& t, | ||
|  |                 Predicate pred) | ||
|  |         { | ||
|  |             while (!pred()) | ||
|  |             { | ||
|  |                 if (wait_until(lock, t) == cv_status::timeout) | ||
|  |                     return pred(); | ||
|  |             } | ||
|  |             return true; | ||
|  |         } | ||
|  | 
 | ||
|  |         template <class lock_type, class Rep, class Period, class Predicate> | ||
|  |         bool | ||
|  |         wait_for( | ||
|  |                 lock_type& lock, | ||
|  |                 const chrono::duration<Rep, Period>& d, | ||
|  |                 Predicate pred) | ||
|  |         { | ||
|  |           return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); | ||
|  |         } | ||
|  | #endif | ||
|  | 
 | ||
|  |         void notify_one() BOOST_NOEXCEPT | ||
|  |         { | ||
|  |             boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); | ||
|  |             BOOST_VERIFY(!pthread_cond_signal(&cond)); | ||
|  |         } | ||
|  | 
 | ||
|  |         void notify_all() BOOST_NOEXCEPT | ||
|  |         { | ||
|  |             boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); | ||
|  |             BOOST_VERIFY(!pthread_cond_broadcast(&cond)); | ||
|  |         } | ||
|  |     private: // used by boost::thread::try_join_until | ||
|  | 
 | ||
|  |         template <class lock_type> | ||
|  |         bool do_wait_until( | ||
|  |           lock_type& m, | ||
|  |           struct timespec const &timeout) | ||
|  |         { | ||
|  |           int res=0; | ||
|  |           { | ||
|  |               thread_cv_detail::lock_on_exit<lock_type> guard; | ||
|  | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | ||
|  |               detail::interruption_checker check_for_interruption(&internal_mutex,&cond); | ||
|  | #else | ||
|  |               boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); | ||
|  | #endif | ||
|  |               guard.activate(m); | ||
|  |               res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); | ||
|  |           } | ||
|  | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | ||
|  |           this_thread::interruption_point(); | ||
|  | #endif | ||
|  |           if(res==ETIMEDOUT) | ||
|  |           { | ||
|  |               return false; | ||
|  |           } | ||
|  |           if(res) | ||
|  |           { | ||
|  |               boost::throw_exception(condition_error(res, "boost::condition_variable_any::do_wait_until() failed in pthread_cond_timedwait")); | ||
|  |           } | ||
|  |           return true; | ||
|  |         } | ||
|  |     }; | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | #include <boost/config/abi_suffix.hpp> | ||
|  | 
 | ||
|  | #endif |