From: Mike Crowe Date: Sun, 14 Sep 2025 20:21:32 +0000 (+0100) Subject: libstdc++: Add std::recursive_timed_mutex tests for negative timeouts [PR116586] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9a3ff39d6b4a3e900533db64c8071317bd7b8a17;p=thirdparty%2Fgcc.git libstdc++: Add std::recursive_timed_mutex tests for negative timeouts [PR116586] Add tests to show that std::recursive_timed_mutex::try_lock_until and std::recursive_timed_mutex::try_lock_for correctly handle negative timeouts. libstdc++-v3/ChangeLog: PR libstdc++/116586 * testsuite/30_threads/recursive_timed_mutex/try_lock_until/116586.cc: New test. Signed-off-by: Mike Crowe --- diff --git a/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/116586.cc b/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/116586.cc new file mode 100644 index 000000000000..941f3af16b98 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/116586.cc @@ -0,0 +1,72 @@ +// { dg-do run { target c++11 } } + +#include +#include +#include +#include +#include + +namespace chrono = std::chrono; + +// thread.timedmutex.requirements.general: +// If abs_time has already passed, the function attempts to obtain +// ownership without blocking (as if by calling try_lock()). + +template +void +test_absolute(chrono::nanoseconds offset) +{ + std::recursive_timed_mutex mtx; + chrono::time_point tp(offset); + VERIFY(mtx.try_lock_until(tp)); + + { + // To test failing to lock a recursive mutex we need to try to lock on a + // different thread. + auto t = std::async(std::launch::async, [&mtx, tp]() { + VERIFY(!mtx.try_lock_until(tp)); + }); + } +} + +// The type of clock used for the actual wait depends on whether +// _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK is defined. We might as well just test +// both steady_clock and system_clock. +template +void +test_relative(chrono::nanoseconds offset) +{ + std::recursive_timed_mutex mtx; + const auto d = -Clock::now().time_since_epoch() + offset; + VERIFY(mtx.try_lock_for(d)); + + { + // To test failing to lock a recursive mutex we need to try to lock on a + // different thread. + auto t = std::async(std::launch::async, [&mtx, d]() { + VERIFY(!mtx.try_lock_for(d)); + }); + } +} + +int main() +{ + // Try once with an offset that ought to result in tv_sec == 0, tv_nsec < 0 + // and one with an offset that ought to result in tv_sec < 0, tv_nsec == 0 + // for the absolute calls at least. It's not really possible to arrange for + // the relative calls to have tv_nsec == 0 due to time advancing. + for (const chrono::nanoseconds offset : { + // tv_sec == 0, tv_nsec == 0 + chrono::nanoseconds{0}, + // tv_sec == 0, tv_nsec < 0 + chrono::duration_cast(chrono::milliseconds{-10}), + // tv_sec < 0 + chrono::duration_cast(chrono::seconds{-10}) + }) { + test_absolute(offset); + test_relative(offset); + + test_absolute(offset); + test_relative(offset); + } +}