[v4,6/7] libstdc++ atomic_futex: Avoid rounding errors in std::future::wait_for

Message ID dd9f82596aa4f1e44befc528869323f0995c2335.1572191159.git-series.mac@mcrowe.com
State New
Headers show
Series
  • std::future::wait_* improvements
Related show

Commit Message

Mike Crowe Oct. 27, 2019, 3:46 p.m.
Convert the specified duration to the target clock's duration type before
adding it to the current time.  This avoids the situation described in PR
libstdc++/68519 when the specified duration type lacks sufficient
precision.

	* libstdc++-v3/include/bits/atomic_futex.h:
	(__atomic_futex_unsigned::_M_load_when_equal_for): Round up timeout
	if required after conversion to reference clock duration.

	* libstdc++-v3/testsuite/30_threads/async/async.cc: (test_pr68519):
          New test for the equivalent of PR libstdc++/68519.
---
 libstdc++-v3/include/bits/atomic_futex.h         |  6 +++++-
 libstdc++-v3/testsuite/30_threads/async/async.cc | 15 +++++++++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

-- 
git-series 0.9.1

Patch

diff --git a/libstdc++-v3/include/bits/atomic_futex.h b/libstdc++-v3/include/bits/atomic_futex.h
index b04e806..ec823eb 100644
--- a/libstdc++-v3/include/bits/atomic_futex.h
+++ b/libstdc++-v3/include/bits/atomic_futex.h
@@ -219,8 +219,12 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _M_load_when_equal_for(unsigned __val, memory_order __mo,
 	  const chrono::duration<_Rep, _Period>& __rtime)
       {
+	using __dur = typename __clock_t::duration;
+	auto __reltime = chrono::duration_cast<__dur>(__rtime);
+	if (__reltime < __rtime)
+	  ++__reltime;
 	return _M_load_when_equal_until(__val, __mo,
-					__clock_t::now() + __rtime);
+					__clock_t::now() + __reltime);
       }
 
     // Returns false iff a timeout occurred.
diff --git a/libstdc++-v3/testsuite/30_threads/async/async.cc b/libstdc++-v3/testsuite/30_threads/async/async.cc
index 7700913..ddd007d 100644
--- a/libstdc++-v3/testsuite/30_threads/async/async.cc
+++ b/libstdc++-v3/testsuite/30_threads/async/async.cc
@@ -140,6 +140,20 @@  void test04()
   }
 }
 
+void test_pr68519()
+{
+  future<void> f1 = async(launch::async, []() {
+      std::this_thread::sleep_for(std::chrono::seconds(1));
+    });
+
+  std::chrono::duration<float> const wait_time = std::chrono::seconds(1);
+  auto const start_steady = chrono::steady_clock::now();
+  auto status = f1.wait_for(wait_time);
+  auto const elapsed_steady = chrono::steady_clock::now() - start_steady;
+
+  VERIFY( elapsed_steady >= std::chrono::seconds(1) );
+}
+
 int main()
 {
   test01();
@@ -148,5 +162,6 @@  int main()
   test03<std::chrono::steady_clock>();
   test03<slow_clock>();
   test04();
+  test_pr68519();
   return 0;
 }