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.
The __atomic_wait_address_until_v and __atomic_wait_address_for_v function templates are apparently never used or instantiated, because they don't compile. This fixes them, but they're still unused. I plan to make use of them in a later commit. In __atomic_wait_address_until_v, __res.first in the return statement should have also been changed when r16-1000-g225622398a9631 changed __wait_result_type, and &__args should have been changed to just __args by r16-988-g219bb905a60d95. In __atomic_wait_address_for_v, the parameter is a copy & paste error and should use chrono::duration not chrono::time_point 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. (__atomic_wait_address_until_v): Do not take address of __args in call to __detail::__wait_until. Fix return statement to refer to member of __wait_result_type. (__atomic_wait_address_for_v): Change parameter type from time_point to duration. * src/c++20/atomic.cc (__spin_until_impl): Fix incorrect return value. Reuse result of first call to clock. --- This combined patch replaces: [PATCH v2] libstdc++: Fix errors in atomic timed waiting functions [PATCH v2] libstdc++: Fix incorrect return values and comments on atomic timed waits Tested x86_64-linux. Pushed to trunk. libstdc++-v3/include/bits/atomic_timed_wait.h | 7 +++--- libstdc++-v3/src/c++20/atomic.cc | 24 ++++++++++++------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h index 230afbc96e7d..bd2e6bf61ecf 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, @@ -158,8 +157,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool __bare_wait = false) noexcept { __detail::__wait_args __args{ __addr, __old, __order, __bare_wait }; - auto __res = __detail::__wait_until(__addr, &__args, __atime); - return __res.first; // C++26 will also return last observed __val + auto __res = __detail::__wait_until(__addr, __args, __atime); + return !__res._M_timeout; // C++26 will also return last observed __val } template<typename _Tp, typename _ValFn, @@ -203,7 +202,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __atomic_wait_address_for_v(const __detail::__platform_wait_t* __addr, __detail::__platform_wait_t __old, int __order, - const chrono::time_point<_Rep, _Period>& __rtime, + const chrono::duration<_Rep, _Period>& __rtime, bool __bare_wait = false) noexcept { __detail::__wait_args __args{ __addr, __old, __order, __bare_wait }; 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