Passing a timeout from before the epoch to __platform_wait_until()
currently results in an exception being thrown because futex(2) doesn't
support negative timeouts. Let's just immediately return indicating a
timeout has happened.
Add test cases to prove that this bug is fixed for std::binary_semaphore
(which is just an alias for std::counting_semaphore<1>). The tests
exercise cases that aren't problematic with the current code since
system_clock is converted to steady_clock before calling
__platform_wait_until() is called but they will protect against changes
in the implementation reintroducing this bug.
PR libstdc++/116586
libstdc++-v3/ChangeLog:
* src/c++20/atomic.cc (__platform_wait_until): Return false on
timeout before epoch.
* testsuite/30_threads/semaphore/try_acquire_for.cc: Add tests.
* testsuite/30_threads/semaphore/try_acquire_until.cc: Add tests.
Signed-off-by: Mike Crowe <[email protected]>
---
libstdc++-v3/src/c++20/atomic.cc | 4 ++++
.../30_threads/semaphore/try_acquire_for.cc | 20 +++++++++++++++++
.../30_threads/semaphore/try_acquire_until.cc | 22 +++++++++++++++++++
3 files changed, 46 insertions(+)
diff --git a/libstdc++-v3/src/c++20/atomic.cc b/libstdc++-v3/src/c++20/atomic.cc
index 4120e1a0817..1e987213d80 100644
--- a/libstdc++-v3/src/c++20/atomic.cc
+++ b/libstdc++-v3/src/c++20/atomic.cc
@@ -359,6 +359,10 @@ __platform_wait_until(const __platform_wait_t* __addr,
static_cast<long>(__ns.count())
};
+ // SYS_futex returns EINVAL if timeout is negative, act as if we timed out
immediately
+ if (__rt.tv_sec < 0 || __rt.tv_nsec < 0)
+ return false;
+
if (syscall (SYS_futex, __addr,
static_cast<int>(__futex_wait_flags::__wait_bitset_private),
__old, &__rt, nullptr,
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
index 39681c7ee56..fe0d704baf8 100644
--- a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -90,9 +90,29 @@ test03()
s.try_acquire_for(timeout);
}
+// Prove semaphore doesn't suffer from PR116586
+template <typename Clock>
+void
+test_relative(std::chrono::nanoseconds offset)
+{
+ std::binary_semaphore sem(1);
+ VERIFY(sem.try_acquire_for(offset));
+ VERIFY(!sem.try_acquire_for(offset));
+}
+
int main()
{
test01();
test02();
test03();
+ for (const std::chrono::nanoseconds offset : {
+ std::chrono::nanoseconds{0},
+
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds{-10}),
+
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds{-10})
+ }) {
+ test_relative<std::chrono::system_clock>(offset);
+ test_relative<std::chrono::system_clock>(offset -
std::chrono::system_clock::now().time_since_epoch());
+ test_relative<std::chrono::steady_clock>(offset);
+ test_relative<std::chrono::steady_clock>(offset -
std::chrono::steady_clock::now().time_since_epoch());
+ }
}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
index de0068d670a..a00f124b147 100644
--- a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -87,8 +87,30 @@ void test02()
b.wait(1);
}
+// Prove semaphore doesn't suffer from PR116586
+template <typename Clock>
+void
+test_absolute(std::chrono::nanoseconds offset)
+{
+ std::binary_semaphore sem(1);
+ std::chrono::time_point<Clock> tp(offset);
+ VERIFY(sem.try_acquire_until(tp));
+ VERIFY(!sem.try_acquire_until(tp));
+}
+
int main()
{
test01();
test02();
+ for (const std::chrono::nanoseconds offset : {
+ // tv_sec == 0, tv_nsec == 0
+ std::chrono::nanoseconds{0},
+ // tv_sec == 0, tv_nsec < 0
+
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds{-10}),
+ // tv_sec < 0
+
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds{-10})
+ }) {
+ test_absolute<std::chrono::system_clock>(offset);
+ test_absolute<std::chrono::steady_clock>(offset);
+ }
}
--
2.39.5