atomic_futex: Avoid rounding errors in std::future::wait_for

Message ID 20180802112257.31446-1-mac@mcrowe.com
State Superseded
Headers show
Series
  • atomic_futex: Avoid rounding errors in std::future::wait_for
Related show

Commit Message

Mike Crowe Aug. 2, 2018, 11:22 a.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         |  6 +++++-
 libstdc++-v3/testsuite/30_threads/async/async.cc | 15 +++++++++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

This change depends on the some of the changes in the series I posted
yesterday. See https://gcc.gnu.org/ml/libstdc++/2018-08/msg00001.html

-- 
2.11.0

Patch

diff --git a/libstdc++-v3/include/bits/atomic_futex.h b/libstdc++-v3/include/bits/atomic_futex.h
index b7ffb7fb191..9703d752981 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 755c95cbea6..cd5113d5010 100644
--- a/libstdc++-v3/testsuite/30_threads/async/async.cc
+++ b/libstdc++-v3/testsuite/30_threads/async/async.cc
@@ -157,6 +157,20 @@  void test04()
   }
 }
 
+void test_pr36827()
+{
+  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();
@@ -165,5 +179,6 @@  int main()
   test03<std::chrono::steady_clock>();
   test03<steady_clock_copy>();
   test04();
+  test_pr36827();
   return 0;
 }