diff options
Diffstat (limited to 'boost/thread/pthread')
-rw-r--r-- | boost/thread/pthread/condition_variable.hpp | 277 | ||||
-rw-r--r-- | boost/thread/pthread/condition_variable_fwd.hpp | 271 | ||||
-rw-r--r-- | boost/thread/pthread/mutex.hpp | 104 | ||||
-rw-r--r-- | boost/thread/pthread/pthread_helpers.hpp | 42 | ||||
-rw-r--r-- | boost/thread/pthread/recursive_mutex.hpp | 98 | ||||
-rw-r--r-- | boost/thread/pthread/shared_mutex.hpp | 241 | ||||
-rw-r--r-- | boost/thread/pthread/shared_mutex_assert.hpp | 724 | ||||
-rw-r--r-- | boost/thread/pthread/thread_data.hpp | 161 | ||||
-rw-r--r-- | boost/thread/pthread/timespec.hpp | 138 |
9 files changed, 674 insertions, 1382 deletions
diff --git a/boost/thread/pthread/condition_variable.hpp b/boost/thread/pthread/condition_variable.hpp index b66b710a24..285785ff59 100644 --- a/boost/thread/pthread/condition_variable.hpp +++ b/boost/thread/pthread/condition_variable.hpp @@ -6,8 +6,10 @@ // (C) Copyright 2007-10 Anthony Williams // (C) Copyright 2011-2012 Vicente J. Botet Escriba -#include <boost/thread/pthread/timespec.hpp> +#include <boost/thread/detail/platform_time.hpp> #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> +#include <boost/thread/pthread/pthread_helpers.hpp> + #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS #include <boost/thread/pthread/thread_data.hpp> #endif @@ -18,6 +20,8 @@ #endif #include <boost/thread/detail/delete.hpp> +#include <algorithm> + #include <boost/config/abi_prefix.hpp> namespace boost @@ -95,9 +99,18 @@ namespace boost } } + // When this function returns true: + // * A notification (or sometimes a spurious OS signal) has been received + // * Do not assume that the timeout has not been reached + // * Do not assume that the predicate has been changed + // + // When this function returns false: + // * The timeout has been reached + // * Do not assume that a notification has not been received + // * Do not assume that the predicate has not been changed inline bool condition_variable::do_wait_until( unique_lock<mutex>& m, - struct timespec const &timeout) + detail::internal_platform_timepoint const &timeout) { #if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED if (!m.owns_lock()) @@ -112,12 +125,12 @@ namespace boost detail::interruption_checker check_for_interruption(&internal_mutex,&cond); pthread_mutex_t* the_mutex = &internal_mutex; guard.activate(m); - cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout); + cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs()); check_for_interruption.unlock_if_locked(); guard.deactivate(); #else pthread_mutex_t* the_mutex = m.mutex()->native_handle(); - cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout); + cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs()); #endif } #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS @@ -164,11 +177,11 @@ namespace boost { 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); + int const res2 = 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")); + boost::throw_exception(thread_resource_error(res2, "boost::condition_variable_any::condition_variable_any() failed in pthread::cond_init")); } } ~condition_variable_any() @@ -205,15 +218,35 @@ namespace boost template<typename lock_type,typename predicate_type> void wait(lock_type& m,predicate_type pred) { - while(!pred()) wait(m); + 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); +#if defined BOOST_THREAD_WAIT_BUG + const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG); +#else + const detail::real_platform_timepoint ts(abs_time); +#endif +#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + const detail::platform_duration d(ts - detail::real_platform_clock::now()); + do_wait_until(m, detail::internal_platform_clock::now() + d); + return ts > detail::real_platform_clock::now(); +#else + return do_wait_until(m, ts); +#endif } template<typename lock_type> bool timed_wait(lock_type& m,xtime const& abs_time) @@ -224,18 +257,55 @@ namespace boost 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); + if (wait_duration.is_pos_infinity()) + { + wait(m); + return true; + } + if (wait_duration.is_special()) + { + return true; + } + detail::platform_duration d(wait_duration); +#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); + do_wait_until(m, detail::internal_platform_clock::now() + d); + return ts > detail::mono_platform_clock::now(); +#else + return do_wait_until(m, detail::internal_platform_clock::now() + d); +#endif } template<typename lock_type,typename predicate_type> bool timed_wait(lock_type& m,boost::system_time const& abs_time, predicate_type pred) { +#if defined BOOST_THREAD_WAIT_BUG + const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG); +#else + const detail::real_platform_timepoint ts(abs_time); +#endif while (!pred()) { - if(!timed_wait(m, abs_time)) - return pred(); +#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + detail::platform_duration d(ts - detail::real_platform_clock::now()); + if (d <= detail::platform_duration::zero()) break; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + do_wait_until(m, detail::internal_platform_clock::now() + d); +#else + if (!do_wait_until(m, ts)) break; // timeout occurred +#endif } - return true; + return pred(); } template<typename lock_type,typename predicate_type> @@ -247,24 +317,52 @@ namespace boost 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); + if (wait_duration.is_pos_infinity()) + { + while (!pred()) + { + wait(m); + } + return true; + } + if (wait_duration.is_special()) + { + return pred(); + } + detail::platform_duration d(wait_duration); +#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); + while (!pred()) + { + if (d <= detail::platform_duration::zero()) break; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + do_wait_until(m, detail::internal_platform_clock::now() + d); + d = ts - detail::mono_platform_clock::now(); + } +#else + const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d); + while (!pred()) + { + if (!do_wait_until(m, ts)) break; // timeout occurred + } +#endif + return 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) + const chrono::time_point<detail::internal_chrono_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; + const boost::detail::internal_platform_timepoint ts(t); + if (do_wait_until(lock, ts)) return cv_status::no_timeout; + else return cv_status::timeout; } template <class lock_type, class Clock, class Duration> @@ -273,11 +371,18 @@ namespace boost 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; + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; + common_duration d(t - Clock::now()); + do_wait_until(lock, detail::internal_chrono_clock::now() + d); + if (t > Clock::now()) return cv_status::no_timeout; + else return cv_status::timeout; } template <class lock_type, class Rep, class Period> @@ -286,86 +391,24 @@ namespace boost 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; + return wait_until(lock, chrono::steady_clock::now() + d); } -#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 + template <class lock_type, class Duration, class Predicate> + bool 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) + lock_type& lock, + const chrono::time_point<detail::internal_chrono_clock, Duration>& t, + Predicate pred) { - 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; + const detail::internal_platform_timepoint ts(t); + while (!pred()) + { + if (!do_wait_until(lock, ts)) break; // timeout occurred + } + return pred(); } -#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( @@ -373,12 +416,18 @@ namespace boost const chrono::time_point<Clock, Duration>& t, Predicate pred) { + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; while (!pred()) { - if (wait_until(lock, t) == cv_status::timeout) - return pred(); + common_duration d(t - Clock::now()); + if (d <= common_duration::zero()) break; // timeout occurred + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d)); } - return true; + return pred(); } template <class lock_type, class Rep, class Period, class Predicate> @@ -388,7 +437,7 @@ namespace boost const chrono::duration<Rep, Period>& d, Predicate pred) { - return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); + return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); } #endif @@ -403,12 +452,21 @@ namespace boost boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); BOOST_VERIFY(!pthread_cond_broadcast(&cond)); } - private: // used by boost::thread::try_join_until - + private: + + // When this function returns true: + // * A notification (or sometimes a spurious OS signal) has been received + // * Do not assume that the timeout has not been reached + // * Do not assume that the predicate has been changed + // + // When this function returns false: + // * The timeout has been reached + // * Do not assume that a notification has not been received + // * Do not assume that the predicate has not been changed template <class lock_type> bool do_wait_until( lock_type& m, - struct timespec const &timeout) + detail::internal_platform_timepoint const &timeout) { int res=0; { @@ -419,7 +477,7 @@ namespace boost boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); #endif guard.activate(m); - res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); + res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout.getTs()); check_for_interruption.unlock_if_locked(); guard.deactivate(); } @@ -437,7 +495,6 @@ namespace boost return true; } }; - } #include <boost/config/abi_suffix.hpp> diff --git a/boost/thread/pthread/condition_variable_fwd.hpp b/boost/thread/pthread/condition_variable_fwd.hpp index 0ea34e238d..dc471d56a0 100644 --- a/boost/thread/pthread/condition_variable_fwd.hpp +++ b/boost/thread/pthread/condition_variable_fwd.hpp @@ -13,7 +13,9 @@ #include <boost/thread/mutex.hpp> #include <boost/thread/lock_types.hpp> #include <boost/thread/thread_time.hpp> -#include <boost/thread/pthread/timespec.hpp> +#include <boost/thread/detail/platform_time.hpp> +#include <boost/thread/pthread/pthread_helpers.hpp> + #if defined BOOST_THREAD_USES_DATETIME #include <boost/thread/xtime.hpp> #endif @@ -25,31 +27,12 @@ #include <boost/thread/detail/delete.hpp> #include <boost/date_time/posix_time/posix_time_duration.hpp> +#include <algorithm> + #include <boost/config/abi_prefix.hpp> namespace boost { - namespace detail { - inline int monotonic_pthread_cond_init(pthread_cond_t& cond) { - -#ifdef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC - pthread_condattr_t attr; - int res = pthread_condattr_init(&attr); - if (res) - { - return res; - } - pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); - res=pthread_cond_init(&cond,&attr); - pthread_condattr_destroy(&attr); - return res; -#else - return pthread_cond_init(&cond,NULL); -#endif - - } - } - class condition_variable { private: @@ -61,21 +44,9 @@ namespace boost public: //private: // used by boost::thread::try_join_until - inline bool do_wait_until( + bool do_wait_until( unique_lock<mutex>& lock, - struct timespec const &timeout); - - bool do_wait_for( - unique_lock<mutex>& lock, - struct timespec const &timeout) - { -#if defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC - return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now_monotonic())); -#else - // old behavior was fine for monotonic - return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now_realtime())); -#endif - } + detail::internal_platform_timepoint const &timeout); public: BOOST_THREAD_NO_COPYABLE(condition_variable) @@ -93,14 +64,14 @@ namespace boost boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread_mutex_init")); } //#endif - res = detail::monotonic_pthread_cond_init(cond); + res = pthread::cond_init(cond); if (res) { //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS // ditto BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); //#endif - boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in detail::monotonic_pthread_cond_init")); + boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread::cond_init")); } } ~condition_variable() @@ -124,20 +95,35 @@ namespace boost template<typename predicate_type> void wait(unique_lock<mutex>& m,predicate_type pred) { - while(!pred()) wait(m); + while (!pred()) + { + wait(m); + } } #if defined BOOST_THREAD_USES_DATETIME - inline bool timed_wait( + bool timed_wait( unique_lock<mutex>& m, boost::system_time const& abs_time) { #if defined BOOST_THREAD_WAIT_BUG - struct timespec const timeout=detail::to_timespec(abs_time + BOOST_THREAD_WAIT_BUG); - return do_wait_until(m, timeout); + const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG); +#else + const detail::real_platform_timepoint ts(abs_time); +#endif +#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + const detail::platform_duration d(ts - detail::real_platform_clock::now()); + do_wait_until(m, detail::internal_platform_clock::now() + d); + return ts > detail::real_platform_clock::now(); #else - struct timespec const timeout=detail::to_timespec(abs_time); - return do_wait_until(m, timeout); + return do_wait_until(m, ts); #endif } bool timed_wait( @@ -154,14 +140,28 @@ namespace boost { if (wait_duration.is_pos_infinity()) { - wait(m); // or do_wait(m,detail::timeout::sentinel()); + wait(m); return true; } if (wait_duration.is_special()) { return true; } - return timed_wait(m,get_system_time()+wait_duration); + detail::platform_duration d(wait_duration); +#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); + do_wait_until(m, detail::internal_platform_clock::now() + d); + return ts > detail::mono_platform_clock::now(); +#else + return do_wait_until(m, detail::internal_platform_clock::now() + d); +#endif } template<typename predicate_type> @@ -169,12 +169,26 @@ namespace boost unique_lock<mutex>& m, boost::system_time const& abs_time,predicate_type pred) { +#if defined BOOST_THREAD_WAIT_BUG + const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG); +#else + const detail::real_platform_timepoint ts(abs_time); +#endif while (!pred()) { - if(!timed_wait(m, abs_time)) - return pred(); +#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + detail::platform_duration d(ts - detail::real_platform_clock::now()); + if (d <= detail::platform_duration::zero()) break; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + do_wait_until(m, detail::internal_platform_clock::now() + d); +#else + if (!do_wait_until(m, ts)) break; // timeout occurred +#endif } - return true; + return pred(); } template<typename predicate_type> @@ -194,7 +208,7 @@ namespace boost { while (!pred()) { - wait(m); // or do_wait(m,detail::timeout::sentinel()); + wait(m); } return true; } @@ -202,26 +216,41 @@ namespace boost { return pred(); } - return timed_wait(m,get_system_time()+wait_duration,pred); + detail::platform_duration d(wait_duration); +#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); + while (!pred()) + { + if (d <= detail::platform_duration::zero()) break; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + do_wait_until(m, detail::internal_platform_clock::now() + d); + d = ts - detail::mono_platform_clock::now(); + } +#else + const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d); + while (!pred()) + { + if (!do_wait_until(m, ts)) break; // timeout occurred + } +#endif + return pred(); } #endif -#ifndef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC - #ifdef BOOST_THREAD_USES_CHRONO template <class Duration> cv_status wait_until( unique_lock<mutex>& lock, - const chrono::time_point<chrono::system_clock, Duration>& t) + const chrono::time_point<detail::internal_chrono_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; + const detail::internal_platform_timepoint ts(t); + if (do_wait_until(lock, ts)) return cv_status::no_timeout; + else return cv_status::timeout; } template <class Clock, class Duration> @@ -230,100 +259,44 @@ namespace boost unique_lock<mutex>& 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; + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; + common_duration d(t - Clock::now()); + do_wait_until(lock, detail::internal_chrono_clock::now() + d); + if (t > Clock::now()) return cv_status::no_timeout; + else return cv_status::timeout; } - - template <class Rep, class Period> cv_status wait_for( unique_lock<mutex>& 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; - - } - - inline cv_status wait_until( - unique_lock<mutex>& 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; + return wait_until(lock, chrono::steady_clock::now() + d); } -#endif -#else // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC -#ifdef BOOST_THREAD_USES_CHRONO - - template <class Duration> - cv_status - wait_until( - unique_lock<mutex>& 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 Clock, class Duration> - cv_status + template <class Duration, class Predicate> + bool wait_until( - unique_lock<mutex>& 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 Rep, class Period> - cv_status - wait_for( - unique_lock<mutex>& 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; - } - - inline cv_status wait_until( - unique_lock<mutex>& lk, - chrono::time_point<chrono::steady_clock, chrono::nanoseconds> tp) + unique_lock<mutex>& lock, + const chrono::time_point<detail::internal_chrono_clock, Duration>& t, + Predicate pred) { - 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; + const detail::internal_platform_timepoint ts(t); + while (!pred()) + { + if (!do_wait_until(lock, ts)) break; // timeout occurred + } + return pred(); } -#endif - -#endif // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC -#ifdef BOOST_THREAD_USES_CHRONO template <class Clock, class Duration, class Predicate> bool wait_until( @@ -331,12 +304,18 @@ namespace boost const chrono::time_point<Clock, Duration>& t, Predicate pred) { + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; while (!pred()) { - if (wait_until(lock, t) == cv_status::timeout) - return pred(); + common_duration d(t - Clock::now()); + if (d <= common_duration::zero()) break; // timeout occurred + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d)); } - return true; + return pred(); } template <class Rep, class Period, class Predicate> @@ -346,7 +325,7 @@ namespace boost const chrono::duration<Rep, Period>& d, Predicate pred) { - return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); + return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); } #endif @@ -359,15 +338,11 @@ namespace boost void notify_one() BOOST_NOEXCEPT; void notify_all() BOOST_NOEXCEPT; - - }; BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk); - } - #include <boost/config/abi_suffix.hpp> #endif diff --git a/boost/thread/pthread/mutex.hpp b/boost/thread/pthread/mutex.hpp index 9ac808b6f4..6180ac5ebd 100644 --- a/boost/thread/pthread/mutex.hpp +++ b/boost/thread/pthread/mutex.hpp @@ -16,24 +16,20 @@ #include <boost/thread/lock_types.hpp> #endif #include <boost/thread/thread_time.hpp> +#if defined BOOST_THREAD_USES_DATETIME #include <boost/thread/xtime.hpp> +#endif #include <boost/assert.hpp> #include <errno.h> -#include <boost/thread/pthread/timespec.hpp> +#include <boost/thread/detail/platform_time.hpp> #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> +#include <boost/thread/pthread/pthread_helpers.hpp> #ifdef BOOST_THREAD_USES_CHRONO #include <boost/chrono/system_clocks.hpp> #include <boost/chrono/ceil.hpp> #endif #include <boost/thread/detail/delete.hpp> -#if (defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS-0)>=200112L) \ - || (defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21) -#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK -#define BOOST_PTHREAD_HAS_TIMEDLOCK -#endif -#endif - #include <boost/config/abi_prefix.hpp> @@ -165,7 +161,7 @@ namespace boost { private: pthread_mutex_t m; -#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK +#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK pthread_cond_t cond; bool is_locked; #endif @@ -178,13 +174,12 @@ namespace boost { boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init")); } -#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK - int const res2=pthread_cond_init(&cond,NULL); +#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK + int const res2=pthread::cond_init(cond); if(res2) { BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); - //BOOST_VERIFY(!pthread_mutex_destroy(&m)); - boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init")); + boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread::cond_init")); } is_locked=false; #endif @@ -192,7 +187,7 @@ namespace boost ~timed_mutex() { BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); -#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK +#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK BOOST_VERIFY(!pthread_cond_destroy(&cond)); #endif } @@ -201,14 +196,36 @@ namespace boost template<typename TimeDuration> bool timed_lock(TimeDuration const & relative_time) { - return timed_lock(get_system_time()+relative_time); + if (relative_time.is_pos_infinity()) + { + lock(); + return true; + } + if (relative_time.is_special()) + { + return true; + } + detail::platform_duration d(relative_time); +#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) + const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) ) + { + d = ts - detail::mono_platform_clock::now(); + if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } + return true; +#else + return do_try_lock_until(detail::internal_platform_clock::now() + d); +#endif } bool timed_lock(boost::xtime const & absolute_time) { return timed_lock(system_time(absolute_time)); } #endif -#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK +#ifdef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK void lock() { int res = posix::pthread_mutex_lock(&m); @@ -246,9 +263,9 @@ namespace boost private: - bool do_try_lock_until(struct timespec const &timeout) + bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) { - int const res=pthread_mutex_timedlock(&m,&timeout); + int const res=pthread_mutex_timedlock(&m,&timeout.getTs()); BOOST_ASSERT(!res || res==ETIMEDOUT); return !res; } @@ -284,18 +301,22 @@ namespace boost } private: - bool do_try_lock_until(struct timespec const &timeout) + bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) { boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); while(is_locked) { - int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout); + int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout.getTs()); if(cond_res==ETIMEDOUT) { - return false; + break; } BOOST_ASSERT(!cond_res); } + if(is_locked) + { + return false; + } is_locked=true; return true; } @@ -305,8 +326,20 @@ namespace boost #if defined BOOST_THREAD_USES_DATETIME bool timed_lock(system_time const & abs_time) { - struct timespec const ts=boost::detail::to_timespec(abs_time); + const detail::real_platform_timepoint ts(abs_time); +#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + detail::platform_duration d(ts - detail::real_platform_clock::now()); + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) ) + { + d = ts - detail::real_platform_clock::now(); + if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } + return true; +#else return do_try_lock_until(ts); +#endif } #endif #ifdef BOOST_THREAD_USES_CHRONO @@ -318,23 +351,21 @@ namespace boost template <class Clock, class Duration> bool try_lock_until(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(); - return try_lock_until(s_now + ceil<nanoseconds>(t - c_now)); + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; + common_duration d(t - Clock::now()); + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + while ( ! try_lock_until(detail::internal_chrono_clock::now() + d)) + { + d = t - Clock::now(); + if ( d <= common_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + } + return true; } template <class Duration> - bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t) + bool try_lock_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t) { - using namespace chrono; - typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; - return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); - } - bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp) - { - //using namespace chrono; - chrono::nanoseconds d = tp.time_since_epoch(); - timespec ts = boost::detail::to_timespec(d); + detail::internal_platform_timepoint ts(t); return do_try_lock_until(ts); } #endif @@ -352,7 +383,6 @@ namespace boost typedef scoped_timed_lock scoped_lock; #endif }; - } #include <boost/config/abi_suffix.hpp> diff --git a/boost/thread/pthread/pthread_helpers.hpp b/boost/thread/pthread/pthread_helpers.hpp new file mode 100644 index 0000000000..c1ff0f9239 --- /dev/null +++ b/boost/thread/pthread/pthread_helpers.hpp @@ -0,0 +1,42 @@ +#ifndef BOOST_THREAD_PTHREAD_PTHREAD_HELPERS_HPP +#define BOOST_THREAD_PTHREAD_PTHREAD_HELPERS_HPP +// Copyright (C) 2017 +// Vicente J. Botet Escriba +// +// 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) + +#include <boost/thread/detail/config.hpp> +#include <pthread.h> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace pthread + { + inline int cond_init(pthread_cond_t& cond) { + + #ifdef BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + pthread_condattr_t attr; + int res = pthread_condattr_init(&attr); + if (res) + { + return res; + } + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + res=pthread_cond_init(&cond,&attr); + pthread_condattr_destroy(&attr); + return res; + #else + return pthread_cond_init(&cond,NULL); + #endif + + } + } +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/pthread/recursive_mutex.hpp b/boost/thread/pthread/recursive_mutex.hpp index 4caae0b5df..ce9a8ce44b 100644 --- a/boost/thread/pthread/recursive_mutex.hpp +++ b/boost/thread/pthread/recursive_mutex.hpp @@ -19,27 +19,22 @@ #endif #include <boost/date_time/posix_time/conversion.hpp> #include <errno.h> -#include <boost/thread/pthread/timespec.hpp> +#include <boost/thread/detail/platform_time.hpp> #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> +#include <boost/thread/pthread/pthread_helpers.hpp> #ifdef BOOST_THREAD_USES_CHRONO #include <boost/chrono/system_clocks.hpp> #include <boost/chrono/ceil.hpp> #endif #include <boost/thread/detail/delete.hpp> -#if (defined _POSIX_TIMEOUTS && (_POSIX_TIMEOUTS-0)>=200112L) \ - || (defined __ANDROID__ && defined __ANDROID_API__ && __ANDROID_API__ >= 21) -#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK -#define BOOST_PTHREAD_HAS_TIMEDLOCK -#endif -#endif #if defined BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE \ || defined __ANDROID__ #define BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE #endif -#if defined BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE && defined BOOST_PTHREAD_HAS_TIMEDLOCK +#if defined BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE && defined BOOST_THREAD_USES_PTHREAD_TIMEDLOCK #define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK #endif @@ -89,11 +84,11 @@ namespace boost { boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init")); } - int const res2=pthread_cond_init(&cond,NULL); + int const res2=pthread::cond_init(cond); if(res2) { BOOST_VERIFY(!pthread_mutex_destroy(&m)); - boost::throw_exception(thread_resource_error(res2, "boost:: recursive_mutex constructor failed in pthread_cond_init")); + boost::throw_exception(thread_resource_error(res2, "boost:: recursive_mutex constructor failed in pthread::cond_init")); } is_locked=false; count=0; @@ -224,11 +219,11 @@ namespace boost { boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init")); } - int const res2=pthread_cond_init(&cond,NULL); + int const res2=pthread::cond_init(cond); if(res2) { BOOST_VERIFY(!pthread_mutex_destroy(&m)); - boost::throw_exception(thread_resource_error(res2, "boost:: recursive_timed_mutex constructor failed in pthread_cond_init")); + boost::throw_exception(thread_resource_error(res2, "boost:: recursive_timed_mutex constructor failed in pthread::cond_init")); } is_locked=false; count=0; @@ -246,7 +241,29 @@ namespace boost template<typename TimeDuration> bool timed_lock(TimeDuration const & relative_time) { - return timed_lock(get_system_time()+relative_time); + if (relative_time.is_pos_infinity()) + { + lock(); + return true; + } + if (relative_time.is_special()) + { + return true; + } + detail::platform_duration d(relative_time); +#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) + const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) ) + { + d = ts - detail::mono_platform_clock::now(); + if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } + return true; +#else + return do_try_lock_until(detail::internal_platform_clock::now() + d); +#endif } #endif @@ -268,9 +285,9 @@ namespace boost return !res; } private: - bool do_try_lock_until(struct timespec const &timeout) + bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) { - int const res=pthread_mutex_timedlock(&m,&timeout); + int const res=pthread_mutex_timedlock(&m,&timeout.getTs()); BOOST_ASSERT(!res || res==ETIMEDOUT); return !res; } @@ -320,7 +337,7 @@ namespace boost } private: - bool do_try_lock_until(struct timespec const &timeout) + bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) { boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); if(is_locked && pthread_equal(owner,pthread_self())) @@ -330,13 +347,17 @@ namespace boost } while(is_locked) { - int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout); + int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout.getTs()); if(cond_res==ETIMEDOUT) { - return false; + break; } BOOST_ASSERT(!cond_res); } + if(is_locked) + { + return false; + } is_locked=true; ++count; owner=pthread_self(); @@ -349,8 +370,20 @@ namespace boost #if defined BOOST_THREAD_USES_DATETIME bool timed_lock(system_time const & abs_time) { - struct timespec const ts=detail::to_timespec(abs_time); + const detail::real_platform_timepoint ts(abs_time); +#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + detail::platform_duration d(ts - detail::real_platform_clock::now()); + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) ) + { + d = ts - detail::real_platform_clock::now(); + if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } + return true; +#else return do_try_lock_until(ts); +#endif } #endif #ifdef BOOST_THREAD_USES_CHRONO @@ -362,23 +395,22 @@ namespace boost template <class Clock, class Duration> bool try_lock_until(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(); - return try_lock_until(s_now + ceil<nanoseconds>(t - c_now)); + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; + common_duration d(t - Clock::now()); + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + while ( ! try_lock_until(detail::internal_chrono_clock::now() + d)) + { + d = t - Clock::now(); + if ( d <= common_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + } + return true; + } template <class Duration> - bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t) - { - using namespace chrono; - typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; - return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); - } - bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp) + bool try_lock_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t) { - //using namespace chrono; - chrono::nanoseconds d = tp.time_since_epoch(); - timespec ts = boost::detail::to_timespec(d); + detail::internal_platform_timepoint ts(t); return do_try_lock_until(ts); } #endif diff --git a/boost/thread/pthread/shared_mutex.hpp b/boost/thread/pthread/shared_mutex.hpp index e4ec24fe3f..ed9a296f2e 100644 --- a/boost/thread/pthread/shared_mutex.hpp +++ b/boost/thread/pthread/shared_mutex.hpp @@ -9,6 +9,7 @@ // http://www.boost.org/LICENSE_1_0.txt) #include <boost/assert.hpp> +#include <boost/bind.hpp> #include <boost/static_assert.hpp> #include <boost/thread/mutex.hpp> #include <boost/thread/condition_variable.hpp> @@ -78,11 +79,6 @@ namespace boost return ! (shared_count || exclusive); } - void exclusive_blocked (bool blocked) - { - exclusive_waiting_blocked = blocked; - } - void lock () { exclusive = true; @@ -99,17 +95,19 @@ namespace boost return ! (exclusive || exclusive_waiting_blocked); } - bool more_shared () const + bool no_shared () const { - return shared_count > 0 ; + return shared_count==0; } - unsigned get_shared_count () const + + bool one_shared () const { - return shared_count ; + return shared_count==1; } - unsigned lock_shared () + + void lock_shared () { - return ++shared_count; + ++shared_count; } @@ -118,18 +116,6 @@ namespace boost --shared_count; } - bool unlock_shared_downgrades() - { - if (upgrade) { - upgrade=false; - exclusive=true; - return true; - } else { - exclusive_waiting_blocked=false; - return false; - } - } - void lock_upgrade () { ++shared_count; @@ -185,10 +171,7 @@ namespace boost boost::this_thread::disable_interruption do_not_disturb; #endif boost::unique_lock<boost::mutex> lk(state_change); - while(!state.can_lock_shared()) - { - shared_cond.wait(lk); - } + shared_cond.wait(lk, boost::bind(&state_data::can_lock_shared, boost::ref(state))); state.lock_shared(); } @@ -211,13 +194,9 @@ namespace boost boost::this_thread::disable_interruption do_not_disturb; #endif boost::unique_lock<boost::mutex> lk(state_change); - - while(!state.can_lock_shared()) + if(!shared_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock_shared, boost::ref(state)))) { - if(!shared_cond.timed_wait(lk,timeout)) - { - return false; - } + return false; } state.lock_shared(); return true; @@ -226,7 +205,16 @@ namespace boost template<typename TimeDuration> bool timed_lock_shared(TimeDuration const & relative_time) { - return timed_lock_shared(get_system_time()+relative_time); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + if(!shared_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock_shared, boost::ref(state)))) + { + return false; + } + state.lock_shared(); + return true; } #endif #ifdef BOOST_THREAD_USES_CHRONO @@ -242,14 +230,9 @@ namespace boost boost::this_thread::disable_interruption do_not_disturb; #endif boost::unique_lock<boost::mutex> lk(state_change); - - while(!state.can_lock_shared()) - //while(state.exclusive || state.exclusive_waiting_blocked) + if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_shared, boost::ref(state)))) { - if(cv_status::timeout==shared_cond.wait_until(lk,abs_time)) - { - return false; - } + return false; } state.lock_shared(); return true; @@ -260,11 +243,11 @@ namespace boost boost::unique_lock<boost::mutex> lk(state_change); state.assert_lock_shared(); state.unlock_shared(); - if (! state.more_shared()) + if (state.no_shared()) { if (state.upgrade) { - // As there is a thread doing a unlock_upgrade_and_lock that is waiting for ! state.more_shared() + // As there is a thread doing a unlock_upgrade_and_lock that is waiting for state.no_shared() // avoid other threads to lock, lock_upgrade or lock_shared, so only this thread is notified. state.upgrade=false; state.exclusive=true; @@ -286,12 +269,8 @@ namespace boost boost::this_thread::disable_interruption do_not_disturb; #endif boost::unique_lock<boost::mutex> lk(state_change); - - while (state.shared_count || state.exclusive) - { - state.exclusive_waiting_blocked=true; - exclusive_cond.wait(lk); - } + state.exclusive_waiting_blocked=true; + exclusive_cond.wait(lk, boost::bind(&state_data::can_lock, boost::ref(state))); state.exclusive=true; } @@ -302,20 +281,12 @@ namespace boost boost::this_thread::disable_interruption do_not_disturb; #endif boost::unique_lock<boost::mutex> lk(state_change); - - while(state.shared_count || state.exclusive) + state.exclusive_waiting_blocked=true; + if(!exclusive_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock, boost::ref(state)))) { - state.exclusive_waiting_blocked=true; - if(!exclusive_cond.timed_wait(lk,timeout)) - { - if(state.shared_count || state.exclusive) - { - state.exclusive_waiting_blocked=false; - release_waiters(); - return false; - } - break; - } + state.exclusive_waiting_blocked=false; + release_waiters(); + return false; } state.exclusive=true; return true; @@ -324,7 +295,19 @@ namespace boost template<typename TimeDuration> bool timed_lock(TimeDuration const & relative_time) { - return timed_lock(get_system_time()+relative_time); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + state.exclusive_waiting_blocked=true; + if(!exclusive_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock, boost::ref(state)))) + { + state.exclusive_waiting_blocked=false; + release_waiters(); + return false; + } + state.exclusive=true; + return true; } #endif #ifdef BOOST_THREAD_USES_CHRONO @@ -340,20 +323,12 @@ namespace boost boost::this_thread::disable_interruption do_not_disturb; #endif boost::unique_lock<boost::mutex> lk(state_change); - - while(state.shared_count || state.exclusive) + state.exclusive_waiting_blocked=true; + if(!exclusive_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock, boost::ref(state)))) { - state.exclusive_waiting_blocked=true; - if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time)) - { - if(state.shared_count || state.exclusive) - { - state.exclusive_waiting_blocked=false; - release_waiters(); - return false; - } - break; - } + state.exclusive_waiting_blocked=false; + release_waiters(); + return false; } state.exclusive=true; return true; @@ -363,17 +338,12 @@ namespace boost bool try_lock() { boost::unique_lock<boost::mutex> lk(state_change); - - if(state.shared_count || state.exclusive) + if(!state.can_lock()) { return false; } - else - { - state.exclusive=true; - return true; - } - + state.exclusive=true; + return true; } void unlock() @@ -392,10 +362,7 @@ namespace boost boost::this_thread::disable_interruption do_not_disturb; #endif boost::unique_lock<boost::mutex> lk(state_change); - while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) - { - shared_cond.wait(lk); - } + shared_cond.wait(lk, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))); state.lock_shared(); state.upgrade=true; } @@ -407,16 +374,9 @@ namespace boost boost::this_thread::disable_interruption do_not_disturb; #endif boost::unique_lock<boost::mutex> lk(state_change); - while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + if(!shared_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock_upgrade, boost::ref(state)))) { - if(!shared_cond.timed_wait(lk,timeout)) - { - if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) - { - return false; - } - break; - } + return false; } state.lock_shared(); state.upgrade=true; @@ -426,7 +386,17 @@ namespace boost template<typename TimeDuration> bool timed_lock_upgrade(TimeDuration const & relative_time) { - return timed_lock_upgrade(get_system_time()+relative_time); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + if(!shared_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state)))) + { + return false; + } + state.lock_shared(); + state.upgrade=true; + return true; } #endif #ifdef BOOST_THREAD_USES_CHRONO @@ -442,16 +412,9 @@ namespace boost boost::this_thread::disable_interruption do_not_disturb; #endif boost::unique_lock<boost::mutex> lk(state_change); - while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state)))) { - if(cv_status::timeout == shared_cond.wait_until(lk,abs_time)) - { - if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) - { - return false; - } - break; - } + return false; } state.lock_shared(); state.upgrade=true; @@ -461,17 +424,14 @@ namespace boost bool try_lock_upgrade() { boost::unique_lock<boost::mutex> lk(state_change); - if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + if(!state.can_lock_upgrade()) { return false; } - else - { - state.lock_shared(); - state.upgrade=true; - state.assert_lock_upgraded(); - return true; - } + state.lock_shared(); + state.upgrade=true; + state.assert_lock_upgraded(); + return true; } void unlock_upgrade() @@ -479,7 +439,7 @@ namespace boost boost::unique_lock<boost::mutex> lk(state_change); //state.upgrade=false; state.unlock_upgrade(); - if(! state.more_shared() ) + if(state.no_shared()) { state.exclusive_waiting_blocked=false; release_waiters(); @@ -497,10 +457,7 @@ namespace boost boost::unique_lock<boost::mutex> lk(state_change); state.assert_lock_upgraded(); state.unlock_shared(); - while (state.more_shared()) - { - upgrade_cond.wait(lk); - } + upgrade_cond.wait(lk, boost::bind(&state_data::no_shared, boost::ref(state))); state.upgrade=false; state.exclusive=true; state.assert_locked(); @@ -554,16 +511,9 @@ namespace boost #endif boost::unique_lock<boost::mutex> lk(state_change); state.assert_lock_upgraded(); - if (state.shared_count != 1) + if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::one_shared, boost::ref(state)))) { - for (;;) - { - cv_status status = shared_cond.wait_until(lk,abs_time); - if (state.shared_count == 1) - break; - if(status == cv_status::timeout) - return false; - } + return false; } state.upgrade=false; state.exclusive=true; @@ -619,16 +569,9 @@ namespace boost #endif boost::unique_lock<boost::mutex> lk(state_change); state.assert_lock_shared(); - if (state.shared_count != 1) + if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::one_shared, boost::ref(state)))) { - for (;;) - { - cv_status status = shared_cond.wait_until(lk,abs_time); - if (state.shared_count == 1) - break; - if(status == cv_status::timeout) - return false; - } + return false; } state.upgrade=false; state.exclusive=true; @@ -654,10 +597,7 @@ namespace boost { boost::unique_lock<boost::mutex> lk(state_change); state.assert_lock_shared(); - if( !state.exclusive - && !state.exclusive_waiting_blocked - && !state.upgrade - ) + if(state.can_lock_upgrade()) { state.upgrade=true; return true; @@ -683,22 +623,9 @@ namespace boost #endif boost::unique_lock<boost::mutex> lk(state_change); state.assert_lock_shared(); - if( state.exclusive - || state.exclusive_waiting_blocked - || state.upgrade - ) + if(!exclusive_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state)))) { - for (;;) - { - cv_status status = exclusive_cond.wait_until(lk,abs_time); - if( ! state.exclusive - && ! state.exclusive_waiting_blocked - && ! state.upgrade - ) - break; - if(status == cv_status::timeout) - return false; - } + return false; } state.upgrade=true; return true; diff --git a/boost/thread/pthread/shared_mutex_assert.hpp b/boost/thread/pthread/shared_mutex_assert.hpp deleted file mode 100644 index 186ab7984b..0000000000 --- a/boost/thread/pthread/shared_mutex_assert.hpp +++ /dev/null @@ -1,724 +0,0 @@ -#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP -#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP - -// (C) Copyright 2006-8 Anthony Williams -// (C) Copyright 2012 Vicente J. Botet Escriba -// -// 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) - -#include <boost/assert.hpp> -#include <boost/static_assert.hpp> -#include <boost/thread/mutex.hpp> -#include <boost/thread/condition_variable.hpp> -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS -#include <boost/thread/detail/thread_interruption.hpp> -#endif -#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/assert.hpp> - -#include <boost/config/abi_prefix.hpp> - -namespace boost -{ - class shared_mutex - { - private: - class state_data - { - public: - state_data () : - shared_count(0), - exclusive(false), - upgrade(false), - exclusive_waiting_blocked(false) - {} - - void assert_free() const - { - BOOST_ASSERT( ! exclusive ); - BOOST_ASSERT( ! upgrade ); - BOOST_ASSERT( shared_count==0 ); - } - - void assert_locked() const - { - BOOST_ASSERT( exclusive ); - BOOST_ASSERT( shared_count==0 ); - BOOST_ASSERT( ! upgrade ); - } - - void assert_lock_shared () const - { - BOOST_ASSERT( ! exclusive ); - BOOST_ASSERT( shared_count>0 ); - //BOOST_ASSERT( (! upgrade) || (shared_count>1)); - // if upgraded there are at least 2 threads sharing the mutex, - // except when unlock_upgrade_and_lock has decreased the number of readers but has not taken yet exclusive ownership. - } - - void assert_lock_upgraded () const - { - BOOST_ASSERT( ! exclusive ); - BOOST_ASSERT( upgrade ); - BOOST_ASSERT( shared_count>0 ); - } - - void assert_lock_not_upgraded () const - { - BOOST_ASSERT( ! upgrade ); - } - - bool can_lock () const - { - return ! (shared_count || exclusive); - } - - void exclusive_blocked (bool blocked) - { - exclusive_waiting_blocked = blocked; - } - - void lock () - { - exclusive = true; - } - - void unlock () - { - exclusive = false; - exclusive_waiting_blocked = false; - } - - bool can_lock_shared () const - { - return ! (exclusive || exclusive_waiting_blocked); - } - - bool is_last_shared () const - { - return !shared_count ; - } - unsigned get_shared_count () const - { - return shared_count ; - } - unsigned lock_shared () - { - return ++shared_count; - } - - - void unlock_shared () - { - --shared_count; - } - - bool unlock_shared_downgrades() - { - if (upgrade) { - upgrade=false; - exclusive=true; - return true; - } else { - exclusive_waiting_blocked=false; - return false; - } - } - - void lock_upgrade () - { - lock_shared (); - upgrade=true; - } - bool can_lock_upgrade () const - { - return ! (exclusive || exclusive_waiting_blocked || upgrade); - } - - void unlock_upgrade () - { - upgrade=false; - unlock_shared(); - } - - //private: - unsigned shared_count; - bool exclusive; - bool upgrade; - bool exclusive_waiting_blocked; - }; - - - - state_data state; - boost::mutex state_change; - boost::condition_variable shared_cond; - boost::condition_variable exclusive_cond; - boost::condition_variable upgrade_cond; - - void release_waiters() - { - exclusive_cond.notify_one(); - shared_cond.notify_all(); - } - - public: - BOOST_THREAD_NO_COPYABLE(shared_mutex) - - shared_mutex() - { - } - - ~shared_mutex() - { - } - - void lock_shared() - { -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - boost::this_thread::disable_interruption do_not_disturb; -#endif - boost::unique_lock<boost::mutex> lk(state_change); - - while(!state.can_lock_shared()) - { - shared_cond.wait(lk); - } - state.lock_shared(); - } - - bool try_lock_shared() - { - boost::unique_lock<boost::mutex> lk(state_change); - if(!state.can_lock_shared()) - { - return false; - } - else - { - state.lock_shared(); - return true; - } - } - -#if defined BOOST_THREAD_USES_DATETIME - bool timed_lock_shared(system_time const& timeout) - { -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - boost::this_thread::disable_interruption do_not_disturb; -#endif - boost::unique_lock<boost::mutex> lk(state_change); - - while(!state.can_lock_shared()) - { - if(!shared_cond.timed_wait(lk,timeout)) - { - return false; - } - } - state.lock_shared(); - return true; - } - - template<typename TimeDuration> - bool timed_lock_shared(TimeDuration const & relative_time) - { - return timed_lock_shared(get_system_time()+relative_time); - } -#endif -#ifdef BOOST_THREAD_USES_CHRONO - template <class Rep, class Period> - bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time) - { - return try_lock_shared_until(chrono::steady_clock::now() + rel_time); - } - template <class Clock, class Duration> - bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time) - { -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - boost::this_thread::disable_interruption do_not_disturb; -#endif - boost::unique_lock<boost::mutex> lk(state_change); - - while(!state.can_lock_shared()) - { - if(cv_status::timeout==shared_cond.wait_until(lk,abs_time)) - { - return false; - } - } - state.lock_shared(); - return true; - } -#endif - void unlock_shared() - { - boost::unique_lock<boost::mutex> lk(state_change); - state.assert_lock_shared(); - state.unlock_shared(); - if (state.get_shared_count () == 0) - { - if (state.unlock_shared_downgrades()) - { - lk.unlock(); - upgrade_cond.notify_one(); - } else { - lk.unlock(); - } - release_waiters(); - } - } - - void lock() - { -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - boost::this_thread::disable_interruption do_not_disturb; -#endif - boost::unique_lock<boost::mutex> lk(state_change); - - while(!state.can_lock()) - { - state.exclusive_blocked(true); - exclusive_cond.wait(lk); - } - state.lock(); - } - -#if defined BOOST_THREAD_USES_DATETIME - bool timed_lock(system_time const& timeout) - { -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - boost::this_thread::disable_interruption do_not_disturb; -#endif - boost::unique_lock<boost::mutex> lk(state_change); - - while(!state.can_lock()) - { - state.exclusive_blocked(true); - if(!exclusive_cond.timed_wait(lk,timeout)) - { - if(!state.can_lock()) - { - state.exclusive_blocked(false); - release_waiters(); - return false; - } - break; - } - } - state.exclusive=true; - //state.lock(); - return true; - } - - template<typename TimeDuration> - bool timed_lock(TimeDuration const & relative_time) - { - return timed_lock(get_system_time()+relative_time); - } -#endif -#ifdef BOOST_THREAD_USES_CHRONO - template <class Rep, class Period> - bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) - { - return try_lock_until(chrono::steady_clock::now() + rel_time); - } - template <class Clock, class Duration> - bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time) - { -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - boost::this_thread::disable_interruption do_not_disturb; -#endif - boost::unique_lock<boost::mutex> lk(state_change); - - while(!state.can_lock()) - { - state.exclusive_blocked(true); - if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time)) - { - if(!state.can_lock()) - { - state.exclusive_blocked(false); - release_waiters(); - return false; - } - break; - } - } - state.exclusive=true; - //state.lock(); - return true; - } -#endif - - bool try_lock() - { - boost::unique_lock<boost::mutex> lk(state_change); - - if(!state.can_lock()) - { - return false; - } - else - { - state.lock(); - return true; - } - - } - - void unlock() - { - boost::unique_lock<boost::mutex> lk(state_change); - state.assert_locked(); - state.unlock(); - state.assert_free(); - release_waiters(); - } - - void lock_upgrade() - { -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - boost::this_thread::disable_interruption do_not_disturb; -#endif - boost::unique_lock<boost::mutex> lk(state_change); - while(!state.can_lock_upgrade()) - { - shared_cond.wait(lk); - } - state.lock_upgrade(); - } - -#if defined BOOST_THREAD_USES_DATETIME - bool timed_lock_upgrade(system_time const& timeout) - { -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - boost::this_thread::disable_interruption do_not_disturb; -#endif - boost::unique_lock<boost::mutex> lk(state_change); - while(!state.can_lock_upgrade()) - { - if(!shared_cond.timed_wait(lk,timeout)) - { - if(!state.can_lock_upgrade()) - { - return false; - } - break; - } - } - state.lock_upgrade(); - return true; - } - - template<typename TimeDuration> - bool timed_lock_upgrade(TimeDuration const & relative_time) - { - return timed_lock_upgrade(get_system_time()+relative_time); - } -#endif -#ifdef BOOST_THREAD_USES_CHRONO - template <class Rep, class Period> - bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time) - { - return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time); - } - template <class Clock, class Duration> - bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time) - { -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - boost::this_thread::disable_interruption do_not_disturb; -#endif - boost::unique_lock<boost::mutex> lk(state_change); - while(!state.can_lock_upgrade()) - { - if(cv_status::timeout == shared_cond.wait_until(lk,abs_time)) - { - if(!state.can_lock_upgrade()) - { - return false; - } - break; - } - } - state.lock_upgrade(); - return true; - } -#endif - bool try_lock_upgrade() - { - boost::unique_lock<boost::mutex> lk(state_change); - if(!state.can_lock_upgrade()) - { - return false; - } - else - { - state.lock_upgrade(); - state.assert_lock_upgraded(); - return true; - } - } - - void unlock_upgrade() - { - boost::unique_lock<boost::mutex> lk(state_change); - state.assert_lock_upgraded(); - state.unlock_upgrade(); - state.assert_lock_not_upgraded (); - if(state.get_shared_count () == 0) - { - state.exclusive_blocked(false); - lk.unlock(); - release_waiters(); - } else { - lk.unlock(); - shared_cond.notify_all(); - } - } - - // Upgrade <-> Exclusive - void unlock_upgrade_and_lock() - { -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - boost::this_thread::disable_interruption do_not_disturb; -#endif - boost::unique_lock<boost::mutex> lk(state_change); - state.assert_lock_upgraded(); - // assert state.get_shared_count() >=1 - while( - //! state.exclusive_waiting_blocked // Fixme: is this needed? - //&& - state.get_shared_count()!=1) - { - upgrade_cond.wait(lk); - } - state.unlock_upgrade(); - state.lock(); - state.assert_locked(); - } - - void unlock_and_lock_upgrade() - { - boost::unique_lock<boost::mutex> lk(state_change); - state.assert_locked(); - state.unlock(); - state.lock_upgrade(); - state.assert_lock_upgraded(); - release_waiters(); - } - - bool try_unlock_upgrade_and_lock() - { - boost::unique_lock<boost::mutex> lk(state_change); - state.assert_lock_upgraded(); - if( //!state.exclusive // this should be removed once the assertion work - ! state.exclusive_waiting_blocked // Fixme: why this is needed? - //&& state.upgrade // this should be removed once the assertion work - && state.get_shared_count()==1) - { - state.unlock_upgrade(); - state.lock(); - state.assert_locked(); - return true; - } - return false; - } -#ifdef BOOST_THREAD_USES_CHRONO - template <class Rep, class Period> - bool - try_unlock_upgrade_and_lock_for( - const chrono::duration<Rep, Period>& rel_time) - { - return try_unlock_upgrade_and_lock_until( - chrono::steady_clock::now() + rel_time); - } - template <class Clock, class Duration> - bool - try_unlock_upgrade_and_lock_until( - const chrono::time_point<Clock, Duration>& abs_time) - { -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - boost::this_thread::disable_interruption do_not_disturb; -#endif - boost::unique_lock<boost::mutex> lk(state_change); - state.assert_lock_upgraded(); - if (//state.exclusive // this should be removed once the assertion work - state.exclusive_waiting_blocked // Fixme: is this needed? - //|| ! state.upgrade // this should be removed once the assertion work - || state.get_shared_count() != 1) - { - for (;;) - { - //cv_status status = shared_cond.wait_until(lk,abs_time); - cv_status status = upgrade_cond.wait_until(lk,abs_time); - if (//!state.exclusive // this should be removed once the assertion work - ! state.exclusive_waiting_blocked // Fixme: is this needed? - //&& ! state.upgrade // this should be removed once the assertion work - && state.get_shared_count() == 1) - break; - if(status == cv_status::timeout) - return false; - } - } - state.unlock_upgrade(); - state.lock(); - return true; - } -#endif - - // Shared <-> Exclusive - void unlock_and_lock_shared() - { - boost::unique_lock<boost::mutex> lk(state_change); - state.assert_locked(); - state.unlock(); - state.lock_shared(); - release_waiters(); - } - -#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS - bool try_unlock_shared_and_lock() - { - boost::unique_lock<boost::mutex> lk(state_change); - state.assert_lock_shared(); - if( //!state.exclusive // this should be removed once the assertion work - ! state.exclusive_waiting_blocked // Fixme: why this is needed? - //&& ! state.upgrade // Fixme: why this is needed if state.get_shared_count()==1? - && state.get_shared_count()==1) - { - state.unlock_shared(); - state.lock(); - return true; - } - return false; - } -#ifdef BOOST_THREAD_USES_CHRONO - template <class Rep, class Period> - bool - try_unlock_shared_and_lock_for( - const chrono::duration<Rep, Period>& rel_time) - { - return try_unlock_shared_and_lock_until( - chrono::steady_clock::now() + rel_time); - } - template <class Clock, class Duration> - bool - try_unlock_shared_and_lock_until( - const chrono::time_point<Clock, Duration>& abs_time) - { -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - boost::this_thread::disable_interruption do_not_disturb; -#endif - boost::unique_lock<boost::mutex> lk(state_change); - state.assert_lock_shared(); - if ( // !state.exclusive // this should be removed once the assertion work - state.exclusive_waiting_blocked // Fixme: is this needed? - //|| state.upgrade // Fixme: why this is needed if state.get_shared_count()==1? - || state.get_shared_count() != 1) - { - for (;;) - { - cv_status status = shared_cond.wait_until(lk,abs_time); - if ( //! state.exclusive // this should be removed once the assertion work - ! state.exclusive_waiting_blocked // Fixme: is this needed? - //&& ! state.upgrade - && state.get_shared_count() == 1) - break; - if(status == cv_status::timeout) - return false; - } - } - state.unlock_shared(); - state.lock(); - state.upgrade=false; // Is this absolutely needed? - state.exclusive_waiting_blocked=false; // Is this absolutely needed? - return true; - } -#endif -#endif - - // Shared <-> Upgrade - void unlock_upgrade_and_lock_shared() - { - boost::unique_lock<boost::mutex> lk(state_change); - state.assert_lock_upgraded(); - //state.unlock_upgrade(); - //state.lock_shared(); // less efficient - state.upgrade=false; - state.exclusive_waiting_blocked=false; // Is this absolutely needed? - release_waiters(); - } - -#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS - bool try_unlock_shared_and_lock_upgrade() - { - boost::unique_lock<boost::mutex> lk(state_change); - state.assert_lock_shared(); - if( //! state.exclusive // this should be removed once the assertion work - ! state.exclusive_waiting_blocked // Fixme: is this needed? - && ! state.upgrade - ) - { - state.upgrade=true; - return true; - } - return false; - } -#ifdef BOOST_THREAD_USES_CHRONO - template <class Rep, class Period> - bool - try_unlock_shared_and_lock_upgrade_for( - const chrono::duration<Rep, Period>& rel_time) - { - return try_unlock_shared_and_lock_upgrade_until( - chrono::steady_clock::now() + rel_time); - } - template <class Clock, class Duration> - bool - try_unlock_shared_and_lock_upgrade_until( - const chrono::time_point<Clock, Duration>& abs_time) - { -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - boost::this_thread::disable_interruption do_not_disturb; -#endif - boost::unique_lock<boost::mutex> lk(state_change); - state.assert_lock_shared(); - if( //state.exclusive // this should be removed once the assertion work - state.exclusive_waiting_blocked // Fixme: is this needed? - || state.upgrade - ) - { - for (;;) - { - cv_status status = exclusive_cond.wait_until(lk,abs_time); - if( //! state.exclusive // this should be removed once the assertion work - ! state.exclusive_waiting_blocked // Fixme: is this needed? - && ! state.upgrade - ) - break; - if(status == cv_status::timeout) - return false; - } - } - //state.unlock_shared(); - //state.lock_upgrade(); // less efficient - state.upgrade=true; - return true; - } -#endif -#endif - }; - - typedef shared_mutex upgrade_mutex; -} - -#include <boost/config/abi_suffix.hpp> - -#endif diff --git a/boost/thread/pthread/thread_data.hpp b/boost/thread/pthread/thread_data.hpp index f6575f1c22..859ccfbd2a 100644 --- a/boost/thread/pthread/thread_data.hpp +++ b/boost/thread/pthread/thread_data.hpp @@ -16,6 +16,7 @@ #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/assert.hpp> +#include <boost/thread/detail/platform_time.hpp> #ifdef BOOST_THREAD_USES_CHRONO #include <boost/chrono/system_clocks.hpp> #endif @@ -111,8 +112,6 @@ namespace boost pthread_t thread_handle; boost::mutex data_mutex; boost::condition_variable done_condition; - boost::mutex sleep_mutex; - boost::condition_variable sleep_condition; bool done; bool join_started; bool joined; @@ -241,66 +240,158 @@ namespace boost namespace this_thread { + void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; + namespace hidden { - void BOOST_THREAD_DECL sleep_for(const timespec& ts); - void BOOST_THREAD_DECL sleep_until_realtime(const timespec& ts); + inline bool always_false() + { + return false; + } + } + +#if defined BOOST_THREAD_USES_DATETIME +#ifdef __DECXXX + /// Workaround of DECCXX issue of incorrect template substitution + template<> +#endif + inline void sleep(system_time const& abs_time) + { + mutex mx; + unique_lock<mutex> lock(mx); + condition_variable cond; + cond.timed_wait(lock, abs_time, hidden::always_false); } + template<typename TimeDuration> + void sleep(TimeDuration const& rel_time) + { + mutex mx; + unique_lock<mutex> lock(mx); + condition_variable cond; + cond.timed_wait(lock, rel_time, hidden::always_false); + } +#endif + #ifdef BOOST_THREAD_USES_CHRONO - template <class Rep, class Period> - void sleep_for(const chrono::duration<Rep, Period>& d); -#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY + template <class Clock, class Duration> + void sleep_until(const chrono::time_point<Clock, Duration>& t) + { + mutex mut; + unique_lock<mutex> lk(mut); + condition_variable cv; + cv.wait_until(lk, t, hidden::always_false); + } - inline - void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns) + template <class Rep, class Period> + void sleep_for(const chrono::duration<Rep, Period>& d) { - return boost::this_thread::hidden::sleep_for(boost::detail::to_timespec(ns)); + mutex mut; + unique_lock<mutex> lk(mut); + condition_variable cv; + cv.wait_for(lk, d, hidden::always_false); } #endif -#endif // BOOST_THREAD_USES_CHRONO namespace no_interruption_point { +#if defined BOOST_THREAD_SLEEP_FOR_IS_STEADY +// Use pthread_delay_np or nanosleep when available +// because they do not provide an interruption point. + namespace hidden { - void BOOST_THREAD_DECL sleep_for(const timespec& ts); - void BOOST_THREAD_DECL sleep_until_realtime(const timespec& ts); + void BOOST_THREAD_DECL sleep_for_internal(const detail::platform_duration& ts); } - #ifdef BOOST_THREAD_USES_CHRONO +#if defined BOOST_THREAD_USES_DATETIME +#ifdef __DECXXX + /// Workaround of DECCXX issue of incorrect template substitution + template<> +#endif + inline void sleep(system_time const& abs_time) + { + const detail::real_platform_timepoint ts(abs_time); + detail::platform_duration d(ts - detail::real_platform_clock::now()); + while (d > detail::platform_duration::zero()) + { + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + hidden::sleep_for_internal(d); + d = ts - detail::real_platform_clock::now(); + } + } + + template<typename TimeDuration> + void sleep(TimeDuration const& rel_time) + { + hidden::sleep_for_internal(detail::platform_duration(rel_time)); + } +#endif + +#ifdef BOOST_THREAD_USES_CHRONO template <class Rep, class Period> - void sleep_for(const chrono::duration<Rep, Period>& d); - #ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY + void sleep_for(const chrono::duration<Rep, Period>& d) + { + hidden::sleep_for_internal(detail::platform_duration(d)); + } - inline - void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns) + template <class Duration> + void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t) { - return boost::this_thread::no_interruption_point::hidden::sleep_for(boost::detail::to_timespec(ns)); + sleep_for(t - chrono::steady_clock::now()); } - #endif - #endif // BOOST_THREAD_USES_CHRONO - } // no_interruption_point + template <class Clock, class Duration> + void sleep_until(const chrono::time_point<Clock, Duration>& t) + { + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; + common_duration d(t - Clock::now()); + while (d > common_duration::zero()) + { + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + hidden::sleep_for_internal(detail::platform_duration(d)); + d = t - Clock::now(); + } + } +#endif - void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; +#else // BOOST_THREAD_SLEEP_FOR_IS_STEADY +// When pthread_delay_np and nanosleep are not available, +// fall back to using the interruptible sleep functions. #if defined BOOST_THREAD_USES_DATETIME #ifdef __DECXXX - /// Workaround of DECCXX issue of incorrect template substitution - template<> + /// Workaround of DECCXX issue of incorrect template substitution + template<> #endif - inline void sleep(system_time const& abs_time) - { - return boost::this_thread::hidden::sleep_until_realtime(boost::detail::to_timespec(abs_time)); - } + inline void sleep(system_time const& abs_time) + { + this_thread::sleep(abs_time); + } - template<typename TimeDuration> - inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) - { - this_thread::sleep(get_system_time()+rel_time); - } -#endif // BOOST_THREAD_USES_DATETIME + template<typename TimeDuration> + void sleep(TimeDuration const& rel_time) + { + this_thread::sleep(rel_time); + } +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + template <class Clock, class Duration> + void sleep_until(const chrono::time_point<Clock, Duration>& t) + { + this_thread::sleep_until(t); + } + + template <class Rep, class Period> + void sleep_for(const chrono::duration<Rep, Period>& d) + { + this_thread::sleep_for(d); + } +#endif + +#endif // BOOST_THREAD_SLEEP_FOR_IS_STEADY + } // no_interruption_point } // this_thread } diff --git a/boost/thread/pthread/timespec.hpp b/boost/thread/pthread/timespec.hpp deleted file mode 100644 index 1fb8de94c8..0000000000 --- a/boost/thread/pthread/timespec.hpp +++ /dev/null @@ -1,138 +0,0 @@ -#ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP -#define BOOST_THREAD_PTHREAD_TIMESPEC_HPP -// (C) Copyright 2007-8 Anthony Williams -// (C) Copyright 2012 Vicente J. Botet Escriba -// -// 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) - -#include <boost/thread/detail/config.hpp> -#include <boost/thread/thread_time.hpp> -#if defined BOOST_THREAD_USES_DATETIME -#include <boost/date_time/posix_time/conversion.hpp> -#endif -#include <pthread.h> -#ifndef _WIN32 -#include <unistd.h> -#endif -#ifdef BOOST_THREAD_USES_CHRONO -#include <boost/chrono/duration.hpp> -#endif - -#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) -# define BOOST_THREAD_TIMESPEC_MAC_API -#include <sys/time.h> //for gettimeofday and timeval -#else -#include <time.h> // for clock_gettime -#endif - -#include <boost/config/abi_prefix.hpp> - -namespace boost -{ - namespace detail - { -#if defined BOOST_THREAD_USES_DATETIME - inline struct timespec to_timespec(boost::system_time const& abs_time) - { - struct timespec timeout = { 0,0}; - boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0); - - timeout.tv_sec=time_since_epoch.total_seconds(); - timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second())); - return timeout; - } -#endif -#if defined BOOST_THREAD_USES_CHRONO - inline timespec to_timespec(chrono::nanoseconds const& ns) - { - struct timespec ts; - ts.tv_sec = static_cast<long>(chrono::duration_cast<chrono::seconds>(ns).count()); - ts.tv_nsec = static_cast<long>((ns - chrono::duration_cast<chrono::seconds>(ns)).count()); - return ts; - } - -#endif - - inline timespec to_timespec(boost::intmax_t const& ns) - { - boost::intmax_t s = ns / 1000000000l; - struct timespec ts; - ts.tv_sec = static_cast<long> (s); - ts.tv_nsec = static_cast<long> (ns - s * 1000000000l); - return ts; - } - inline boost::intmax_t to_nanoseconds_int_max(timespec const& ts) - { - return static_cast<boost::intmax_t>(ts.tv_sec) * 1000000000l + ts.tv_nsec; - } - inline bool timespec_ge_zero(timespec const& ts) - { - return (ts.tv_sec >= 0) || (ts.tv_nsec >= 0); - } -#if defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC - - inline timespec timespec_now_monotonic() - { - timespec ts; - - if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) ) - { - ts.tv_sec = 0; - ts.tv_nsec = 0; - BOOST_ASSERT(0 && "Boost::Thread - Internal Error"); - } - return ts; - } -#endif - - inline timespec timespec_now_realtime() - { - timespec ts; - -#if defined(BOOST_THREAD_TIMESPEC_MAC_API) - timeval tv; - ::gettimeofday(&tv, 0); - ts.tv_sec = tv.tv_sec; - ts.tv_nsec = tv.tv_usec * 1000; -#else - if ( ::clock_gettime( CLOCK_REALTIME, &ts ) ) - { - ts.tv_sec = 0; - ts.tv_nsec = 0; - BOOST_ASSERT(0 && "Boost::Thread - Internal Error"); - } -#endif - return ts; - } - inline timespec timespec_zero() - { - timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = 0; - return ts; - } - inline timespec timespec_plus(timespec const& lhs, timespec const& rhs) - { - return to_timespec(to_nanoseconds_int_max(lhs) + to_nanoseconds_int_max(rhs)); - } - inline timespec timespec_minus(timespec const& lhs, timespec const& rhs) - { - return to_timespec(to_nanoseconds_int_max(lhs) - to_nanoseconds_int_max(rhs)); - } - inline bool timespec_gt(timespec const& lhs, timespec const& rhs) - { - return to_nanoseconds_int_max(lhs) > to_nanoseconds_int_max(rhs); - } - inline bool timespec_ge(timespec const& lhs, timespec const& rhs) - { - return to_nanoseconds_int_max(lhs) >= to_nanoseconds_int_max(rhs); - } - - } -} - -#include <boost/config/abi_suffix.hpp> - -#endif |