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.

Reply via email to