From 3c01e39481996951c804c315cd3fc8f0c27cda6f Mon Sep 17 00:00:00 2001 From: Austin Beer Date: Fri, 13 Oct 2017 11:37:39 -0600 Subject: [PATCH] Add and fix sleep functions - Added no_interruption_point::sleep() functions to pthreads to be consistent with Windows. - Fixed an issue where the no_interruption_point::sleep_*() functions were still interruptible on Windows. --- include/boost/thread/detail/thread.hpp | 1 + include/boost/thread/pthread/thread_data.hpp | 176 ++++++++++++++----- include/boost/thread/v2/thread.hpp | 108 ------------ include/boost/thread/win32/thread_data.hpp | 56 ++++++ src/pthread/thread.cpp | 43 +---- 5 files changed, 200 insertions(+), 184 deletions(-) diff --git a/include/boost/thread/detail/thread.hpp b/include/boost/thread/detail/thread.hpp index 5ce56332..4a021ceb 100644 --- a/include/boost/thread/detail/thread.hpp +++ b/include/boost/thread/detail/thread.hpp @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef BOOST_THREAD_USES_CHRONO #include #include diff --git a/include/boost/thread/pthread/thread_data.hpp b/include/boost/thread/pthread/thread_data.hpp index 0e708caa..6c917f8b 100644 --- a/include/boost/thread/pthread/thread_data.hpp +++ b/include/boost/thread/pthread/thread_data.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef BOOST_THREAD_USES_CHRONO #include #endif @@ -239,32 +240,16 @@ namespace boost namespace this_thread { + void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; + namespace hidden { - void BOOST_THREAD_DECL sleep_for(const detail::platform_duration& ts); + inline bool always_false() + { + return false; + } } - namespace no_interruption_point - { - namespace hidden - { - void BOOST_THREAD_DECL sleep_for(const detail::platform_duration& ts); - } - - #ifdef BOOST_THREAD_USES_CHRONO - #ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY - template - void sleep_for(const chrono::duration& d) - { - return boost::this_thread::no_interruption_point::hidden::sleep_for(detail::platform_duration(d)); - } - #endif - #endif // BOOST_THREAD_USES_CHRONO - - } // no_interruption_point - - void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; - #if defined BOOST_THREAD_USES_DATETIME #ifdef __DECXXX /// Workaround of DECCXX issue of incorrect template substitution @@ -272,30 +257,141 @@ namespace boost #endif inline void sleep(system_time const& abs_time) { - const detail::real_platform_timepoint ts(abs_time); - mutex mx; - unique_lock lock(mx); - condition_variable cond; - -#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO - detail::platform_duration d = ts - detail::real_platform_clock::now(); - while (d > detail::platform_duration::zero()) - { - d = (std::min)(d, detail::platform_milliseconds(100)); - cond.do_wait_until(lock, detail::internal_platform_clock::now() + d); - d = ts - detail::real_platform_clock::now(); - } -#else - while (cond.do_wait_until(lock, ts)) {} -#endif + mutex mx; + unique_lock lock(mx); + condition_variable cond; + cond.timed_wait(lock, abs_time, hidden::always_false); } template void sleep(TimeDuration const& rel_time) { - boost::this_thread::hidden::sleep_for(detail::platform_duration(rel_time)); + mutex mx; + unique_lock lock(mx); + condition_variable cond; + cond.timed_wait(lock, rel_time, hidden::always_false); } -#endif // BOOST_THREAD_USES_DATETIME +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + template + void sleep_until(const chrono::time_point& t) + { + mutex mut; + unique_lock lk(mut); + condition_variable cv; + cv.wait_until(lk, t, hidden::always_false); + } + + template + void sleep_for(const chrono::duration& d) + { + mutex mut; + unique_lock lk(mut); + condition_variable cv; + cv.wait_for(lk, d, hidden::always_false); + } +#endif + + 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_internal(const detail::platform_duration& ts); + } + +#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(100)); + hidden::sleep_for_internal(d); + d = ts - detail::real_platform_clock::now(); + } + } + + template + void sleep(TimeDuration const& rel_time) + { + hidden::sleep_for_internal(detail::platform_duration(rel_time)); + } +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + template + void sleep_for(const chrono::duration& d) + { + hidden::sleep_for_internal(detail::platform_duration(d)); + } + + template + void sleep_until(const chrono::time_point& t) + { + sleep_for(t - chrono::steady_clock::now()); + } + + template + void sleep_until(const chrono::time_point& t) + { + typedef typename common_type::type CD; + CD d = t - Clock::now(); + while (d > CD::zero()) + { + d = (std::min)(d, CD(chrono::milliseconds(100))); + hidden::sleep_for_internal(detail::platform_duration(d)); + d = t - Clock::now(); + } + } +#endif + +#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<> +#endif + inline void sleep(system_time const& abs_time) + { + this_thread::sleep(abs_time); + } + + template + void sleep(TimeDuration const& rel_time) + { + this_thread::sleep(rel_time); + } +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + template + void sleep_until(const chrono::time_point& t) + { + this_thread::sleep_until(t); + } + + template + void sleep_for(const chrono::duration& d) + { + this_thread::sleep_for(d); + } +#endif + +#endif // BOOST_THREAD_SLEEP_FOR_IS_STEADY + } // no_interruption_point } // this_thread } diff --git a/include/boost/thread/v2/thread.hpp b/include/boost/thread/v2/thread.hpp index 1d6b7d6e..81ae7665 100644 --- a/include/boost/thread/v2/thread.hpp +++ b/include/boost/thread/v2/thread.hpp @@ -14,112 +14,4 @@ #include #include -namespace boost -{ - namespace this_thread - { - namespace no_interruption_point - { -#ifdef BOOST_THREAD_USES_CHRONO - -// Use pthread_delay_np or nanosleep whenever possible here in the no_interruption_point -// namespace because they do not provide an interruption point. -#if defined BOOST_THREAD_SLEEP_FOR_IS_STEADY - - // sleep_for(const chrono::duration& d) is defined in pthread/thread_data.hpp - - template - void sleep_until(const chrono::time_point& t) - { - sleep_for(t - chrono::steady_clock::now()); - } - - template - void sleep_until(const chrono::time_point& t) - { - typedef typename common_type::type CD; - CD d = t - Clock::now(); - while (d > CD::zero()) - { - d = (std::min)(d, CD(chrono::milliseconds(100))); - sleep_for(d); - d = t - Clock::now(); - } - } - -#else - - template - void sleep_for(const chrono::duration& d) - { - if (d > chrono::duration::zero()) - { - sleep_until(chrono::steady_clock::now() + d); - } - } - - template - void sleep_until(const chrono::time_point& t) - { - mutex mut; - condition_variable cv; - unique_lock lk(mut); - while (cv_status::no_timeout == cv.wait_until(lk, t)) {} - } - - template - void sleep_until(const chrono::time_point& t) - { - typedef typename common_type::type CD; - CD d = t - Clock::now(); - while (d > CD::zero()) - { - d = (std::min)(d, CD(chrono::milliseconds(100))); - sleep_until(detail::internal_chrono_clock::now() + d); - d = t - Clock::now(); - } - } - -#endif - -#endif - } -#ifdef BOOST_THREAD_USES_CHRONO - - template - void sleep_until(const chrono::time_point& t) - { - mutex mut; - condition_variable cv; - unique_lock lk(mut); - while (cv_status::no_timeout == cv.wait_until(lk, t)) {} - } - - template - void sleep_until(const chrono::time_point& t) - { - typedef typename common_type::type CD; - CD d = t - Clock::now(); - while (d > CD::zero()) - { - d = (std::min)(d, CD(chrono::milliseconds(100))); - sleep_until(detail::internal_chrono_clock::now() + d); - d = t - Clock::now(); - } - } - - template - void sleep_for(const chrono::duration& d) - { - if (d > chrono::duration::zero()) - { - sleep_until(chrono::steady_clock::now() + d); - } - } - -#endif - } -} - - #endif diff --git a/include/boost/thread/win32/thread_data.hpp b/include/boost/thread/win32/thread_data.hpp index 6c273751..19e2ea3a 100644 --- a/include/boost/thread/win32/thread_data.hpp +++ b/include/boost/thread/win32/thread_data.hpp @@ -189,6 +189,7 @@ namespace boost { interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(rel_time)); } + inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time) { const detail::real_platform_timepoint ts(abs_time); @@ -202,6 +203,33 @@ namespace boost } #endif +#ifdef BOOST_THREAD_USES_CHRONO + template + void sleep_for(const chrono::duration& d) + { + interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(d)); + } + + template + void sleep_until(const chrono::time_point& t) + { + sleep_for(t - chrono::steady_clock::now()); + } + + template + void sleep_until(const chrono::time_point& t) + { + typedef typename common_type::type CD; + CD d = t - Clock::now(); + while (d > CD::zero()) + { + d = (std::min)(d, CD(chrono::milliseconds(100))); + sleep_for(d); + d = t - Clock::now(); + } + } +#endif + namespace no_interruption_point { bool BOOST_THREAD_DECL non_interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout); @@ -212,6 +240,7 @@ namespace boost { non_interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(rel_time)); } + inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time) { const detail::real_platform_timepoint ts(abs_time); @@ -224,6 +253,33 @@ namespace boost } } #endif + +#ifdef BOOST_THREAD_USES_CHRONO + template + void sleep_for(const chrono::duration& d) + { + non_interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(d)); + } + + template + void sleep_until(const chrono::time_point& t) + { + sleep_for(t - chrono::steady_clock::now()); + } + + template + void sleep_until(const chrono::time_point& t) + { + typedef typename common_type::type CD; + CD d = t - Clock::now(); + while (d > CD::zero()) + { + d = (std::min)(d, CD(chrono::milliseconds(100))); + sleep_for(d); + d = t - Clock::now(); + } + } +#endif } } diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index 15cef271..aa1652cf 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -433,10 +433,9 @@ namespace boost { namespace hidden { - void BOOST_THREAD_DECL sleep_for(const detail::platform_duration& ts) + void BOOST_THREAD_DECL sleep_for_internal(const detail::platform_duration& ts) { - - if (ts > detail::platform_duration::zero()) + if (ts > detail::platform_duration::zero()) { // Use pthread_delay_np or nanosleep whenever possible here in the no_interruption_point // namespace because they do not provide an interruption point. @@ -449,44 +448,13 @@ namespace boost # elif defined(BOOST_HAS_NANOSLEEP) nanosleep(&ts.getTs(), 0); # else - // Fall back to using a condition variable even though it does provide an interruption point. - const detail::internal_platform_timepoint ts2 = detail::internal_platform_clock::now() + ts; - mutex mx; - unique_lock lock(mx); - condition_variable cond; - while (cond.do_wait_until(lock, ts2)) {} + // This should never be reached due to BOOST_THREAD_SLEEP_FOR_IS_STEADY # endif } } } } - namespace hidden - { - void BOOST_THREAD_DECL sleep_for(const detail::platform_duration& ts) - { - mutex mx; - unique_lock lock(mx); - condition_variable cond; -#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) - const detail::mono_platform_timepoint& ts2 = detail::mono_platform_clock::now() + ts; - detail::platform_duration d = ts; - while (d > detail::platform_duration::zero()) - { - d = (std::min)(d, detail::platform_milliseconds(100)); - cond.do_wait_until(lock, detail::internal_platform_clock::now() + d); - d = ts2 - detail::mono_platform_clock::now(); - } -#else - const detail::internal_platform_timepoint ts2 = detail::internal_platform_clock::now() + ts; - while (cond.do_wait_until(lock, ts2)) {} -#endif - } - } // hidden - } // this_thread - - namespace this_thread - { void yield() BOOST_NOEXCEPT { # if defined(BOOST_HAS_SCHED_YIELD) @@ -499,7 +467,10 @@ namespace boost // sleep(xt); // sleep_for(chrono::milliseconds(0)); # else - hidden::sleep_for(detail::platform_duration::zero()); + mutex mx; + unique_lock lock(mx); + condition_variable cond; + cond.do_wait_until(lock, detail::internal_platform_clock::now()) # endif } }