On Fri, Jan 9, 2026 at 7:43 PM Jonathan Wakely <[email protected]> wrote:
> 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? > Looks good. > > > 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. > >
