This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC 2/2] Add steady_clock support to condition_variable


If __gthread_cond_timedwaitonclock is available it can be used it to fix
part of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41861 by supporting
std::chrono::steady_clock properly with std::condition_variable.

This means that code using std::condition_variable::wait_for or
std::condition_variable::wait_until with std::chrono::steady_clock is no
longer subject to timing out early or potentially waiting for much
longer if the system clock is changed at an inopportune moment.

If __gthread_cond_timedwaitonclock is available then
std::chrono::steady_clock is deemed to be the "best" clock available
which means that it is used for the relative wait_for calls and absolute
wait_until calls that aren't choosing to use std::chrono::system_clock.
Calls explicitly using std::chrono::system_clock continue to use
CLOCK_REALTIME.

If __gthread_cond_timedwaitonclock is not available then
std::chrono::system_clock is deemed to be the "best" clock available
which means that the previous suboptimal behaviour remains.

Signed-off-by: Mike Crowe <mac@mcrowe.com>
---
 libstdc++-v3/include/std/condition_variable        | 56 ++++++++++++++++++----
 .../30_threads/condition_variable/members/2.cc     |  8 ++--
 2 files changed, 53 insertions(+), 11 deletions(-)

diff --git a/libstdc++-v3/include/std/condition_variable b/libstdc++-v3/include/std/condition_variable
index f7da017..625ecfe 100644
--- a/libstdc++-v3/include/std/condition_variable
+++ b/libstdc++-v3/include/std/condition_variable
@@ -63,7 +63,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// condition_variable
   class condition_variable
   {
-    typedef chrono::system_clock	__clock_t;
+#ifdef _GTHREAD_USE_COND_TIMEDWAITONCLOCK
+    typedef chrono::steady_clock	__steady_clock_t;
+    typedef chrono::steady_clock	__best_clock_t;
+#else
+    typedef chrono::system_clock	__best_clock_t;
+#endif
+    typedef chrono::system_clock	__system_clock_t;
     typedef __gthread_cond_t		__native_type;
 
 #ifdef __GTHREAD_COND_INIT
@@ -98,10 +104,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  wait(__lock);
       }
 
+#ifdef _GTHREAD_USE_COND_TIMEDWAITONCLOCK
     template<typename _Duration>
       cv_status
       wait_until(unique_lock<mutex>& __lock,
-		 const chrono::time_point<__clock_t, _Duration>& __atime)
+		 const chrono::time_point<__steady_clock_t, _Duration>& __atime)
+      { return __wait_until_impl(__lock, __atime); }
+#endif
+
+    template<typename _Duration>
+      cv_status
+      wait_until(unique_lock<mutex>& __lock,
+		 const chrono::time_point<__system_clock_t, _Duration>& __atime)
       { return __wait_until_impl(__lock, __atime); }
 
     template<typename _Clock, typename _Duration>
@@ -109,9 +123,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       wait_until(unique_lock<mutex>& __lock,
 		 const chrono::time_point<_Clock, _Duration>& __atime)
       {
-	// DR 887 - Sync unknown clock to known clock.
 	const typename _Clock::time_point __c_entry = _Clock::now();
-	const __clock_t::time_point __s_entry = __clock_t::now();
+	const __best_clock_t::time_point __s_entry = __best_clock_t::now();
 	const auto __delta = __atime - __c_entry;
 	const auto __s_atime = __s_entry + __delta;
 
@@ -134,24 +147,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       cv_status
       wait_for(unique_lock<mutex>& __lock,
 	       const chrono::duration<_Rep, _Period>& __rtime)
-      { return wait_until(__lock, __clock_t::now() + __rtime); }
+      { return wait_until(__lock, __best_clock_t::now() + __rtime); }
 
     template<typename _Rep, typename _Period, typename _Predicate>
       bool
       wait_for(unique_lock<mutex>& __lock,
 	       const chrono::duration<_Rep, _Period>& __rtime,
 	       _Predicate __p)
-      { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
+      { return wait_until(__lock, __best_clock_t::now() + __rtime, std::move(__p)); }
 
     native_handle_type
     native_handle()
     { return &_M_cond; }
 
   private:
+#ifdef _GTHREAD_USE_COND_TIMEDWAITONCLOCK
+    template<typename _Dur>
+      cv_status
+      __wait_until_impl(unique_lock<mutex>& __lock,
+			const chrono::time_point<__steady_clock_t, _Dur>& __atime)
+      {
+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	__gthread_time_t __ts =
+	  {
+	    static_cast<std::time_t>(__s.time_since_epoch().count()),
+	    static_cast<long>(__ns.count())
+	  };
+
+	__gthread_cond_timedwaitonclock(&_M_cond, __lock.mutex()->native_handle(),
+					__GTHREAD_CLOCK_MONOTONIC,
+					&__ts);
+
+	return (__steady_clock_t::now() < __atime
+		? cv_status::no_timeout : cv_status::timeout);
+      }
+#endif
     template<typename _Dur>
       cv_status
       __wait_until_impl(unique_lock<mutex>& __lock,
-			const chrono::time_point<__clock_t, _Dur>& __atime)
+			const chrono::time_point<__system_clock_t, _Dur>& __atime)
       {
 	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
 	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
@@ -165,7 +201,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	__gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(),
 				 &__ts);
 
-	return (__clock_t::now() < __atime
+	return (__system_clock_t::now() < __atime
 		? cv_status::no_timeout : cv_status::timeout);
       }
   };
@@ -185,7 +221,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Like above, but mutex is not required to have try_lock.
   class condition_variable_any
   {
+#ifdef _GTHREAD_USE_COND_TIMEDWAITONCLOCK
+    typedef chrono::steady_clock	__clock_t;
+#else
     typedef chrono::system_clock	__clock_t;
+#endif
     condition_variable			_M_cond;
     shared_ptr<mutex>			_M_mutex;
 
diff --git a/libstdc++-v3/testsuite/30_threads/condition_variable/members/2.cc b/libstdc++-v3/testsuite/30_threads/condition_variable/members/2.cc
index 04945f1..79d511e 100644
--- a/libstdc++-v3/testsuite/30_threads/condition_variable/members/2.cc
+++ b/libstdc++-v3/testsuite/30_threads/condition_variable/members/2.cc
@@ -27,6 +27,7 @@
 #include <system_error>
 #include <testsuite_hooks.h>
 
+template <typename CLOCK>
 void test01()
 {
   bool test __attribute__((unused)) = true;
@@ -38,10 +39,10 @@ void test01()
       std::mutex m;
       std::unique_lock<std::mutex> l(m);
 
-      auto then = std::chrono::steady_clock::now();
+      auto then = CLOCK::now();
       std::cv_status result = c1.wait_until(l, then + ms);
       VERIFY( result == std::cv_status::timeout );
-      VERIFY( (std::chrono::steady_clock::now() - then) >= ms );
+      VERIFY( (CLOCK::now() - then) >= ms );
       VERIFY( l.owns_lock() );
     }
   catch (const std::system_error& e)
@@ -56,6 +57,7 @@ void test01()
 
 int main()
 {
-  test01();
+  test01<std::chrono::steady_clock>();
+  test01<std::chrono::system_clock>();
   return 0;
 }
-- 
2.1.4


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]