1/*-------------------------------------------------------------------------
4 * Implement higher level operations based on some lower level atomic
7 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
10 * src/include/port/atomics/generic.h
12 *-------------------------------------------------------------------------
15/* intentionally no include guards, should only be included by atomics.h */
16#ifndef INSIDE_ATOMICS_H
17# error "should be included via atomics.h"
21 * If read or write barriers are undefined, we upgrade them to full memory
24#if !defined(pg_read_barrier_impl)
25 # define pg_read_barrier_impl pg_memory_barrier_impl
27#if !defined(pg_write_barrier_impl)
28 # define pg_write_barrier_impl pg_memory_barrier_impl
31#ifndef PG_HAVE_SPIN_DELAY
32#define PG_HAVE_SPIN_DELAY
33 #define pg_spin_delay_impl() ((void)0)
38#if !defined(PG_HAVE_ATOMIC_FLAG_SUPPORT) && defined(PG_HAVE_ATOMIC_U32_SUPPORT)
39#define PG_HAVE_ATOMIC_FLAG_SUPPORT
43#ifndef PG_HAVE_ATOMIC_READ_U32
44 #define PG_HAVE_ATOMIC_READ_U32
52#ifndef PG_HAVE_ATOMIC_WRITE_U32
53 #define PG_HAVE_ATOMIC_WRITE_U32
61#ifndef PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32
62 #define PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32
71 * provide fallback for test_and_set using atomic_exchange if available
73#if !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) && defined(PG_HAVE_ATOMIC_EXCHANGE_U32)
75#define PG_HAVE_ATOMIC_INIT_FLAG
77pg_atomic_init_flag_impl(
volatile pg_atomic_flag *ptr)
82#define PG_HAVE_ATOMIC_TEST_SET_FLAG
84pg_atomic_test_set_flag_impl(
volatile pg_atomic_flag *ptr)
89#define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
91pg_atomic_unlocked_test_flag_impl(
volatile pg_atomic_flag *ptr)
97#define PG_HAVE_ATOMIC_CLEAR_FLAG
99pg_atomic_clear_flag_impl(
volatile pg_atomic_flag *ptr)
101 /* XXX: release semantics suffice? */
107 * provide fallback for test_and_set using atomic_compare_exchange if
110#elif !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
112#define PG_HAVE_ATOMIC_INIT_FLAG
114pg_atomic_init_flag_impl(
volatile pg_atomic_flag *ptr)
119#define PG_HAVE_ATOMIC_TEST_SET_FLAG
121pg_atomic_test_set_flag_impl(
volatile pg_atomic_flag *ptr)
127#define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
129pg_atomic_unlocked_test_flag_impl(
volatile pg_atomic_flag *ptr)
134#define PG_HAVE_ATOMIC_CLEAR_FLAG
136pg_atomic_clear_flag_impl(
volatile pg_atomic_flag *ptr)
138 /* XXX: release semantics suffice? */
143#elif !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG)
144# error "No pg_atomic_test_and_set provided"
145#endif /* !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) */
148#ifndef PG_HAVE_ATOMIC_INIT_U32
149 #define PG_HAVE_ATOMIC_INIT_U32
157#if !defined(PG_HAVE_ATOMIC_EXCHANGE_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
158#define PG_HAVE_ATOMIC_EXCHANGE_U32
163 old = ptr->
value;
/* ok if read is not atomic */
170#if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
171#define PG_HAVE_ATOMIC_FETCH_ADD_U32
176 old = ptr->
value;
/* ok if read is not atomic */
183#if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
184#define PG_HAVE_ATOMIC_FETCH_SUB_U32
192#if !defined(PG_HAVE_ATOMIC_FETCH_AND_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
193#define PG_HAVE_ATOMIC_FETCH_AND_U32
198 old = ptr->
value;
/* ok if read is not atomic */
205#if !defined(PG_HAVE_ATOMIC_FETCH_OR_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
206#define PG_HAVE_ATOMIC_FETCH_OR_U32
211 old = ptr->
value;
/* ok if read is not atomic */
218#if !defined(PG_HAVE_ATOMIC_ADD_FETCH_U32) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U32)
219#define PG_HAVE_ATOMIC_ADD_FETCH_U32
227#if !defined(PG_HAVE_ATOMIC_SUB_FETCH_U32) && defined(PG_HAVE_ATOMIC_FETCH_SUB_U32)
228#define PG_HAVE_ATOMIC_SUB_FETCH_U32
232 return pg_atomic_fetch_sub_u32_impl(ptr, sub_) - sub_;
236#if !defined(PG_HAVE_ATOMIC_READ_MEMBARRIER_U32) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U32)
237#define PG_HAVE_ATOMIC_READ_MEMBARRIER_U32
245#if !defined(PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U32) && defined(PG_HAVE_ATOMIC_EXCHANGE_U32)
246#define PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U32
254#if !defined(PG_HAVE_ATOMIC_EXCHANGE_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
255#define PG_HAVE_ATOMIC_EXCHANGE_U64
260 old = ptr->
value;
/* ok if read is not atomic */
267#ifndef PG_HAVE_ATOMIC_WRITE_U64
268 #define PG_HAVE_ATOMIC_WRITE_U64
270#if defined(PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY) && \
271 !defined(PG_HAVE_ATOMIC_U64_SIMULATION)
277 * On this platform aligned 64bit writes are guaranteed to be atomic,
278 * except if using the fallback implementation, where can't guarantee the
279 * required alignment.
291 * 64 bit writes aren't safe on all platforms. In the generic
292 * implementation implement them as an atomic exchange.
294 pg_atomic_exchange_u64_impl(ptr,
val);
297#endif /* PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY && !PG_HAVE_ATOMIC_U64_SIMULATION */
298#endif /* PG_HAVE_ATOMIC_WRITE_U64 */
300#ifndef PG_HAVE_ATOMIC_READ_U64
301 #define PG_HAVE_ATOMIC_READ_U64
303#if defined(PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY) && \
304 !defined(PG_HAVE_ATOMIC_U64_SIMULATION)
310 * On this platform aligned 64-bit reads are guaranteed to be atomic.
324 * 64-bit reads aren't atomic on all platforms. In the generic
325 * implementation implement them as a compare/exchange with 0. That'll
326 * fail or succeed, but always return the old value. Possibly might store
327 * a 0, but only if the previous value also was a 0 - i.e. harmless.
333#endif /* PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY && !PG_HAVE_ATOMIC_U64_SIMULATION */
334#endif /* PG_HAVE_ATOMIC_READ_U64 */
336#ifndef PG_HAVE_ATOMIC_INIT_U64
337 #define PG_HAVE_ATOMIC_INIT_U64
345#if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
346#define PG_HAVE_ATOMIC_FETCH_ADD_U64
351 old = ptr->
value;
/* ok if read is not atomic */
358#if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
359#define PG_HAVE_ATOMIC_FETCH_SUB_U64
367#if !defined(PG_HAVE_ATOMIC_FETCH_AND_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
368#define PG_HAVE_ATOMIC_FETCH_AND_U64
373 old = ptr->
value;
/* ok if read is not atomic */
380#if !defined(PG_HAVE_ATOMIC_FETCH_OR_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
381#define PG_HAVE_ATOMIC_FETCH_OR_U64
386 old = ptr->
value;
/* ok if read is not atomic */
393#if !defined(PG_HAVE_ATOMIC_ADD_FETCH_U64) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U64)
394#define PG_HAVE_ATOMIC_ADD_FETCH_U64
402#if !defined(PG_HAVE_ATOMIC_SUB_FETCH_U64) && defined(PG_HAVE_ATOMIC_FETCH_SUB_U64)
403#define PG_HAVE_ATOMIC_SUB_FETCH_U64
407 return pg_atomic_fetch_sub_u64_impl(ptr, sub_) - sub_;
411#if !defined(PG_HAVE_ATOMIC_READ_MEMBARRIER_U64) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U64)
412#define PG_HAVE_ATOMIC_READ_MEMBARRIER_U64
420#if !defined(PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U64) && defined(PG_HAVE_ATOMIC_EXCHANGE_U64)
421#define PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U64
425 (void) pg_atomic_exchange_u64_impl(ptr,
val);
static bool pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 *expected, uint32 newval)
static uint32 pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
uint64 pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
bool pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 *expected, uint64 newval)
#define AssertPointerAlignment(ptr, bndr)
#define pg_memory_barrier_impl()
static uint32 pg_atomic_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 newval)
static void pg_atomic_unlocked_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val)
static uint64 pg_atomic_read_u64_impl(volatile pg_atomic_uint64 *ptr)
static void pg_atomic_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val)
static void pg_atomic_init_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val_)
static void pg_atomic_write_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val)
static uint32 pg_atomic_read_u32_impl(volatile pg_atomic_uint32 *ptr)
static void pg_atomic_init_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val_)