Re: locked reads for atomics

From: Andres Freund <andres(at)anarazel(dot)de>
To: Nathan Bossart <nathandbossart(at)gmail(dot)com>
Cc: pgsql-hackers(at)postgresql(dot)org
Subject: Re: locked reads for atomics
Date: 2023-11-11 02:48:39
Message-ID: 20231111024839.op2d2id33x777mll@alap3.anarazel.de
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

On 2023-11-10 20:38:13 -0600, Nathan Bossart wrote:
> On Fri, Nov 10, 2023 at 03:11:50PM -0800, Andres Freund wrote:
> > On 2023-11-10 14:51:28 -0600, Nathan Bossart wrote:
> >> + * This read is guaranteed to read the current value,
> >
> > It doesn't guarantee that *at all*. What it guarantees is solely that the
> > current CPU won't be doing something that could lead to reading an outdated
> > value. To actually ensure the value is up2date, the modifying side also needs
> > to have used a form of barrier (in the form of fetch_add, compare_exchange,
> > etc or an explicit barrier).
>
> Okay, I think I was missing that this doesn't work along with
> pg_atomic_write_u32() because that doesn't have any barrier semantics
> (probably because the spinlock version does). IIUC you'd want to use
> pg_atomic_exchange_u32() to write the value instead, which seems to really
> just be another compare/exchange under the hood.

Yes. We should optimize pg_atomic_exchange_u32() one of these days - it can be
done *far* faster than a cmpxchg. When I was adding the atomic abstraction
there was concern with utilizing too many different atomic instructions. I
didn't really agree back then, but these days I really don't see a reason to
not use a few more intrinsics.

> Speaking of the spinlock implementation of pg_atomic_write_u32(), I've been
> staring at this comment for a while and can't make sense of it:
>
> void
> pg_atomic_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val)
> {
> /*
> * One might think that an unlocked write doesn't need to acquire the
> * spinlock, but one would be wrong. Even an unlocked write has to cause a
> * concurrent pg_atomic_compare_exchange_u32() (et al) to fail.
> */
> SpinLockAcquire((slock_t *) &ptr->sema);
> ptr->value = val;
> SpinLockRelease((slock_t *) &ptr->sema);
> }
>
> It refers to "unlocked writes," but this isn't
> pg_atomic_unlocked_write_u32_impl(). The original thread for this comment
> [0] doesn't offer any hints, either. Does "unlocked" mean something
> different here, such as "write without any barrier semantics?"

It's just about not using the spinlock. If we were to *not* use a spinlock
here, we'd break pg_atomic_compare_exchange_u32(), because the
spinlock-implementation of pg_atomic_compare_exchange_u32() needs to actually
be able to rely on no concurrent changes to the value to happen.

Greetings,

Andres Freund

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Erik Rijkers 2023-11-11 02:52:42 Re: remaining sql/json patches
Previous Message Nathan Bossart 2023-11-11 02:38:13 Re: locked reads for atomics