https://gcc.gnu.org/g:e0525a6d2bba07d623424ab6f10a023de90e65a2
commit r16-4426-ge0525a6d2bba07d623424ab6f10a023de90e65a2 Author: Mike Crowe <[email protected]> Date: Sun Sep 14 21:21:28 2025 +0100 libstdc++: Add std::binary_semaphore tests for negative timeouts [PR116586] Add test cases to prove that negative timeouts are correctly handled by 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. libstdc++-v3/ChangeLog: PR libstdc++/116586 * 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]> Diff: --- .../30_threads/semaphore/try_acquire_for.cc | 22 ++++++++++++++++++++ .../30_threads/semaphore/try_acquire_until.cc | 24 ++++++++++++++++++++++ 2 files changed, 46 insertions(+) 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 39681c7ee56b..94acb253091e 100644 --- a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc +++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc @@ -24,6 +24,7 @@ #include <chrono> #include <thread> #include <atomic> +#include <initializer_list> #include <testsuite_hooks.h> void test01() @@ -90,9 +91,30 @@ 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(); + using namespace std::chrono; + for (const nanoseconds offset : { + nanoseconds{0}, + nanoseconds{-10ms}, + nanoseconds{-10s} + }) { + 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 de0068d670ad..ed6bd118fee4 100644 --- a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc +++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc @@ -24,6 +24,7 @@ #include <chrono> #include <thread> #include <atomic> +#include <initializer_list> #include <testsuite_hooks.h> void test01() @@ -87,8 +88,31 @@ 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(); + using namespace std::chrono; + for (const nanoseconds offset : { + // tv_sec == 0, tv_nsec == 0 + nanoseconds{0}, + // tv_sec == 0, tv_nsec < 0 + nanoseconds{-10ms}, + // tv_sec < 0 + nanoseconds{-10s} + }) { + test_absolute<std::chrono::system_clock>(offset); + test_absolute<std::chrono::steady_clock>(offset); + } }
