On Fri, 9 Jan 2026 at 17:55, Tomasz Kaminski <[email protected]> wrote: > > > > On Fri, Jan 9, 2026 at 6:44 PM Jonathan Wakely <[email protected]> wrote: >> >> As noted in Bug 122878 comment 2, the _M_try_acquire_for implementation >> doesn't reduce the remaining timeout each time it returns from an atomic >> waiting function. This means that it can wait longer than requested, or >> even loop forever. If there is a spurious wake from the timed waiting >> function (__wait_until_impl) it will return indicating no timeout >> occurred, which means the caller will check the value and potentially >> sleep again. If spurious wakes happen every time, it will just keep >> sleeping in a loop forever. This is observed to actually happen on >> FreeBSD 14.0-STABLE where pthread_cond_timedwait gets a spurious wake >> and so never times out. >> >> The solution in this commit is to replace the implementation of >> _M_try_acquire_for with a call to _M_try_acquire_until, converting the >> relative timeout to an absolute timeout against the steady clock. > > Could you mention that __atomic_wait"_for was already doing that anyway, > for non-zero durations, as we only define __platform_wait_until primitive. >> >> >> As noted in comment 4 of the PR, this requires some changes to >> _M_try_acquire which was relying on an implementation detail of >> _M_try_acquire_for, namely that waiting for a zero duration will just >> check if the value changes in a spinloop, without actually sleeping. >> This behaviour is desirable for _M_try_acquire so that it can handle >> short-lived contention without failing immediately. To preserve that >> behaviour of _M_try_acquire it is changed to do its own loop and to call >> __atomic_wait_address_for directly to do the spinloop. > > I would add to call __atomic_wait_address_for with zero duration.
How's this? The solution in this commit is to replace the implementation of _M_try_acquire_for with a call to _M_try_acquire_until, converting the relative timeout to an absolute timeout against the steady clock. This is what ends up happening anyway, because we only have a __wait_until_impl entry point into the library internals, so __atomic_wait_address_for already converts the relative timeout to an absolute timeout (except for the special case of a zero-value duration, which only checks for an update while spinning for a finite number of iterations, and doesn't sleep). As noted in comment 4 of the PR, this requires some changes to _M_try_acquire which was relying on the behaviour of _M_try_acquire_for for zero-value durations. That behaviour is desirable for _M_try_acquire so that it can handle short-lived contention without failing immediately. To preserve that behaviour of _M_try_acquire it is changed to do its own loop and to call __atomic_wait_address_for directly with a zero duration, to do the spinloop.
