[07/11] PR libstdc++/91906 Fix timed_mutex::try_lock_until on arbitrary clock

Message ID d8d73a87335bea8e19c41a84f10ea7d02252104d.1569660153.git-series.mac@mcrowe.com
State New
Headers show
Series
  • timed_mutex, shared_timed_mutex: Add full steady clock support
Related show

Commit Message

Mike Crowe Sept. 28, 2019, 8:44 a.m.
A non-standard clock may tick more slowly than std::chrono::steady_clock.
This means that we risk returning false early when the specified timeout
may not have expired. This can be avoided by looping until the timeout time
as reported by the non-standard clock has been reached.

Unfortunately, we have no way to tell whether the non-standard clock ticks
more quickly that std::chrono::steady_clock. If it does then we risk
returning later than would be expected, but that is unavoidable and
permitted by the standard.

	* include/std/mutex (_M_try_lock_until): Loop until the absolute
	timeout time is reached as measured against the appropriate clock.
	* testsuite/30_threads/timed_mutex/try_lock_until/3.cc:
	Also run test using slow_clock to test above fix.
	* testsuite/30_threads/recursive_timed_mutex/try_lock_until/3.cc:
	Likewise.
---
 libstdc++-v3/include/std/mutex                                              | 13 +++++++++++--
 libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/3.cc |  2 ++
 libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/3.cc           |  2 ++
 3 files changed, 15 insertions(+), 2 deletions(-)

-- 
git-series 0.9.1

Patch

diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex
index e06d286..bb3a41b 100644
--- a/libstdc++-v3/include/std/mutex
+++ b/libstdc++-v3/include/std/mutex
@@ -189,8 +189,17 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	bool
 	_M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
 	{
-	  auto __rtime = __atime - _Clock::now();
-	  return _M_try_lock_for(__rtime);
+          // The user-supplied clock may not tick at the same rate as
+          // steady_clock, so we must loop in order to guarantee that
+          // the timeout has expired before returning false.
+          auto __now = _Clock::now();
+          while (__atime > __now) {
+            auto __rtime = __atime - __now;
+            if (_M_try_lock_for(__rtime))
+              return true;
+            __now = _Clock::now();
+          }
+          return false;
 	}
     };
 
diff --git a/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/3.cc b/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/3.cc
index 4f0b0b5..a845cbf 100644
--- a/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/3.cc
+++ b/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/3.cc
@@ -26,6 +26,7 @@ 
 #include <thread>
 #include <system_error>
 #include <testsuite_hooks.h>
+#include <slow_clock.h>
 
 template <typename clock_type>
 void test()
@@ -71,4 +72,5 @@  int main()
 {
   test<std::chrono::system_clock>();
   test<std::chrono::steady_clock>();
+  test<slow_clock>();
 }
diff --git a/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/3.cc b/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/3.cc
index 69d1ea5..9f34644 100644
--- a/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/3.cc
+++ b/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/3.cc
@@ -26,6 +26,7 @@ 
 #include <thread>
 #include <system_error>
 #include <testsuite_hooks.h>
+#include <slow_clock.h>
 
 template <typename clock_type>
 void test()
@@ -71,4 +72,5 @@  int main()
 {
   test<std::chrono::system_clock>();
   test<std::chrono::steady_clock>();
+  test<slow_clock>();
 }