The __detail::__wait_until function has a comment that should have been removed when r16-1000-g225622398a9631 changed the return type from a std::pair to a struct with three members.
Fix _M_spin_until_impl so that the _M_has_val member of the result is accurate. If the deadline has passed then it never enters the loop and so never loads a fresh value, so _M_has_val should be false. There's also a redundant clock::now() call in __spin_until_impl which can be removed, we can reuse the call immediately before it. libstdc++-v3/ChangeLog: * include/bits/atomic_timed_wait.h (__detail::__wait_until): Remove incorrect comment. * src/c++20/atomic.cc (__spin_until_impl): Fix incorrect return value. Reuse result of first call to clock. --- Patch v2 adjusts the commit summary to not say it only changes comments. Also removed the change to the __atomic_wait_address_for_v return statement, which logically belongs in the other patch touching that funciton. Tested x86_64-linux. libstdc++-v3/include/bits/atomic_timed_wait.h | 1 - libstdc++-v3/src/c++20/atomic.cc | 24 ++++++++++++------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h index 230afbc96e7d..71638fd59a05 100644 --- a/libstdc++-v3/include/bits/atomic_timed_wait.h +++ b/libstdc++-v3/include/bits/atomic_timed_wait.h @@ -87,7 +87,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __wait_until_impl(const void* __addr, __wait_args_base& __args, const __wait_clock_t::duration& __atime); - // Returns {true, val} if wait ended before a timeout. template<typename _Clock, typename _Dur> __wait_result_type __wait_until(const void* __addr, __wait_args_base& __args, diff --git a/libstdc++-v3/src/c++20/atomic.cc b/libstdc++-v3/src/c++20/atomic.cc index a3ec92a10d56..4120e1a0817f 100644 --- a/libstdc++-v3/src/c++20/atomic.cc +++ b/libstdc++-v3/src/c++20/atomic.cc @@ -397,17 +397,18 @@ __cond_wait_until(__condvar& __cv, mutex& __mx, } #endif // ! HAVE_PLATFORM_TIMED_WAIT -// Like __spin_impl, always returns _M_has_val == true. +// Unlike __spin_impl, does not always return _M_has_val == true. +// If the deadline has already passed then no fresh value is loaded. __wait_result_type __spin_until_impl(const __platform_wait_t* __addr, const __wait_args_base& __args, const __wait_clock_t::time_point& __deadline) { - auto __t0 = __wait_clock_t::now(); using namespace literals::chrono_literals; - __platform_wait_t __val{}; - auto __now = __wait_clock_t::now(); + __wait_result_type __res{}; + auto __t0 = __wait_clock_t::now(); + auto __now = __t0; for (; __now < __deadline; __now = __wait_clock_t::now()) { auto __elapsed = __now - __t0; @@ -422,16 +423,21 @@ __spin_until_impl(const __platform_wait_t* __addr, __thread_yield(); else { - auto __res = __detail::__spin_impl(__addr, __args); + __res = __detail::__spin_impl(__addr, __args); if (!__res._M_timeout) return __res; } - __atomic_load(__addr, &__val, __args._M_order); - if (__val != __args._M_old) - return { ._M_val = __val, ._M_has_val = true, ._M_timeout = false }; + __atomic_load(__addr, &__res._M_val, __args._M_order); + __res._M_has_val = true; + if (__res._M_val != __args._M_old) + { + __res._M_timeout = false; + return __res; + } } - return { ._M_val = __val, ._M_has_val = true, ._M_timeout = true }; + __res._M_timeout = true; + return __res; } } // namespace -- 2.49.0