public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH v4 5/7] libstdc++ futex: Loop when waiting against arbitrary clock
  2019-10-27 15:47 [PATCH v4 0/7] std::future::wait_* improvements Mike Crowe
@ 2019-10-27 15:46 ` Mike Crowe
  2019-10-27 15:47 ` [PATCH v4 7/7] libstdc++: Extra async tests, not for merging Mike Crowe
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Mike Crowe @ 2019-10-27 15:46 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Mike Crowe

If std::future::wait_until is passed a time point measured against a clock
that is neither std::chrono::steady_clock nor std::chrono::system_clock
then the generic implementation of
__atomic_futex_unsigned::_M_load_when_equal_until is called which
calculates the timeout based on __clock_t and calls the
_M_load_when_equal_until method for that clock to perform the actual wait.

There's no guarantee that __clock_t is running at the same speed as the
caller's clock, so if the underlying wait times out timeout we need to
check the timeout against the caller's clock again before potentially
looping.

Also add two extra tests to the testsuite's async.cc:

* run test03 with steady_clock_copy, which behaves identically to
  std::chrono::steady_clock, but isn't std::chrono::steady_clock. This
  causes the overload of __atomic_futex_unsigned::_M_load_when_equal_until
  that takes an arbitrary clock to be called.

* invent test04 which uses a deliberately slow running clock in order to
  exercise the looping behaviour o
  __atomic_futex_unsigned::_M_load_when_equal_until described above.

	* libstdc++-v3/include/bits/atomic_futex.h:
	(__atomic_futex_unsigned) Add loop to _M_load_when_equal_until on
	generic _Clock to check the timeout against _Clock again after
	_M_load_when_equal_until returns indicating a timeout.

	* libstdc++-v3/testsuite/30_threads/async/async.cc: Invent
	slow_clock that runs at an eleventh of steady_clock's speed. Use it
	to test the user-supplied-clock variant of
	__atomic_futex_unsigned::_M_load_when_equal_until works generally
	with test03 and loops correctly when the timeout time hasn't been
	reached in test04.
---
 libstdc++-v3/include/bits/atomic_futex.h         | 15 +++--
 libstdc++-v3/testsuite/30_threads/async/async.cc | 52 +++++++++++++++++-
 2 files changed, 62 insertions(+), 5 deletions(-)

diff --git a/libstdc++-v3/include/bits/atomic_futex.h b/libstdc++-v3/include/bits/atomic_futex.h
index 387ee9d..b04e806 100644
--- a/libstdc++-v3/include/bits/atomic_futex.h
+++ b/libstdc++-v3/include/bits/atomic_futex.h
@@ -229,11 +229,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _M_load_when_equal_until(unsigned __val, memory_order __mo,
 	  const chrono::time_point<_Clock, _Duration>& __atime)
       {
-	const typename _Clock::time_point __c_entry = _Clock::now();
-	const __clock_t::time_point __s_entry = __clock_t::now();
-	const auto __delta = __atime - __c_entry;
-	const auto __s_atime = __s_entry + __delta;
-	return _M_load_when_equal_until(__val, __mo, __s_atime);
+	typename _Clock::time_point __c_entry = _Clock::now();
+	do {
+	  const __clock_t::time_point __s_entry = __clock_t::now();
+	  const auto __delta = __atime - __c_entry;
+	  const auto __s_atime = __s_entry + __delta;
+	  if (_M_load_when_equal_until(__val, __mo, __s_atime))
+	    return true;
+	  __c_entry = _Clock::now();
+	} while (__c_entry < __atime);
+	return false;
       }
 
     // 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 1b6e2ff..7700913 100644
--- a/libstdc++-v3/testsuite/30_threads/async/async.cc
+++ b/libstdc++-v3/testsuite/30_threads/async/async.cc
@@ -90,11 +90,63 @@ void test03()
   VERIFY( elapsed < std::chrono::seconds(5) );
 }
 
+// This clock is supposed to run at a tenth of normal speed, but we
+// don't have to worry about rounding errors causing us to wake up
+// slightly too early below if we actually run it at an eleventh of
+// normal speed. It is used to exercise the
+// __atomic_futex_unsigned::_M_load_when_equal_until overload that
+// takes an arbitrary clock.
+struct slow_clock
+{
+  using rep = std::chrono::steady_clock::rep;
+  using period = std::chrono::steady_clock::period;
+  using duration = std::chrono::steady_clock::duration;
+  using time_point = std::chrono::time_point<slow_clock, duration>;
+  static constexpr bool is_steady = true;
+
+  static time_point now()
+  {
+    auto steady = std::chrono::steady_clock::now();
+    return time_point{steady.time_since_epoch() / 11};
+  }
+};
+
+void test04()
+{
+  using namespace std::chrono;
+
+  auto const slow_start = slow_clock::now();
+  future<void> f1 = async(launch::async, []() {
+      std::this_thread::sleep_for(std::chrono::seconds(2));
+    });
+
+  // Wait for ~1s
+  {
+    auto const steady_begin = steady_clock::now();
+    auto const status = f1.wait_until(slow_start + milliseconds(100));
+    VERIFY(status == std::future_status::timeout);
+    auto const elapsed = steady_clock::now() - steady_begin;
+    VERIFY(elapsed >= seconds(1));
+    VERIFY(elapsed < seconds(2));
+  }
+
+  // Wait for up to ~2s more
+  {
+    auto const steady_begin = steady_clock::now();
+    auto const status = f1.wait_until(slow_start + milliseconds(300));
+    VERIFY(status == std::future_status::ready);
+    auto const elapsed = steady_clock::now() - steady_begin;
+    VERIFY(elapsed < seconds(2));
+  }
+}
+
 int main()
 {
   test01();
   test02();
   test03<std::chrono::system_clock>();
   test03<std::chrono::steady_clock>();
+  test03<slow_clock>();
+  test04();
   return 0;
 }
-- 
git-series 0.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v4 7/7] libstdc++: Extra async tests, not for merging
  2019-10-27 15:47 [PATCH v4 0/7] std::future::wait_* improvements Mike Crowe
  2019-10-27 15:46 ` [PATCH v4 5/7] libstdc++ futex: Loop when waiting against arbitrary clock Mike Crowe
@ 2019-10-27 15:47 ` Mike Crowe
  2019-10-27 15:47 ` [PATCH v4 6/7] libstdc++ atomic_futex: Avoid rounding errors in std::future::wait_for Mike Crowe
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Mike Crowe @ 2019-10-27 15:47 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Mike Crowe

These tests show that changing the system clock has an effect on
std::future::wait_until when using std::chrono::system_clock but not when
using std::chrono::steady_clock.  Unfortunately these tests have a number
of downsides:

1. Nothing that is attempting to keep the clock set correctly (ntpd,
   systemd-timesyncd) can be running at the same time.

2. The test process requires the CAP_SYS_TIME capability (although, as it's
   written it checks for being root.)

3. Other processes running concurrently may misbehave when the clock darts
   back and forth.

4. They are slow to run.

As such, I don't think they are suitable for merging. I include them here
because I wanted to document how I had tested the changes in the previous
commits.
---
 libstdc++-v3/testsuite/30_threads/async/async.cc | 70 +++++++++++++++++-
 1 file changed, 70 insertions(+)

diff --git a/libstdc++-v3/testsuite/30_threads/async/async.cc b/libstdc++-v3/testsuite/30_threads/async/async.cc
index ddd007d..979f5b4 100644
--- a/libstdc++-v3/testsuite/30_threads/async/async.cc
+++ b/libstdc++-v3/testsuite/30_threads/async/async.cc
@@ -24,6 +24,7 @@
 
 #include <future>
 #include <testsuite_hooks.h>
+#include <sys/time.h>
 
 using namespace std;
 
@@ -154,6 +155,71 @@ void test_pr68519()
   VERIFY( elapsed_steady >= std::chrono::seconds(1) );
 }
 
+void perturb_system_clock(const std::chrono::seconds &seconds)
+{
+  struct timeval tv;
+  if (gettimeofday(&tv, NULL))
+    abort();
+
+  tv.tv_sec += seconds.count();
+  if (settimeofday(&tv, NULL))
+    abort();
+}
+
+// Ensure that advancing CLOCK_REALTIME doesn't make any difference
+// when we're waiting on std::chrono::steady_clock.
+void test05()
+{
+  auto const start = chrono::steady_clock::now();
+  future<void> f1 = async(launch::async, []() {
+      std::this_thread::sleep_for(std::chrono::seconds(10));
+    });
+
+  perturb_system_clock(chrono::seconds(20));
+
+  std::future_status status;
+  status = f1.wait_for(std::chrono::seconds(4));
+  VERIFY( status == std::future_status::timeout );
+
+  status = f1.wait_until(start + std::chrono::seconds(6));
+  VERIFY( status == std::future_status::timeout );
+
+  status = f1.wait_until(start + std::chrono::seconds(12));
+  VERIFY( status == std::future_status::ready );
+
+  auto const elapsed = chrono::steady_clock::now() - start;
+  VERIFY( elapsed >= std::chrono::seconds(10) );
+  VERIFY( elapsed < std::chrono::seconds(15) );
+
+  perturb_system_clock(chrono::seconds(-20));
+}
+
+// Ensure that advancing CLOCK_REALTIME does make a difference when
+// we're waiting on std::chrono::system_clock.
+void test06()
+{
+  auto const start = chrono::system_clock::now();
+  auto const start_steady = chrono::steady_clock::now();
+
+  future<void> f1 = async(launch::async, []() {
+      std::this_thread::sleep_for(std::chrono::seconds(5));
+      perturb_system_clock(chrono::seconds(60));
+      std::this_thread::sleep_for(std::chrono::seconds(5));
+    });
+  future_status status;
+  status = f1.wait_until(start + std::chrono::seconds(60));
+  VERIFY( status == std::future_status::timeout );
+
+  auto const elapsed_steady = chrono::steady_clock::now() - start_steady;
+  VERIFY( elapsed_steady >= std::chrono::seconds(5) );
+  VERIFY( elapsed_steady < std::chrono::seconds(10) );
+
+  status = f1.wait_until(start + std::chrono::seconds(75));
+  VERIFY( status == std::future_status::ready );
+
+  perturb_system_clock(chrono::seconds(-60));
+}
+
 int main()
 {
   test01();
@@ -163,5 +229,9 @@ int main()
   test03<slow_clock>();
   test04();
   test_pr68519();
+  if (geteuid() == 0) {
+    test05();
+    test06();
+  }
   return 0;
 }
-- 
git-series 0.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v4 6/7] libstdc++ atomic_futex: Avoid rounding errors in std::future::wait_for
  2019-10-27 15:47 [PATCH v4 0/7] std::future::wait_* improvements Mike Crowe
  2019-10-27 15:46 ` [PATCH v4 5/7] libstdc++ futex: Loop when waiting against arbitrary clock Mike Crowe
  2019-10-27 15:47 ` [PATCH v4 7/7] libstdc++: Extra async tests, not for merging Mike Crowe
@ 2019-10-27 15:47 ` Mike Crowe
  2019-10-27 15:47 ` [PATCH v4 2/7] libstdc++ futex: Use FUTEX_CLOCK_REALTIME for wait Mike Crowe
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Mike Crowe @ 2019-10-27 15:47 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Mike Crowe

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(-)

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;
 }
-- 
git-series 0.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v4 1/7] libstdc++: Improve async test
  2019-10-27 15:47 [PATCH v4 0/7] std::future::wait_* improvements Mike Crowe
                   ` (3 preceding siblings ...)
  2019-10-27 15:47 ` [PATCH v4 2/7] libstdc++ futex: Use FUTEX_CLOCK_REALTIME for wait Mike Crowe
@ 2019-10-27 15:47 ` Mike Crowe
  2019-10-27 15:47 ` [PATCH v4 4/7] libstdc++ atomic_futex: Use std::chrono::steady_clock as reference clock Mike Crowe
  2019-10-27 15:50 ` [PATCH v4 3/7] libstdc++ futex: Support waiting on std::chrono::steady_clock directly Mike Crowe
  6 siblings, 0 replies; 8+ messages in thread
From: Mike Crowe @ 2019-10-27 15:47 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Mike Crowe

Add tests for waiting for the future using both std::chrono::steady_clock
and std::chrono::system_clock in preparation for dealing with those clocks
properly in futex.cc.

	 * libstdc++-v3/testsuite/30_threads/async/async.cc (test02): Test
	 steady_clock with std::future::wait_until.  (test03): Add new test
	 templated on clock type waiting for future associated with async
	 to resolve.  (main): Call test03 to test both system_clock and
	 steady_clock.
---
 libstdc++-v3/testsuite/30_threads/async/async.cc | 33 +++++++++++++++++-
 1 file changed, 33 insertions(+)

diff --git a/libstdc++-v3/testsuite/30_threads/async/async.cc b/libstdc++-v3/testsuite/30_threads/async/async.cc
index 851925b..1b6e2ff 100644
--- a/libstdc++-v3/testsuite/30_threads/async/async.cc
+++ b/libstdc++-v3/testsuite/30_threads/async/async.cc
@@ -51,17 +51,50 @@ void test02()
   VERIFY( status == std::future_status::timeout );
   status = f1.wait_until(std::chrono::system_clock::now());
   VERIFY( status == std::future_status::timeout );
+  status = f1.wait_until(std::chrono::steady_clock::now());
+  VERIFY( status == std::future_status::timeout );
   l.unlock();  // allow async thread to proceed
   f1.wait();   // wait for it to finish
   status = f1.wait_for(std::chrono::milliseconds(0));
   VERIFY( status == std::future_status::ready );
   status = f1.wait_until(std::chrono::system_clock::now());
   VERIFY( status == std::future_status::ready );
+  status = f1.wait_until(std::chrono::steady_clock::now());
+  VERIFY( status == std::future_status::ready );
+}
+
+// This test is prone to failures if run on a loaded machine where the
+// kernel decides not to schedule us for several seconds. It also
+// assumes that no-one will warp CLOCK whilst the test is
+// running when CLOCK is std::chrono::system_clock.
+template<typename CLOCK>
+void test03()
+{
+  auto const start = CLOCK::now();
+  future<void> f1 = async(launch::async, []() {
+      std::this_thread::sleep_for(std::chrono::seconds(2));
+    });
+  std::future_status status;
+
+  status = f1.wait_for(std::chrono::milliseconds(500));
+  VERIFY( status == std::future_status::timeout );
+
+  status = f1.wait_until(start + std::chrono::seconds(1));
+  VERIFY( status == std::future_status::timeout );
+
+  status = f1.wait_until(start + std::chrono::seconds(5));
+  VERIFY( status == std::future_status::ready );
+
+  auto const elapsed = CLOCK::now() - start;
+  VERIFY( elapsed >= std::chrono::seconds(2) );
+  VERIFY( elapsed < std::chrono::seconds(5) );
 }
 
 int main()
 {
   test01();
   test02();
+  test03<std::chrono::system_clock>();
+  test03<std::chrono::steady_clock>();
   return 0;
 }
-- 
git-series 0.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v4 2/7] libstdc++ futex: Use FUTEX_CLOCK_REALTIME for wait
  2019-10-27 15:47 [PATCH v4 0/7] std::future::wait_* improvements Mike Crowe
                   ` (2 preceding siblings ...)
  2019-10-27 15:47 ` [PATCH v4 6/7] libstdc++ atomic_futex: Avoid rounding errors in std::future::wait_for Mike Crowe
@ 2019-10-27 15:47 ` Mike Crowe
  2019-10-27 15:47 ` [PATCH v4 1/7] libstdc++: Improve async test Mike Crowe
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Mike Crowe @ 2019-10-27 15:47 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Mike Crowe

The futex system call supports waiting for an absolute time if
FUTEX_WAIT_BITSET is used rather than FUTEX_WAIT.  Doing so provides two
benefits:

1. The call to gettimeofday is not required in order to calculate a
   relative timeout.

2. If someone changes the system clock during the wait then the futex
   timeout will correctly expire earlier or later.  Currently that only
   happens if the clock is changed prior to the call to gettimeofday.

According to futex(2), support for FUTEX_CLOCK_REALTIME was added in the
v2.6.28 Linux kernel and FUTEX_WAIT_BITSET was added in v2.6.25.  To ensure
that the code still works correctly with earlier kernel versions, an ENOSYS
error from futex[1] results in the futex_clock_realtime_unavailable flag
being set.  This flag is used to avoid the unnecessary unsupported futex
call in the future and to fall back to the previous gettimeofday and
relative time implementation.

glibc applied an equivalent switch in pthread_cond_timedwait to use
FUTEX_CLOCK_REALTIME and FUTEX_WAIT_BITSET rather than FUTEX_WAIT for
glibc-2.10 back in 2009.  See
glibc:cbd8aeb836c8061c23a5e00419e0fb25a34abee7

The futex_clock_realtime_unavailable flag is accessed using
std::memory_order_relaxed to stop it becoming a bottleneck.  If the first
two calls to _M_futex_wait_until happen to happen simultaneously then the
only consequence is that both will try to use FUTEX_CLOCK_REALTIME, both
risk discovering that it doesn't work and, if so, both set the flag.

[1] This is how glibc's nptl-init.c determines whether these flags are
    supported.

	* libstdc++-v3/src/c++11/futex.cc: Add new constants for required
	futex flags.  Add futex_clock_realtime_unavailable flag to store
	result of trying to use
	FUTEX_CLOCK_REALTIME. (__atomic_futex_unsigned_base::_M_futex_wait_until):
	Try to use FUTEX_WAIT_BITSET with FUTEX_CLOCK_REALTIME and only
	fall back to using gettimeofday and FUTEX_WAIT if that's not
	supported.
---
 libstdc++-v3/src/c++11/futex.cc | 37 ++++++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+)

diff --git a/libstdc++-v3/src/c++11/futex.cc b/libstdc++-v3/src/c++11/futex.cc
index 3ea32f7..38ae448 100644
--- a/libstdc++-v3/src/c++11/futex.cc
+++ b/libstdc++-v3/src/c++11/futex.cc
@@ -35,8 +35,16 @@
 
 // Constants for the wait/wake futex syscall operations
 const unsigned futex_wait_op = 0;
+const unsigned futex_wait_bitset_op = 9;
+const unsigned futex_clock_realtime_flag = 256;
+const unsigned futex_bitset_match_any = ~0;
 const unsigned futex_wake_op = 1;
 
+namespace
+{
+  std::atomic<bool> futex_clock_realtime_unavailable;
+}
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -58,6 +66,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
     else
       {
+	if (!futex_clock_realtime_unavailable.load(std::memory_order_relaxed))
+	  {
+	    struct timespec rt;
+	    rt.tv_sec = __s.count();
+	    rt.tv_nsec = __ns.count();
+	    if (syscall (SYS_futex, __addr,
+			 futex_wait_bitset_op | futex_clock_realtime_flag,
+			 __val, &rt, nullptr, futex_bitset_match_any) == -1)
+	      {
+		__glibcxx_assert(errno == EINTR || errno == EAGAIN
+				|| errno == ETIMEDOUT || errno == ENOSYS);
+		if (errno == ETIMEDOUT)
+		  return false;
+		if (errno == ENOSYS)
+		  {
+		    futex_clock_realtime_unavailable.store(true,
+						    std::memory_order_relaxed);
+		    // Fall through to legacy implementation if the system
+		    // call is unavailable.
+		  }
+		else
+		  return true;
+	      }
+	    else
+	      return true;
+	  }
+
+	// We only get to here if futex_clock_realtime_unavailable was
+	// true or has just been set to true.
 	struct timeval tv;
 	gettimeofday (&tv, NULL);
 	// Convert the absolute timeout value to a relative timeout
-- 
git-series 0.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v4 4/7] libstdc++ atomic_futex: Use std::chrono::steady_clock as reference clock
  2019-10-27 15:47 [PATCH v4 0/7] std::future::wait_* improvements Mike Crowe
                   ` (4 preceding siblings ...)
  2019-10-27 15:47 ` [PATCH v4 1/7] libstdc++: Improve async test Mike Crowe
@ 2019-10-27 15:47 ` Mike Crowe
  2019-10-27 15:50 ` [PATCH v4 3/7] libstdc++ futex: Support waiting on std::chrono::steady_clock directly Mike Crowe
  6 siblings, 0 replies; 8+ messages in thread
From: Mike Crowe @ 2019-10-27 15:47 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Mike Crowe

The user-visible effect of this change is that std::future::wait_for now
uses std::chrono::steady_clock to determine the timeout.  This makes it
immune to changes made to the system clock.  It also means that anyone
using their own clock types with std::future::wait_until will have the
timeout converted to std::chrono::steady_clock rather than
std::chrono::system_clock.

Now that use of both std::chrono::steady_clock and
std::chrono::system_clock are correctly supported for the wait timeout, I
believe that std::chrono::steady_clock is a better choice for the reference
clock that all other clocks are converted to since it is guaranteed to
advance steadily.  The previous behaviour of converting to
std::chrono::system_clock risks timeouts changing dramatically when the
system clock is changed.

	* libstdc++-v3/include/bits/atomic_futex.h:
	(__atomic_futex_unsigned): Change __clock_t typedef to use
	steady_clock so that unknown clocks are synced to it rather than
	system_clock. Change existing __clock_t overloads of
	_M_load_and_text_until_impl and _M_load_when_equal_until to use
	system_clock explicitly. Remove comment about DR 887 since these
	changes address that problem as best as we currently able.
---
 libstdc++-v3/include/bits/atomic_futex.h | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/bits/atomic_futex.h b/libstdc++-v3/include/bits/atomic_futex.h
index 6d28d28..387ee9d 100644
--- a/libstdc++-v3/include/bits/atomic_futex.h
+++ b/libstdc++-v3/include/bits/atomic_futex.h
@@ -71,7 +71,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template <unsigned _Waiter_bit = 0x80000000>
   class __atomic_futex_unsigned : __atomic_futex_unsigned_base
   {
-    typedef chrono::system_clock __clock_t;
+    typedef chrono::steady_clock __clock_t;
 
     // This must be lock-free and at offset 0.
     atomic<unsigned> _M_data;
@@ -169,7 +169,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     unsigned
     _M_load_and_test_until_impl(unsigned __assumed, unsigned __operand,
 	bool __equal, memory_order __mo,
-	const chrono::time_point<__clock_t, _Dur>& __atime)
+	const chrono::time_point<std::chrono::system_clock, _Dur>& __atime)
     {
       auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
       auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
@@ -229,7 +229,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _M_load_when_equal_until(unsigned __val, memory_order __mo,
 	  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 auto __delta = __atime - __c_entry;
@@ -241,7 +240,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     template<typename _Duration>
     _GLIBCXX_ALWAYS_INLINE bool
     _M_load_when_equal_until(unsigned __val, memory_order __mo,
-	const chrono::time_point<__clock_t, _Duration>& __atime)
+	const chrono::time_point<std::chrono::system_clock, _Duration>& __atime)
     {
       unsigned __i = _M_load(__mo);
       if ((__i & ~_Waiter_bit) == __val)
-- 
git-series 0.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v4 0/7] std::future::wait_* improvements
@ 2019-10-27 15:47 Mike Crowe
  2019-10-27 15:46 ` [PATCH v4 5/7] libstdc++ futex: Loop when waiting against arbitrary clock Mike Crowe
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Mike Crowe @ 2019-10-27 15:47 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Mike Crowe

v1 of this series was originally posted back in September 2017 (see
https://gcc.gnu.org/ml/libstdc++/2017-09/msg00083.html )

v2 of this series was originally posted back in January 2018 (see
https://gcc.gnu.org/ml/libstdc++/2018-01/msg00035.html )

v3 of this series was originally posted back in August 2018 (see
https://gcc.gnu.org/ml/libstdc++/2018-08/msg00001.html )

Changes since v3:

* Update libstdc++-v3/config/abi/pre/gnu.ver as recommended by
  Jonathan Wakely in
  https://gcc.gnu.org/ml/libstdc++/2018-08/msg00015.html .

* Replace _GLIBCXX_DEBUG_ASSERT with __glibcxx_assert in futex.cc as
  recommended by Jonathan Wakely in
  https://gcc.gnu.org/ml/libstdc++/2018-08/msg00014.html .

* Incorporate extra patch originally posted separately in
  https://gcc.gnu.org/ml/libstdc++/2018-08/msg00017.html .

* Rename incorrect futex_clock_realtime_unavailable to
  futex_clock_monotonic_unavailable in comment.	 Spotted by Jonathan
  Wakely.

* Improve commit messages to use GNU two-spaces-after-periods style
  and add changelogs.

* Restrict lines to eighty columns or less.

* Remove unnecessarily-added steady_clock_copy from test - slow_clock
  works just as well.

* A few other minor tweaks to tests and comments.

Combined ChangeLog entry (generated from the separate messages in each
commit):

2019-10-27  Mike Crowe	<mac@mcrowe.com>

	* libstdc++-v3/testsuite/30_threads/async/async.cc (test02):
	Test steady_clock with std::future::wait_until.	 (test03): Add
	new test templated on clock type waiting for future associated
	with async to resolve.	(main): Call test03 to test both
	system_clock and steady_clock.

	* libstdc++-v3/src/c++11/futex.cc: Add new constants for
	required futex flags.  Add futex_clock_realtime_unavailable
	flag to store result of trying to use FUTEX_CLOCK_REALTIME.
	(__atomic_futex_unsigned_base::_M_futex_wait_until): Try to
	use FUTEX_WAIT_BITSET with FUTEX_CLOCK_REALTIME and only fall
	back to using gettimeofday and FUTEX_WAIT if that's not
	supported.

	* libstdc++-v3/config/abi/pre/gnu.ver: Update for addition of
	__atomic_futex_unsigned_base::_M_futex_wait_until_steady.
	* libstdc++-v3/include/bits/atomic_futex.h
	(__atomic_futex_unsigned_base): Add comments to clarify that
	_M_futex_wait_until _M_load_and_test_until use CLOCK_REALTIME.
	Declare new _M_futex_wait_until_steady and
	_M_load_and_text_until_steady methods that use
	CLOCK_MONOTONIC.  Add _M_load_and_test_until_impl and
	_M_load_when_equal_until overloads that accept a steady_clock
	time_point and use these new methods.
	* libstdc++-v3/src/c++11/futex.cc: Include headers required
	for clock_gettime. Add futex_clock_monotonic_flag constant to
	tell futex to use CLOCK_MONOTONIC to match the existing
	futex_clock_realtime_flag.  Add
	futex_clock_monotonic_unavailable to store the result of
	trying to use CLOCK_MONOTONIC.
	(__atomic_futex_unsigned_base::_M_futex_wait_until_steady):
	Add new variant of _M_futex_wait_until that uses
	CLOCK_MONOTONIC to support waiting using steady_clock.

	* libstdc++-v3/include/bits/atomic_futex.h:
	(__atomic_futex_unsigned): Change __clock_t typedef to use
	steady_clock so that unknown clocks are synced to it rather
	than system_clock. Change existing __clock_t overloads of
	_M_load_and_text_until_impl and _M_load_when_equal_until to
	use system_clock explicitly. Remove comment about DR 887 since
	these changes address that problem as best as we currently
	able.

	* libstdc++-v3/include/bits/atomic_futex.h:
	(__atomic_futex_unsigned) Add loop to _M_load_when_equal_until
	on generic _Clock to check the timeout against _Clock again
	after _M_load_when_equal_until returns indicating a timeout.
	* libstdc++-v3/testsuite/30_threads/async/async.cc: Invent
	slow_clock that runs at an eleventh of steady_clock's
	speed. Use it to test the user-supplied-clock variant of
	__atomic_futex_unsigned::_M_load_when_equal_until works
	generally with test03 and loops correctly when the timeout
	time hasn't been reached in test04.

	* 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.

Mike Crowe (7):
  libstdc++: Improve async test
  libstdc++ futex: Use FUTEX_CLOCK_REALTIME for wait
  libstdc++ futex: Support waiting on std::chrono::steady_clock directly
  libstdc++ atomic_futex: Use std::chrono::steady_clock as reference clock
  libstdc++ futex: Loop when waiting against arbitrary clock
  libstdc++ atomic_futex: Avoid rounding errors in std::future::wait_for
  libstdc++: Extra async tests, not for merging

 libstdc++-v3/config/abi/pre/gnu.ver              |  10 +-
 libstdc++-v3/include/bits/atomic_futex.h         |  95 +++++++--
 libstdc++-v3/src/c++11/futex.cc                  | 119 +++++++++++-
 libstdc++-v3/testsuite/30_threads/async/async.cc | 170 ++++++++++++++++-
 4 files changed, 379 insertions(+), 15 deletions(-)

base-commit: 541ec0fe27585fce2b27750ca2bb1cf8985b043e
-- 
git-series 0.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v4 3/7] libstdc++ futex: Support waiting on std::chrono::steady_clock directly
  2019-10-27 15:47 [PATCH v4 0/7] std::future::wait_* improvements Mike Crowe
                   ` (5 preceding siblings ...)
  2019-10-27 15:47 ` [PATCH v4 4/7] libstdc++ atomic_futex: Use std::chrono::steady_clock as reference clock Mike Crowe
@ 2019-10-27 15:50 ` Mike Crowe
  6 siblings, 0 replies; 8+ messages in thread
From: Mike Crowe @ 2019-10-27 15:50 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Mike Crowe

The user-visible effect of this change is for std::future::wait_until to
use CLOCK_MONOTONIC when passed a timeout of std::chrono::steady_clock
type.  This makes it immune to any changes made to the system clock
CLOCK_REALTIME.

Add an overload of __atomic_futex_unsigned::_M_load_and_text_until_impl
that accepts a std::chrono::steady_clock, and correctly passes this through
to __atomic_futex_unsigned_base::_M_futex_wait_until_steady which uses
CLOCK_MONOTONIC for the timeout within the futex system call.  These
functions are mostly just copies of the std::chrono::system_clock versions
with small tweaks.

Prior to this commit, a std::chrono::steady timeout would be converted via
std::chrono::system_clock which risks reducing or increasing the timeout if
someone changes CLOCK_REALTIME whilst the wait is happening.  (The commit
immediately prior to this one increases the window of opportunity for that
from a short period during the calculation of a relative timeout, to the
entire duration of the wait.)

FUTEX_WAIT_BITSET was added in kernel v2.6.25.  If futex reports ENOSYS to
indicate that this operation is not supported then the code falls back to
using clock_gettime(2) to calculate a relative time to wait for.

I believe that I've added this functionality in a way that it doesn't break
ABI compatibility, but that has made it more verbose and less type safe.  I
believe that it would be better to maintain the timeout as an instance of
the correct clock type all the way down to a single _M_futex_wait_until
function with an overload for each clock.  The current scheme of separating
out the seconds and nanoseconds early risks accidentally calling the wait
function for the wrong clock.  Unfortunately, doing this would break code
that compiled against the old header.

	* libstdc++-v3/config/abi/pre/gnu.ver: Update for addition of
          __atomic_futex_unsigned_base::_M_futex_wait_until_steady.

	* libstdc++-v3/include/bits/atomic_futex.h
          (__atomic_futex_unsigned_base): Add comments to clarify that
          _M_futex_wait_until _M_load_and_test_until use CLOCK_REALTIME.
          Declare new _M_futex_wait_until_steady and
          _M_load_and_text_until_steady methods that use CLOCK_MONOTONIC.
          Add _M_load_and_test_until_impl and _M_load_when_equal_until
          overloads that accept a steady_clock time_point and use these new
          methods.

	* libstdc++-v3/src/c++11/futex.cc: Include headers required for
	clock_gettime. Add futex_clock_monotonic_flag constant to tell
	futex to use CLOCK_MONOTONIC to match the existing
	futex_clock_realtime_flag.  Add futex_clock_monotonic_unavailable
	to store the result of trying to use
	CLOCK_MONOTONIC. (__atomic_futex_unsigned_base::_M_futex_wait_until_steady):
	Add new variant of _M_futex_wait_until that uses CLOCK_MONOTONIC to
	support waiting using steady_clock.
---
 libstdc++-v3/config/abi/pre/gnu.ver      | 10 +--
 libstdc++-v3/include/bits/atomic_futex.h | 67 +++++++++++++++++++-
 libstdc++-v3/src/c++11/futex.cc          | 82 +++++++++++++++++++++++++-
 3 files changed, 154 insertions(+), 5 deletions(-)

diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index e61fbe0..26492bc 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -1916,10 +1916,9 @@ GLIBCXX_3.4.21 {
     _ZNSt7codecvtID[is]c*;
     _ZT[ISV]St7codecvtID[is]c*E;
 
-    extern "C++"
-    {
-      std::__atomic_futex_unsigned_base*;
-    };
+    # std::__atomic_futex_unsigned_base members
+    _ZNSt28__atomic_futex_unsigned_base19_M_futex_notify_all*;
+    _ZNSt28__atomic_futex_unsigned_base19_M_futex_wait_until*;
 
     # codecvt_utf8 etc.
     _ZNKSt19__codecvt_utf8_base*;
@@ -2291,6 +2290,9 @@ GLIBCXX_3.4.28 {
     _ZNSt12__shared_ptrINSt10filesystem28recursive_directory_iterator10_Dir_stackELN9__gnu_cxx12_Lock_policyE[012]EEC2EOS5_;
     _ZNSt12__shared_ptrINSt10filesystem7__cxx1128recursive_directory_iterator10_Dir_stackELN9__gnu_cxx12_Lock_policyE[012]EEC2EOS6_;
 
+    # std::__atomic_futex_unsigned_base::_M_futex_wait_until_steady
+    _ZNSt28__atomic_futex_unsigned_base26_M_futex_wait_until_steady*;
+
 } GLIBCXX_3.4.27;
 
 # Symbols in the support library (libsupc++) have their own tag.
diff --git a/libstdc++-v3/include/bits/atomic_futex.h b/libstdc++-v3/include/bits/atomic_futex.h
index 36fda38..6d28d28 100644
--- a/libstdc++-v3/include/bits/atomic_futex.h
+++ b/libstdc++-v3/include/bits/atomic_futex.h
@@ -52,11 +52,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if defined(_GLIBCXX_HAVE_LINUX_FUTEX) && ATOMIC_INT_LOCK_FREE > 1
   struct __atomic_futex_unsigned_base
   {
-    // Returns false iff a timeout occurred.
+    // __s and __ns are measured against CLOCK_REALTIME. Returns false
+    // iff a timeout occurred.
     bool
     _M_futex_wait_until(unsigned *__addr, unsigned __val, bool __has_timeout,
 	chrono::seconds __s, chrono::nanoseconds __ns);
 
+    // __s and __ns are measured against CLOCK_MONOTONIC. Returns
+    // false iff a timeout occurred.
+    bool
+    _M_futex_wait_until_steady(unsigned *__addr, unsigned __val,
+	bool __has_timeout, chrono::seconds __s, chrono::nanoseconds __ns);
+
     // This can be executed after the object has been destroyed.
     static void _M_futex_notify_all(unsigned* __addr);
   };
@@ -86,6 +93,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     // value if equal is false.
     // The assumed value is the caller's assumption about the current value
     // when making the call.
+    // __s and __ns are measured against CLOCK_REALTIME.
     unsigned
     _M_load_and_test_until(unsigned __assumed, unsigned __operand,
 	bool __equal, memory_order __mo, bool __has_timeout,
@@ -110,6 +118,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
     }
 
+    // If a timeout occurs, returns a current value after the timeout;
+    // otherwise, returns the operand's value if equal is true or a different
+    // value if equal is false.
+    // The assumed value is the caller's assumption about the current value
+    // when making the call.
+    // __s and __ns are measured against CLOCK_MONOTONIC.
+    unsigned
+    _M_load_and_test_until_steady(unsigned __assumed, unsigned __operand,
+	bool __equal, memory_order __mo, bool __has_timeout,
+	chrono::seconds __s, chrono::nanoseconds __ns)
+    {
+      for (;;)
+	{
+	  // Don't bother checking the value again because we expect the caller
+	  // to have done it recently.
+	  // memory_order_relaxed is sufficient because we can rely on just the
+	  // modification order (store_notify uses an atomic RMW operation too),
+	  // and the futex syscalls synchronize between themselves.
+	  _M_data.fetch_or(_Waiter_bit, memory_order_relaxed);
+	  bool __ret = _M_futex_wait_until_steady((unsigned*)(void*)&_M_data,
+					   __assumed | _Waiter_bit,
+					   __has_timeout, __s, __ns);
+	  // Fetch the current value after waiting (clears _Waiter_bit).
+	  __assumed = _M_load(__mo);
+	  if (!__ret || ((__operand == __assumed) == __equal))
+	    return __assumed;
+	  // TODO adapt wait time
+	}
+    }
+
     // Returns the operand's value if equal is true or a different value if
     // equal is false.
     // The assumed value is the caller's assumption about the current value
@@ -140,6 +178,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  true, __s.time_since_epoch(), __ns);
     }
 
+    template<typename _Dur>
+    unsigned
+    _M_load_and_test_until_impl(unsigned __assumed, unsigned __operand,
+	bool __equal, memory_order __mo,
+	const chrono::time_point<std::chrono::steady_clock, _Dur>& __atime)
+    {
+      auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+      auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+      // XXX correct?
+      return _M_load_and_test_until_steady(__assumed, __operand, __equal, __mo,
+	  true, __s.time_since_epoch(), __ns);
+    }
+
   public:
 
     _GLIBCXX_ALWAYS_INLINE unsigned
@@ -200,6 +251,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return (__i & ~_Waiter_bit) == __val;
     }
 
+    // Returns false iff a timeout occurred.
+    template<typename _Duration>
+    _GLIBCXX_ALWAYS_INLINE bool
+    _M_load_when_equal_until(unsigned __val, memory_order __mo,
+	const chrono::time_point<std::chrono::steady_clock, _Duration>& __atime)
+    {
+      unsigned __i = _M_load(__mo);
+      if ((__i & ~_Waiter_bit) == __val)
+	return true;
+      // TODO Spin-wait first.  Ignore effect on timeout.
+      __i = _M_load_and_test_until_impl(__i, __val, true, __mo, __atime);
+      return (__i & ~_Waiter_bit) == __val;
+    }
+
     _GLIBCXX_ALWAYS_INLINE void
     _M_store_notify_all(unsigned __val, memory_order __mo)
     {
diff --git a/libstdc++-v3/src/c++11/futex.cc b/libstdc++-v3/src/c++11/futex.cc
index 38ae448..1df84bb 100644
--- a/libstdc++-v3/src/c++11/futex.cc
+++ b/libstdc++-v3/src/c++11/futex.cc
@@ -33,9 +33,15 @@
 #include <errno.h>
 #include <debug/debug.h>
 
+#ifdef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL
+#include <unistd.h>
+#include <sys/syscall.h>
+#endif
+
 // Constants for the wait/wake futex syscall operations
 const unsigned futex_wait_op = 0;
 const unsigned futex_wait_bitset_op = 9;
+const unsigned futex_clock_monotonic_flag = 0;
 const unsigned futex_clock_realtime_flag = 256;
 const unsigned futex_bitset_match_any = ~0;
 const unsigned futex_wake_op = 1;
@@ -43,6 +49,7 @@ const unsigned futex_wake_op = 1;
 namespace
 {
   std::atomic<bool> futex_clock_realtime_unavailable;
+  std::atomic<bool> futex_clock_monotonic_unavailable;
 }
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -121,6 +128,81 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
   }
 
+  bool
+  __atomic_futex_unsigned_base::_M_futex_wait_until_steady(unsigned *__addr,
+      unsigned __val,
+      bool __has_timeout, chrono::seconds __s, chrono::nanoseconds __ns)
+  {
+    if (!__has_timeout)
+      {
+	// Ignore whether we actually succeeded to block because at worst,
+	// we will fall back to spin-waiting.  The only thing we could do
+	// here on errors is abort.
+	int ret __attribute__((unused));
+	ret = syscall (SYS_futex, __addr, futex_wait_op, __val, nullptr);
+	__glibcxx_assert(ret == 0 || errno == EINTR || errno == EAGAIN);
+	return true;
+      }
+    else
+      {
+	if (!futex_clock_monotonic_unavailable.load(std::memory_order_relaxed))
+	  {
+	    struct timespec rt;
+	    rt.tv_sec = __s.count();
+	    rt.tv_nsec = __ns.count();
+
+	    if (syscall (SYS_futex, __addr,
+			 futex_wait_bitset_op | futex_clock_monotonic_flag,
+			 __val, &rt, nullptr, futex_bitset_match_any) == -1)
+	      {
+		__glibcxx_assert(errno == EINTR || errno == EAGAIN
+				 || errno == ETIMEDOUT || errno == ENOSYS);
+		if (errno == ETIMEDOUT)
+		  return false;
+		else if (errno == ENOSYS)
+		  {
+		    futex_clock_monotonic_unavailable.store(true,
+						    std::memory_order_relaxed);
+		    // Fall through to legacy implementation if the system
+		    // call is unavailable.
+		  }
+		else
+		  return true;
+	      }
+	  }
+
+	// We only get to here if futex_clock_monotonic_unavailable was
+	// true or has just been set to true.
+	struct timespec ts;
+#ifdef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL
+	syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts);
+#else
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+#endif
+	// Convert the absolute timeout value to a relative timeout
+	struct timespec rt;
+	rt.tv_sec = __s.count() - ts.tv_sec;
+	rt.tv_nsec = __ns.count() - ts.tv_nsec;
+	if (rt.tv_nsec < 0)
+	  {
+	    rt.tv_nsec += 1000000000;
+	    --rt.tv_sec;
+	  }
+	// Did we already time out?
+	if (rt.tv_sec < 0)
+	  return false;
+
+	if (syscall (SYS_futex, __addr, futex_wait_op, __val, &rt) == -1)
+	  {
+	    __glibcxx_assert(errno == EINTR || errno == EAGAIN
+			     || errno == ETIMEDOUT);
+	    if (errno == ETIMEDOUT)
+	      return false;
+	  }
+	return true;
+      }
+  }
+
   void
   __atomic_futex_unsigned_base::_M_futex_notify_all(unsigned* __addr)
   {
-- 
git-series 0.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2019-10-27 15:50 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-27 15:47 [PATCH v4 0/7] std::future::wait_* improvements Mike Crowe
2019-10-27 15:46 ` [PATCH v4 5/7] libstdc++ futex: Loop when waiting against arbitrary clock Mike Crowe
2019-10-27 15:47 ` [PATCH v4 7/7] libstdc++: Extra async tests, not for merging Mike Crowe
2019-10-27 15:47 ` [PATCH v4 6/7] libstdc++ atomic_futex: Avoid rounding errors in std::future::wait_for Mike Crowe
2019-10-27 15:47 ` [PATCH v4 2/7] libstdc++ futex: Use FUTEX_CLOCK_REALTIME for wait Mike Crowe
2019-10-27 15:47 ` [PATCH v4 1/7] libstdc++: Improve async test Mike Crowe
2019-10-27 15:47 ` [PATCH v4 4/7] libstdc++ atomic_futex: Use std::chrono::steady_clock as reference clock Mike Crowe
2019-10-27 15:50 ` [PATCH v4 3/7] libstdc++ futex: Support waiting on std::chrono::steady_clock directly Mike Crowe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).