C++ Logo

std-discussion

Advanced search

Re: Synchronization of atomic notify and wait

From: Thiago Macieira <thiago_at_[hidden]>
Date: Mon, 25 Jul 2022 22:45:06 -0700
On Monday, 25 July 2022 19:02:14 PDT Andrey Semashev via Std-Discussion wrote:
> On 7/26/22 03:49, Thiago Macieira via Std-Discussion wrote:
> > On Monday, 25 July 2022 17:26:56 PDT Ryan Nicholl wrote:
> >> 64 bit wait is just two 32bit waits right next to each other... not
> >> complicated with waitv. So yes, waitv allows any size wait.
> >
> > Right, for 64-bit you could do that. But you couldn't do a half 32-bit
> > wait to support uint16_t or, for that matter, a quarter-word wait to wait
> > on an atomic<bool> or atomic_flag.
>
> You can, with masking. It may upset sanitizers and cause excessive
> spurious wakeups, but it'll work. I was under impression that
> gcc/libstdc++ used masking when small enough atomics were not supported
> natively and I'd be surprised if they didn't do this for wait/notify.

Do you mean by using FUTEX_WAIT_BITSET? Hmm.. interesting idea. It might be
possible, but it also needs to be aligned (see get_futex_key[1]), which means
the mask also becomes address-dependent. That means you're right that it would
cause spurious wake-ups if the other bytes in the word got woken up.

Anyway, no, they do not use this technique.

libstdc++ uses direct futexes ONLY for 4-byte scalar types with alignment
bigger than or equal to int's (so not for std::complex<int16_t>). For
everything else, as I said previously, it uses the futex on a global int that
is hashed by your atomic's pointer address.

libc++ never does it inline. It has special code for dealing with ints and
only ints (read: not for unsigned ints) on Linux, while for everything else
it's simply based on the pointer address.

IMNSHO, both designs are flawed because they do not allow for future extension.
libstdc++'s is entirely inline, so it can't be changed. libc++ failed by not
passing the size (and probably the alignment) of the type being waited on (see
[2]), so the internals cannot be updated with futex_waitv or a similar future
technique. They're both locked in until they decide to break ABI on their
libraries. At best, it could be an opt-in choice for code, but that's just a
partial ABI break by another name, since you need to ensure that all waiters
and notifiers on that atomic have made the same choice.

libstdc++ took my advice and made std::counting_semaphore count up to INT_MAX
(not PTRDIFF_MAX) so can be backed by int and use a futex directly.

[1] https://code.woboq.org/linux/linux/kernel/futex.c.html#get_futex_key
[2] https://github.com/llvm/llvm-project/blob/main/libcxx/include/
atomic#L1478-L1486
-- 
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel DPG Cloud Engineering

Received on 2022-07-26 05:45:09