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