[gcc r16-1076] libstdc++: Fix errors and incorrect returns in atomic timed waits
Jonathan Wakely
redi@gcc.gnu.org
Tue Jun 3 10:18:35 GMT 2025
https://gcc.gnu.org/g:973c43faf077736de420a1dd9d0729096db48cc0
commit r16-1076-g973c43faf077736de420a1dd9d0729096db48cc0
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Mon Jun 2 11:24:32 2025 +0100
libstdc++: Fix errors and incorrect returns in atomic timed waits
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.
Diff:
---
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
More information about the Libstdc++-cvs
mailing list