public inbox for [email protected]  
help / color / mirror / Atom feed
Trying out <stdatomic.h>
19+ messages / 7 participants
[nested] [flat]

* Trying out <stdatomic.h>
@ 2025-11-10 13:17 Thomas Munro <[email protected]>
  2025-11-10 13:57 ` Re: Trying out <stdatomic.h> Heikki Linnakangas <[email protected]>
  2025-11-23 15:22 ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
  0 siblings, 2 replies; 19+ messages in thread

From: Thomas Munro @ 2025-11-10 13:17 UTC (permalink / raw)
  To: PostgreSQL Hackers <[email protected]>

Hi,

Here is an experimental patch to try out standard C (and C++) atomics
to implement port/atomics.h, and also add more types and operations.
It's mostly just redirecting our names to the standard ones, except
for our barriers and slightly extended pg_atomic_flag, so there isn't
much left of the code.

Here also is a semi-independent patch to implement storage/spin.h with
pg_atomic_flag.  It keeps a small amount of the architecture-specific
magic, but moves it out to src/port/spin_delay.h.

I'm not saying they're correct, performant or portable yet, that'll
require studying codegen and performance on a bunch of weird and
wonderful systems, but they at least passes basic testing on the usual
suspects and CI systems, except for Windows which needs a newer
toolchain so I haven't tried yet.  It should hopefully just work™ on
VS 2022 (same version that provides <threads.h>, about which more
soon).

All that being the case, it's not far enough along to be a serious
proposal, but I imagine others will be looking into things like this
since we pulled the trigger on C11 and I figured I might as well share
a basic working patch set to avoid duplicated effort...   Hopefully it
works well enough to kick the tyres and try to find the difficult
problems, test it out on weird systems, etc etc.


Attachments:

  [application/octet-stream] v1-0001-Add-some-missing-include-limits.h.patch (1.7K, 2-v1-0001-Add-some-missing-include-limits.h.patch)
  download | inline diff:
From 000dd41412fa39fc0047a7ddc9ca76b1acb7b437 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Mon, 10 Nov 2025 15:04:38 +1300
Subject: [PATCH v1 1/4] Add some missing #include <limits.h>.

These files relied on transitive inclusion via port/atomics.h for
constants CHAR_BIT and INT_MAX.
---
 src/backend/access/brin/brin_bloom.c          | 1 +
 src/backend/lib/dshash.c                      | 2 ++
 src/backend/storage/lmgr/condition_variable.c | 2 ++
 3 files changed, 5 insertions(+)

diff --git a/src/backend/access/brin/brin_bloom.c b/src/backend/access/brin/brin_bloom.c
index d6da3abc8de..64dbb7b8532 100644
--- a/src/backend/access/brin/brin_bloom.c
+++ b/src/backend/access/brin/brin_bloom.c
@@ -114,6 +114,7 @@
  */
 #include "postgres.h"
 
+#include <limits.h>
 #include <math.h>
 
 #include "access/brin.h"
diff --git a/src/backend/lib/dshash.c b/src/backend/lib/dshash.c
index b8d031f2015..2ffb4c106bd 100644
--- a/src/backend/lib/dshash.c
+++ b/src/backend/lib/dshash.c
@@ -36,6 +36,8 @@
 #include "storage/lwlock.h"
 #include "utils/dsa.h"
 
+#include <limits.h>
+
 /*
  * An item in the hash table.  This wraps the user's entry object in an
  * envelop that holds a pointer back to the bucket and a pointer to the next
diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c
index 228303e77f7..bee9525b540 100644
--- a/src/backend/storage/lmgr/condition_variable.c
+++ b/src/backend/storage/lmgr/condition_variable.c
@@ -25,6 +25,8 @@
 #include "storage/proclist.h"
 #include "storage/spin.h"
 
+#include <limits.h>
+
 /* Initially, we are not prepared to sleep on any condition variable. */
 static ConditionVariable *cv_sleep_target = NULL;
 
-- 
2.50.1 (Apple Git-155)



  [application/octet-stream] v1-0002-Redefine-port-atomics.h-on-top-of-stdatomic.h.patch (67.9K, 3-v1-0002-Redefine-port-atomics.h-on-top-of-stdatomic.h.patch)
  download | inline diff:
From 7eac4aecb0e608180685a7215fda7c06f200c1a1 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Tue, 2 Jul 2024 22:31:42 +1200
Subject: [PATCH v1 2/4] Redefine port/atomics.h on top of <stdatomic.h>.

 * Redirect types and functions to standard C/C++
 * Use <atomic> instead for C++11 extensions (as formalized by C++23)
 * Add pg_atomic_uint8, pg_atomic_uint16 and pg_atomic(T)
 * Provide generic pg_atomic_read(), pg_atomic_write()
 * Assume that most basic operations will be called by
   standardized generics in future code, eg atomic_fetch_add()
 * Forward all the traditional _32, _64 function names for
   existing code
 * Reimplement pg_atomic_flag with pg_atomic(uint8) to allow relaxed load
   (impossible with standard atomic_flag, and pg_atomic(bool) doesn't seem
   to be portable enough)
 * Let the compiler/runtime emulate 64 bit atomics with locks for armv7
 * The per-compiler headers now just define pg_compiler_barrier_impl()
 * The per-arch headers now optionally define
   pg_{memory,read,write}_barrier_impl() but only if they think they can
   do something better than compilers (to investigate...)
 * Drop the secondary copy of the ancient spinlock ops from atomics
 * Drop arch-{arm,ppc}.h, fallback.h and generic.h

WIP!

Need to research generated code on all architectures and see if anything
important is lost.  Need to think about whether alignment
assertions are worth saving.  Need to test on Visual Studio 2022 with
/experimental:c11atomics (?).
---
 src/include/port/atomics.h              | 621 ++++++------------------
 src/include/port/atomics/arch-arm.h     |  32 --
 src/include/port/atomics/arch-ppc.h     | 256 ----------
 src/include/port/atomics/arch-x86.h     | 205 --------
 src/include/port/atomics/fallback.h     |  42 --
 src/include/port/atomics/generic-gcc.h  | 307 +-----------
 src/include/port/atomics/generic-msvc.h |  98 +---
 src/include/port/atomics/generic.h      | 427 ----------------
 src/tools/pgindent/typedefs.list        |   2 +
 9 files changed, 166 insertions(+), 1824 deletions(-)
 delete mode 100644 src/include/port/atomics/arch-arm.h
 delete mode 100644 src/include/port/atomics/arch-ppc.h
 delete mode 100644 src/include/port/atomics/fallback.h
 delete mode 100644 src/include/port/atomics/generic.h

diff --git a/src/include/port/atomics.h b/src/include/port/atomics.h
index 96f1858da97..61a6b4322fd 100644
--- a/src/include/port/atomics.h
+++ b/src/include/port/atomics.h
@@ -3,24 +3,33 @@
  * atomics.h
  *	  Atomic operations.
  *
- * Hardware and compiler dependent functions for manipulating memory
- * atomically and dealing with cache coherency. Used to implement locking
- * facilities and lockless algorithms/data structures.
+ * These interfaces are for manipulating memory atomically and dealing with
+ * cache coherency. They can be used to implement locking facilities and
+ * lockless algorithms/data structures.
  *
- * To bring up postgres on a platform/compiler at the very least
- * implementations for the following operations should be provided:
- * * pg_compiler_barrier(), pg_write_barrier(), pg_read_barrier()
- * * pg_atomic_compare_exchange_u32(), pg_atomic_fetch_add_u32()
- * * pg_atomic_test_set_flag(), pg_atomic_init_flag(), pg_atomic_clear_flag()
- * * PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY should be defined if appropriate.
+ * This is mostly a renaming of <stdatomic.h>, with some differences:
  *
- * There exist generic, hardware independent, implementations for several
- * compilers which might be sufficient, although possibly not optimal, for a
- * new platform. If no such generic implementation is available spinlocks will
- * be used to implement the 64-bit parts of the API.
+ * * read/write barriers (weaker than acquire/release)
+ * * they affect even non-atomic access without dependency on atomic access
+ * * pg_atomic_flag semantics don't allow mapping to atomic_flag
  *
- * Implement _u64 atomics if and only if your platform can use them
- * efficiently (and obviously correctly).
+ * PostgreSQL atomic type width assumptions:
+ *
+ * 8, 16:  Required to be lock-free (even though implemented with wider
+ *         instructions by the compiler on some RISC-V systems).
+ *
+ * 32:     Required to be lock-free.  No known modern system lacks them.
+ *
+ * 64:     These can reasonably be expected to be lock-free and fast on
+ *         all modern-ish systems.  For one known low-end system  they are
+ *         emulated by the compiler/runtime with locks (armv7).
+ *
+ * In all cases values must be well aligned or undefined behavior results.
+ *
+ * To bring up postgres on a compiler, provide:
+ * * pg_compiler_barrier()
+ * Optionally also:
+ * * pg_memory_barrier(), pg_write_barrier(), pg_read_barrier()
  *
  * Use higher level functionality (lwlocks, spinlocks, heavyweight locks)
  * whenever possible. Writing correct code using these facilities is hard.
@@ -38,48 +47,59 @@
 #ifndef ATOMICS_H
 #define ATOMICS_H
 
-#ifdef FRONTEND
-#error "atomics.h may not be included from frontend code"
-#endif
-
 #define INSIDE_ATOMICS_H
 
-#include <limits.h>
+#if defined(__cplusplus) && __cplusplus < 202302L
+/* C++11 couldn't handle <stdatomic.h>.  Use approach from C++23 33.5.12. */
+extern "C++"
+{
+#include <atomic>
+#define pg_atomic(T) std::atomic<T>
+	using		std::memory_order_relaxed;
+	using		std::memory_order_acquire;
+	using		std::memory_order_release;
+	using		std::memory_order_acq_rel;
+	using		std::memory_order_seq_cst;
+}
+#else
+#include <stdatomic.h>
+#define pg_atomic(T) _Atomic(T)
+#endif
+
+/* Assumptions about lock-free access. */
+StaticAssertDecl(ATOMIC_CHAR_LOCK_FREE >= 2, "need lock-free 8-bit atomics");
+StaticAssertDecl(ATOMIC_SHORT_LOCK_FREE >= 2, "need lock-free 16-bit atomics");
+StaticAssertDecl(ATOMIC_INT_LOCK_FREE >= 2, "need lock-free 32-bit atomics");
+
+/* Can't use standard atomic_flag due to extended semantics, see below. */
+typedef pg_atomic(uint8)
+pg_atomic_flag;
+
+/* Common supported atomic integer types. */
+typedef pg_atomic(uint8)
+pg_atomic_uint8;
+typedef pg_atomic(uint16)
+pg_atomic_uint16;
+typedef pg_atomic(uint32)
+pg_atomic_uint32;
+typedef pg_atomic(uint64)
+pg_atomic_uint64;
 
 /*
  * First a set of architecture specific files is included.
  *
- * These files can provide the full set of atomics or can do pretty much
- * nothing if all the compilers commonly used on these platforms provide
- * usable generics.
- *
- * Don't add an inline assembly of the actual atomic operations if all the
- * common implementations of your platform provide intrinsics. Intrinsics are
- * much easier to understand and potentially support more architectures.
- *
  * It will often make sense to define memory barrier semantics here, since
  * e.g. generic compiler intrinsics for x86 memory barriers can't know that
  * postgres doesn't need x86 read/write barriers do anything more than a
  * compiler barrier.
- *
  */
-#if defined(__arm__) || defined(__arm) || defined(__aarch64__)
-#include "port/atomics/arch-arm.h"
-#elif defined(__i386__) || defined(__i386) || defined(__x86_64__)
+#if defined(__i386__) || defined(__i386) || defined(__x86_64__)
 #include "port/atomics/arch-x86.h"
-#elif defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__)
-#include "port/atomics/arch-ppc.h"
 #endif
 
 /*
  * Compiler specific, but architecture independent implementations.
- *
- * Provide architecture independent implementations of the atomic
- * facilities. At the very least compiler barriers should be provided, but a
- * full implementation of
- * * pg_compiler_barrier(), pg_write_barrier(), pg_read_barrier()
- * * pg_atomic_compare_exchange_u32(), pg_atomic_fetch_add_u32()
- * using compiler intrinsics are a good idea.
+ * This defines compiler barriers.
  */
 /*
  * gcc or compatible, including clang and icc.
@@ -93,29 +113,9 @@
 #endif
 
 /* Fail if we couldn't find implementations of required facilities. */
-#if !defined(PG_HAVE_ATOMIC_U32_SUPPORT)
-#error "could not find an implementation of pg_atomic_uint32"
-#endif
 #if !defined(pg_compiler_barrier_impl)
 #error "could not find an implementation of pg_compiler_barrier"
 #endif
-#if !defined(pg_memory_barrier_impl)
-#error "could not find an implementation of pg_memory_barrier_impl"
-#endif
-
-
-/*
- * Provide a spinlock-based implementation of the 64 bit variants, if
- * necessary.
- */
-#include "port/atomics/fallback.h"
-
-/*
- * Provide additional operations using supported infrastructure. These are
- * expected to be efficient if the underlying atomic operations are efficient.
- */
-#include "port/atomics/generic.h"
-
 
 /*
  * pg_compiler_barrier - prevent the compiler from moving code across
@@ -125,6 +125,10 @@
  * reorder loads or stores to main memory around the barrier.  However, the
  * CPU may still reorder loads or stores at runtime, if the architecture's
  * memory model permits this.
+ *
+ * Unlike standard atomic_signal_fence(), pg_compiler_barrier() prevents
+ * reordering of non-atomic, non-volatile accesses, so a compiler-specific
+ * definition is required.
  */
 #define pg_compiler_barrier()	pg_compiler_barrier_impl()
 
@@ -137,8 +141,20 @@
  * loads and stores are totally ordered (which is not the case on most
  * architectures) this requires issuing some sort of memory fencing
  * instruction.
+ *
+ * Unlike standard atomic_thread_fence(), pg_{read,write}_barrier() affects
+ * non-atomic, non-volatile accesses.
  */
-#define pg_memory_barrier() pg_memory_barrier_impl()
+static inline void
+pg_memory_barrier(void)
+{
+#ifdef pg_memory_barrier_impl
+	pg_memory_barrier_impl();
+#else
+	pg_compiler_barrier();
+	atomic_thread_fence(memory_order_seq_cst);
+#endif
+}
 
 /*
  * pg_(read|write)_barrier - prevent the CPU from reordering memory access
@@ -150,427 +166,116 @@
  * are thus weaker than a full memory barrier, but stronger than a compiler
  * barrier.  In practice, on machines with strong memory ordering, read and
  * write barriers may require nothing more than a compiler barrier.
- */
-#define pg_read_barrier()	pg_read_barrier_impl()
-#define pg_write_barrier()	pg_write_barrier_impl()
-
-/*
- * Spinloop delay - Allow CPU to relax in busy loops
- */
-#define pg_spin_delay() pg_spin_delay_impl()
-
-/*
- * pg_atomic_init_flag - initialize atomic flag.
- *
- * No barrier semantics.
- */
-static inline void
-pg_atomic_init_flag(volatile pg_atomic_flag *ptr)
-{
-	pg_atomic_init_flag_impl(ptr);
-}
-
-/*
- * pg_atomic_test_set_flag - TAS()
- *
- * Returns true if the flag has successfully been set, false otherwise.
- *
- * Acquire (including read barrier) semantics.
- */
-static inline bool
-pg_atomic_test_set_flag(volatile pg_atomic_flag *ptr)
-{
-	return pg_atomic_test_set_flag_impl(ptr);
-}
-
-/*
- * pg_atomic_unlocked_test_flag - Check if the lock is free
- *
- * Returns true if the flag currently is not set, false otherwise.
- *
- * No barrier semantics.
- */
-static inline bool
-pg_atomic_unlocked_test_flag(volatile pg_atomic_flag *ptr)
-{
-	return pg_atomic_unlocked_test_flag_impl(ptr);
-}
-
-/*
- * pg_atomic_clear_flag - release lock set by TAS()
  *
- * Release (including write barrier) semantics.
+ * Unlike standard atomic_thread_fence(), pg_{read,write}_barrier() affects
+ * non-atomic, non-volatile accesses.  The default implementation uses
+ * acquire/release fences, but these are strictly stronger than read/write.
  */
-static inline void
-pg_atomic_clear_flag(volatile pg_atomic_flag *ptr)
-{
-	pg_atomic_clear_flag_impl(ptr);
-}
-
 
-/*
- * pg_atomic_init_u32 - initialize atomic variable
- *
- * Has to be done before any concurrent usage..
- *
- * No barrier semantics.
- */
 static inline void
-pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
-{
-	AssertPointerAlignment(ptr, 4);
-
-	pg_atomic_init_u32_impl(ptr, val);
-}
-
-/*
- * pg_atomic_read_u32 - unlocked read from atomic variable.
- *
- * The read is guaranteed to return a value as it has been written by this or
- * another process at some point in the past. There's however no cache
- * coherency interaction guaranteeing the value hasn't since been written to
- * again.
- *
- * No barrier semantics.
- */
-static inline uint32
-pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
-{
-	AssertPointerAlignment(ptr, 4);
-	return pg_atomic_read_u32_impl(ptr);
-}
-
-/*
- * pg_atomic_read_membarrier_u32 - read with barrier semantics.
- *
- * This read is guaranteed to return the current value, provided that the value
- * is only ever updated via operations with barrier semantics, such as
- * pg_atomic_compare_exchange_u32() and pg_atomic_write_membarrier_u32().
- * While this may be less performant than pg_atomic_read_u32(), it may be
- * easier to reason about correctness with this function in less performance-
- * sensitive code.
- *
- * Full barrier semantics.
- */
-static inline uint32
-pg_atomic_read_membarrier_u32(volatile pg_atomic_uint32 *ptr)
+pg_read_barrier(void)
 {
-	AssertPointerAlignment(ptr, 4);
-
-	return pg_atomic_read_membarrier_u32_impl(ptr);
-}
-
-/*
- * pg_atomic_write_u32 - write to atomic variable.
- *
- * The write is guaranteed to succeed as a whole, i.e. it's not possible to
- * observe a partial write for any reader.  Note that this correctly interacts
- * with pg_atomic_compare_exchange_u32, in contrast to
- * pg_atomic_unlocked_write_u32().
- *
- * No barrier semantics.
- */
-static inline void
-pg_atomic_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
-{
-	AssertPointerAlignment(ptr, 4);
-
-	pg_atomic_write_u32_impl(ptr, val);
-}
-
-/*
- * pg_atomic_unlocked_write_u32 - unlocked write to atomic variable.
- *
- * The write is guaranteed to succeed as a whole, i.e. it's not possible to
- * observe a partial write for any reader.  But note that writing this way is
- * not guaranteed to correctly interact with read-modify-write operations like
- * pg_atomic_compare_exchange_u32.  This should only be used in cases where
- * minor performance regressions due to atomics emulation are unacceptable.
- *
- * No barrier semantics.
- */
-static inline void
-pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
-{
-	AssertPointerAlignment(ptr, 4);
-
-	pg_atomic_unlocked_write_u32_impl(ptr, val);
+#ifdef pg_read_barrier_impl
+	pg_read_barrier_impl();
+#else
+	pg_compiler_barrier();
+	atomic_thread_fence(memory_order_acquire);
+#endif
 }
 
-/*
- * pg_atomic_write_membarrier_u32 - write with barrier semantics.
- *
- * The write is guaranteed to succeed as a whole, i.e., it's not possible to
- * observe a partial write for any reader.  Note that this correctly interacts
- * with both pg_atomic_compare_exchange_u32() and
- * pg_atomic_read_membarrier_u32().  While this may be less performant than
- * pg_atomic_write_u32(), it may be easier to reason about correctness with
- * this function in less performance-sensitive code.
- *
- * Full barrier semantics.
- */
 static inline void
-pg_atomic_write_membarrier_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
+pg_write_barrier(void)
 {
-	AssertPointerAlignment(ptr, 4);
-
-	pg_atomic_write_membarrier_u32_impl(ptr, val);
-}
-
-/*
- * pg_atomic_exchange_u32 - exchange newval with current value
- *
- * Returns the old value of 'ptr' before the swap.
- *
- * Full barrier semantics.
- */
-static inline uint32
-pg_atomic_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 newval)
-{
-	AssertPointerAlignment(ptr, 4);
-
-	return pg_atomic_exchange_u32_impl(ptr, newval);
+#ifdef pg_write_barrier_impl
+	pg_write_barrier_impl();
+#else
+	pg_compiler_barrier();
+	atomic_thread_fence(memory_order_release);
+#endif
 }
 
 /*
- * pg_atomic_compare_exchange_u32 - CAS operation
- *
- * Atomically compare the current value of ptr with *expected and store newval
- * iff ptr and *expected have the same value. The current value of *ptr will
- * always be stored in *expected.
- *
- * Return true if values have been exchanged, false otherwise.
+ * Operations corresponding to standard atomic_flag.  We have to use an integer
+ * instead of mapping directly to the standard names, to support our relaxed
+ * check function.
  *
- * Full barrier semantics.
+ * Acquire and release fences, which are respectively stronger than read and
+ * write barriers.
  */
-static inline bool
-pg_atomic_compare_exchange_u32(volatile pg_atomic_uint32 *ptr,
-							   uint32 *expected, uint32 newval)
-{
-	AssertPointerAlignment(ptr, 4);
-	AssertPointerAlignment(expected, 4);
-
-	return pg_atomic_compare_exchange_u32_impl(ptr, expected, newval);
-}
+#define pg_atomic_init_flag(p) atomic_init((p), 1)
+#define pg_atomic_test_set_flag(p) \
+	atomic_fetch_and_explicit((p), 0, memory_order_acquire)
+#define pg_atomic_clear_flag(p) \
+	atomic_store_explicit((p), 1, memory_order_release)
+#define pg_atomic_unlocked_test_flag(p) \
+	atomic_load_explicit((p), memory_order_relaxed)
 
 /*
- * pg_atomic_fetch_add_u32 - atomically add to variable
- *
- * Returns the value of ptr before the arithmetic operation.
- *
- * Full barrier semantics.
+ * Local convention for load/store, relaxed AKA no barrier.  These are the only
+ * "generic" functions provided with pg_ prefixes.  It seems pointless to
+ * rename everything in <stdatomic.h>, but these two are PostgreSQL's
+ * established way of representing relaxed access, and a lot shorter.
  */
-static inline uint32
-pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	AssertPointerAlignment(ptr, 4);
-	return pg_atomic_fetch_add_u32_impl(ptr, add_);
-}
+#define pg_atomic_read(p) \
+	atomic_load_explicit((p), memory_order_relaxed)
+#define pg_atomic_write(p, v) \
+	atomic_store_explicit((p), (v), memory_order_relaxed)
 
 /*
- * pg_atomic_fetch_sub_u32 - atomically subtract from variable
+ * Backward-compatible type-specific function names.  Only the historical _u32
+ * and _64 names are provided.  New code and code using other atomic types
+ * should use the generic functions from the standard directly, and
+ * pg_atomic_{read,write}() for relaxed access.
  *
- * Returns the value of ptr before the arithmetic operation. Note that sub_
- * may not be INT_MIN due to platform limitations.
- *
- * Full barrier semantics.
+ * All of these except pg_atomic_(unlocked_){read,write}_{32,64} have seq cst
+ * AKA full barrier semantics.
  */
-static inline uint32
-pg_atomic_fetch_sub_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
-{
-	AssertPointerAlignment(ptr, 4);
-	Assert(sub_ != INT_MIN);
-	return pg_atomic_fetch_sub_u32_impl(ptr, sub_);
-}
+#define pg_atomic_init_u32 atomic_init
+#define pg_atomic_init_u64 atomic_init
+#define pg_atomic_read_u32 pg_atomic_read
+#define pg_atomic_read_u64 pg_atomic_read
+#define pg_atomic_write_u32 pg_atomic_write
+#define pg_atomic_write_u64 pg_atomic_write
+#define pg_atomic_unlocked_read_u32 pg_atomic_read
+#define pg_atomic_unlocked_read_u64 pg_atomic_read
+#define pg_atomic_unlocked_write_u32 pg_atomic_write
+#define pg_atomic_unlocked_write_u64 pg_atomic_write
+#define pg_atomic_read_membarrier_u32 atomic_load
+#define pg_atomic_read_membarrier_u64 atomic_load
+#define pg_atomic_write_membarrier_u32 atomic_store
+#define pg_atomic_write_membarrier_u64 atomic_store
+#define pg_atomic_exchange_u32 atomic_exchange
+#define pg_atomic_exchange_u64 atomic_exchange
+#define pg_atomic_compare_exchange_u32 atomic_compare_exchange_strong
+#define pg_atomic_compare_exchange_u64 atomic_compare_exchange_strong
+#define pg_atomic_fetch_add_u32 atomic_fetch_add
+#define pg_atomic_fetch_add_u64 atomic_fetch_add
+#define pg_atomic_fetch_sub_u32 atomic_fetch_sub
+#define pg_atomic_fetch_sub_u64 atomic_fetch_sub
+#define pg_atomic_fetch_and_u32 atomic_fetch_and
+#define pg_atomic_fetch_and_u64 atomic_fetch_and
+#define pg_atomic_fetch_or_u32 atomic_fetch_or
+#define pg_atomic_fetch_or_u64 atomic_fetch_or
 
 /*
- * pg_atomic_fetch_and_u32 - atomically bit-and and_ with variable
- *
- * Returns the value of ptr before the arithmetic operation.
- *
- * Full barrier semantics.
+ * The rest of this file defines non-fundamental convenience functions with no
+ * counterpart in <stdatomic.h>.
  */
-static inline uint32
-pg_atomic_fetch_and_u32(volatile pg_atomic_uint32 *ptr, uint32 and_)
-{
-	AssertPointerAlignment(ptr, 4);
-	return pg_atomic_fetch_and_u32_impl(ptr, and_);
-}
 
 /*
- * pg_atomic_fetch_or_u32 - atomically bit-or or_ with variable
- *
- * Returns the value of ptr before the arithmetic operation.
- *
- * Full barrier semantics.
+ * Fetch and add/subtract wrappers that return the new value instead of the old
+ * value.  We need functions to avoid double evaluation of v.
  */
-static inline uint32
-pg_atomic_fetch_or_u32(volatile pg_atomic_uint32 *ptr, uint32 or_)
-{
-	AssertPointerAlignment(ptr, 4);
-	return pg_atomic_fetch_or_u32_impl(ptr, or_);
-}
-
-/*
- * pg_atomic_add_fetch_u32 - atomically add to variable
- *
- * Returns the value of ptr after the arithmetic operation.
- *
- * Full barrier semantics.
- */
-static inline uint32
-pg_atomic_add_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	AssertPointerAlignment(ptr, 4);
-	return pg_atomic_add_fetch_u32_impl(ptr, add_);
-}
-
-/*
- * pg_atomic_sub_fetch_u32 - atomically subtract from variable
- *
- * Returns the value of ptr after the arithmetic operation. Note that sub_ may
- * not be INT_MIN due to platform limitations.
- *
- * Full barrier semantics.
- */
-static inline uint32
-pg_atomic_sub_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
-{
-	AssertPointerAlignment(ptr, 4);
-	Assert(sub_ != INT_MIN);
-	return pg_atomic_sub_fetch_u32_impl(ptr, sub_);
-}
-
-/* ----
- * The 64 bit operations have the same semantics as their 32bit counterparts
- * if they are available. Check the corresponding 32bit function for
- * documentation.
- * ----
- */
-static inline void
-pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
-{
-	/*
-	 * Can't necessarily enforce alignment - and don't need it - when using
-	 * the spinlock based fallback implementation. Therefore only assert when
-	 * not using it.
-	 */
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	pg_atomic_init_u64_impl(ptr, val);
-}
-
-static inline uint64
-pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_read_u64_impl(ptr);
-}
-
-static inline uint64
-pg_atomic_read_membarrier_u64(volatile pg_atomic_uint64 *ptr)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_read_membarrier_u64_impl(ptr);
-}
-
-static inline void
-pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	pg_atomic_write_u64_impl(ptr, val);
-}
-
-static inline void
-pg_atomic_write_membarrier_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	pg_atomic_write_membarrier_u64_impl(ptr, val);
-}
-
-static inline uint64
-pg_atomic_exchange_u64(volatile pg_atomic_uint64 *ptr, uint64 newval)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_exchange_u64_impl(ptr, newval);
-}
-
-static inline bool
-pg_atomic_compare_exchange_u64(volatile pg_atomic_uint64 *ptr,
-							   uint64 *expected, uint64 newval)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_compare_exchange_u64_impl(ptr, expected, newval);
-}
-
-static inline uint64
-pg_atomic_fetch_add_u64(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_fetch_add_u64_impl(ptr, add_);
-}
-
-static inline uint64
-pg_atomic_fetch_sub_u64(volatile pg_atomic_uint64 *ptr, int64 sub_)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	Assert(sub_ != PG_INT64_MIN);
-	return pg_atomic_fetch_sub_u64_impl(ptr, sub_);
-}
-
-static inline uint64
-pg_atomic_fetch_and_u64(volatile pg_atomic_uint64 *ptr, uint64 and_)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_fetch_and_u64_impl(ptr, and_);
-}
-
-static inline uint64
-pg_atomic_fetch_or_u64(volatile pg_atomic_uint64 *ptr, uint64 or_)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_fetch_or_u64_impl(ptr, or_);
-}
-
-static inline uint64
-pg_atomic_add_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_add_fetch_u64_impl(ptr, add_);
-}
-
-static inline uint64
-pg_atomic_sub_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 sub_)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	Assert(sub_ != PG_INT64_MIN);
-	return pg_atomic_sub_fetch_u64_impl(ptr, sub_);
+#define PG_ATOMIC_GEN_REVERSE_FETCH(size, name, op) \
+static inline uint##size \
+pg_atomic_##name##_fetch_u##size(volatile pg_atomic_uint##size *p, uint##size v) \
+{ \
+	return atomic_fetch_##name(p, v) op v; \
 }
+PG_ATOMIC_GEN_REVERSE_FETCH(32, add, +);
+PG_ATOMIC_GEN_REVERSE_FETCH(64, add, +);
+PG_ATOMIC_GEN_REVERSE_FETCH(32, sub, -);
+PG_ATOMIC_GEN_REVERSE_FETCH(64, sub, -);
 
 /*
  * Monotonically advance the given variable using only atomic operations until
@@ -584,11 +289,7 @@ pg_atomic_monotonic_advance_u64(volatile pg_atomic_uint64 *ptr, uint64 target)
 {
 	uint64		currval;
 
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-
-	currval = pg_atomic_read_u64_impl(ptr);
+	currval = pg_atomic_read_u64(ptr);
 	if (currval >= target)
 	{
 		pg_memory_barrier();
diff --git a/src/include/port/atomics/arch-arm.h b/src/include/port/atomics/arch-arm.h
deleted file mode 100644
index eb7e0ac93ba..00000000000
--- a/src/include/port/atomics/arch-arm.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * arch-arm.h
- *	  Atomic operations considerations specific to ARM
- *
- * Portions Copyright (c) 2013-2025, PostgreSQL Global Development Group
- *
- * NOTES:
- *
- * src/include/port/atomics/arch-arm.h
- *
- *-------------------------------------------------------------------------
- */
-
-/* intentionally no include guards, should only be included by atomics.h */
-#ifndef INSIDE_ATOMICS_H
-#error "should be included via atomics.h"
-#endif
-
-/*
- * 64 bit atomics on ARM32 are implemented using kernel fallbacks and thus
- * might be slow, so disable entirely. On ARM64 that problem doesn't exist.
- */
-#if !defined(__aarch64__)
-#define PG_DISABLE_64_BIT_ATOMICS
-#else
-/*
- * Architecture Reference Manual for ARMv8 states aligned read/write to/from
- * general purpose register is atomic.
- */
-#define PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY
-#endif  /* __aarch64__ */
diff --git a/src/include/port/atomics/arch-ppc.h b/src/include/port/atomics/arch-ppc.h
deleted file mode 100644
index b93f6766d29..00000000000
--- a/src/include/port/atomics/arch-ppc.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * arch-ppc.h
- *	  Atomic operations considerations specific to PowerPC
- *
- * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * NOTES:
- *
- * src/include/port/atomics/arch-ppc.h
- *
- *-------------------------------------------------------------------------
- */
-
-#if defined(__GNUC__)
-
-/*
- * lwsync orders loads with respect to each other, and similarly with stores.
- * But a load can be performed before a subsequent store, so sync must be used
- * for a full memory barrier.
- */
-#define pg_memory_barrier_impl()	__asm__ __volatile__ ("sync" : : : "memory")
-#define pg_read_barrier_impl()		__asm__ __volatile__ ("lwsync" : : : "memory")
-#define pg_write_barrier_impl()		__asm__ __volatile__ ("lwsync" : : : "memory")
-#endif
-
-#define PG_HAVE_ATOMIC_U32_SUPPORT
-typedef struct pg_atomic_uint32
-{
-	volatile uint32 value;
-} pg_atomic_uint32;
-
-/* 64bit atomics are only supported in 64bit mode */
-#if SIZEOF_VOID_P >= 8
-#define PG_HAVE_ATOMIC_U64_SUPPORT
-typedef struct pg_atomic_uint64
-{
-	volatile uint64 value pg_attribute_aligned(8);
-} pg_atomic_uint64;
-
-#endif
-
-/*
- * This mimics gcc __atomic_compare_exchange_n(..., __ATOMIC_SEQ_CST), but
- * code generation differs at the end.  __atomic_compare_exchange_n():
- *  100:	isync
- *  104:	mfcr    r3
- *  108:	rlwinm  r3,r3,3,31,31
- *  10c:	bne     120 <.eb+0x10>
- *  110:	clrldi  r3,r3,63
- *  114:	addi    r1,r1,112
- *  118:	blr
- *  11c:	nop
- *  120:	clrldi  r3,r3,63
- *  124:	stw     r9,0(r4)
- *  128:	addi    r1,r1,112
- *  12c:	blr
- *
- * This:
- *   f0:	isync
- *   f4:	mfcr    r9
- *   f8:	rldicl. r3,r9,35,63
- *   fc:	bne     104 <.eb>
- *  100:	stw     r10,0(r4)
- *  104:	addi    r1,r1,112
- *  108:	blr
- *
- * This implementation may or may not have materially different performance.
- * It's not exploiting the fact that cr0 still holds the relevant comparison
- * bits, set during the __asm__.  One could fix that by moving more code into
- * the __asm__.  (That would remove the freedom to eliminate dead stores when
- * the caller ignores "expected", but few callers do.)
- *
- * Recognizing constant "newval" would be superfluous, because there's no
- * immediate-operand version of stwcx.
- */
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32
-static inline bool
-pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr,
-									uint32 *expected, uint32 newval)
-{
-	uint32 found;
-	uint32 condition_register;
-	bool ret;
-
-#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P
-	if (__builtin_constant_p(*expected) &&
-		(int32) *expected <= PG_INT16_MAX &&
-		(int32) *expected >= PG_INT16_MIN)
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	lwarx   %0,0,%5,1	\n"
-			"	cmpwi   %0,%3		\n"
-			"	bne     $+12		\n"		/* branch to lwsync */
-			"	stwcx.  %4,0,%5		\n"
-			"	bne     $-16		\n"		/* branch to lwarx */
-			"	lwsync				\n"
-			"	mfcr    %1          \n"
-:			"=&r"(found), "=r"(condition_register), "+m"(ptr->value)
-:			"i"(*expected), "r"(newval), "r"(&ptr->value)
-:			"memory", "cc");
-	else
-#endif
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	lwarx   %0,0,%5,1	\n"
-			"	cmpw    %0,%3		\n"
-			"	bne     $+12		\n"		/* branch to lwsync */
-			"	stwcx.  %4,0,%5		\n"
-			"	bne     $-16		\n"		/* branch to lwarx */
-			"	lwsync				\n"
-			"	mfcr    %1          \n"
-:			"=&r"(found), "=r"(condition_register), "+m"(ptr->value)
-:			"r"(*expected), "r"(newval), "r"(&ptr->value)
-:			"memory", "cc");
-
-	ret = (condition_register >> 29) & 1;	/* test eq bit of cr0 */
-	if (!ret)
-		*expected = found;
-	return ret;
-}
-
-/*
- * This mirrors gcc __sync_fetch_and_add().
- *
- * Like tas(), use constraint "=&b" to avoid allocating r0.
- */
-#define PG_HAVE_ATOMIC_FETCH_ADD_U32
-static inline uint32
-pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	uint32 _t;
-	uint32 res;
-
-#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P
-	if (__builtin_constant_p(add_) &&
-		add_ <= PG_INT16_MAX && add_ >= PG_INT16_MIN)
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	lwarx   %1,0,%4,1	\n"
-			"	addi    %0,%1,%3	\n"
-			"	stwcx.  %0,0,%4		\n"
-			"	bne     $-12		\n"		/* branch to lwarx */
-			"	lwsync				\n"
-:			"=&r"(_t), "=&b"(res), "+m"(ptr->value)
-:			"i"(add_), "r"(&ptr->value)
-:			"memory", "cc");
-	else
-#endif
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	lwarx   %1,0,%4,1	\n"
-			"	add     %0,%1,%3	\n"
-			"	stwcx.  %0,0,%4		\n"
-			"	bne     $-12		\n"		/* branch to lwarx */
-			"	lwsync				\n"
-:			"=&r"(_t), "=&r"(res), "+m"(ptr->value)
-:			"r"(add_), "r"(&ptr->value)
-:			"memory", "cc");
-
-	return res;
-}
-
-#ifdef PG_HAVE_ATOMIC_U64_SUPPORT
-
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
-static inline bool
-pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
-									uint64 *expected, uint64 newval)
-{
-	uint64 found;
-	uint32 condition_register;
-	bool ret;
-
-	AssertPointerAlignment(expected, 8);
-
-	/* Like u32, but s/lwarx/ldarx/; s/stwcx/stdcx/; s/cmpw/cmpd/ */
-#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P
-	if (__builtin_constant_p(*expected) &&
-		(int64) *expected <= PG_INT16_MAX &&
-		(int64) *expected >= PG_INT16_MIN)
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	ldarx   %0,0,%5,1	\n"
-			"	cmpdi   %0,%3		\n"
-			"	bne     $+12		\n"		/* branch to lwsync */
-			"	stdcx.  %4,0,%5		\n"
-			"	bne     $-16		\n"		/* branch to ldarx */
-			"	lwsync				\n"
-			"	mfcr    %1          \n"
-:			"=&r"(found), "=r"(condition_register), "+m"(ptr->value)
-:			"i"(*expected), "r"(newval), "r"(&ptr->value)
-:			"memory", "cc");
-	else
-#endif
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	ldarx   %0,0,%5,1	\n"
-			"	cmpd    %0,%3		\n"
-			"	bne     $+12		\n"		/* branch to lwsync */
-			"	stdcx.  %4,0,%5		\n"
-			"	bne     $-16		\n"		/* branch to ldarx */
-			"	lwsync				\n"
-			"	mfcr    %1          \n"
-:			"=&r"(found), "=r"(condition_register), "+m"(ptr->value)
-:			"r"(*expected), "r"(newval), "r"(&ptr->value)
-:			"memory", "cc");
-
-	ret = (condition_register >> 29) & 1;	/* test eq bit of cr0 */
-	if (!ret)
-		*expected = found;
-	return ret;
-}
-
-#define PG_HAVE_ATOMIC_FETCH_ADD_U64
-static inline uint64
-pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-	uint64 _t;
-	uint64 res;
-
-	/* Like u32, but s/lwarx/ldarx/; s/stwcx/stdcx/ */
-#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P
-	if (__builtin_constant_p(add_) &&
-		add_ <= PG_INT16_MAX && add_ >= PG_INT16_MIN)
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	ldarx   %1,0,%4,1	\n"
-			"	addi    %0,%1,%3	\n"
-			"	stdcx.  %0,0,%4		\n"
-			"	bne     $-12		\n"		/* branch to ldarx */
-			"	lwsync				\n"
-:			"=&r"(_t), "=&b"(res), "+m"(ptr->value)
-:			"i"(add_), "r"(&ptr->value)
-:			"memory", "cc");
-	else
-#endif
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	ldarx   %1,0,%4,1	\n"
-			"	add     %0,%1,%3	\n"
-			"	stdcx.  %0,0,%4		\n"
-			"	bne     $-12		\n"		/* branch to ldarx */
-			"	lwsync				\n"
-:			"=&r"(_t), "=&r"(res), "+m"(ptr->value)
-:			"r"(add_), "r"(&ptr->value)
-:			"memory", "cc");
-
-	return res;
-}
-
-#endif /* PG_HAVE_ATOMIC_U64_SUPPORT */
-
-/* per architecture manual doubleword accesses have single copy atomicity */
-#define PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY
diff --git a/src/include/port/atomics/arch-x86.h b/src/include/port/atomics/arch-x86.h
index 4ba2ccc0591..acd612099fa 100644
--- a/src/include/port/atomics/arch-x86.h
+++ b/src/include/port/atomics/arch-x86.h
@@ -3,10 +3,6 @@
  * arch-x86.h
  *	  Atomic operations considerations specific to intel x86
  *
- * Note that we actually require a 486 upwards because the 386 doesn't have
- * support for xadd and cmpxchg. Given that the 386 isn't supported anywhere
- * anymore that's not much of a restriction luckily.
- *
  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
@@ -43,204 +39,3 @@
 
 #define pg_read_barrier_impl()		pg_compiler_barrier_impl()
 #define pg_write_barrier_impl()		pg_compiler_barrier_impl()
-
-/*
- * Provide implementation for atomics using inline assembly on x86 gcc. It's
- * nice to support older gcc's and the compare/exchange implementation here is
- * actually more efficient than the * __sync variant.
- */
-#if defined(__GNUC__) || defined(__INTEL_COMPILER)
-
-#define PG_HAVE_ATOMIC_FLAG_SUPPORT
-typedef struct pg_atomic_flag
-{
-	volatile char value;
-} pg_atomic_flag;
-
-#define PG_HAVE_ATOMIC_U32_SUPPORT
-typedef struct pg_atomic_uint32
-{
-	volatile uint32 value;
-} pg_atomic_uint32;
-
-/*
- * It's too complicated to write inline asm for 64bit types on 32bit and the
- * 486 can't do it anyway.
- */
-#ifdef __x86_64__
-#define PG_HAVE_ATOMIC_U64_SUPPORT
-typedef struct pg_atomic_uint64
-{
-	/* alignment guaranteed due to being on a 64bit platform */
-	volatile uint64 value;
-} pg_atomic_uint64;
-#endif	/* __x86_64__ */
-
-#endif /* defined(__GNUC__) || defined(__INTEL_COMPILER) */
-
-#if !defined(PG_HAVE_SPIN_DELAY)
-/*
- * This sequence is equivalent to the PAUSE instruction ("rep" is
- * ignored by old IA32 processors if the following instruction is
- * not a string operation); the IA-32 Architecture Software
- * Developer's Manual, Vol. 3, Section 7.7.2 describes why using
- * PAUSE in the inner loop of a spin lock is necessary for good
- * performance:
- *
- *     The PAUSE instruction improves the performance of IA-32
- *     processors supporting Hyper-Threading Technology when
- *     executing spin-wait loops and other routines where one
- *     thread is accessing a shared lock or semaphore in a tight
- *     polling loop. When executing a spin-wait loop, the
- *     processor can suffer a severe performance penalty when
- *     exiting the loop because it detects a possible memory order
- *     violation and flushes the core processor's pipeline. The
- *     PAUSE instruction provides a hint to the processor that the
- *     code sequence is a spin-wait loop. The processor uses this
- *     hint to avoid the memory order violation and prevent the
- *     pipeline flush. In addition, the PAUSE instruction
- *     de-pipelines the spin-wait loop to prevent it from
- *     consuming execution resources excessively.
- */
-#if defined(__GNUC__) || defined(__INTEL_COMPILER)
-#define PG_HAVE_SPIN_DELAY
-static __inline__ void
-pg_spin_delay_impl(void)
-{
-	__asm__ __volatile__(" rep; nop			\n");
-}
-#elif defined(_MSC_VER) && defined(__x86_64__)
-#define PG_HAVE_SPIN_DELAY
-static __forceinline void
-pg_spin_delay_impl(void)
-{
-	_mm_pause();
-}
-#elif defined(_MSC_VER)
-#define PG_HAVE_SPIN_DELAY
-static __forceinline void
-pg_spin_delay_impl(void)
-{
-	/* See comment for gcc code. Same code, MASM syntax */
-	__asm rep nop;
-}
-#endif
-#endif /* !defined(PG_HAVE_SPIN_DELAY) */
-
-
-#if defined(__GNUC__) || defined(__INTEL_COMPILER)
-
-#define PG_HAVE_ATOMIC_TEST_SET_FLAG
-static inline bool
-pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	char		_res = 1;
-
-	__asm__ __volatile__(
-		"	lock			\n"
-		"	xchgb	%0,%1	\n"
-:		"+q"(_res), "+m"(ptr->value)
-:
-:		"memory");
-	return _res == 0;
-}
-
-#define PG_HAVE_ATOMIC_CLEAR_FLAG
-static inline void
-pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	/*
-	 * On a TSO architecture like x86 it's sufficient to use a compiler
-	 * barrier to achieve release semantics.
-	 */
-	__asm__ __volatile__("" ::: "memory");
-	ptr->value = 0;
-}
-
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32
-static inline bool
-pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr,
-									uint32 *expected, uint32 newval)
-{
-	char	ret;
-
-	/*
-	 * Perform cmpxchg and use the zero flag which it implicitly sets when
-	 * equal to measure the success.
-	 */
-	__asm__ __volatile__(
-		"	lock				\n"
-		"	cmpxchgl	%4,%5	\n"
-		"   setz		%2		\n"
-:		"=a" (*expected), "=m"(ptr->value), "=q" (ret)
-:		"a" (*expected), "r" (newval), "m"(ptr->value)
-:		"memory", "cc");
-	return (bool) ret;
-}
-
-#define PG_HAVE_ATOMIC_FETCH_ADD_U32
-static inline uint32
-pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	uint32 res;
-	__asm__ __volatile__(
-		"	lock				\n"
-		"	xaddl	%0,%1		\n"
-:		"=q"(res), "=m"(ptr->value)
-:		"0" (add_), "m"(ptr->value)
-:		"memory", "cc");
-	return res;
-}
-
-#ifdef __x86_64__
-
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
-static inline bool
-pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
-									uint64 *expected, uint64 newval)
-{
-	char	ret;
-
-	AssertPointerAlignment(expected, 8);
-
-	/*
-	 * Perform cmpxchg and use the zero flag which it implicitly sets when
-	 * equal to measure the success.
-	 */
-	__asm__ __volatile__(
-		"	lock				\n"
-		"	cmpxchgq	%4,%5	\n"
-		"   setz		%2		\n"
-:		"=a" (*expected), "=m"(ptr->value), "=q" (ret)
-:		"a" (*expected), "r" (newval), "m"(ptr->value)
-:		"memory", "cc");
-	return (bool) ret;
-}
-
-#define PG_HAVE_ATOMIC_FETCH_ADD_U64
-static inline uint64
-pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-	uint64 res;
-	__asm__ __volatile__(
-		"	lock				\n"
-		"	xaddq	%0,%1		\n"
-:		"=q"(res), "=m"(ptr->value)
-:		"0" (add_), "m"(ptr->value)
-:		"memory", "cc");
-	return res;
-}
-
-#endif /* __x86_64__ */
-
-#endif /* defined(__GNUC__) || defined(__INTEL_COMPILER) */
-
-/*
- * 8 byte reads / writes have single-copy atomicity on 32 bit x86 platforms
- * since at least the 586. As well as on all x86-64 cpus.
- */
-#if defined(__i568__) || defined(__i668__) || /* gcc i586+ */  \
-	(defined(_M_IX86) && _M_IX86 >= 500) || /* msvc i586+ */ \
-	defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) /* gcc, msvc */
-#define PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY
-#endif /* 8 byte single-copy atomicity */
diff --git a/src/include/port/atomics/fallback.h b/src/include/port/atomics/fallback.h
deleted file mode 100644
index d2f1b851668..00000000000
--- a/src/include/port/atomics/fallback.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * fallback.h
- *    Fallback for platforms without 64 bit atomics support. Slower
- *    than native atomics support, but not unusably slow.
- *
- * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * src/include/port/atomics/fallback.h
- *
- *-------------------------------------------------------------------------
- */
-
-/* intentionally no include guards, should only be included by atomics.h */
-#ifndef INSIDE_ATOMICS_H
-#	error "should be included via atomics.h"
-#endif
-
-
-#if !defined(PG_HAVE_ATOMIC_U64_SUPPORT)
-
-#define PG_HAVE_ATOMIC_U64_SIMULATION
-
-#define PG_HAVE_ATOMIC_U64_SUPPORT
-typedef struct pg_atomic_uint64
-{
-	int			sema;
-	volatile uint64 value;
-} pg_atomic_uint64;
-
-#define PG_HAVE_ATOMIC_INIT_U64
-extern void pg_atomic_init_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val_);
-
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
-extern bool pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
-												uint64 *expected, uint64 newval);
-
-#define PG_HAVE_ATOMIC_FETCH_ADD_U64
-extern uint64 pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_);
-
-#endif /* PG_HAVE_ATOMIC_U64_SUPPORT */
diff --git a/src/include/port/atomics/generic-gcc.h b/src/include/port/atomics/generic-gcc.h
index a0751f2286a..78555a27861 100644
--- a/src/include/port/atomics/generic-gcc.h
+++ b/src/include/port/atomics/generic-gcc.h
@@ -1,19 +1,11 @@
 /*-------------------------------------------------------------------------
  *
  * generic-gcc.h
- *	  Atomic operations, implemented using gcc (or compatible) intrinsics.
+ *	  Compiler barriers for GCC (or compatible)
  *
  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * NOTES:
- *
- * Documentation:
- * * Legacy __sync Built-in Functions for Atomic Memory Access
- *   https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/_005f_005fsync-Builtins.html
- * * Built-in functions for memory model aware atomic operations
- *   https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/_005f_005fatomic-Builtins.html
- *
  * src/include/port/atomics/generic-gcc.h
  *
  *-------------------------------------------------------------------------
@@ -28,300 +20,3 @@
  * An empty asm block should be a sufficient compiler barrier.
  */
 #define pg_compiler_barrier_impl()	__asm__ __volatile__("" ::: "memory")
-
-/*
- * If we're on GCC, we should be able to get a memory barrier
- * out of this compiler built-in.  But we prefer to rely on platform specific
- * definitions where possible, and use this only as a fallback.
- */
-#if !defined(pg_memory_barrier_impl)
-#	if defined(HAVE_GCC__ATOMIC_INT32_CAS)
-#		define pg_memory_barrier_impl()		__atomic_thread_fence(__ATOMIC_SEQ_CST)
-#	elif defined(__GNUC__)
-#		define pg_memory_barrier_impl()		__sync_synchronize()
-#	endif
-#endif /* !defined(pg_memory_barrier_impl) */
-
-#if !defined(pg_read_barrier_impl) && defined(HAVE_GCC__ATOMIC_INT32_CAS)
-/* acquire semantics include read barrier semantics */
-#		define pg_read_barrier_impl() do \
-{ \
-	pg_compiler_barrier_impl(); \
-	__atomic_thread_fence(__ATOMIC_ACQUIRE); \
-} while (0)
-#endif
-
-#if !defined(pg_write_barrier_impl) && defined(HAVE_GCC__ATOMIC_INT32_CAS)
-/* release semantics include write barrier semantics */
-#		define pg_write_barrier_impl() do \
-{ \
-	pg_compiler_barrier_impl(); \
-	__atomic_thread_fence(__ATOMIC_RELEASE); \
-} while (0)
-#endif
-
-
-/* generic gcc based atomic flag implementation */
-#if !defined(PG_HAVE_ATOMIC_FLAG_SUPPORT) \
-	&& (defined(HAVE_GCC__SYNC_INT32_TAS) || defined(HAVE_GCC__SYNC_CHAR_TAS))
-
-#define PG_HAVE_ATOMIC_FLAG_SUPPORT
-typedef struct pg_atomic_flag
-{
-	/*
-	 * If we have a choice, use int-width TAS, because that is more efficient
-	 * and/or more reliably implemented on most non-Intel platforms.  (Note
-	 * that this code isn't used on x86[_64]; see arch-x86.h for that.)
-	 */
-#ifdef HAVE_GCC__SYNC_INT32_TAS
-	volatile int value;
-#else
-	volatile char value;
-#endif
-} pg_atomic_flag;
-
-#endif /* !ATOMIC_FLAG_SUPPORT && SYNC_INT32_TAS */
-
-/* generic gcc based atomic uint32 implementation */
-#if !defined(PG_HAVE_ATOMIC_U32_SUPPORT) \
-	&& (defined(HAVE_GCC__ATOMIC_INT32_CAS) || defined(HAVE_GCC__SYNC_INT32_CAS))
-
-#define PG_HAVE_ATOMIC_U32_SUPPORT
-typedef struct pg_atomic_uint32
-{
-	volatile uint32 value;
-} pg_atomic_uint32;
-
-#endif /* defined(HAVE_GCC__ATOMIC_INT32_CAS) || defined(HAVE_GCC__SYNC_INT32_CAS) */
-
-/* generic gcc based atomic uint64 implementation */
-#if !defined(PG_HAVE_ATOMIC_U64_SUPPORT) \
-	&& !defined(PG_DISABLE_64_BIT_ATOMICS) \
-	&& (defined(HAVE_GCC__ATOMIC_INT64_CAS) || defined(HAVE_GCC__SYNC_INT64_CAS))
-
-#define PG_HAVE_ATOMIC_U64_SUPPORT
-
-typedef struct pg_atomic_uint64
-{
-	volatile uint64 value pg_attribute_aligned(8);
-} pg_atomic_uint64;
-
-#endif /* defined(HAVE_GCC__ATOMIC_INT64_CAS) || defined(HAVE_GCC__SYNC_INT64_CAS) */
-
-#ifdef PG_HAVE_ATOMIC_FLAG_SUPPORT
-
-#if defined(HAVE_GCC__SYNC_CHAR_TAS) || defined(HAVE_GCC__SYNC_INT32_TAS)
-
-#ifndef PG_HAVE_ATOMIC_TEST_SET_FLAG
-#define PG_HAVE_ATOMIC_TEST_SET_FLAG
-static inline bool
-pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	/* NB: only an acquire barrier, not a full one */
-	/* some platform only support a 1 here */
-	return __sync_lock_test_and_set(&ptr->value, 1) == 0;
-}
-#endif
-
-#endif /* defined(HAVE_GCC__SYNC_*_TAS) */
-
-#ifndef PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
-#define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
-static inline bool
-pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	return ptr->value == 0;
-}
-#endif
-
-#ifndef PG_HAVE_ATOMIC_CLEAR_FLAG
-#define PG_HAVE_ATOMIC_CLEAR_FLAG
-static inline void
-pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	__sync_lock_release(&ptr->value);
-}
-#endif
-
-#ifndef PG_HAVE_ATOMIC_INIT_FLAG
-#define PG_HAVE_ATOMIC_INIT_FLAG
-static inline void
-pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	pg_atomic_clear_flag_impl(ptr);
-}
-#endif
-
-#endif /* defined(PG_HAVE_ATOMIC_FLAG_SUPPORT) */
-
-/* prefer __atomic, it has a better API */
-#if !defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32) && defined(HAVE_GCC__ATOMIC_INT32_CAS)
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32
-static inline bool
-pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr,
-									uint32 *expected, uint32 newval)
-{
-	/* FIXME: we can probably use a lower consistency model */
-	return __atomic_compare_exchange_n(&ptr->value, expected, newval, false,
-									   __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32) && defined(HAVE_GCC__SYNC_INT32_CAS)
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32
-static inline bool
-pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr,
-									uint32 *expected, uint32 newval)
-{
-	bool	ret;
-	uint32	current;
-	current = __sync_val_compare_and_swap(&ptr->value, *expected, newval);
-	ret = current == *expected;
-	*expected = current;
-	return ret;
-}
-#endif
-
-/*
- * __sync_lock_test_and_set() only supports setting the value to 1 on some
- * platforms, so we only provide an __atomic implementation for
- * pg_atomic_exchange.
- *
- * We assume the availability of 32-bit __atomic_compare_exchange_n() implies
- * the availability of 32-bit __atomic_exchange_n().
- */
-#if !defined(PG_HAVE_ATOMIC_EXCHANGE_U32) && defined(HAVE_GCC__ATOMIC_INT32_CAS)
-#define PG_HAVE_ATOMIC_EXCHANGE_U32
-static inline uint32
-pg_atomic_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 newval)
-{
-	return __atomic_exchange_n(&ptr->value, newval, __ATOMIC_SEQ_CST);
-}
-#endif
-
-/* if we have 32-bit __sync_val_compare_and_swap, assume we have these too: */
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U32) && defined(HAVE_GCC__SYNC_INT32_CAS)
-#define PG_HAVE_ATOMIC_FETCH_ADD_U32
-static inline uint32
-pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	return __sync_fetch_and_add(&ptr->value, add_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U32) && defined(HAVE_GCC__SYNC_INT32_CAS)
-#define PG_HAVE_ATOMIC_FETCH_SUB_U32
-static inline uint32
-pg_atomic_fetch_sub_u32_impl(volatile pg_atomic_uint32 *ptr, int32 sub_)
-{
-	return __sync_fetch_and_sub(&ptr->value, sub_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_AND_U32) && defined(HAVE_GCC__SYNC_INT32_CAS)
-#define PG_HAVE_ATOMIC_FETCH_AND_U32
-static inline uint32
-pg_atomic_fetch_and_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 and_)
-{
-	return __sync_fetch_and_and(&ptr->value, and_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_OR_U32) && defined(HAVE_GCC__SYNC_INT32_CAS)
-#define PG_HAVE_ATOMIC_FETCH_OR_U32
-static inline uint32
-pg_atomic_fetch_or_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 or_)
-{
-	return __sync_fetch_and_or(&ptr->value, or_);
-}
-#endif
-
-
-#if !defined(PG_DISABLE_64_BIT_ATOMICS)
-
-#if !defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64) && defined(HAVE_GCC__ATOMIC_INT64_CAS)
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
-static inline bool
-pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
-									uint64 *expected, uint64 newval)
-{
-	AssertPointerAlignment(expected, 8);
-	return __atomic_compare_exchange_n(&ptr->value, expected, newval, false,
-									   __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64) && defined(HAVE_GCC__SYNC_INT64_CAS)
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
-static inline bool
-pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
-									uint64 *expected, uint64 newval)
-{
-	bool	ret;
-	uint64	current;
-
-	AssertPointerAlignment(expected, 8);
-	current = __sync_val_compare_and_swap(&ptr->value, *expected, newval);
-	ret = current == *expected;
-	*expected = current;
-	return ret;
-}
-#endif
-
-/*
- * __sync_lock_test_and_set() only supports setting the value to 1 on some
- * platforms, so we only provide an __atomic implementation for
- * pg_atomic_exchange.
- *
- * We assume the availability of 64-bit __atomic_compare_exchange_n() implies
- * the availability of 64-bit __atomic_exchange_n().
- */
-#if !defined(PG_HAVE_ATOMIC_EXCHANGE_U64) && defined(HAVE_GCC__ATOMIC_INT64_CAS)
-#define PG_HAVE_ATOMIC_EXCHANGE_U64
-static inline uint64
-pg_atomic_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 newval)
-{
-	return __atomic_exchange_n(&ptr->value, newval, __ATOMIC_SEQ_CST);
-}
-#endif
-
-/* if we have 64-bit __sync_val_compare_and_swap, assume we have these too: */
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U64) && defined(HAVE_GCC__SYNC_INT64_CAS)
-#define PG_HAVE_ATOMIC_FETCH_ADD_U64
-static inline uint64
-pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-	return __sync_fetch_and_add(&ptr->value, add_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U64) && defined(HAVE_GCC__SYNC_INT64_CAS)
-#define PG_HAVE_ATOMIC_FETCH_SUB_U64
-static inline uint64
-pg_atomic_fetch_sub_u64_impl(volatile pg_atomic_uint64 *ptr, int64 sub_)
-{
-	return __sync_fetch_and_sub(&ptr->value, sub_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_AND_U64) && defined(HAVE_GCC__SYNC_INT64_CAS)
-#define PG_HAVE_ATOMIC_FETCH_AND_U64
-static inline uint64
-pg_atomic_fetch_and_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 and_)
-{
-	return __sync_fetch_and_and(&ptr->value, and_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_OR_U64) && defined(HAVE_GCC__SYNC_INT64_CAS)
-#define PG_HAVE_ATOMIC_FETCH_OR_U64
-static inline uint64
-pg_atomic_fetch_or_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 or_)
-{
-	return __sync_fetch_and_or(&ptr->value, or_);
-}
-#endif
-
-#endif /* !defined(PG_DISABLE_64_BIT_ATOMICS) */
diff --git a/src/include/port/atomics/generic-msvc.h b/src/include/port/atomics/generic-msvc.h
index a6ea5f1c2e7..4cb5eab5be6 100644
--- a/src/include/port/atomics/generic-msvc.h
+++ b/src/include/port/atomics/generic-msvc.h
@@ -1,17 +1,11 @@
 /*-------------------------------------------------------------------------
  *
  * generic-msvc.h
- *	  Atomic operations support when using MSVC
+ *   Compiler barriers when using MSVC
  *
  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * NOTES:
- *
- * Documentation:
- * * Interlocked Variable Access
- *   http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx
- *
  * src/include/port/atomics/generic-msvc.h
  *
  *-------------------------------------------------------------------------
@@ -24,92 +18,4 @@
 #endif
 
 #pragma intrinsic(_ReadWriteBarrier)
-#define pg_compiler_barrier_impl()	_ReadWriteBarrier()
-
-#ifndef pg_memory_barrier_impl
-#define pg_memory_barrier_impl()	MemoryBarrier()
-#endif
-
-#define PG_HAVE_ATOMIC_U32_SUPPORT
-typedef struct pg_atomic_uint32
-{
-	volatile uint32 value;
-} pg_atomic_uint32;
-
-#define PG_HAVE_ATOMIC_U64_SUPPORT
-typedef struct pg_attribute_aligned(8) pg_atomic_uint64
-{
-	volatile uint64 value;
-} pg_atomic_uint64;
-
-
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32
-static inline bool
-pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr,
-									uint32 *expected, uint32 newval)
-{
-	bool	ret;
-	uint32	current;
-	current = InterlockedCompareExchange(&ptr->value, newval, *expected);
-	ret = current == *expected;
-	*expected = current;
-	return ret;
-}
-
-#define PG_HAVE_ATOMIC_EXCHANGE_U32
-static inline uint32
-pg_atomic_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 newval)
-{
-	return InterlockedExchange(&ptr->value, newval);
-}
-
-#define PG_HAVE_ATOMIC_FETCH_ADD_U32
-static inline uint32
-pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	return InterlockedExchangeAdd(&ptr->value, add_);
-}
-
-/*
- * The non-intrinsics versions are only available in vista upwards, so use the
- * intrinsic version. Only supported on >486, but we require XP as a minimum
- * baseline, which doesn't support the 486, so we don't need to add checks for
- * that case.
- */
-#pragma intrinsic(_InterlockedCompareExchange64)
-
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
-static inline bool
-pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
-									uint64 *expected, uint64 newval)
-{
-	bool	ret;
-	uint64	current;
-	current = _InterlockedCompareExchange64(&ptr->value, newval, *expected);
-	ret = current == *expected;
-	*expected = current;
-	return ret;
-}
-
-/* Only implemented on 64bit builds */
-#ifdef _WIN64
-
-#pragma intrinsic(_InterlockedExchange64)
-
-#define PG_HAVE_ATOMIC_EXCHANGE_U64
-static inline uint64
-pg_atomic_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 newval)
-{
-	return _InterlockedExchange64(&ptr->value, newval);
-}
-
-#pragma intrinsic(_InterlockedExchangeAdd64)
-
-#define PG_HAVE_ATOMIC_FETCH_ADD_U64
-static inline uint64
-pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-	return _InterlockedExchangeAdd64(&ptr->value, add_);
-}
-
-#endif /* _WIN64 */
+#define pg_compiler_barrier_impl() _ReadWriteBarrier()
diff --git a/src/include/port/atomics/generic.h b/src/include/port/atomics/generic.h
deleted file mode 100644
index 6b61a7b5416..00000000000
--- a/src/include/port/atomics/generic.h
+++ /dev/null
@@ -1,427 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * generic.h
- *	  Implement higher level operations based on some lower level atomic
- *	  operations.
- *
- * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * src/include/port/atomics/generic.h
- *
- *-------------------------------------------------------------------------
- */
-
-/* intentionally no include guards, should only be included by atomics.h */
-#ifndef INSIDE_ATOMICS_H
-#	error "should be included via atomics.h"
-#endif
-
-/*
- * If read or write barriers are undefined, we upgrade them to full memory
- * barriers.
- */
-#if !defined(pg_read_barrier_impl)
-#	define pg_read_barrier_impl pg_memory_barrier_impl
-#endif
-#if !defined(pg_write_barrier_impl)
-#	define pg_write_barrier_impl pg_memory_barrier_impl
-#endif
-
-#ifndef PG_HAVE_SPIN_DELAY
-#define PG_HAVE_SPIN_DELAY
-#define pg_spin_delay_impl()	((void)0)
-#endif
-
-
-/* provide fallback */
-#if !defined(PG_HAVE_ATOMIC_FLAG_SUPPORT) && defined(PG_HAVE_ATOMIC_U32_SUPPORT)
-#define PG_HAVE_ATOMIC_FLAG_SUPPORT
-typedef pg_atomic_uint32 pg_atomic_flag;
-#endif
-
-#ifndef PG_HAVE_ATOMIC_READ_U32
-#define PG_HAVE_ATOMIC_READ_U32
-static inline uint32
-pg_atomic_read_u32_impl(volatile pg_atomic_uint32 *ptr)
-{
-	return ptr->value;
-}
-#endif
-
-#ifndef PG_HAVE_ATOMIC_WRITE_U32
-#define PG_HAVE_ATOMIC_WRITE_U32
-static inline void
-pg_atomic_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val)
-{
-	ptr->value = val;
-}
-#endif
-
-#ifndef PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32
-#define PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32
-static inline void
-pg_atomic_unlocked_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val)
-{
-	ptr->value = val;
-}
-#endif
-
-/*
- * provide fallback for test_and_set using atomic_exchange if available
- */
-#if !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) && defined(PG_HAVE_ATOMIC_EXCHANGE_U32)
-
-#define PG_HAVE_ATOMIC_INIT_FLAG
-static inline void
-pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	pg_atomic_write_u32_impl(ptr, 0);
-}
-
-#define PG_HAVE_ATOMIC_TEST_SET_FLAG
-static inline bool
-pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	return pg_atomic_exchange_u32_impl(ptr, 1) == 0;
-}
-
-#define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
-static inline bool
-pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	return pg_atomic_read_u32_impl(ptr) == 0;
-}
-
-
-#define PG_HAVE_ATOMIC_CLEAR_FLAG
-static inline void
-pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	/* XXX: release semantics suffice? */
-	pg_memory_barrier_impl();
-	pg_atomic_write_u32_impl(ptr, 0);
-}
-
-/*
- * provide fallback for test_and_set using atomic_compare_exchange if
- * available.
- */
-#elif !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
-
-#define PG_HAVE_ATOMIC_INIT_FLAG
-static inline void
-pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	pg_atomic_write_u32_impl(ptr, 0);
-}
-
-#define PG_HAVE_ATOMIC_TEST_SET_FLAG
-static inline bool
-pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	uint32 value = 0;
-	return pg_atomic_compare_exchange_u32_impl(ptr, &value, 1);
-}
-
-#define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
-static inline bool
-pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	return pg_atomic_read_u32_impl(ptr) == 0;
-}
-
-#define PG_HAVE_ATOMIC_CLEAR_FLAG
-static inline void
-pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	/* XXX: release semantics suffice? */
-	pg_memory_barrier_impl();
-	pg_atomic_write_u32_impl(ptr, 0);
-}
-
-#elif !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG)
-#	error "No pg_atomic_test_and_set provided"
-#endif /* !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) */
-
-
-#ifndef PG_HAVE_ATOMIC_INIT_U32
-#define PG_HAVE_ATOMIC_INIT_U32
-static inline void
-pg_atomic_init_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val_)
-{
-	ptr->value = val_;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_EXCHANGE_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
-#define PG_HAVE_ATOMIC_EXCHANGE_U32
-static inline uint32
-pg_atomic_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 xchg_)
-{
-	uint32 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, xchg_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
-#define PG_HAVE_ATOMIC_FETCH_ADD_U32
-static inline uint32
-pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	uint32 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, old + add_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
-#define PG_HAVE_ATOMIC_FETCH_SUB_U32
-static inline uint32
-pg_atomic_fetch_sub_u32_impl(volatile pg_atomic_uint32 *ptr, int32 sub_)
-{
-	return pg_atomic_fetch_add_u32_impl(ptr, -sub_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_AND_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
-#define PG_HAVE_ATOMIC_FETCH_AND_U32
-static inline uint32
-pg_atomic_fetch_and_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 and_)
-{
-	uint32 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, old & and_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_OR_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
-#define PG_HAVE_ATOMIC_FETCH_OR_U32
-static inline uint32
-pg_atomic_fetch_or_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 or_)
-{
-	uint32 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, old | or_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_ADD_FETCH_U32) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U32)
-#define PG_HAVE_ATOMIC_ADD_FETCH_U32
-static inline uint32
-pg_atomic_add_fetch_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	return pg_atomic_fetch_add_u32_impl(ptr, add_) + add_;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_SUB_FETCH_U32) && defined(PG_HAVE_ATOMIC_FETCH_SUB_U32)
-#define PG_HAVE_ATOMIC_SUB_FETCH_U32
-static inline uint32
-pg_atomic_sub_fetch_u32_impl(volatile pg_atomic_uint32 *ptr, int32 sub_)
-{
-	return pg_atomic_fetch_sub_u32_impl(ptr, sub_) - sub_;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_READ_MEMBARRIER_U32) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U32)
-#define PG_HAVE_ATOMIC_READ_MEMBARRIER_U32
-static inline uint32
-pg_atomic_read_membarrier_u32_impl(volatile pg_atomic_uint32 *ptr)
-{
-	return pg_atomic_fetch_add_u32_impl(ptr, 0);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U32) && defined(PG_HAVE_ATOMIC_EXCHANGE_U32)
-#define PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U32
-static inline void
-pg_atomic_write_membarrier_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val)
-{
-	(void) pg_atomic_exchange_u32_impl(ptr, val);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_EXCHANGE_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
-#define PG_HAVE_ATOMIC_EXCHANGE_U64
-static inline uint64
-pg_atomic_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 xchg_)
-{
-	uint64 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, xchg_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#ifndef PG_HAVE_ATOMIC_WRITE_U64
-#define PG_HAVE_ATOMIC_WRITE_U64
-
-#if defined(PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY) && \
-	!defined(PG_HAVE_ATOMIC_U64_SIMULATION)
-
-static inline void
-pg_atomic_write_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val)
-{
-	/*
-	 * On this platform aligned 64bit writes are guaranteed to be atomic,
-	 * except if using the fallback implementation, where can't guarantee the
-	 * required alignment.
-	 */
-	AssertPointerAlignment(ptr, 8);
-	ptr->value = val;
-}
-
-#else
-
-static inline void
-pg_atomic_write_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val)
-{
-	/*
-	 * 64 bit writes aren't safe on all platforms. In the generic
-	 * implementation implement them as an atomic exchange.
-	 */
-	pg_atomic_exchange_u64_impl(ptr, val);
-}
-
-#endif /* PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY && !PG_HAVE_ATOMIC_U64_SIMULATION */
-#endif /* PG_HAVE_ATOMIC_WRITE_U64 */
-
-#ifndef PG_HAVE_ATOMIC_READ_U64
-#define PG_HAVE_ATOMIC_READ_U64
-
-#if defined(PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY) && \
-	!defined(PG_HAVE_ATOMIC_U64_SIMULATION)
-
-static inline uint64
-pg_atomic_read_u64_impl(volatile pg_atomic_uint64 *ptr)
-{
-	/*
-	 * On this platform aligned 64-bit reads are guaranteed to be atomic.
-	 */
-	AssertPointerAlignment(ptr, 8);
-	return ptr->value;
-}
-
-#else
-
-static inline uint64
-pg_atomic_read_u64_impl(volatile pg_atomic_uint64 *ptr)
-{
-	uint64 old = 0;
-
-	/*
-	 * 64-bit reads aren't atomic on all platforms. In the generic
-	 * implementation implement them as a compare/exchange with 0. That'll
-	 * fail or succeed, but always return the old value. Possibly might store
-	 * a 0, but only if the previous value also was a 0 - i.e. harmless.
-	 */
-	pg_atomic_compare_exchange_u64_impl(ptr, &old, 0);
-
-	return old;
-}
-#endif /* PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY && !PG_HAVE_ATOMIC_U64_SIMULATION */
-#endif /* PG_HAVE_ATOMIC_READ_U64 */
-
-#ifndef PG_HAVE_ATOMIC_INIT_U64
-#define PG_HAVE_ATOMIC_INIT_U64
-static inline void
-pg_atomic_init_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val_)
-{
-	ptr->value = val_;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
-#define PG_HAVE_ATOMIC_FETCH_ADD_U64
-static inline uint64
-pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-	uint64 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, old + add_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
-#define PG_HAVE_ATOMIC_FETCH_SUB_U64
-static inline uint64
-pg_atomic_fetch_sub_u64_impl(volatile pg_atomic_uint64 *ptr, int64 sub_)
-{
-	return pg_atomic_fetch_add_u64_impl(ptr, -sub_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_AND_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
-#define PG_HAVE_ATOMIC_FETCH_AND_U64
-static inline uint64
-pg_atomic_fetch_and_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 and_)
-{
-	uint64 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, old & and_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_OR_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
-#define PG_HAVE_ATOMIC_FETCH_OR_U64
-static inline uint64
-pg_atomic_fetch_or_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 or_)
-{
-	uint64 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, old | or_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_ADD_FETCH_U64) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U64)
-#define PG_HAVE_ATOMIC_ADD_FETCH_U64
-static inline uint64
-pg_atomic_add_fetch_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-	return pg_atomic_fetch_add_u64_impl(ptr, add_) + add_;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_SUB_FETCH_U64) && defined(PG_HAVE_ATOMIC_FETCH_SUB_U64)
-#define PG_HAVE_ATOMIC_SUB_FETCH_U64
-static inline uint64
-pg_atomic_sub_fetch_u64_impl(volatile pg_atomic_uint64 *ptr, int64 sub_)
-{
-	return pg_atomic_fetch_sub_u64_impl(ptr, sub_) - sub_;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_READ_MEMBARRIER_U64) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U64)
-#define PG_HAVE_ATOMIC_READ_MEMBARRIER_U64
-static inline uint64
-pg_atomic_read_membarrier_u64_impl(volatile pg_atomic_uint64 *ptr)
-{
-	return pg_atomic_fetch_add_u64_impl(ptr, 0);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U64) && defined(PG_HAVE_ATOMIC_EXCHANGE_U64)
-#define PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U64
-static inline void
-pg_atomic_write_membarrier_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val)
-{
-	(void) pg_atomic_exchange_u64_impl(ptr, val);
-}
-#endif
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 432509277c9..315014c96ad 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -3861,6 +3861,8 @@ pendingPosition
 pending_label
 pgParameterStatus
 pg_atomic_flag
+pg_atomic_uint8
+pg_atomic_uint16
 pg_atomic_uint32
 pg_atomic_uint64
 pg_be_sasl_mech
-- 
2.50.1 (Apple Git-155)



  [application/octet-stream] v1-0003-Use-atomics-API-to-implement-spinlocks.patch (36.2K, 4-v1-0003-Use-atomics-API-to-implement-spinlocks.patch)
  download | inline diff:
From a0836815a8cf177025bfa0d220fb150cc55a3b9f Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Wed, 31 Jul 2024 13:11:35 +1200
Subject: [PATCH v1 3/4] Use atomics API to implement spinlocks.

Since our spinlock API pre-dates our C11-inspired atomics API by
decades, it had its own hand-crafted operations written in assembler.

Use the modern atomics API instead, to simplify and de-duplicate.  We
couldn't have done this until fairly recently, because that would have
been be circular: atomics were simulated with spinlocks in
--disable-atomics builds.  Commit 81385261 removed that option, so now
we can delete most of the system-specific spinlock code and use
pg_atomic_flag.

The remaining architecture-specific knowledge is moved into
src/include/port/spin_delay.h:

* implementation of pg_spin_delay()
* whether it is believed to be a good idea to perform a relaxed load
  before attempting test-and-set while spinning (carried forward from
  the old hand-crafted code)

WIP!
---
 src/backend/port/meson.build      |   2 +-
 src/backend/port/tas/dummy.s      |   0
 src/backend/storage/lmgr/s_lock.c | 128 +-----
 src/include/port/spin_delay.h     |  91 ++++
 src/include/storage/s_lock.h      | 737 ------------------------------
 src/include/storage/spin.h        |  70 ++-
 src/template/solaris              |   4 -
 src/test/regress/regress.c        |  25 +-
 8 files changed, 176 insertions(+), 881 deletions(-)
 delete mode 100644 src/backend/port/tas/dummy.s
 create mode 100644 src/include/port/spin_delay.h
 delete mode 100644 src/include/storage/s_lock.h
 delete mode 100644 src/template/solaris

diff --git a/src/backend/port/meson.build b/src/backend/port/meson.build
index 09d54e01d13..45438fcec17 100644
--- a/src/backend/port/meson.build
+++ b/src/backend/port/meson.build
@@ -30,4 +30,4 @@ if host_system == 'windows'
 endif
 
 # autoconf generates the file there, ensure we get a conflict
-generated_sources_ac += {'src/backend/port': ['pg_sema.c', 'pg_shmem.c', 'tas.s']}
+generated_sources_ac += {'src/backend/port': ['pg_sema.c', 'pg_shmem.c']}
diff --git a/src/backend/port/tas/dummy.s b/src/backend/port/tas/dummy.s
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/src/backend/storage/lmgr/s_lock.c b/src/backend/storage/lmgr/s_lock.c
index d26e192f4bc..a2fc129c688 100644
--- a/src/backend/storage/lmgr/s_lock.c
+++ b/src/backend/storage/lmgr/s_lock.c
@@ -51,7 +51,9 @@
 #include <unistd.h>
 
 #include "common/pg_prng.h"
-#include "storage/s_lock.h"
+#include "port/atomics.h"
+#include "port/spin_delay.h"
+#include "storage/spin.h"
 #include "utils/wait_event.h"
 
 #define MIN_SPINS_PER_DELAY 10
@@ -92,7 +94,7 @@ s_lock_stuck(const char *file, int line, const char *func)
 }
 
 /*
- * s_lock(lock) - platform-independent portion of waiting for a spinlock.
+ * s_lock(lock) - out-of-line portion of waiting for a spinlock.
  */
 int
 s_lock(volatile slock_t *lock, const char *file, int line, const char *func)
@@ -101,8 +103,25 @@ s_lock(volatile slock_t *lock, const char *file, int line, const char *func)
 
 	init_spin_delay(&delayStatus, file, line, func);
 
-	while (TAS_SPIN(lock))
+	for (;;)
 	{
+		bool		try_to_set;
+
+#ifdef PG_SPIN_TRY_RELAXED
+
+		/*
+		 * It is known to be more efficient to test the lock with a relaxed
+		 * load first, while spinning, on this platform.
+		 */
+		try_to_set = pg_atomic_unlocked_test_flag(lock);
+#else
+		try_to_set = true;
+#endif
+
+		/* Try to get the lock. */
+		if (try_to_set && pg_atomic_test_set_flag(lock))
+			break;
+
 		perform_spin_delay(&delayStatus);
 	}
 
@@ -111,14 +130,6 @@ s_lock(volatile slock_t *lock, const char *file, int line, const char *func)
 	return delayStatus.delays;
 }
 
-#ifdef USE_DEFAULT_S_UNLOCK
-void
-s_unlock(volatile slock_t *lock)
-{
-	*lock = 0;
-}
-#endif
-
 /*
  * Wait while spinning on a contended spinlock.
  */
@@ -126,7 +137,7 @@ void
 perform_spin_delay(SpinDelayStatus *status)
 {
 	/* CPU-specific delay each time through the loop */
-	SPIN_DELAY();
+	pg_spin_delay();
 
 	/* Block the process every spins_per_delay tries */
 	if (++(status->spins) >= spins_per_delay)
@@ -229,96 +240,3 @@ update_spins_per_delay(int shared_spins_per_delay)
 	 */
 	return (shared_spins_per_delay * 15 + spins_per_delay) / 16;
 }
-
-
-/*****************************************************************************/
-#if defined(S_LOCK_TEST)
-
-/*
- * test program for verifying a port's spinlock support.
- */
-
-struct test_lock_struct
-{
-	char		pad1;
-	slock_t		lock;
-	char		pad2;
-};
-
-volatile struct test_lock_struct test_lock;
-
-int
-main()
-{
-	pg_prng_seed(&pg_global_prng_state, (uint64) time(NULL));
-
-	test_lock.pad1 = test_lock.pad2 = 0x44;
-
-	S_INIT_LOCK(&test_lock.lock);
-
-	if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
-	{
-		printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
-		return 1;
-	}
-
-	if (!S_LOCK_FREE(&test_lock.lock))
-	{
-		printf("S_LOCK_TEST: failed, lock not initialized\n");
-		return 1;
-	}
-
-	S_LOCK(&test_lock.lock);
-
-	if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
-	{
-		printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
-		return 1;
-	}
-
-	if (S_LOCK_FREE(&test_lock.lock))
-	{
-		printf("S_LOCK_TEST: failed, lock not locked\n");
-		return 1;
-	}
-
-	S_UNLOCK(&test_lock.lock);
-
-	if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
-	{
-		printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
-		return 1;
-	}
-
-	if (!S_LOCK_FREE(&test_lock.lock))
-	{
-		printf("S_LOCK_TEST: failed, lock not unlocked\n");
-		return 1;
-	}
-
-	S_LOCK(&test_lock.lock);
-
-	if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
-	{
-		printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
-		return 1;
-	}
-
-	if (S_LOCK_FREE(&test_lock.lock))
-	{
-		printf("S_LOCK_TEST: failed, lock not re-locked\n");
-		return 1;
-	}
-
-	printf("S_LOCK_TEST: this will print %d stars and then\n", NUM_DELAYS);
-	printf("             exit with a 'stuck spinlock' message\n");
-	printf("             if S_LOCK() and TAS() are working.\n");
-	fflush(stdout);
-
-	s_lock(&test_lock.lock, __FILE__, __LINE__, __func__);
-
-	printf("S_LOCK_TEST: failed, lock not locked\n");
-	return 1;
-}
-
-#endif							/* S_LOCK_TEST */
diff --git a/src/include/port/spin_delay.h b/src/include/port/spin_delay.h
new file mode 100644
index 00000000000..c583698af8e
--- /dev/null
+++ b/src/include/port/spin_delay.h
@@ -0,0 +1,91 @@
+/*-------------------------------------------------------------------------
+ *
+ * spin_delay.h
+ *	   Implementation of architecture-specific spinlock delay.
+ *
+ * Note to implementors: the default implementation does nothing.
+ *
+ * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *	  src/include/port/spin_delay.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SPIN_DELAY_H
+#define SPIN_DELAY_H
+
+static pg_attribute_always_inline void
+pg_spin_delay(void)
+{
+#if defined(__GNUC__) || defined(__INTEL_COMPILER)
+#ifdef __i386__					/* 32-bit i386 */
+	/*
+	 * This sequence is equivalent to the PAUSE instruction ("rep" is ignored
+	 * by old IA32 processors if the following instruction is not a string
+	 * operation); the IA-32 Architecture Software Developer's Manual, Vol. 3,
+	 * Section 7.7.2 describes why using PAUSE in the inner loop of a spin
+	 * lock is necessary for good performance:
+	 *
+	 * The PAUSE instruction improves the performance of IA-32 processors
+	 * supporting Hyper-Threading Technology when executing spin-wait loops
+	 * and other routines where one thread is accessing a shared lock or
+	 * semaphore in a tight polling loop. When executing a spin-wait loop, the
+	 * processor can suffer a severe performance penalty when exiting the loop
+	 * because it detects a possible memory order violation and flushes the
+	 * core processor's pipeline. The PAUSE instruction provides a hint to the
+	 * processor that the code sequence is a spin-wait loop. The processor
+	 * uses this hint to avoid the memory order violation and prevent the
+	 * pipeline flush. In addition, the PAUSE instruction de-pipelines the
+	 * spin-wait loop to prevent it from consuming execution resources
+	 * excessively.
+	 */
+	__asm__ __volatile__(
+						 " rep; nop			\n");
+#endif							/* __i386__ */
+#ifdef __x86_64__				/* AMD Opteron, Intel EM64T */
+
+	/*
+	 * Adding a PAUSE in the spin delay loop is demonstrably a no-op on
+	 * Opteron, but it may be of some use on EM64T, so we keep it.
+	 */
+	__asm__ __volatile__(
+						 " rep; nop			\n");
+#endif							/* __x86_64__ */
+#if defined(__aarch64__)
+
+	/*
+	 * Using an ISB instruction to delay in spinlock loops appears beneficial
+	 * on high-core-count ARM64 processors.  It seems mostly a wash for
+	 * smaller gear, and ISB doesn't exist at all on pre-v7 ARM chips.
+	 */
+	__asm__ __volatile__(
+						 " isb;				\n");
+#endif							/* __aarch64__ */
+#endif							/* defined(__GNUC__) ||
+								 * defined(__INTEL_COMPILER) */
+
+#ifdef _MSC_VER
+
+	/*
+	 * If using Visual C++ on Win64, inline assembly is unavailable.  Use a
+	 * _mm_pause intrinsic instead of rep nop.
+	 */
+#if defined(_WIN64)
+	_mm_pause();
+#else
+	/* See comment for gcc code. Same code, MASM syntax */
+	__asm		rep nop;
+#endif
+#endif							/* _MSC_VER */
+}
+
+/* Architectures on which a relaxed load is recommended while spinning. */
+#if defined(__i386__) || defined(__x86_64__) || \
+	defined(_M_IX86) || defined(_M_AMD64) || \
+	defined(__ppc__) || defined(__powerpc__) || \
+	defined(__ppc64__) || defined(__powerpc64__)
+#define PG_SPIN_TRY_RELAXED
+#endif
+
+#endif							/* SPIN_DELAY_H */
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
deleted file mode 100644
index 7f8f566bd40..00000000000
--- a/src/include/storage/s_lock.h
+++ /dev/null
@@ -1,737 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * s_lock.h
- *	   Implementation of spinlocks.
- *
- *	NOTE: none of the macros in this file are intended to be called directly.
- *	Call them through the macros in spin.h.
- *
- *	The following hardware-dependent macros must be provided for each
- *	supported platform:
- *
- *	void S_INIT_LOCK(slock_t *lock)
- *		Initialize a spinlock (to the unlocked state).
- *
- *	int S_LOCK(slock_t *lock)
- *		Acquire a spinlock, waiting if necessary.
- *		Time out and abort() if unable to acquire the lock in a
- *		"reasonable" amount of time --- typically ~ 1 minute.
- *		Should return number of "delays"; see s_lock.c
- *
- *	void S_UNLOCK(slock_t *lock)
- *		Unlock a previously acquired lock.
- *
- *	bool S_LOCK_FREE(slock_t *lock)
- *		Tests if the lock is free. Returns true if free, false if locked.
- *		This does *not* change the state of the lock.
- *
- *	void SPIN_DELAY(void)
- *		Delay operation to occur inside spinlock wait loop.
- *
- *	Note to implementors: there are default implementations for all these
- *	macros at the bottom of the file.  Check if your platform can use
- *	these or needs to override them.
- *
- *  Usually, S_LOCK() is implemented in terms of even lower-level macros
- *	TAS() and TAS_SPIN():
- *
- *	int TAS(slock_t *lock)
- *		Atomic test-and-set instruction.  Attempt to acquire the lock,
- *		but do *not* wait.	Returns 0 if successful, nonzero if unable
- *		to acquire the lock.
- *
- *	int TAS_SPIN(slock_t *lock)
- *		Like TAS(), but this version is used when waiting for a lock
- *		previously found to be contended.  By default, this is the
- *		same as TAS(), but on some architectures it's better to poll a
- *		contended lock using an unlocked instruction and retry the
- *		atomic test-and-set only when it appears free.
- *
- *	TAS() and TAS_SPIN() are NOT part of the API, and should never be called
- *	directly.
- *
- *	CAUTION: on some platforms TAS() and/or TAS_SPIN() may sometimes report
- *	failure to acquire a lock even when the lock is not locked.  For example,
- *	on Alpha TAS() will "fail" if interrupted.  Therefore a retry loop must
- *	always be used, even if you are certain the lock is free.
- *
- *	It is the responsibility of these macros to make sure that the compiler
- *	does not re-order accesses to shared memory to precede the actual lock
- *	acquisition, or follow the lock release.  Prior to PostgreSQL 9.5, this
- *	was the caller's responsibility, which meant that callers had to use
- *	volatile-qualified pointers to refer to both the spinlock itself and the
- *	shared data being accessed within the spinlocked critical section.  This
- *	was notationally awkward, easy to forget (and thus error-prone), and
- *	prevented some useful compiler optimizations.  For these reasons, we
- *	now require that the macros themselves prevent compiler re-ordering,
- *	so that the caller doesn't need to take special precautions.
- *
- *	On platforms with weak memory ordering, the TAS(), TAS_SPIN(), and
- *	S_UNLOCK() macros must further include hardware-level memory fence
- *	instructions to prevent similar re-ordering at the hardware level.
- *	TAS() and TAS_SPIN() must guarantee that loads and stores issued after
- *	the macro are not executed until the lock has been obtained.  Conversely,
- *	S_UNLOCK() must guarantee that loads and stores issued before the macro
- *	have been executed before the lock is released.
- *
- *	On most supported platforms, TAS() uses a tas() function written
- *	in assembly language to execute a hardware atomic-test-and-set
- *	instruction.  Equivalent OS-supplied mutex routines could be used too.
- *
- *
- * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *	  src/include/storage/s_lock.h
- *
- *-------------------------------------------------------------------------
- */
-#ifndef S_LOCK_H
-#define S_LOCK_H
-
-#ifdef FRONTEND
-#error "s_lock.h may not be included from frontend code"
-#endif
-
-#if defined(__GNUC__) || defined(__INTEL_COMPILER)
-/*************************************************************************
- * All the gcc inlines
- * Gcc consistently defines the CPU as __cpu__.
- * Other compilers use __cpu or __cpu__ so we test for both in those cases.
- */
-
-/*----------
- * Standard gcc asm format (assuming "volatile slock_t *lock"):
-
-	__asm__ __volatile__(
-		"	instruction	\n"
-		"	instruction	\n"
-		"	instruction	\n"
-:		"=r"(_res), "+m"(*lock)		// return register, in/out lock value
-:		"r"(lock)					// lock pointer, in input register
-:		"memory", "cc");			// show clobbered registers here
-
- * The output-operands list (after first colon) should always include
- * "+m"(*lock), whether or not the asm code actually refers to this
- * operand directly.  This ensures that gcc believes the value in the
- * lock variable is used and set by the asm code.  Also, the clobbers
- * list (after third colon) should always include "memory"; this prevents
- * gcc from thinking it can cache the values of shared-memory fields
- * across the asm code.  Add "cc" if your asm code changes the condition
- * code register, and also list any temp registers the code uses.
- *----------
- */
-
-
-#ifdef __i386__		/* 32-bit i386 */
-#define HAS_TEST_AND_SET
-
-typedef unsigned char slock_t;
-
-#define TAS(lock) tas(lock)
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	slock_t		_res = 1;
-
-	/*
-	 * Use a non-locking test before asserting the bus lock.  Note that the
-	 * extra test appears to be a small loss on some x86 platforms and a small
-	 * win on others; it's by no means clear that we should keep it.
-	 *
-	 * When this was last tested, we didn't have separate TAS() and TAS_SPIN()
-	 * macros.  Nowadays it probably would be better to do a non-locking test
-	 * in TAS_SPIN() but not in TAS(), like on x86_64, but no-one's done the
-	 * testing to verify that.  Without some empirical evidence, better to
-	 * leave it alone.
-	 */
-	__asm__ __volatile__(
-		"	cmpb	$0,%1	\n"
-		"	jne		1f		\n"
-		"	lock			\n"
-		"	xchgb	%0,%1	\n"
-		"1: \n"
-:		"+q"(_res), "+m"(*lock)
-:		/* no inputs */
-:		"memory", "cc");
-	return (int) _res;
-}
-
-#define SPIN_DELAY() spin_delay()
-
-static __inline__ void
-spin_delay(void)
-{
-	/*
-	 * This sequence is equivalent to the PAUSE instruction ("rep" is
-	 * ignored by old IA32 processors if the following instruction is
-	 * not a string operation); the IA-32 Architecture Software
-	 * Developer's Manual, Vol. 3, Section 7.7.2 describes why using
-	 * PAUSE in the inner loop of a spin lock is necessary for good
-	 * performance:
-	 *
-	 *     The PAUSE instruction improves the performance of IA-32
-	 *     processors supporting Hyper-Threading Technology when
-	 *     executing spin-wait loops and other routines where one
-	 *     thread is accessing a shared lock or semaphore in a tight
-	 *     polling loop. When executing a spin-wait loop, the
-	 *     processor can suffer a severe performance penalty when
-	 *     exiting the loop because it detects a possible memory order
-	 *     violation and flushes the core processor's pipeline. The
-	 *     PAUSE instruction provides a hint to the processor that the
-	 *     code sequence is a spin-wait loop. The processor uses this
-	 *     hint to avoid the memory order violation and prevent the
-	 *     pipeline flush. In addition, the PAUSE instruction
-	 *     de-pipelines the spin-wait loop to prevent it from
-	 *     consuming execution resources excessively.
-	 */
-	__asm__ __volatile__(
-		" rep; nop			\n");
-}
-
-#endif	 /* __i386__ */
-
-
-#ifdef __x86_64__		/* AMD Opteron, Intel EM64T */
-#define HAS_TEST_AND_SET
-
-typedef unsigned char slock_t;
-
-#define TAS(lock) tas(lock)
-
-/*
- * On Intel EM64T, it's a win to use a non-locking test before the xchg proper,
- * but only when spinning.
- *
- * See also Implementing Scalable Atomic Locks for Multi-Core Intel(tm) EM64T
- * and IA32, by Michael Chynoweth and Mary R. Lee. As of this writing, it is
- * available at:
- * http://software.intel.com/en-us/articles/implementing-scalable-atomic-locks-for-multi-core-intel-em64t-and-ia32-architectures
- */
-#define TAS_SPIN(lock)    (*(lock) ? 1 : TAS(lock))
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	slock_t		_res = 1;
-
-	__asm__ __volatile__(
-		"	lock			\n"
-		"	xchgb	%0,%1	\n"
-:		"+q"(_res), "+m"(*lock)
-:		/* no inputs */
-:		"memory", "cc");
-	return (int) _res;
-}
-
-#define SPIN_DELAY() spin_delay()
-
-static __inline__ void
-spin_delay(void)
-{
-	/*
-	 * Adding a PAUSE in the spin delay loop is demonstrably a no-op on
-	 * Opteron, but it may be of some use on EM64T, so we keep it.
-	 */
-	__asm__ __volatile__(
-		" rep; nop			\n");
-}
-
-#endif	 /* __x86_64__ */
-
-
-/*
- * On ARM and ARM64, we use __sync_lock_test_and_set(int *, int) if available.
- *
- * We use the int-width variant of the builtin because it works on more chips
- * than other widths.
- */
-#if defined(__arm__) || defined(__arm) || defined(__aarch64__)
-#ifdef HAVE_GCC__SYNC_INT32_TAS
-#define HAS_TEST_AND_SET
-
-#define TAS(lock) tas(lock)
-
-typedef int slock_t;
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	return __sync_lock_test_and_set(lock, 1);
-}
-
-#define S_UNLOCK(lock) __sync_lock_release(lock)
-
-#if defined(__aarch64__)
-
-/*
- * On ARM64, it's a win to use a non-locking test before the TAS proper.  It
- * may be a win on 32-bit ARM, too, but nobody's tested it yet.
- */
-#define TAS_SPIN(lock)	(*(lock) ? 1 : TAS(lock))
-
-#define SPIN_DELAY() spin_delay()
-
-static __inline__ void
-spin_delay(void)
-{
-	/*
-	 * Using an ISB instruction to delay in spinlock loops appears beneficial
-	 * on high-core-count ARM64 processors.  It seems mostly a wash for smaller
-	 * gear, and ISB doesn't exist at all on pre-v7 ARM chips.
-	 */
-	__asm__ __volatile__(
-		" isb;				\n");
-}
-
-#endif	 /* __aarch64__ */
-#endif	 /* HAVE_GCC__SYNC_INT32_TAS */
-#endif	 /* __arm__ || __arm || __aarch64__ */
-
-
-/* S/390 and S/390x Linux (32- and 64-bit zSeries) */
-#if defined(__s390__) || defined(__s390x__)
-#define HAS_TEST_AND_SET
-
-typedef unsigned int slock_t;
-
-#define TAS(lock)	   tas(lock)
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	int			_res = 0;
-
-	__asm__	__volatile__(
-		"	cs 	%0,%3,0(%2)		\n"
-:		"+d"(_res), "+m"(*lock)
-:		"a"(lock), "d"(1)
-:		"memory", "cc");
-	return _res;
-}
-
-#endif	 /* __s390__ || __s390x__ */
-
-
-#if defined(__sparc__)		/* Sparc */
-/*
- * Solaris has always run sparc processors in TSO (total store) mode, but
- * linux didn't use to and the *BSDs still don't. So, be careful about
- * acquire/release semantics. The CPU will treat superfluous members as
- * NOPs, so it's just code space.
- */
-#define HAS_TEST_AND_SET
-
-typedef unsigned char slock_t;
-
-#define TAS(lock) tas(lock)
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	slock_t		_res;
-
-	/*
-	 * "cas" would be better than "ldstub", but it is only present on
-	 * sparcv8plus and later, while some platforms still support sparcv7 or
-	 * sparcv8.  Also, "cas" requires that the system be running in TSO mode.
-	 */
-	__asm__ __volatile__(
-		"	ldstub	[%2], %0	\n"
-:		"=r"(_res), "+m"(*lock)
-:		"r"(lock)
-:		"memory");
-#if defined(__sparcv7) || defined(__sparc_v7__)
-	/*
-	 * No stbar or membar available, luckily no actually produced hardware
-	 * requires a barrier.
-	 */
-#elif defined(__sparcv8) || defined(__sparc_v8__)
-	/* stbar is available (and required for both PSO, RMO), membar isn't */
-	__asm__ __volatile__ ("stbar	 \n":::"memory");
-#else
-	/*
-	 * #LoadStore (RMO) | #LoadLoad (RMO) together are the appropriate acquire
-	 * barrier for sparcv8+ upwards.
-	 */
-	__asm__ __volatile__ ("membar #LoadStore | #LoadLoad \n":::"memory");
-#endif
-	return (int) _res;
-}
-
-#if defined(__sparcv7) || defined(__sparc_v7__)
-/*
- * No stbar or membar available, luckily no actually produced hardware
- * requires a barrier.  We fall through to the default gcc definition of
- * S_UNLOCK in this case.
- */
-#elif defined(__sparcv8) || defined(__sparc_v8__)
-/* stbar is available (and required for both PSO, RMO), membar isn't */
-#define S_UNLOCK(lock)	\
-do \
-{ \
-	__asm__ __volatile__ ("stbar	 \n":::"memory"); \
-	*((volatile slock_t *) (lock)) = 0; \
-} while (0)
-#else
-/*
- * #LoadStore (RMO) | #StoreStore (RMO, PSO) together are the appropriate
- * release barrier for sparcv8+ upwards.
- */
-#define S_UNLOCK(lock)	\
-do \
-{ \
-	__asm__ __volatile__ ("membar #LoadStore | #StoreStore \n":::"memory"); \
-	*((volatile slock_t *) (lock)) = 0; \
-} while (0)
-#endif
-
-#endif	 /* __sparc__ */
-
-
-/* PowerPC */
-#if defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__)
-#define HAS_TEST_AND_SET
-
-typedef unsigned int slock_t;
-
-#define TAS(lock) tas(lock)
-
-/* On PPC, it's a win to use a non-locking test before the lwarx */
-#define TAS_SPIN(lock)	(*(lock) ? 1 : TAS(lock))
-
-/*
- * The second operand of addi can hold a constant zero or a register number,
- * hence constraint "=&b" to avoid allocating r0.  "b" stands for "address
- * base register"; most operands having this register-or-zero property are
- * address bases, e.g. the second operand of lwax.
- *
- * NOTE: per the Enhanced PowerPC Architecture manual, v1.0 dated 7-May-2002,
- * an isync is a sufficient synchronization barrier after a lwarx/stwcx loop.
- * But if the spinlock is in ordinary memory, we can use lwsync instead for
- * better performance.
- */
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	slock_t _t;
-	int _res;
-
-	__asm__ __volatile__(
-"	lwarx   %0,0,%3,1	\n"
-"	cmpwi   %0,0		\n"
-"	bne     1f			\n"
-"	addi    %0,%0,1		\n"
-"	stwcx.  %0,0,%3		\n"
-"	beq     2f			\n"
-"1: \n"
-"	li      %1,1		\n"
-"	b       3f			\n"
-"2: \n"
-"	lwsync				\n"
-"	li      %1,0		\n"
-"3: \n"
-:	"=&b"(_t), "=r"(_res), "+m"(*lock)
-:	"r"(lock)
-:	"memory", "cc");
-	return _res;
-}
-
-/*
- * PowerPC S_UNLOCK is almost standard but requires a "sync" instruction.
- * But we can use lwsync instead for better performance.
- */
-#define S_UNLOCK(lock)	\
-do \
-{ \
-	__asm__ __volatile__ ("	lwsync \n" ::: "memory"); \
-	*((volatile slock_t *) (lock)) = 0; \
-} while (0)
-
-#endif /* powerpc */
-
-
-#if defined(__mips__) && !defined(__sgi)	/* non-SGI MIPS */
-#define HAS_TEST_AND_SET
-
-typedef unsigned int slock_t;
-
-#define TAS(lock) tas(lock)
-
-/*
- * Original MIPS-I processors lacked the LL/SC instructions, but if we are
- * so unfortunate as to be running on one of those, we expect that the kernel
- * will handle the illegal-instruction traps and emulate them for us.  On
- * anything newer (and really, MIPS-I is extinct) LL/SC is the only sane
- * choice because any other synchronization method must involve a kernel
- * call.  Unfortunately, many toolchains still default to MIPS-I as the
- * codegen target; if the symbol __mips shows that that's the case, we
- * have to force the assembler to accept LL/SC.
- *
- * R10000 and up processors require a separate SYNC, which has the same
- * issues as LL/SC.
- */
-#if __mips < 2
-#define MIPS_SET_MIPS2	"       .set mips2          \n"
-#else
-#define MIPS_SET_MIPS2
-#endif
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	volatile slock_t *_l = lock;
-	int			_res;
-	int			_tmp;
-
-	__asm__ __volatile__(
-		"       .set push           \n"
-		MIPS_SET_MIPS2
-		"       .set noreorder      \n"
-		"       .set nomacro        \n"
-		"       ll      %0, %2      \n"
-		"       or      %1, %0, 1   \n"
-		"       sc      %1, %2      \n"
-		"       xori    %1, 1       \n"
-		"       or      %0, %0, %1  \n"
-		"       sync                \n"
-		"       .set pop              "
-:		"=&r" (_res), "=&r" (_tmp), "+R" (*_l)
-:		/* no inputs */
-:		"memory");
-	return _res;
-}
-
-/* MIPS S_UNLOCK is almost standard but requires a "sync" instruction */
-#define S_UNLOCK(lock)	\
-do \
-{ \
-	__asm__ __volatile__( \
-		"       .set push           \n" \
-		MIPS_SET_MIPS2 \
-		"       .set noreorder      \n" \
-		"       .set nomacro        \n" \
-		"       sync                \n" \
-		"       .set pop              " \
-:		/* no outputs */ \
-:		/* no inputs */	\
-:		"memory"); \
-	*((volatile slock_t *) (lock)) = 0; \
-} while (0)
-
-#endif /* __mips__ && !__sgi */
-
-
-
-/*
- * If we have no platform-specific knowledge, but we found that the compiler
- * provides __sync_lock_test_and_set(), use that.  Prefer the int-width
- * version over the char-width version if we have both, on the rather dubious
- * grounds that that's known to be more likely to work in the ARM ecosystem.
- * (But we dealt with ARM above.)
- */
-#if !defined(HAS_TEST_AND_SET)
-
-#if defined(HAVE_GCC__SYNC_INT32_TAS)
-#define HAS_TEST_AND_SET
-
-#define TAS(lock) tas(lock)
-
-typedef int slock_t;
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	return __sync_lock_test_and_set(lock, 1);
-}
-
-#define S_UNLOCK(lock) __sync_lock_release(lock)
-
-#elif defined(HAVE_GCC__SYNC_CHAR_TAS)
-#define HAS_TEST_AND_SET
-
-#define TAS(lock) tas(lock)
-
-typedef char slock_t;
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	return __sync_lock_test_and_set(lock, 1);
-}
-
-#define S_UNLOCK(lock) __sync_lock_release(lock)
-
-#endif	 /* HAVE_GCC__SYNC_INT32_TAS */
-
-#endif	/* !defined(HAS_TEST_AND_SET) */
-
-
-/*
- * Default implementation of S_UNLOCK() for gcc/icc.
- *
- * Note that this implementation is unsafe for any platform that can reorder
- * a memory access (either load or store) after a following store.  That
- * happens not to be possible on x86 and most legacy architectures (some are
- * single-processor!), but many modern systems have weaker memory ordering.
- * Those that do must define their own version of S_UNLOCK() rather than
- * relying on this one.
- */
-#if !defined(S_UNLOCK)
-#define S_UNLOCK(lock)	\
-	do { __asm__ __volatile__("" : : : "memory");  *(lock) = 0; } while (0)
-#endif
-
-#endif	/* defined(__GNUC__) || defined(__INTEL_COMPILER) */
-
-
-/*
- * ---------------------------------------------------------------------
- * Platforms that use non-gcc inline assembly:
- * ---------------------------------------------------------------------
- */
-
-#if !defined(HAS_TEST_AND_SET)	/* We didn't trigger above, let's try here */
-
-#ifdef _MSC_VER
-typedef LONG slock_t;
-
-#define HAS_TEST_AND_SET
-#define TAS(lock) (InterlockedCompareExchange(lock, 1, 0))
-
-#define SPIN_DELAY() spin_delay()
-
-/* If using Visual C++ on Win64, inline assembly is unavailable.
- * Use a _mm_pause intrinsic instead of rep nop.
- */
-#if defined(_WIN64)
-static __forceinline void
-spin_delay(void)
-{
-	_mm_pause();
-}
-#else
-static __forceinline void
-spin_delay(void)
-{
-	/* See comment for gcc code. Same code, MASM syntax */
-	__asm rep nop;
-}
-#endif
-
-#include <intrin.h>
-#pragma intrinsic(_ReadWriteBarrier)
-
-#define S_UNLOCK(lock)	\
-	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
-
-#endif
-
-
-#endif	/* !defined(HAS_TEST_AND_SET) */
-
-
-/* Blow up if we didn't have any way to do spinlocks */
-#ifndef HAS_TEST_AND_SET
-#error PostgreSQL does not have spinlock support on this platform.  Please report this to [email protected].
-#endif
-
-
-/*
- * Default Definitions - override these above as needed.
- */
-
-#if !defined(S_LOCK)
-#define S_LOCK(lock) \
-	(TAS(lock) ? s_lock((lock), __FILE__, __LINE__, __func__) : 0)
-#endif	 /* S_LOCK */
-
-#if !defined(S_LOCK_FREE)
-#define S_LOCK_FREE(lock)	(*(lock) == 0)
-#endif	 /* S_LOCK_FREE */
-
-#if !defined(S_UNLOCK)
-/*
- * Our default implementation of S_UNLOCK is essentially *(lock) = 0.  This
- * is unsafe if the platform can reorder a memory access (either load or
- * store) after a following store; platforms where this is possible must
- * define their own S_UNLOCK.  But CPU reordering is not the only concern:
- * if we simply defined S_UNLOCK() as an inline macro, the compiler might
- * reorder instructions from inside the critical section to occur after the
- * lock release.  Since the compiler probably can't know what the external
- * function s_unlock is doing, putting the same logic there should be adequate.
- * A sufficiently-smart globally optimizing compiler could break that
- * assumption, though, and the cost of a function call for every spinlock
- * release may hurt performance significantly, so we use this implementation
- * only for platforms where we don't know of a suitable intrinsic.  For the
- * most part, those are relatively obscure platform/compiler combinations to
- * which the PostgreSQL project does not have access.
- */
-#define USE_DEFAULT_S_UNLOCK
-extern void s_unlock(volatile slock_t *lock);
-#define S_UNLOCK(lock)		s_unlock(lock)
-#endif	 /* S_UNLOCK */
-
-#if !defined(S_INIT_LOCK)
-#define S_INIT_LOCK(lock)	S_UNLOCK(lock)
-#endif	 /* S_INIT_LOCK */
-
-#if !defined(SPIN_DELAY)
-#define SPIN_DELAY()	((void) 0)
-#endif	 /* SPIN_DELAY */
-
-#if !defined(TAS)
-extern int	tas(volatile slock_t *lock);		/* in port/.../tas.s, or
-												 * s_lock.c */
-
-#define TAS(lock)		tas(lock)
-#endif	 /* TAS */
-
-#if !defined(TAS_SPIN)
-#define TAS_SPIN(lock)	TAS(lock)
-#endif	 /* TAS_SPIN */
-
-
-/*
- * Platform-independent out-of-line support routines
- */
-extern int s_lock(volatile slock_t *lock, const char *file, int line, const char *func);
-
-/* Support for dynamic adjustment of spins_per_delay */
-#define DEFAULT_SPINS_PER_DELAY  100
-
-extern void set_spins_per_delay(int shared_spins_per_delay);
-extern int	update_spins_per_delay(int shared_spins_per_delay);
-
-/*
- * Support for spin delay which is useful in various places where
- * spinlock-like procedures take place.
- */
-typedef struct
-{
-	int			spins;
-	int			delays;
-	int			cur_delay;
-	const char *file;
-	int			line;
-	const char *func;
-} SpinDelayStatus;
-
-static inline void
-init_spin_delay(SpinDelayStatus *status,
-				const char *file, int line, const char *func)
-{
-	status->spins = 0;
-	status->delays = 0;
-	status->cur_delay = 0;
-	status->file = file;
-	status->line = line;
-	status->func = func;
-}
-
-#define init_local_spin_delay(status) init_spin_delay(status, __FILE__, __LINE__, __func__)
-extern void perform_spin_delay(SpinDelayStatus *status);
-extern void finish_spin_delay(SpinDelayStatus *status);
-
-#endif	 /* S_LOCK_H */
diff --git a/src/include/storage/spin.h b/src/include/storage/spin.h
index 33e2ab87572..eece7026d3b 100644
--- a/src/include/storage/spin.h
+++ b/src/include/storage/spin.h
@@ -14,9 +14,11 @@
  *		Acquire a spinlock, waiting if necessary.
  *		Time out and abort() if unable to acquire the lock in a
  *		"reasonable" amount of time --- typically ~ 1 minute.
+ *		Acquire (including read barrier) semantics.
  *
  *	void SpinLockRelease(volatile slock_t *lock)
  *		Unlock a previously acquired lock.
+ *		Release (including write barrier) semantics.
  *
  *	bool SpinLockFree(slock_t *lock)
  *		Tests if the lock is free. Returns true if free, false if locked.
@@ -35,11 +37,6 @@
  *	for a CHECK_FOR_INTERRUPTS() to occur while holding a spinlock, and so
  *	it is not necessary to do HOLD/RESUME_INTERRUPTS() in these macros.
  *
- *	These macros are implemented in terms of hardware-dependent macros
- *	supplied by s_lock.h.  There is not currently any extra functionality
- *	added by this header, but there has been in the past and may someday
- *	be again.
- *
  *
  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
@@ -51,15 +48,68 @@
 #ifndef SPIN_H
 #define SPIN_H
 
-#include "storage/s_lock.h"
+#ifdef FRONTEND
+#error "spin.h may not be included from frontend code"
+#endif
+
+#include "port/atomics.h"
+
+/* Support for dynamic adjustment of spins_per_delay */
+#define DEFAULT_SPINS_PER_DELAY  100
+
+typedef pg_atomic_flag slock_t;
+
+/*
+ * Support for spin delay which is useful in various places where
+ * spinlock-like procedures take place.
+ */
+typedef struct
+{
+	int			spins;
+	int			delays;
+	int			cur_delay;
+	const char *file;
+	int			line;
+	const char *func;
+} SpinDelayStatus;
+
+static inline void
+init_spin_delay(SpinDelayStatus *status,
+				const char *file, int line, const char *func)
+{
+	status->spins = 0;
+	status->delays = 0;
+	status->cur_delay = 0;
+	status->file = file;
+	status->line = line;
+	status->func = func;
+}
 
+#define init_local_spin_delay(status) init_spin_delay(status, __FILE__, __LINE__, __func__)
+extern void perform_spin_delay(SpinDelayStatus *status);
+extern void finish_spin_delay(SpinDelayStatus *status);
+extern void set_spins_per_delay(int shared_spins_per_delay);
+extern int	update_spins_per_delay(int shared_spins_per_delay);
 
-#define SpinLockInit(lock)	S_INIT_LOCK(lock)
+/* Out-of-line part of spinlock acquisition. */
+extern int	s_lock(volatile slock_t *lock,
+				   const char *file, int line,
+				   const char *func);
 
-#define SpinLockAcquire(lock) S_LOCK(lock)
+static inline void
+SpinLockInit(volatile slock_t *lock)
+{
+	pg_atomic_init_flag(lock);
+}
 
-#define SpinLockRelease(lock) S_UNLOCK(lock)
+#define SpinLockAcquire(lock)						\
+	(pg_atomic_test_set_flag(lock) ? 0 :			\
+	 s_lock((lock), __FILE__, __LINE__, __func__))
 
-#define SpinLockFree(lock)	S_LOCK_FREE(lock)
+static inline void
+SpinLockRelease(volatile slock_t *lock)
+{
+	pg_atomic_clear_flag(lock);
+}
 
 #endif							/* SPIN_H */
diff --git a/src/template/solaris b/src/template/solaris
deleted file mode 100644
index a4d8d38a8f8..00000000000
--- a/src/template/solaris
+++ /dev/null
@@ -1,4 +0,0 @@
-# src/template/solaris
-
-# Extra CFLAGS for code that will go into a shared library
-CFLAGS_SL="-fPIC"
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index a2db6080876..dd4034e8eda 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -658,32 +658,9 @@ test_spinlock(void)
 		SpinLockAcquire(&struct_w_lock.lock);
 		SpinLockRelease(&struct_w_lock.lock);
 
-		/* test basic operations via underlying S_* API */
-		S_INIT_LOCK(&struct_w_lock.lock);
-		S_LOCK(&struct_w_lock.lock);
-		S_UNLOCK(&struct_w_lock.lock);
-
 		/* and that "contended" acquisition works */
 		s_lock(&struct_w_lock.lock, "testfile", 17, "testfunc");
-		S_UNLOCK(&struct_w_lock.lock);
-
-		/*
-		 * Check, using TAS directly, that a single spin cycle doesn't block
-		 * when acquiring an already acquired lock.
-		 */
-#ifdef TAS
-		S_LOCK(&struct_w_lock.lock);
-
-		if (!TAS(&struct_w_lock.lock))
-			elog(ERROR, "acquired already held spinlock");
-
-#ifdef TAS_SPIN
-		if (!TAS_SPIN(&struct_w_lock.lock))
-			elog(ERROR, "acquired already held spinlock");
-#endif							/* defined(TAS_SPIN) */
-
-		S_UNLOCK(&struct_w_lock.lock);
-#endif							/* defined(TAS) */
+		SpinLockRelease(&struct_w_lock.lock);
 
 		/*
 		 * Verify that after all of this the non-lock contents are still
-- 
2.50.1 (Apple Git-155)



  [application/octet-stream] v1-0004-Remove-configure-meson-checks-for-atomics.patch (16.1K, 5-v1-0004-Remove-configure-meson-checks-for-atomics.patch)
  download | inline diff:
From 60d21c1950f92ed0b0a10b2cec29b242a17fa276 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Mon, 10 Nov 2025 23:03:00 +1300
Subject: [PATCH v1 4/4] Remove configure/meson checks for atomics.

These are now unreferenced, but this was kept separate from the two
patches that did that to disentangle them.
---
 config/c-compiler.m4        |  99 ------------------
 configure                   | 200 ------------------------------------
 configure.ac                |  10 --
 meson.build                 |  63 ------------
 src/backend/Makefile        |   2 +-
 src/backend/port/.gitignore |   1 -
 src/include/pg_config.h.in  |  20 ----
 7 files changed, 1 insertion(+), 394 deletions(-)

diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 236a59e8536..e05570255b3 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -446,105 +446,6 @@ AC_DEFUN([PGAC_PROG_CC_LDFLAGS_OPT],
 [PGAC_PROG_CC_LD_VARFLAGS_OPT(LDFLAGS, [$1], [$2])
 ])# PGAC_PROG_CC_LDFLAGS_OPT
 
-
-# PGAC_HAVE_GCC__SYNC_CHAR_TAS
-# ----------------------------
-# Check if the C compiler understands __sync_lock_test_and_set(char),
-# and define HAVE_GCC__SYNC_CHAR_TAS
-#
-# NB: There are platforms where test_and_set is available but compare_and_swap
-# is not, so test this separately.
-# NB: Some platforms only do 32bit tas, others only do 8bit tas. Test both.
-AC_DEFUN([PGAC_HAVE_GCC__SYNC_CHAR_TAS],
-[AC_CACHE_CHECK(for builtin __sync char locking functions, pgac_cv_gcc_sync_char_tas,
-[AC_LINK_IFELSE([AC_LANG_PROGRAM([],
-  [char lock = 0;
-   __sync_lock_test_and_set(&lock, 1);
-   __sync_lock_release(&lock);])],
-  [pgac_cv_gcc_sync_char_tas="yes"],
-  [pgac_cv_gcc_sync_char_tas="no"])])
-if test x"$pgac_cv_gcc_sync_char_tas" = x"yes"; then
-  AC_DEFINE(HAVE_GCC__SYNC_CHAR_TAS, 1, [Define to 1 if you have __sync_lock_test_and_set(char *) and friends.])
-fi])# PGAC_HAVE_GCC__SYNC_CHAR_TAS
-
-# PGAC_HAVE_GCC__SYNC_INT32_TAS
-# -----------------------------
-# Check if the C compiler understands __sync_lock_test_and_set(),
-# and define HAVE_GCC__SYNC_INT32_TAS
-AC_DEFUN([PGAC_HAVE_GCC__SYNC_INT32_TAS],
-[AC_CACHE_CHECK(for builtin __sync int32 locking functions, pgac_cv_gcc_sync_int32_tas,
-[AC_LINK_IFELSE([AC_LANG_PROGRAM([],
-  [int lock = 0;
-   __sync_lock_test_and_set(&lock, 1);
-   __sync_lock_release(&lock);])],
-  [pgac_cv_gcc_sync_int32_tas="yes"],
-  [pgac_cv_gcc_sync_int32_tas="no"])])
-if test x"$pgac_cv_gcc_sync_int32_tas" = x"yes"; then
-  AC_DEFINE(HAVE_GCC__SYNC_INT32_TAS, 1, [Define to 1 if you have __sync_lock_test_and_set(int *) and friends.])
-fi])# PGAC_HAVE_GCC__SYNC_INT32_TAS
-
-# PGAC_HAVE_GCC__SYNC_INT32_CAS
-# -----------------------------
-# Check if the C compiler understands __sync_compare_and_swap() for 32bit
-# types, and define HAVE_GCC__SYNC_INT32_CAS if so.
-AC_DEFUN([PGAC_HAVE_GCC__SYNC_INT32_CAS],
-[AC_CACHE_CHECK(for builtin __sync int32 atomic operations, pgac_cv_gcc_sync_int32_cas,
-[AC_LINK_IFELSE([AC_LANG_PROGRAM([],
-  [int val = 0;
-   __sync_val_compare_and_swap(&val, 0, 37);])],
-  [pgac_cv_gcc_sync_int32_cas="yes"],
-  [pgac_cv_gcc_sync_int32_cas="no"])])
-if test x"$pgac_cv_gcc_sync_int32_cas" = x"yes"; then
-  AC_DEFINE(HAVE_GCC__SYNC_INT32_CAS, 1, [Define to 1 if you have __sync_val_compare_and_swap(int *, int, int).])
-fi])# PGAC_HAVE_GCC__SYNC_INT32_CAS
-
-# PGAC_HAVE_GCC__SYNC_INT64_CAS
-# -----------------------------
-# Check if the C compiler understands __sync_compare_and_swap() for 64bit
-# types, and define HAVE_GCC__SYNC_INT64_CAS if so.
-AC_DEFUN([PGAC_HAVE_GCC__SYNC_INT64_CAS],
-[AC_CACHE_CHECK(for builtin __sync int64 atomic operations, pgac_cv_gcc_sync_int64_cas,
-[AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <stdint.h>],
-  [int64_t lock = 0;
-   __sync_val_compare_and_swap(&lock, 0, (int64_t) 37);])],
-  [pgac_cv_gcc_sync_int64_cas="yes"],
-  [pgac_cv_gcc_sync_int64_cas="no"])])
-if test x"$pgac_cv_gcc_sync_int64_cas" = x"yes"; then
-  AC_DEFINE(HAVE_GCC__SYNC_INT64_CAS, 1, [Define to 1 if you have __sync_val_compare_and_swap(int64_t *, int64_t, int64_t).])
-fi])# PGAC_HAVE_GCC__SYNC_INT64_CAS
-
-# PGAC_HAVE_GCC__ATOMIC_INT32_CAS
-# -------------------------------
-# Check if the C compiler understands __atomic_compare_exchange_n() for 32bit
-# types, and define HAVE_GCC__ATOMIC_INT32_CAS if so.
-AC_DEFUN([PGAC_HAVE_GCC__ATOMIC_INT32_CAS],
-[AC_CACHE_CHECK(for builtin __atomic int32 atomic operations, pgac_cv_gcc_atomic_int32_cas,
-[AC_LINK_IFELSE([AC_LANG_PROGRAM([],
-  [int val = 0;
-   int expect = 0;
-   __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);])],
-  [pgac_cv_gcc_atomic_int32_cas="yes"],
-  [pgac_cv_gcc_atomic_int32_cas="no"])])
-if test x"$pgac_cv_gcc_atomic_int32_cas" = x"yes"; then
-  AC_DEFINE(HAVE_GCC__ATOMIC_INT32_CAS, 1, [Define to 1 if you have __atomic_compare_exchange_n(int *, int *, int).])
-fi])# PGAC_HAVE_GCC__ATOMIC_INT32_CAS
-
-# PGAC_HAVE_GCC__ATOMIC_INT64_CAS
-# -------------------------------
-# Check if the C compiler understands __atomic_compare_exchange_n() for 64bit
-# types, and define HAVE_GCC__ATOMIC_INT64_CAS if so.
-AC_DEFUN([PGAC_HAVE_GCC__ATOMIC_INT64_CAS],
-[AC_CACHE_CHECK(for builtin __atomic int64 atomic operations, pgac_cv_gcc_atomic_int64_cas,
-[AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <stdint.h>],
-  [int64_t val = 0;
-   int64_t expect = 0;
-   __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);])],
-  [pgac_cv_gcc_atomic_int64_cas="yes"],
-  [pgac_cv_gcc_atomic_int64_cas="no"])])
-if test x"$pgac_cv_gcc_atomic_int64_cas" = x"yes"; then
-  AC_DEFINE(HAVE_GCC__ATOMIC_INT64_CAS, 1, [Define to 1 if you have __atomic_compare_exchange_n(int64 *, int64 *, int64).])
-fi])# PGAC_HAVE_GCC__ATOMIC_INT64_CAS
-
 # PGAC_SSE42_CRC32_INTRINSICS
 # ---------------------------
 # Check if the compiler supports the x86 CRC instructions added in SSE 4.2,
diff --git a/configure b/configure
index 3a0ed11fa8e..bd7dee3fdf3 100755
--- a/configure
+++ b/configure
@@ -17167,206 +17167,6 @@ _ACEOF
   fi
 fi
 
-# Check for various atomic operations now that we have checked how to declare
-# 64bit integers.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __sync char locking functions" >&5
-$as_echo_n "checking for builtin __sync char locking functions... " >&6; }
-if ${pgac_cv_gcc_sync_char_tas+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-char lock = 0;
-   __sync_lock_test_and_set(&lock, 1);
-   __sync_lock_release(&lock);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  pgac_cv_gcc_sync_char_tas="yes"
-else
-  pgac_cv_gcc_sync_char_tas="no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_gcc_sync_char_tas" >&5
-$as_echo "$pgac_cv_gcc_sync_char_tas" >&6; }
-if test x"$pgac_cv_gcc_sync_char_tas" = x"yes"; then
-
-$as_echo "#define HAVE_GCC__SYNC_CHAR_TAS 1" >>confdefs.h
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __sync int32 locking functions" >&5
-$as_echo_n "checking for builtin __sync int32 locking functions... " >&6; }
-if ${pgac_cv_gcc_sync_int32_tas+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-int lock = 0;
-   __sync_lock_test_and_set(&lock, 1);
-   __sync_lock_release(&lock);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  pgac_cv_gcc_sync_int32_tas="yes"
-else
-  pgac_cv_gcc_sync_int32_tas="no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_gcc_sync_int32_tas" >&5
-$as_echo "$pgac_cv_gcc_sync_int32_tas" >&6; }
-if test x"$pgac_cv_gcc_sync_int32_tas" = x"yes"; then
-
-$as_echo "#define HAVE_GCC__SYNC_INT32_TAS 1" >>confdefs.h
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __sync int32 atomic operations" >&5
-$as_echo_n "checking for builtin __sync int32 atomic operations... " >&6; }
-if ${pgac_cv_gcc_sync_int32_cas+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-int val = 0;
-   __sync_val_compare_and_swap(&val, 0, 37);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  pgac_cv_gcc_sync_int32_cas="yes"
-else
-  pgac_cv_gcc_sync_int32_cas="no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_gcc_sync_int32_cas" >&5
-$as_echo "$pgac_cv_gcc_sync_int32_cas" >&6; }
-if test x"$pgac_cv_gcc_sync_int32_cas" = x"yes"; then
-
-$as_echo "#define HAVE_GCC__SYNC_INT32_CAS 1" >>confdefs.h
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __sync int64 atomic operations" >&5
-$as_echo_n "checking for builtin __sync int64 atomic operations... " >&6; }
-if ${pgac_cv_gcc_sync_int64_cas+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdint.h>
-int
-main ()
-{
-int64_t lock = 0;
-   __sync_val_compare_and_swap(&lock, 0, (int64_t) 37);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  pgac_cv_gcc_sync_int64_cas="yes"
-else
-  pgac_cv_gcc_sync_int64_cas="no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_gcc_sync_int64_cas" >&5
-$as_echo "$pgac_cv_gcc_sync_int64_cas" >&6; }
-if test x"$pgac_cv_gcc_sync_int64_cas" = x"yes"; then
-
-$as_echo "#define HAVE_GCC__SYNC_INT64_CAS 1" >>confdefs.h
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __atomic int32 atomic operations" >&5
-$as_echo_n "checking for builtin __atomic int32 atomic operations... " >&6; }
-if ${pgac_cv_gcc_atomic_int32_cas+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-int val = 0;
-   int expect = 0;
-   __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  pgac_cv_gcc_atomic_int32_cas="yes"
-else
-  pgac_cv_gcc_atomic_int32_cas="no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_gcc_atomic_int32_cas" >&5
-$as_echo "$pgac_cv_gcc_atomic_int32_cas" >&6; }
-if test x"$pgac_cv_gcc_atomic_int32_cas" = x"yes"; then
-
-$as_echo "#define HAVE_GCC__ATOMIC_INT32_CAS 1" >>confdefs.h
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __atomic int64 atomic operations" >&5
-$as_echo_n "checking for builtin __atomic int64 atomic operations... " >&6; }
-if ${pgac_cv_gcc_atomic_int64_cas+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdint.h>
-int
-main ()
-{
-int64_t val = 0;
-   int64_t expect = 0;
-   __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  pgac_cv_gcc_atomic_int64_cas="yes"
-else
-  pgac_cv_gcc_atomic_int64_cas="no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_gcc_atomic_int64_cas" >&5
-$as_echo "$pgac_cv_gcc_atomic_int64_cas" >&6; }
-if test x"$pgac_cv_gcc_atomic_int64_cas" = x"yes"; then
-
-$as_echo "#define HAVE_GCC__ATOMIC_INT64_CAS 1" >>confdefs.h
-
-fi
-
-
 # Check for __get_cpuid() and __cpuid()
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __get_cpuid" >&5
 $as_echo_n "checking for __get_cpuid... " >&6; }
diff --git a/configure.ac b/configure.ac
index c2413720a18..e3b75601df7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2019,16 +2019,6 @@ AC_DEFINE_UNQUOTED(MAXIMUM_ALIGNOF, $MAX_ALIGNOF, [Define as the maximum alignme
 # Some compilers offer a 128-bit integer scalar type.
 PGAC_TYPE_128BIT_INT
 
-# Check for various atomic operations now that we have checked how to declare
-# 64bit integers.
-PGAC_HAVE_GCC__SYNC_CHAR_TAS
-PGAC_HAVE_GCC__SYNC_INT32_TAS
-PGAC_HAVE_GCC__SYNC_INT32_CAS
-PGAC_HAVE_GCC__SYNC_INT64_CAS
-PGAC_HAVE_GCC__ATOMIC_INT32_CAS
-PGAC_HAVE_GCC__ATOMIC_INT64_CAS
-
-
 # Check for __get_cpuid() and __cpuid()
 AC_CACHE_CHECK([for __get_cpuid], [pgac_cv__get_cpuid],
 [AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <cpuid.h>],
diff --git a/meson.build b/meson.build
index 24aeffe929f..3b88f63b0df 100644
--- a/meson.build
+++ b/meson.build
@@ -2212,69 +2212,6 @@ if llvm.found()
 endif
 
 
-
-###############################################################
-# Atomics
-###############################################################
-
-atomic_checks = [
-  {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
-   'desc': '__sync_lock_test_and_set(char)',
-   'test': '''
-char lock = 0;
-__sync_lock_test_and_set(&lock, 1);
-__sync_lock_release(&lock);'''},
-
-  {'name': 'HAVE_GCC__SYNC_INT32_TAS',
-   'desc': '__sync_lock_test_and_set(int32)',
-   'test': '''
-int lock = 0;
-__sync_lock_test_and_set(&lock, 1);
-__sync_lock_release(&lock);'''},
-
-  {'name': 'HAVE_GCC__SYNC_INT32_CAS',
-   'desc': '__sync_val_compare_and_swap(int32)',
-   'test': '''
-int val = 0;
-__sync_val_compare_and_swap(&val, 0, 37);'''},
-
-  {'name': 'HAVE_GCC__SYNC_INT64_CAS',
-   'desc': '__sync_val_compare_and_swap(int64)',
-   'test': '''
-int64_t val = 0;
-__sync_val_compare_and_swap(&val, 0, 37);'''},
-
-  {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
-   'desc': ' __atomic_compare_exchange_n(int32)',
-   'test': '''
-int val = 0;
-int expect = 0;
-__atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
-
-  {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
-   'desc': ' __atomic_compare_exchange_n(int64)',
-   'test': '''
-int64_t val = 0;
-int64_t expect = 0;
-__atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
-]
-
-foreach check : atomic_checks
-  test = '''
-#include <stdint.h>
-int main(void)
-{
-@0@
-}'''.format(check['test'])
-
-  cdata.set(check['name'],
-    cc.links(test,
-      name: check['desc'],
-      args: test_c_args) ? 1 : false
-  )
-endforeach
-
-
 ###############################################################
 # Check for the availability of XSAVE intrinsics.
 ###############################################################
diff --git a/src/backend/Makefile b/src/backend/Makefile
index 7344c8c7f5c..b0d97dc2fa2 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -265,7 +265,7 @@ endif
 
 distclean: clean
 # generated by configure
-	rm -f port/tas.s port/pg_sema.c port/pg_shmem.c
+	rm -f port/pg_sema.c port/pg_shmem.c
 
 
 ##########################################################################
diff --git a/src/backend/port/.gitignore b/src/backend/port/.gitignore
index 4ef36b82c77..6c5067a4a9f 100644
--- a/src/backend/port/.gitignore
+++ b/src/backend/port/.gitignore
@@ -1,3 +1,2 @@
 /pg_sema.c
 /pg_shmem.c
-/tas.s
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index b0b0cfdaf79..ad5663a8915 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -149,26 +149,6 @@
 /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
 #undef HAVE_FSEEKO
 
-/* Define to 1 if you have __atomic_compare_exchange_n(int *, int *, int). */
-#undef HAVE_GCC__ATOMIC_INT32_CAS
-
-/* Define to 1 if you have __atomic_compare_exchange_n(int64 *, int64 *,
-   int64). */
-#undef HAVE_GCC__ATOMIC_INT64_CAS
-
-/* Define to 1 if you have __sync_lock_test_and_set(char *) and friends. */
-#undef HAVE_GCC__SYNC_CHAR_TAS
-
-/* Define to 1 if you have __sync_val_compare_and_swap(int *, int, int). */
-#undef HAVE_GCC__SYNC_INT32_CAS
-
-/* Define to 1 if you have __sync_lock_test_and_set(int *) and friends. */
-#undef HAVE_GCC__SYNC_INT32_TAS
-
-/* Define to 1 if you have __sync_val_compare_and_swap(int64_t *, int64_t,
-   int64_t). */
-#undef HAVE_GCC__SYNC_INT64_CAS
-
 /* Define to 1 if you have the `getauxval' function. */
 #undef HAVE_GETAUXVAL
 
-- 
2.50.1 (Apple Git-155)



^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
@ 2025-11-10 13:57 ` Heikki Linnakangas <[email protected]>
  2025-11-10 15:19   ` Re: Trying out <stdatomic.h> Tom Lane <[email protected]>
  2025-11-13 11:35   ` Re: Trying out <stdatomic.h> Thomas Munro <[email protected]>
  1 sibling, 2 replies; 19+ messages in thread

From: Heikki Linnakangas @ 2025-11-10 13:57 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>

On 10/11/2025 15:17, Thomas Munro wrote:
> Hi,
> 
> Here is an experimental patch to try out standard C (and C++) atomics
> to implement port/atomics.h, and also add more types and operations.
> It's mostly just redirecting our names to the standard ones, except
> for our barriers and slightly extended pg_atomic_flag, so there isn't
> much left of the code.

>  9 files changed, 166 insertions(+), 1824 deletions(-)
>  ...
>  8 files changed, 176 insertions(+), 881 deletions(-)
>  ...
>  7 files changed, 1 insertion(+), 394 deletions(-)

Nice!

> [PATCH v1 1/4] Add some missing #include <limits.h>.

This seems like a good thing regardless of the other patches.

The "#include <limits.h>" lines in src/backend/lib/dshash.c and 
src/backend/storage/lmgr/condition_variable.c are slightly misplaced: 
system headers should be included between "postgres.h" and other 
postgres headers.

> Here also is a semi-independent patch to implement storage/spin.h with
> pg_atomic_flag.  It keeps a small amount of the architecture-specific
> magic, but moves it out to src/port/spin_delay.h.

Makes sense.

The patch removes 'src/template/solaris'. Is that on purpose? Is that an 
independent cleanup that could be committed immediately?

- Heikki






^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-10 13:57 ` Re: Trying out <stdatomic.h> Heikki Linnakangas <[email protected]>
@ 2025-11-10 15:19   ` Tom Lane <[email protected]>
  2025-11-10 20:25     ` Re: Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-23 15:02     ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
  1 sibling, 2 replies; 19+ messages in thread

From: Tom Lane @ 2025-11-10 15:19 UTC (permalink / raw)
  To: Heikki Linnakangas <[email protected]>; +Cc: Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>

Heikki Linnakangas <[email protected]> writes:
> The patch removes 'src/template/solaris'. Is that on purpose? Is that an 
> independent cleanup that could be committed immediately?

Our four Solaris+illumos buildfarm animals would be sad.

			regards, tom lane





^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-10 13:57 ` Re: Trying out <stdatomic.h> Heikki Linnakangas <[email protected]>
  2025-11-10 15:19   ` Re: Trying out <stdatomic.h> Tom Lane <[email protected]>
@ 2025-11-10 20:25     ` Thomas Munro <[email protected]>
  1 sibling, 0 replies; 19+ messages in thread

From: Thomas Munro @ 2025-11-10 20:25 UTC (permalink / raw)
  To: Tom Lane <[email protected]>; +Cc: Heikki Linnakangas <[email protected]>; PostgreSQL Hackers <[email protected]>

On Tue, Nov 11, 2025 at 4:19 AM Tom Lane <[email protected]> wrote:
> Heikki Linnakangas <[email protected]> writes:
> > The patch removes 'src/template/solaris'. Is that on purpose? Is that an
> > independent cleanup that could be committed immediately?
>
> Our four Solaris+illumos buildfarm animals would be sad.

Looks like I overdid it while rebasing over the commit that removed
the dead Sun compiler... will put that bit back.





^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-10 13:57 ` Re: Trying out <stdatomic.h> Heikki Linnakangas <[email protected]>
  2025-11-10 15:19   ` Re: Trying out <stdatomic.h> Tom Lane <[email protected]>
@ 2025-11-23 15:02     ` Greg Burd <[email protected]>
  2025-11-23 17:02       ` Re: Trying out <stdatomic.h> Tom Lane <[email protected]>
  1 sibling, 1 reply; 19+ messages in thread

From: Greg Burd @ 2025-11-23 15:02 UTC (permalink / raw)
  To: Tom Lane <[email protected]>; Heikki Linnakangas <[email protected]>; +Cc: Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>


On Mon, Nov 10, 2025, at 10:19 AM, Tom Lane wrote:
> Heikki Linnakangas <[email protected]> writes:
>> The patch removes 'src/template/solaris'. Is that on purpose? Is that an 
>> independent cleanup that could be committed immediately?
>
> Our four Solaris+illumos buildfarm animals would be sad.
>
> 			regards, tom lane

I have another Illumos animal in the works, but if the plan is to deprecate that platform I can set that aside.  As an old Sun engineer I hate to see it disappear, but it is basically EOL at this point.

-greg





^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-10 13:57 ` Re: Trying out <stdatomic.h> Heikki Linnakangas <[email protected]>
  2025-11-10 15:19   ` Re: Trying out <stdatomic.h> Tom Lane <[email protected]>
  2025-11-23 15:02     ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
@ 2025-11-23 17:02       ` Tom Lane <[email protected]>
  2025-11-23 18:17         ` Re: Trying out <stdatomic.h> Álvaro Herrera <[email protected]>
  2025-11-23 20:16         ` Re: Trying out <stdatomic.h> Thomas Munro <[email protected]>
  0 siblings, 2 replies; 19+ messages in thread

From: Tom Lane @ 2025-11-23 17:02 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; +Cc: Heikki Linnakangas <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>

"Greg Burd" <[email protected]> writes:
> I have another Illumos animal in the works, but if the plan is to deprecate that platform I can set that aside.  As an old Sun engineer I hate to see it disappear, but it is basically EOL at this point.

I think we can keep it going as long as there are people interested
in it.  The gating factor at present is probably whether it can
provide an adequate C11 environment.  But so far I've observed no
issues with the existing BF members.

			regards, tom lane





^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-10 13:57 ` Re: Trying out <stdatomic.h> Heikki Linnakangas <[email protected]>
  2025-11-10 15:19   ` Re: Trying out <stdatomic.h> Tom Lane <[email protected]>
  2025-11-23 15:02     ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
  2025-11-23 17:02       ` Re: Trying out <stdatomic.h> Tom Lane <[email protected]>
@ 2025-11-23 18:17         ` Álvaro Herrera <[email protected]>
  1 sibling, 0 replies; 19+ messages in thread

From: Álvaro Herrera @ 2025-11-23 18:17 UTC (permalink / raw)
  To: Tom Lane <[email protected]>; +Cc: Greg Burd <[email protected]>; Heikki Linnakangas <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>

On 2025-Nov-23, Tom Lane wrote:

> "Greg Burd" <[email protected]> writes:
> > I have another Illumos animal in the works, but if the plan is to deprecate that platform I can set that aside.  As an old Sun engineer I hate to see it disappear, but it is basically EOL at this point.
> 
> I think we can keep it going as long as there are people interested
> in it.  The gating factor at present is probably whether it can
> provide an adequate C11 environment.  But so far I've observed no
> issues with the existing BF members.

Right -- we have

billbug		Solaris 11.4.81 CBE 04.2025	gcc 14.2.0
hake		OpenIndiana / Illumos		gcc 9.3.0
margay		Solaris 11.4.42 CBE		gcc 11.2.0
pollock		OmniOS / illumos		gcc 10.2.0


Hake actually says:
  gcc (OpenIndiana 13.3.0-oi-2) 13.3.0

and pollock:
  gcc (OmniOS 151054/14.2.0-il-1) 14.2.0

so it looks like the oldest is Margay's 11.2, which claims [1] to
support C11, though there are some bugs that were claimed fixed in later
releases of GCC 11.x related to alignment[2].  Perhaps relevant, but I
only searched the strings "align" and "c11" there, they may not apply to
our usage.  At least the owner of margay and billbug is active, so we
can probably get the compiler in these machines updated if needed.


[1] https://gcc.gnu.org/onlinedocs/gcc-11.2.0/gcc/Standards.html#C-Language
[2] https://gcc.gnu.org/bugzilla/buglist.cgi?bug_status=RESOLVED&resolution=FIXED&target_milesto...
    and further for 11.4, 11.5, 11.6.

-- 
Álvaro Herrera        Breisgau, Deutschland  —  https://www.EnterpriseDB.com/





^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-10 13:57 ` Re: Trying out <stdatomic.h> Heikki Linnakangas <[email protected]>
  2025-11-10 15:19   ` Re: Trying out <stdatomic.h> Tom Lane <[email protected]>
  2025-11-23 15:02     ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
  2025-11-23 17:02       ` Re: Trying out <stdatomic.h> Tom Lane <[email protected]>
@ 2025-11-23 20:16         ` Thomas Munro <[email protected]>
  1 sibling, 0 replies; 19+ messages in thread

From: Thomas Munro @ 2025-11-23 20:16 UTC (permalink / raw)
  To: Tom Lane <[email protected]>; +Cc: Greg Burd <[email protected]>; Heikki Linnakangas <[email protected]>; PostgreSQL Hackers <[email protected]>

On Mon, Nov 24, 2025 at 6:02 AM Tom Lane <[email protected]> wrote:
> "Greg Burd" <[email protected]> writes:
> > I have another Illumos animal in the works, but if the plan is to deprecate that platform I can set that aside.  As an old Sun engineer I hate to see it disappear, but it is basically EOL at this point.
>
> I think we can keep it going as long as there are people interested
> in it.  The gating factor at present is probably whether it can
> provide an adequate C11 environment.  But so far I've observed no
> issues with the existing BF members.

Yeah, Solaris has caused comparatively little trouble, if you exclude
the defunct compiler and a build farm animal running a frozen zombie
Solaris version.  It's pretty easy for Linux users to understand
because of its huge influence on standards and conventions back in the
90s.  The buildfarm animals are maintained by people with a real
interest in PostgreSQL on both OSes, and both OSes fix bugs we report
and track POSIX actively.  We've run on SunOS/BSD and descendents for
coming up 40 (POSTGRES) or 30 (PostgreSQL) years, and I'm hoping we'll
even get to complete that Berkeley to-do item about using threads on
SunOS one of these days...  I just goofed when rebasing the v1 patch
and git rm-ed the template file instead of git add-ing it in v1, but I
fixed that in v2.





^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-10 13:57 ` Re: Trying out <stdatomic.h> Heikki Linnakangas <[email protected]>
@ 2025-11-13 11:35   ` Thomas Munro <[email protected]>
  2025-11-19 11:23     ` Re: Trying out <stdatomic.h> Peter Eisentraut <[email protected]>
  2025-11-19 14:03     ` Re: Trying out <stdatomic.h> Aleksander Alekseev <[email protected]>
  1 sibling, 2 replies; 19+ messages in thread

From: Thomas Munro @ 2025-11-13 11:35 UTC (permalink / raw)
  To: Heikki Linnakangas <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>

On Tue, Nov 11, 2025 at 2:57 AM Heikki Linnakangas <[email protected]> wrote:
> > [PATCH v1 1/4] Add some missing #include <limits.h>.
>
> This seems like a good thing regardless of the other patches.

Pushed.

> The patch removes 'src/template/solaris'. Is that on purpose?

Fixed.

It passes with VS 2022 on CI.  I had to skip some assertions about
macros promising lock-free implementation, that it doesn't define in C
mode yet.  They are definitely lock-free though[1], and the macros are
defined for C++, and the same under the covers...  Perhaps
feature/conformance macros won't be defined until a few remaining
pieces (things we don't care about) are accessible from C?  (I see
that Visual Studio 2026 has also just shipped a couple of days ago,
not investigated.)

[1] https://devblogs.microsoft.com/cppblog/c11-atomics-in-visual-studio-2022-version-17-5-preview-2/


Attachments:

  [application/octet-stream] v2-0001-ci-Use-Visual-Studio-2022-for-stdatomic.h.patch (1.2K, 2-v2-0001-ci-Use-Visual-Studio-2022-for-stdatomic.h.patch)
  download | inline diff:
From dd4bea7fd8c1e09ce6d8a66323b30c82e4a568c1 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Thu, 13 Nov 2025 17:48:09 +1300
Subject: [PATCH v2 1/5] ci: Use Visual Studio 2022, for <stdatomic.h>.

XXX No opinion on when we could require this as a baseline.  We only
just pulled the trigger on Visual Studio 2019 which added lots of C11,
but lacked <stdatomic.h>.

(Thanks to Bilal for getting this onto the CI image!)
---
 .cirrus.tasks.yml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index 2fe9671f3dc..266ce99e7db 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -767,11 +767,12 @@ WINDOWS_ENVIRONMENT_BASE: &WINDOWS_ENVIRONMENT_BASE
 
 
 task:
-  name: Windows - Server 2022, VS 2019 - Meson & ninja
+  name: Windows - Server 2022, VS 2022 - Meson & ninja
   << : *WINDOWS_ENVIRONMENT_BASE
 
   env:
     TEST_JOBS: 8 # wild guess, data based value welcome
+    PATH: C:\VS_2022\VC\Auxiliary\Build;${PATH}
 
     # Cirrus defaults to SetErrorMode(SEM_NOGPFAULTERRORBOX | ...). That
     # prevents crash reporting from working unless binaries do SetErrorMode()
-- 
2.50.1 (Apple Git-155)



  [application/octet-stream] v2-0002-Enable-Visual-Studio-s-stdatomic.h-support.patch (790B, 3-v2-0002-Enable-Visual-Studio-s-stdatomic.h-support.patch)
  download | inline diff:
From 58f088ee11236b3b5b20f2b6ffd97d17181f2afc Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Thu, 13 Nov 2025 10:48:14 +1300
Subject: [PATCH v2 2/5] Enable Visual Studio's <stdatomic.h> support.

XXX It's still marked as 'experimental' as of the compiler in CI.
---
 meson.build | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/meson.build b/meson.build
index c1e17aa3040..04c563378c7 100644
--- a/meson.build
+++ b/meson.build
@@ -580,6 +580,10 @@ if not cc.compiles(c11_test, name: 'C11')
   endif
 endif
 
+# XXX Should test whether <stdatomic.h> works without this
+if cc.get_id() == 'msvc'
+  cflags += '/experimental:c11atomics'
+endif
 
 postgres_inc = [include_directories(postgres_inc_d)]
 test_lib_d = postgres_lib_d
-- 
2.50.1 (Apple Git-155)



  [application/octet-stream] v2-0003-Redefine-port-atomics.h-on-top-of-stdatomic.h.patch (68.1K, 4-v2-0003-Redefine-port-atomics.h-on-top-of-stdatomic.h.patch)
  download | inline diff:
From f7274f7320a0b1231dd3e676e2b40d2235481189 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Tue, 2 Jul 2024 22:31:42 +1200
Subject: [PATCH v2 3/5] Redefine port/atomics.h on top of <stdatomic.h>.

 * Redirect types and functions to standard C/C++
 * Use <atomic> instead for C++11 extensions (as formalized by C++23)
 * Add pg_atomic_uint8, pg_atomic_uint16 and pg_atomic(T)
 * Provide generic pg_atomic_read(), pg_atomic_write()
 * Assume that most basic operations will be called by
   standardized generics in future code, eg atomic_fetch_add()
 * Forward all the traditional _32, _64 function names for
   existing code
 * Reimplement pg_atomic_flag with pg_atomic(uint8) to allow relaxed load
   (impossible with standard atomic_flag, and pg_atomic(bool) doesn't seem
   to be portable enough)
 * Let the compiler/runtime emulate 64 bit atomics with locks for armv7
 * The per-compiler headers now just define pg_compiler_barrier_impl()
 * The per-arch headers now optionally define
   pg_{memory,read,write}_barrier_impl() but only if they think they can
   do something better than compilers (to investigate...)
 * Drop the secondary copy of the ancient spinlock ops from atomics
 * Drop arch-{arm,ppc}.h, fallback.h and generic.h

WIP!

TODO: Need to research generated code on all architectures and see if
anything important is lost.
---
 src/include/port/atomics.h              | 626 +++++++-----------------
 src/include/port/atomics/arch-arm.h     |  32 --
 src/include/port/atomics/arch-ppc.h     | 256 ----------
 src/include/port/atomics/arch-x86.h     | 205 --------
 src/include/port/atomics/fallback.h     |  42 --
 src/include/port/atomics/generic-gcc.h  | 307 +-----------
 src/include/port/atomics/generic-msvc.h |  98 +---
 src/include/port/atomics/generic.h      | 427 ----------------
 src/tools/pgindent/typedefs.list        |   2 +
 9 files changed, 172 insertions(+), 1823 deletions(-)
 delete mode 100644 src/include/port/atomics/arch-arm.h
 delete mode 100644 src/include/port/atomics/arch-ppc.h
 delete mode 100644 src/include/port/atomics/fallback.h
 delete mode 100644 src/include/port/atomics/generic.h

diff --git a/src/include/port/atomics.h b/src/include/port/atomics.h
index 96f1858da97..c4d0e5f5821 100644
--- a/src/include/port/atomics.h
+++ b/src/include/port/atomics.h
@@ -3,24 +3,33 @@
  * atomics.h
  *	  Atomic operations.
  *
- * Hardware and compiler dependent functions for manipulating memory
- * atomically and dealing with cache coherency. Used to implement locking
- * facilities and lockless algorithms/data structures.
+ * These interfaces are for manipulating memory atomically and dealing with
+ * cache coherency. They can be used to implement locking facilities and
+ * lockless algorithms/data structures.
  *
- * To bring up postgres on a platform/compiler at the very least
- * implementations for the following operations should be provided:
- * * pg_compiler_barrier(), pg_write_barrier(), pg_read_barrier()
- * * pg_atomic_compare_exchange_u32(), pg_atomic_fetch_add_u32()
- * * pg_atomic_test_set_flag(), pg_atomic_init_flag(), pg_atomic_clear_flag()
- * * PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY should be defined if appropriate.
+ * This is mostly a renaming of <stdatomic.h>, with some differences:
  *
- * There exist generic, hardware independent, implementations for several
- * compilers which might be sufficient, although possibly not optimal, for a
- * new platform. If no such generic implementation is available spinlocks will
- * be used to implement the 64-bit parts of the API.
+ * * read/write barriers (weaker than acquire/release)
+ * * they affect even non-atomic access without dependency on atomic access
+ * * pg_atomic_flag semantics don't allow mapping to atomic_flag
  *
- * Implement _u64 atomics if and only if your platform can use them
- * efficiently (and obviously correctly).
+ * PostgreSQL atomic type width assumptions:
+ *
+ * 8, 16:  Required to be lock-free (even though implemented with wider
+ *         instructions by the compiler on some RISC-V systems).
+ *
+ * 32:     Required to be lock-free.  No known modern system lacks them.
+ *
+ * 64:     These can reasonably be expected to be lock-free and fast on
+ *         all modern-ish systems.  For one known low-end system  they are
+ *         emulated by the compiler/runtime with locks (armv7).
+ *
+ * In all cases values must be well aligned or undefined behavior results.
+ *
+ * To bring up postgres on a compiler, provide:
+ * * pg_compiler_barrier()
+ * Optionally also:
+ * * pg_memory_barrier(), pg_write_barrier(), pg_read_barrier()
  *
  * Use higher level functionality (lwlocks, spinlocks, heavyweight locks)
  * whenever possible. Writing correct code using these facilities is hard.
@@ -38,48 +47,66 @@
 #ifndef ATOMICS_H
 #define ATOMICS_H
 
-#ifdef FRONTEND
-#error "atomics.h may not be included from frontend code"
+#define INSIDE_ATOMICS_H
+
+#if defined(__cplusplus) && __cplusplus < 202302L
+/* C++11 can't include C's <stdatomic.h>.  Use approach from C++23 33.5.12. */
+extern "C++"
+{
+#include <atomic>
+#define pg_atomic(T) std::atomic<T>
+	using		std::memory_order_relaxed;
+	using		std::memory_order_acquire;
+	using		std::memory_order_release;
+	using		std::memory_order_acq_rel;
+	using		std::memory_order_seq_cst;
+}
+#else
+#include <stdatomic.h>
+#define pg_atomic(T) _Atomic(T)
 #endif
 
-#define INSIDE_ATOMICS_H
+/*
+ * Visual Studio 2022 doesn't seem to define these in <stdatomic.h> yet, but
+ * does define them to 2 in <atomic>.  They must hold in C too though, since
+ * they interoperate.
+ */
+#if !defined(_MSC_VER) || defined(__cplusplus)
+/* Assumptions about lock-free access. */
+StaticAssertDecl(ATOMIC_CHAR_LOCK_FREE >= 2, "need lock-free 8-bit atomics");
+StaticAssertDecl(ATOMIC_SHORT_LOCK_FREE >= 2, "need lock-free 16-bit atomics");
+StaticAssertDecl(ATOMIC_INT_LOCK_FREE >= 2, "need lock-free 32-bit atomics");
+#endif
 
-#include <limits.h>
+/* Can't use standard atomic_flag due to extended semantics, see below. */
+typedef pg_atomic(uint8)
+pg_atomic_flag;
+
+/* Common supported atomic integer types. */
+typedef pg_atomic(uint8)
+pg_atomic_uint8;
+typedef pg_atomic(uint16)
+pg_atomic_uint16;
+typedef pg_atomic(uint32)
+pg_atomic_uint32;
+typedef pg_atomic(uint64)
+pg_atomic_uint64;
 
 /*
  * First a set of architecture specific files is included.
  *
- * These files can provide the full set of atomics or can do pretty much
- * nothing if all the compilers commonly used on these platforms provide
- * usable generics.
- *
- * Don't add an inline assembly of the actual atomic operations if all the
- * common implementations of your platform provide intrinsics. Intrinsics are
- * much easier to understand and potentially support more architectures.
- *
  * It will often make sense to define memory barrier semantics here, since
  * e.g. generic compiler intrinsics for x86 memory barriers can't know that
  * postgres doesn't need x86 read/write barriers do anything more than a
  * compiler barrier.
- *
  */
-#if defined(__arm__) || defined(__arm) || defined(__aarch64__)
-#include "port/atomics/arch-arm.h"
-#elif defined(__i386__) || defined(__i386) || defined(__x86_64__)
+#if defined(__i386__) || defined(__i386) || defined(__x86_64__)
 #include "port/atomics/arch-x86.h"
-#elif defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__)
-#include "port/atomics/arch-ppc.h"
 #endif
 
 /*
  * Compiler specific, but architecture independent implementations.
- *
- * Provide architecture independent implementations of the atomic
- * facilities. At the very least compiler barriers should be provided, but a
- * full implementation of
- * * pg_compiler_barrier(), pg_write_barrier(), pg_read_barrier()
- * * pg_atomic_compare_exchange_u32(), pg_atomic_fetch_add_u32()
- * using compiler intrinsics are a good idea.
+ * This defines compiler barriers.
  */
 /*
  * gcc or compatible, including clang and icc.
@@ -93,29 +120,9 @@
 #endif
 
 /* Fail if we couldn't find implementations of required facilities. */
-#if !defined(PG_HAVE_ATOMIC_U32_SUPPORT)
-#error "could not find an implementation of pg_atomic_uint32"
-#endif
 #if !defined(pg_compiler_barrier_impl)
 #error "could not find an implementation of pg_compiler_barrier"
 #endif
-#if !defined(pg_memory_barrier_impl)
-#error "could not find an implementation of pg_memory_barrier_impl"
-#endif
-
-
-/*
- * Provide a spinlock-based implementation of the 64 bit variants, if
- * necessary.
- */
-#include "port/atomics/fallback.h"
-
-/*
- * Provide additional operations using supported infrastructure. These are
- * expected to be efficient if the underlying atomic operations are efficient.
- */
-#include "port/atomics/generic.h"
-
 
 /*
  * pg_compiler_barrier - prevent the compiler from moving code across
@@ -125,6 +132,10 @@
  * reorder loads or stores to main memory around the barrier.  However, the
  * CPU may still reorder loads or stores at runtime, if the architecture's
  * memory model permits this.
+ *
+ * Unlike standard atomic_signal_fence(), pg_compiler_barrier() prevents
+ * reordering of non-atomic, non-volatile accesses, so a compiler-specific
+ * definition is required.
  */
 #define pg_compiler_barrier()	pg_compiler_barrier_impl()
 
@@ -137,8 +148,20 @@
  * loads and stores are totally ordered (which is not the case on most
  * architectures) this requires issuing some sort of memory fencing
  * instruction.
+ *
+ * Unlike standard atomic_thread_fence(), pg_{read,write}_barrier() affects
+ * non-atomic, non-volatile accesses.
  */
-#define pg_memory_barrier() pg_memory_barrier_impl()
+static inline void
+pg_memory_barrier(void)
+{
+#ifdef pg_memory_barrier_impl
+	pg_memory_barrier_impl();
+#else
+	pg_compiler_barrier();
+	atomic_thread_fence(memory_order_seq_cst);
+#endif
+}
 
 /*
  * pg_(read|write)_barrier - prevent the CPU from reordering memory access
@@ -150,427 +173,116 @@
  * are thus weaker than a full memory barrier, but stronger than a compiler
  * barrier.  In practice, on machines with strong memory ordering, read and
  * write barriers may require nothing more than a compiler barrier.
- */
-#define pg_read_barrier()	pg_read_barrier_impl()
-#define pg_write_barrier()	pg_write_barrier_impl()
-
-/*
- * Spinloop delay - Allow CPU to relax in busy loops
- */
-#define pg_spin_delay() pg_spin_delay_impl()
-
-/*
- * pg_atomic_init_flag - initialize atomic flag.
  *
- * No barrier semantics.
+ * Unlike standard atomic_thread_fence(), pg_{read,write}_barrier() affects
+ * non-atomic, non-volatile accesses.  The default implementation uses
+ * acquire/release fences, but these are strictly stronger than read/write.
  */
-static inline void
-pg_atomic_init_flag(volatile pg_atomic_flag *ptr)
-{
-	pg_atomic_init_flag_impl(ptr);
-}
-
-/*
- * pg_atomic_test_set_flag - TAS()
- *
- * Returns true if the flag has successfully been set, false otherwise.
- *
- * Acquire (including read barrier) semantics.
- */
-static inline bool
-pg_atomic_test_set_flag(volatile pg_atomic_flag *ptr)
-{
-	return pg_atomic_test_set_flag_impl(ptr);
-}
 
-/*
- * pg_atomic_unlocked_test_flag - Check if the lock is free
- *
- * Returns true if the flag currently is not set, false otherwise.
- *
- * No barrier semantics.
- */
-static inline bool
-pg_atomic_unlocked_test_flag(volatile pg_atomic_flag *ptr)
-{
-	return pg_atomic_unlocked_test_flag_impl(ptr);
-}
-
-/*
- * pg_atomic_clear_flag - release lock set by TAS()
- *
- * Release (including write barrier) semantics.
- */
-static inline void
-pg_atomic_clear_flag(volatile pg_atomic_flag *ptr)
-{
-	pg_atomic_clear_flag_impl(ptr);
-}
-
-
-/*
- * pg_atomic_init_u32 - initialize atomic variable
- *
- * Has to be done before any concurrent usage..
- *
- * No barrier semantics.
- */
 static inline void
-pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
-{
-	AssertPointerAlignment(ptr, 4);
-
-	pg_atomic_init_u32_impl(ptr, val);
-}
-
-/*
- * pg_atomic_read_u32 - unlocked read from atomic variable.
- *
- * The read is guaranteed to return a value as it has been written by this or
- * another process at some point in the past. There's however no cache
- * coherency interaction guaranteeing the value hasn't since been written to
- * again.
- *
- * No barrier semantics.
- */
-static inline uint32
-pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
+pg_read_barrier(void)
 {
-	AssertPointerAlignment(ptr, 4);
-	return pg_atomic_read_u32_impl(ptr);
-}
-
-/*
- * pg_atomic_read_membarrier_u32 - read with barrier semantics.
- *
- * This read is guaranteed to return the current value, provided that the value
- * is only ever updated via operations with barrier semantics, such as
- * pg_atomic_compare_exchange_u32() and pg_atomic_write_membarrier_u32().
- * While this may be less performant than pg_atomic_read_u32(), it may be
- * easier to reason about correctness with this function in less performance-
- * sensitive code.
- *
- * Full barrier semantics.
- */
-static inline uint32
-pg_atomic_read_membarrier_u32(volatile pg_atomic_uint32 *ptr)
-{
-	AssertPointerAlignment(ptr, 4);
-
-	return pg_atomic_read_membarrier_u32_impl(ptr);
-}
-
-/*
- * pg_atomic_write_u32 - write to atomic variable.
- *
- * The write is guaranteed to succeed as a whole, i.e. it's not possible to
- * observe a partial write for any reader.  Note that this correctly interacts
- * with pg_atomic_compare_exchange_u32, in contrast to
- * pg_atomic_unlocked_write_u32().
- *
- * No barrier semantics.
- */
-static inline void
-pg_atomic_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
-{
-	AssertPointerAlignment(ptr, 4);
-
-	pg_atomic_write_u32_impl(ptr, val);
-}
-
-/*
- * pg_atomic_unlocked_write_u32 - unlocked write to atomic variable.
- *
- * The write is guaranteed to succeed as a whole, i.e. it's not possible to
- * observe a partial write for any reader.  But note that writing this way is
- * not guaranteed to correctly interact with read-modify-write operations like
- * pg_atomic_compare_exchange_u32.  This should only be used in cases where
- * minor performance regressions due to atomics emulation are unacceptable.
- *
- * No barrier semantics.
- */
-static inline void
-pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
-{
-	AssertPointerAlignment(ptr, 4);
-
-	pg_atomic_unlocked_write_u32_impl(ptr, val);
+#ifdef pg_read_barrier_impl
+	pg_read_barrier_impl();
+#else
+	pg_compiler_barrier();
+	atomic_thread_fence(memory_order_acquire);
+#endif
 }
 
-/*
- * pg_atomic_write_membarrier_u32 - write with barrier semantics.
- *
- * The write is guaranteed to succeed as a whole, i.e., it's not possible to
- * observe a partial write for any reader.  Note that this correctly interacts
- * with both pg_atomic_compare_exchange_u32() and
- * pg_atomic_read_membarrier_u32().  While this may be less performant than
- * pg_atomic_write_u32(), it may be easier to reason about correctness with
- * this function in less performance-sensitive code.
- *
- * Full barrier semantics.
- */
 static inline void
-pg_atomic_write_membarrier_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
+pg_write_barrier(void)
 {
-	AssertPointerAlignment(ptr, 4);
-
-	pg_atomic_write_membarrier_u32_impl(ptr, val);
-}
-
-/*
- * pg_atomic_exchange_u32 - exchange newval with current value
- *
- * Returns the old value of 'ptr' before the swap.
- *
- * Full barrier semantics.
- */
-static inline uint32
-pg_atomic_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 newval)
-{
-	AssertPointerAlignment(ptr, 4);
-
-	return pg_atomic_exchange_u32_impl(ptr, newval);
-}
-
-/*
- * pg_atomic_compare_exchange_u32 - CAS operation
- *
- * Atomically compare the current value of ptr with *expected and store newval
- * iff ptr and *expected have the same value. The current value of *ptr will
- * always be stored in *expected.
- *
- * Return true if values have been exchanged, false otherwise.
- *
- * Full barrier semantics.
- */
-static inline bool
-pg_atomic_compare_exchange_u32(volatile pg_atomic_uint32 *ptr,
-							   uint32 *expected, uint32 newval)
-{
-	AssertPointerAlignment(ptr, 4);
-	AssertPointerAlignment(expected, 4);
-
-	return pg_atomic_compare_exchange_u32_impl(ptr, expected, newval);
+#ifdef pg_write_barrier_impl
+	pg_write_barrier_impl();
+#else
+	pg_compiler_barrier();
+	atomic_thread_fence(memory_order_release);
+#endif
 }
 
 /*
- * pg_atomic_fetch_add_u32 - atomically add to variable
- *
- * Returns the value of ptr before the arithmetic operation.
+ * Operations corresponding to standard atomic_flag.  We have to use an integer
+ * instead of mapping directly to the standard names, to support our relaxed
+ * check function.
  *
- * Full barrier semantics.
+ * Acquire and release fences, which are respectively stronger than read and
+ * write barriers.
  */
-static inline uint32
-pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	AssertPointerAlignment(ptr, 4);
-	return pg_atomic_fetch_add_u32_impl(ptr, add_);
-}
+#define pg_atomic_init_flag(p) atomic_init((p), 1)
+#define pg_atomic_test_set_flag(p) \
+	atomic_fetch_and_explicit((p), 0, memory_order_acquire)
+#define pg_atomic_clear_flag(p) \
+	atomic_store_explicit((p), 1, memory_order_release)
+#define pg_atomic_unlocked_test_flag(p) \
+	atomic_load_explicit((p), memory_order_relaxed)
 
 /*
- * pg_atomic_fetch_sub_u32 - atomically subtract from variable
- *
- * Returns the value of ptr before the arithmetic operation. Note that sub_
- * may not be INT_MIN due to platform limitations.
- *
- * Full barrier semantics.
+ * Local convention for load/store, relaxed AKA no barrier.  These are the only
+ * "generic" functions provided with pg_ prefixes.  It seems pointless to
+ * rename everything in <stdatomic.h>, but these two are PostgreSQL's
+ * established way of representing relaxed access, and a lot shorter.
  */
-static inline uint32
-pg_atomic_fetch_sub_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
-{
-	AssertPointerAlignment(ptr, 4);
-	Assert(sub_ != INT_MIN);
-	return pg_atomic_fetch_sub_u32_impl(ptr, sub_);
-}
+#define pg_atomic_read(p) \
+	atomic_load_explicit((p), memory_order_relaxed)
+#define pg_atomic_write(p, v) \
+	atomic_store_explicit((p), (v), memory_order_relaxed)
 
 /*
- * pg_atomic_fetch_and_u32 - atomically bit-and and_ with variable
- *
- * Returns the value of ptr before the arithmetic operation.
+ * Backward-compatible type-specific function names.  Only the historical _u32
+ * and _64 names are provided.  New code and code using other atomic types
+ * should use the generic functions from the standard directly, and
+ * pg_atomic_{read,write}() for relaxed access.
  *
- * Full barrier semantics.
+ * All of these except pg_atomic_(unlocked_){read,write}_{32,64} have seq cst
+ * AKA full barrier semantics.
  */
-static inline uint32
-pg_atomic_fetch_and_u32(volatile pg_atomic_uint32 *ptr, uint32 and_)
-{
-	AssertPointerAlignment(ptr, 4);
-	return pg_atomic_fetch_and_u32_impl(ptr, and_);
-}
+#define pg_atomic_init_u32 atomic_init
+#define pg_atomic_init_u64 atomic_init
+#define pg_atomic_read_u32 pg_atomic_read
+#define pg_atomic_read_u64 pg_atomic_read
+#define pg_atomic_write_u32 pg_atomic_write
+#define pg_atomic_write_u64 pg_atomic_write
+#define pg_atomic_unlocked_read_u32 pg_atomic_read
+#define pg_atomic_unlocked_read_u64 pg_atomic_read
+#define pg_atomic_unlocked_write_u32 pg_atomic_write
+#define pg_atomic_unlocked_write_u64 pg_atomic_write
+#define pg_atomic_read_membarrier_u32 atomic_load
+#define pg_atomic_read_membarrier_u64 atomic_load
+#define pg_atomic_write_membarrier_u32 atomic_store
+#define pg_atomic_write_membarrier_u64 atomic_store
+#define pg_atomic_exchange_u32 atomic_exchange
+#define pg_atomic_exchange_u64 atomic_exchange
+#define pg_atomic_compare_exchange_u32 atomic_compare_exchange_strong
+#define pg_atomic_compare_exchange_u64 atomic_compare_exchange_strong
+#define pg_atomic_fetch_add_u32 atomic_fetch_add
+#define pg_atomic_fetch_add_u64 atomic_fetch_add
+#define pg_atomic_fetch_sub_u32 atomic_fetch_sub
+#define pg_atomic_fetch_sub_u64 atomic_fetch_sub
+#define pg_atomic_fetch_and_u32 atomic_fetch_and
+#define pg_atomic_fetch_and_u64 atomic_fetch_and
+#define pg_atomic_fetch_or_u32 atomic_fetch_or
+#define pg_atomic_fetch_or_u64 atomic_fetch_or
 
 /*
- * pg_atomic_fetch_or_u32 - atomically bit-or or_ with variable
- *
- * Returns the value of ptr before the arithmetic operation.
- *
- * Full barrier semantics.
+ * The rest of this file defines non-fundamental convenience functions with no
+ * counterpart in <stdatomic.h>.
  */
-static inline uint32
-pg_atomic_fetch_or_u32(volatile pg_atomic_uint32 *ptr, uint32 or_)
-{
-	AssertPointerAlignment(ptr, 4);
-	return pg_atomic_fetch_or_u32_impl(ptr, or_);
-}
 
 /*
- * pg_atomic_add_fetch_u32 - atomically add to variable
- *
- * Returns the value of ptr after the arithmetic operation.
- *
- * Full barrier semantics.
+ * Fetch and add/subtract wrappers that return the new value instead of the old
+ * value.  We need functions to avoid double evaluation of v.
  */
-static inline uint32
-pg_atomic_add_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	AssertPointerAlignment(ptr, 4);
-	return pg_atomic_add_fetch_u32_impl(ptr, add_);
-}
-
-/*
- * pg_atomic_sub_fetch_u32 - atomically subtract from variable
- *
- * Returns the value of ptr after the arithmetic operation. Note that sub_ may
- * not be INT_MIN due to platform limitations.
- *
- * Full barrier semantics.
- */
-static inline uint32
-pg_atomic_sub_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
-{
-	AssertPointerAlignment(ptr, 4);
-	Assert(sub_ != INT_MIN);
-	return pg_atomic_sub_fetch_u32_impl(ptr, sub_);
-}
-
-/* ----
- * The 64 bit operations have the same semantics as their 32bit counterparts
- * if they are available. Check the corresponding 32bit function for
- * documentation.
- * ----
- */
-static inline void
-pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
-{
-	/*
-	 * Can't necessarily enforce alignment - and don't need it - when using
-	 * the spinlock based fallback implementation. Therefore only assert when
-	 * not using it.
-	 */
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	pg_atomic_init_u64_impl(ptr, val);
-}
-
-static inline uint64
-pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_read_u64_impl(ptr);
-}
-
-static inline uint64
-pg_atomic_read_membarrier_u64(volatile pg_atomic_uint64 *ptr)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_read_membarrier_u64_impl(ptr);
-}
-
-static inline void
-pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	pg_atomic_write_u64_impl(ptr, val);
-}
-
-static inline void
-pg_atomic_write_membarrier_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	pg_atomic_write_membarrier_u64_impl(ptr, val);
-}
-
-static inline uint64
-pg_atomic_exchange_u64(volatile pg_atomic_uint64 *ptr, uint64 newval)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_exchange_u64_impl(ptr, newval);
-}
-
-static inline bool
-pg_atomic_compare_exchange_u64(volatile pg_atomic_uint64 *ptr,
-							   uint64 *expected, uint64 newval)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_compare_exchange_u64_impl(ptr, expected, newval);
-}
-
-static inline uint64
-pg_atomic_fetch_add_u64(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_fetch_add_u64_impl(ptr, add_);
-}
-
-static inline uint64
-pg_atomic_fetch_sub_u64(volatile pg_atomic_uint64 *ptr, int64 sub_)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	Assert(sub_ != PG_INT64_MIN);
-	return pg_atomic_fetch_sub_u64_impl(ptr, sub_);
-}
-
-static inline uint64
-pg_atomic_fetch_and_u64(volatile pg_atomic_uint64 *ptr, uint64 and_)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_fetch_and_u64_impl(ptr, and_);
-}
-
-static inline uint64
-pg_atomic_fetch_or_u64(volatile pg_atomic_uint64 *ptr, uint64 or_)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_fetch_or_u64_impl(ptr, or_);
-}
-
-static inline uint64
-pg_atomic_add_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	return pg_atomic_add_fetch_u64_impl(ptr, add_);
-}
-
-static inline uint64
-pg_atomic_sub_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 sub_)
-{
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-	Assert(sub_ != PG_INT64_MIN);
-	return pg_atomic_sub_fetch_u64_impl(ptr, sub_);
+#define PG_ATOMIC_GEN_REVERSE_FETCH(size, name, op) \
+static inline uint##size \
+pg_atomic_##name##_fetch_u##size(volatile pg_atomic_uint##size *p, uint##size v) \
+{ \
+	return atomic_fetch_##name(p, v) op v; \
 }
+PG_ATOMIC_GEN_REVERSE_FETCH(32, add, +);
+PG_ATOMIC_GEN_REVERSE_FETCH(64, add, +);
+PG_ATOMIC_GEN_REVERSE_FETCH(32, sub, -);
+PG_ATOMIC_GEN_REVERSE_FETCH(64, sub, -);
 
 /*
  * Monotonically advance the given variable using only atomic operations until
@@ -584,11 +296,7 @@ pg_atomic_monotonic_advance_u64(volatile pg_atomic_uint64 *ptr, uint64 target)
 {
 	uint64		currval;
 
-#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
-	AssertPointerAlignment(ptr, 8);
-#endif
-
-	currval = pg_atomic_read_u64_impl(ptr);
+	currval = pg_atomic_read_u64(ptr);
 	if (currval >= target)
 	{
 		pg_memory_barrier();
diff --git a/src/include/port/atomics/arch-arm.h b/src/include/port/atomics/arch-arm.h
deleted file mode 100644
index eb7e0ac93ba..00000000000
--- a/src/include/port/atomics/arch-arm.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * arch-arm.h
- *	  Atomic operations considerations specific to ARM
- *
- * Portions Copyright (c) 2013-2025, PostgreSQL Global Development Group
- *
- * NOTES:
- *
- * src/include/port/atomics/arch-arm.h
- *
- *-------------------------------------------------------------------------
- */
-
-/* intentionally no include guards, should only be included by atomics.h */
-#ifndef INSIDE_ATOMICS_H
-#error "should be included via atomics.h"
-#endif
-
-/*
- * 64 bit atomics on ARM32 are implemented using kernel fallbacks and thus
- * might be slow, so disable entirely. On ARM64 that problem doesn't exist.
- */
-#if !defined(__aarch64__)
-#define PG_DISABLE_64_BIT_ATOMICS
-#else
-/*
- * Architecture Reference Manual for ARMv8 states aligned read/write to/from
- * general purpose register is atomic.
- */
-#define PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY
-#endif  /* __aarch64__ */
diff --git a/src/include/port/atomics/arch-ppc.h b/src/include/port/atomics/arch-ppc.h
deleted file mode 100644
index b93f6766d29..00000000000
--- a/src/include/port/atomics/arch-ppc.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * arch-ppc.h
- *	  Atomic operations considerations specific to PowerPC
- *
- * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * NOTES:
- *
- * src/include/port/atomics/arch-ppc.h
- *
- *-------------------------------------------------------------------------
- */
-
-#if defined(__GNUC__)
-
-/*
- * lwsync orders loads with respect to each other, and similarly with stores.
- * But a load can be performed before a subsequent store, so sync must be used
- * for a full memory barrier.
- */
-#define pg_memory_barrier_impl()	__asm__ __volatile__ ("sync" : : : "memory")
-#define pg_read_barrier_impl()		__asm__ __volatile__ ("lwsync" : : : "memory")
-#define pg_write_barrier_impl()		__asm__ __volatile__ ("lwsync" : : : "memory")
-#endif
-
-#define PG_HAVE_ATOMIC_U32_SUPPORT
-typedef struct pg_atomic_uint32
-{
-	volatile uint32 value;
-} pg_atomic_uint32;
-
-/* 64bit atomics are only supported in 64bit mode */
-#if SIZEOF_VOID_P >= 8
-#define PG_HAVE_ATOMIC_U64_SUPPORT
-typedef struct pg_atomic_uint64
-{
-	volatile uint64 value pg_attribute_aligned(8);
-} pg_atomic_uint64;
-
-#endif
-
-/*
- * This mimics gcc __atomic_compare_exchange_n(..., __ATOMIC_SEQ_CST), but
- * code generation differs at the end.  __atomic_compare_exchange_n():
- *  100:	isync
- *  104:	mfcr    r3
- *  108:	rlwinm  r3,r3,3,31,31
- *  10c:	bne     120 <.eb+0x10>
- *  110:	clrldi  r3,r3,63
- *  114:	addi    r1,r1,112
- *  118:	blr
- *  11c:	nop
- *  120:	clrldi  r3,r3,63
- *  124:	stw     r9,0(r4)
- *  128:	addi    r1,r1,112
- *  12c:	blr
- *
- * This:
- *   f0:	isync
- *   f4:	mfcr    r9
- *   f8:	rldicl. r3,r9,35,63
- *   fc:	bne     104 <.eb>
- *  100:	stw     r10,0(r4)
- *  104:	addi    r1,r1,112
- *  108:	blr
- *
- * This implementation may or may not have materially different performance.
- * It's not exploiting the fact that cr0 still holds the relevant comparison
- * bits, set during the __asm__.  One could fix that by moving more code into
- * the __asm__.  (That would remove the freedom to eliminate dead stores when
- * the caller ignores "expected", but few callers do.)
- *
- * Recognizing constant "newval" would be superfluous, because there's no
- * immediate-operand version of stwcx.
- */
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32
-static inline bool
-pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr,
-									uint32 *expected, uint32 newval)
-{
-	uint32 found;
-	uint32 condition_register;
-	bool ret;
-
-#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P
-	if (__builtin_constant_p(*expected) &&
-		(int32) *expected <= PG_INT16_MAX &&
-		(int32) *expected >= PG_INT16_MIN)
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	lwarx   %0,0,%5,1	\n"
-			"	cmpwi   %0,%3		\n"
-			"	bne     $+12		\n"		/* branch to lwsync */
-			"	stwcx.  %4,0,%5		\n"
-			"	bne     $-16		\n"		/* branch to lwarx */
-			"	lwsync				\n"
-			"	mfcr    %1          \n"
-:			"=&r"(found), "=r"(condition_register), "+m"(ptr->value)
-:			"i"(*expected), "r"(newval), "r"(&ptr->value)
-:			"memory", "cc");
-	else
-#endif
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	lwarx   %0,0,%5,1	\n"
-			"	cmpw    %0,%3		\n"
-			"	bne     $+12		\n"		/* branch to lwsync */
-			"	stwcx.  %4,0,%5		\n"
-			"	bne     $-16		\n"		/* branch to lwarx */
-			"	lwsync				\n"
-			"	mfcr    %1          \n"
-:			"=&r"(found), "=r"(condition_register), "+m"(ptr->value)
-:			"r"(*expected), "r"(newval), "r"(&ptr->value)
-:			"memory", "cc");
-
-	ret = (condition_register >> 29) & 1;	/* test eq bit of cr0 */
-	if (!ret)
-		*expected = found;
-	return ret;
-}
-
-/*
- * This mirrors gcc __sync_fetch_and_add().
- *
- * Like tas(), use constraint "=&b" to avoid allocating r0.
- */
-#define PG_HAVE_ATOMIC_FETCH_ADD_U32
-static inline uint32
-pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	uint32 _t;
-	uint32 res;
-
-#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P
-	if (__builtin_constant_p(add_) &&
-		add_ <= PG_INT16_MAX && add_ >= PG_INT16_MIN)
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	lwarx   %1,0,%4,1	\n"
-			"	addi    %0,%1,%3	\n"
-			"	stwcx.  %0,0,%4		\n"
-			"	bne     $-12		\n"		/* branch to lwarx */
-			"	lwsync				\n"
-:			"=&r"(_t), "=&b"(res), "+m"(ptr->value)
-:			"i"(add_), "r"(&ptr->value)
-:			"memory", "cc");
-	else
-#endif
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	lwarx   %1,0,%4,1	\n"
-			"	add     %0,%1,%3	\n"
-			"	stwcx.  %0,0,%4		\n"
-			"	bne     $-12		\n"		/* branch to lwarx */
-			"	lwsync				\n"
-:			"=&r"(_t), "=&r"(res), "+m"(ptr->value)
-:			"r"(add_), "r"(&ptr->value)
-:			"memory", "cc");
-
-	return res;
-}
-
-#ifdef PG_HAVE_ATOMIC_U64_SUPPORT
-
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
-static inline bool
-pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
-									uint64 *expected, uint64 newval)
-{
-	uint64 found;
-	uint32 condition_register;
-	bool ret;
-
-	AssertPointerAlignment(expected, 8);
-
-	/* Like u32, but s/lwarx/ldarx/; s/stwcx/stdcx/; s/cmpw/cmpd/ */
-#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P
-	if (__builtin_constant_p(*expected) &&
-		(int64) *expected <= PG_INT16_MAX &&
-		(int64) *expected >= PG_INT16_MIN)
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	ldarx   %0,0,%5,1	\n"
-			"	cmpdi   %0,%3		\n"
-			"	bne     $+12		\n"		/* branch to lwsync */
-			"	stdcx.  %4,0,%5		\n"
-			"	bne     $-16		\n"		/* branch to ldarx */
-			"	lwsync				\n"
-			"	mfcr    %1          \n"
-:			"=&r"(found), "=r"(condition_register), "+m"(ptr->value)
-:			"i"(*expected), "r"(newval), "r"(&ptr->value)
-:			"memory", "cc");
-	else
-#endif
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	ldarx   %0,0,%5,1	\n"
-			"	cmpd    %0,%3		\n"
-			"	bne     $+12		\n"		/* branch to lwsync */
-			"	stdcx.  %4,0,%5		\n"
-			"	bne     $-16		\n"		/* branch to ldarx */
-			"	lwsync				\n"
-			"	mfcr    %1          \n"
-:			"=&r"(found), "=r"(condition_register), "+m"(ptr->value)
-:			"r"(*expected), "r"(newval), "r"(&ptr->value)
-:			"memory", "cc");
-
-	ret = (condition_register >> 29) & 1;	/* test eq bit of cr0 */
-	if (!ret)
-		*expected = found;
-	return ret;
-}
-
-#define PG_HAVE_ATOMIC_FETCH_ADD_U64
-static inline uint64
-pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-	uint64 _t;
-	uint64 res;
-
-	/* Like u32, but s/lwarx/ldarx/; s/stwcx/stdcx/ */
-#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P
-	if (__builtin_constant_p(add_) &&
-		add_ <= PG_INT16_MAX && add_ >= PG_INT16_MIN)
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	ldarx   %1,0,%4,1	\n"
-			"	addi    %0,%1,%3	\n"
-			"	stdcx.  %0,0,%4		\n"
-			"	bne     $-12		\n"		/* branch to ldarx */
-			"	lwsync				\n"
-:			"=&r"(_t), "=&b"(res), "+m"(ptr->value)
-:			"i"(add_), "r"(&ptr->value)
-:			"memory", "cc");
-	else
-#endif
-		__asm__ __volatile__(
-			"	sync				\n"
-			"	ldarx   %1,0,%4,1	\n"
-			"	add     %0,%1,%3	\n"
-			"	stdcx.  %0,0,%4		\n"
-			"	bne     $-12		\n"		/* branch to ldarx */
-			"	lwsync				\n"
-:			"=&r"(_t), "=&r"(res), "+m"(ptr->value)
-:			"r"(add_), "r"(&ptr->value)
-:			"memory", "cc");
-
-	return res;
-}
-
-#endif /* PG_HAVE_ATOMIC_U64_SUPPORT */
-
-/* per architecture manual doubleword accesses have single copy atomicity */
-#define PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY
diff --git a/src/include/port/atomics/arch-x86.h b/src/include/port/atomics/arch-x86.h
index 4ba2ccc0591..acd612099fa 100644
--- a/src/include/port/atomics/arch-x86.h
+++ b/src/include/port/atomics/arch-x86.h
@@ -3,10 +3,6 @@
  * arch-x86.h
  *	  Atomic operations considerations specific to intel x86
  *
- * Note that we actually require a 486 upwards because the 386 doesn't have
- * support for xadd and cmpxchg. Given that the 386 isn't supported anywhere
- * anymore that's not much of a restriction luckily.
- *
  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
@@ -43,204 +39,3 @@
 
 #define pg_read_barrier_impl()		pg_compiler_barrier_impl()
 #define pg_write_barrier_impl()		pg_compiler_barrier_impl()
-
-/*
- * Provide implementation for atomics using inline assembly on x86 gcc. It's
- * nice to support older gcc's and the compare/exchange implementation here is
- * actually more efficient than the * __sync variant.
- */
-#if defined(__GNUC__) || defined(__INTEL_COMPILER)
-
-#define PG_HAVE_ATOMIC_FLAG_SUPPORT
-typedef struct pg_atomic_flag
-{
-	volatile char value;
-} pg_atomic_flag;
-
-#define PG_HAVE_ATOMIC_U32_SUPPORT
-typedef struct pg_atomic_uint32
-{
-	volatile uint32 value;
-} pg_atomic_uint32;
-
-/*
- * It's too complicated to write inline asm for 64bit types on 32bit and the
- * 486 can't do it anyway.
- */
-#ifdef __x86_64__
-#define PG_HAVE_ATOMIC_U64_SUPPORT
-typedef struct pg_atomic_uint64
-{
-	/* alignment guaranteed due to being on a 64bit platform */
-	volatile uint64 value;
-} pg_atomic_uint64;
-#endif	/* __x86_64__ */
-
-#endif /* defined(__GNUC__) || defined(__INTEL_COMPILER) */
-
-#if !defined(PG_HAVE_SPIN_DELAY)
-/*
- * This sequence is equivalent to the PAUSE instruction ("rep" is
- * ignored by old IA32 processors if the following instruction is
- * not a string operation); the IA-32 Architecture Software
- * Developer's Manual, Vol. 3, Section 7.7.2 describes why using
- * PAUSE in the inner loop of a spin lock is necessary for good
- * performance:
- *
- *     The PAUSE instruction improves the performance of IA-32
- *     processors supporting Hyper-Threading Technology when
- *     executing spin-wait loops and other routines where one
- *     thread is accessing a shared lock or semaphore in a tight
- *     polling loop. When executing a spin-wait loop, the
- *     processor can suffer a severe performance penalty when
- *     exiting the loop because it detects a possible memory order
- *     violation and flushes the core processor's pipeline. The
- *     PAUSE instruction provides a hint to the processor that the
- *     code sequence is a spin-wait loop. The processor uses this
- *     hint to avoid the memory order violation and prevent the
- *     pipeline flush. In addition, the PAUSE instruction
- *     de-pipelines the spin-wait loop to prevent it from
- *     consuming execution resources excessively.
- */
-#if defined(__GNUC__) || defined(__INTEL_COMPILER)
-#define PG_HAVE_SPIN_DELAY
-static __inline__ void
-pg_spin_delay_impl(void)
-{
-	__asm__ __volatile__(" rep; nop			\n");
-}
-#elif defined(_MSC_VER) && defined(__x86_64__)
-#define PG_HAVE_SPIN_DELAY
-static __forceinline void
-pg_spin_delay_impl(void)
-{
-	_mm_pause();
-}
-#elif defined(_MSC_VER)
-#define PG_HAVE_SPIN_DELAY
-static __forceinline void
-pg_spin_delay_impl(void)
-{
-	/* See comment for gcc code. Same code, MASM syntax */
-	__asm rep nop;
-}
-#endif
-#endif /* !defined(PG_HAVE_SPIN_DELAY) */
-
-
-#if defined(__GNUC__) || defined(__INTEL_COMPILER)
-
-#define PG_HAVE_ATOMIC_TEST_SET_FLAG
-static inline bool
-pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	char		_res = 1;
-
-	__asm__ __volatile__(
-		"	lock			\n"
-		"	xchgb	%0,%1	\n"
-:		"+q"(_res), "+m"(ptr->value)
-:
-:		"memory");
-	return _res == 0;
-}
-
-#define PG_HAVE_ATOMIC_CLEAR_FLAG
-static inline void
-pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	/*
-	 * On a TSO architecture like x86 it's sufficient to use a compiler
-	 * barrier to achieve release semantics.
-	 */
-	__asm__ __volatile__("" ::: "memory");
-	ptr->value = 0;
-}
-
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32
-static inline bool
-pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr,
-									uint32 *expected, uint32 newval)
-{
-	char	ret;
-
-	/*
-	 * Perform cmpxchg and use the zero flag which it implicitly sets when
-	 * equal to measure the success.
-	 */
-	__asm__ __volatile__(
-		"	lock				\n"
-		"	cmpxchgl	%4,%5	\n"
-		"   setz		%2		\n"
-:		"=a" (*expected), "=m"(ptr->value), "=q" (ret)
-:		"a" (*expected), "r" (newval), "m"(ptr->value)
-:		"memory", "cc");
-	return (bool) ret;
-}
-
-#define PG_HAVE_ATOMIC_FETCH_ADD_U32
-static inline uint32
-pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	uint32 res;
-	__asm__ __volatile__(
-		"	lock				\n"
-		"	xaddl	%0,%1		\n"
-:		"=q"(res), "=m"(ptr->value)
-:		"0" (add_), "m"(ptr->value)
-:		"memory", "cc");
-	return res;
-}
-
-#ifdef __x86_64__
-
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
-static inline bool
-pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
-									uint64 *expected, uint64 newval)
-{
-	char	ret;
-
-	AssertPointerAlignment(expected, 8);
-
-	/*
-	 * Perform cmpxchg and use the zero flag which it implicitly sets when
-	 * equal to measure the success.
-	 */
-	__asm__ __volatile__(
-		"	lock				\n"
-		"	cmpxchgq	%4,%5	\n"
-		"   setz		%2		\n"
-:		"=a" (*expected), "=m"(ptr->value), "=q" (ret)
-:		"a" (*expected), "r" (newval), "m"(ptr->value)
-:		"memory", "cc");
-	return (bool) ret;
-}
-
-#define PG_HAVE_ATOMIC_FETCH_ADD_U64
-static inline uint64
-pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-	uint64 res;
-	__asm__ __volatile__(
-		"	lock				\n"
-		"	xaddq	%0,%1		\n"
-:		"=q"(res), "=m"(ptr->value)
-:		"0" (add_), "m"(ptr->value)
-:		"memory", "cc");
-	return res;
-}
-
-#endif /* __x86_64__ */
-
-#endif /* defined(__GNUC__) || defined(__INTEL_COMPILER) */
-
-/*
- * 8 byte reads / writes have single-copy atomicity on 32 bit x86 platforms
- * since at least the 586. As well as on all x86-64 cpus.
- */
-#if defined(__i568__) || defined(__i668__) || /* gcc i586+ */  \
-	(defined(_M_IX86) && _M_IX86 >= 500) || /* msvc i586+ */ \
-	defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) /* gcc, msvc */
-#define PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY
-#endif /* 8 byte single-copy atomicity */
diff --git a/src/include/port/atomics/fallback.h b/src/include/port/atomics/fallback.h
deleted file mode 100644
index d2f1b851668..00000000000
--- a/src/include/port/atomics/fallback.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * fallback.h
- *    Fallback for platforms without 64 bit atomics support. Slower
- *    than native atomics support, but not unusably slow.
- *
- * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * src/include/port/atomics/fallback.h
- *
- *-------------------------------------------------------------------------
- */
-
-/* intentionally no include guards, should only be included by atomics.h */
-#ifndef INSIDE_ATOMICS_H
-#	error "should be included via atomics.h"
-#endif
-
-
-#if !defined(PG_HAVE_ATOMIC_U64_SUPPORT)
-
-#define PG_HAVE_ATOMIC_U64_SIMULATION
-
-#define PG_HAVE_ATOMIC_U64_SUPPORT
-typedef struct pg_atomic_uint64
-{
-	int			sema;
-	volatile uint64 value;
-} pg_atomic_uint64;
-
-#define PG_HAVE_ATOMIC_INIT_U64
-extern void pg_atomic_init_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val_);
-
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
-extern bool pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
-												uint64 *expected, uint64 newval);
-
-#define PG_HAVE_ATOMIC_FETCH_ADD_U64
-extern uint64 pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_);
-
-#endif /* PG_HAVE_ATOMIC_U64_SUPPORT */
diff --git a/src/include/port/atomics/generic-gcc.h b/src/include/port/atomics/generic-gcc.h
index a0751f2286a..78555a27861 100644
--- a/src/include/port/atomics/generic-gcc.h
+++ b/src/include/port/atomics/generic-gcc.h
@@ -1,19 +1,11 @@
 /*-------------------------------------------------------------------------
  *
  * generic-gcc.h
- *	  Atomic operations, implemented using gcc (or compatible) intrinsics.
+ *	  Compiler barriers for GCC (or compatible)
  *
  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * NOTES:
- *
- * Documentation:
- * * Legacy __sync Built-in Functions for Atomic Memory Access
- *   https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/_005f_005fsync-Builtins.html
- * * Built-in functions for memory model aware atomic operations
- *   https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/_005f_005fatomic-Builtins.html
- *
  * src/include/port/atomics/generic-gcc.h
  *
  *-------------------------------------------------------------------------
@@ -28,300 +20,3 @@
  * An empty asm block should be a sufficient compiler barrier.
  */
 #define pg_compiler_barrier_impl()	__asm__ __volatile__("" ::: "memory")
-
-/*
- * If we're on GCC, we should be able to get a memory barrier
- * out of this compiler built-in.  But we prefer to rely on platform specific
- * definitions where possible, and use this only as a fallback.
- */
-#if !defined(pg_memory_barrier_impl)
-#	if defined(HAVE_GCC__ATOMIC_INT32_CAS)
-#		define pg_memory_barrier_impl()		__atomic_thread_fence(__ATOMIC_SEQ_CST)
-#	elif defined(__GNUC__)
-#		define pg_memory_barrier_impl()		__sync_synchronize()
-#	endif
-#endif /* !defined(pg_memory_barrier_impl) */
-
-#if !defined(pg_read_barrier_impl) && defined(HAVE_GCC__ATOMIC_INT32_CAS)
-/* acquire semantics include read barrier semantics */
-#		define pg_read_barrier_impl() do \
-{ \
-	pg_compiler_barrier_impl(); \
-	__atomic_thread_fence(__ATOMIC_ACQUIRE); \
-} while (0)
-#endif
-
-#if !defined(pg_write_barrier_impl) && defined(HAVE_GCC__ATOMIC_INT32_CAS)
-/* release semantics include write barrier semantics */
-#		define pg_write_barrier_impl() do \
-{ \
-	pg_compiler_barrier_impl(); \
-	__atomic_thread_fence(__ATOMIC_RELEASE); \
-} while (0)
-#endif
-
-
-/* generic gcc based atomic flag implementation */
-#if !defined(PG_HAVE_ATOMIC_FLAG_SUPPORT) \
-	&& (defined(HAVE_GCC__SYNC_INT32_TAS) || defined(HAVE_GCC__SYNC_CHAR_TAS))
-
-#define PG_HAVE_ATOMIC_FLAG_SUPPORT
-typedef struct pg_atomic_flag
-{
-	/*
-	 * If we have a choice, use int-width TAS, because that is more efficient
-	 * and/or more reliably implemented on most non-Intel platforms.  (Note
-	 * that this code isn't used on x86[_64]; see arch-x86.h for that.)
-	 */
-#ifdef HAVE_GCC__SYNC_INT32_TAS
-	volatile int value;
-#else
-	volatile char value;
-#endif
-} pg_atomic_flag;
-
-#endif /* !ATOMIC_FLAG_SUPPORT && SYNC_INT32_TAS */
-
-/* generic gcc based atomic uint32 implementation */
-#if !defined(PG_HAVE_ATOMIC_U32_SUPPORT) \
-	&& (defined(HAVE_GCC__ATOMIC_INT32_CAS) || defined(HAVE_GCC__SYNC_INT32_CAS))
-
-#define PG_HAVE_ATOMIC_U32_SUPPORT
-typedef struct pg_atomic_uint32
-{
-	volatile uint32 value;
-} pg_atomic_uint32;
-
-#endif /* defined(HAVE_GCC__ATOMIC_INT32_CAS) || defined(HAVE_GCC__SYNC_INT32_CAS) */
-
-/* generic gcc based atomic uint64 implementation */
-#if !defined(PG_HAVE_ATOMIC_U64_SUPPORT) \
-	&& !defined(PG_DISABLE_64_BIT_ATOMICS) \
-	&& (defined(HAVE_GCC__ATOMIC_INT64_CAS) || defined(HAVE_GCC__SYNC_INT64_CAS))
-
-#define PG_HAVE_ATOMIC_U64_SUPPORT
-
-typedef struct pg_atomic_uint64
-{
-	volatile uint64 value pg_attribute_aligned(8);
-} pg_atomic_uint64;
-
-#endif /* defined(HAVE_GCC__ATOMIC_INT64_CAS) || defined(HAVE_GCC__SYNC_INT64_CAS) */
-
-#ifdef PG_HAVE_ATOMIC_FLAG_SUPPORT
-
-#if defined(HAVE_GCC__SYNC_CHAR_TAS) || defined(HAVE_GCC__SYNC_INT32_TAS)
-
-#ifndef PG_HAVE_ATOMIC_TEST_SET_FLAG
-#define PG_HAVE_ATOMIC_TEST_SET_FLAG
-static inline bool
-pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	/* NB: only an acquire barrier, not a full one */
-	/* some platform only support a 1 here */
-	return __sync_lock_test_and_set(&ptr->value, 1) == 0;
-}
-#endif
-
-#endif /* defined(HAVE_GCC__SYNC_*_TAS) */
-
-#ifndef PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
-#define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
-static inline bool
-pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	return ptr->value == 0;
-}
-#endif
-
-#ifndef PG_HAVE_ATOMIC_CLEAR_FLAG
-#define PG_HAVE_ATOMIC_CLEAR_FLAG
-static inline void
-pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	__sync_lock_release(&ptr->value);
-}
-#endif
-
-#ifndef PG_HAVE_ATOMIC_INIT_FLAG
-#define PG_HAVE_ATOMIC_INIT_FLAG
-static inline void
-pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	pg_atomic_clear_flag_impl(ptr);
-}
-#endif
-
-#endif /* defined(PG_HAVE_ATOMIC_FLAG_SUPPORT) */
-
-/* prefer __atomic, it has a better API */
-#if !defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32) && defined(HAVE_GCC__ATOMIC_INT32_CAS)
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32
-static inline bool
-pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr,
-									uint32 *expected, uint32 newval)
-{
-	/* FIXME: we can probably use a lower consistency model */
-	return __atomic_compare_exchange_n(&ptr->value, expected, newval, false,
-									   __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32) && defined(HAVE_GCC__SYNC_INT32_CAS)
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32
-static inline bool
-pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr,
-									uint32 *expected, uint32 newval)
-{
-	bool	ret;
-	uint32	current;
-	current = __sync_val_compare_and_swap(&ptr->value, *expected, newval);
-	ret = current == *expected;
-	*expected = current;
-	return ret;
-}
-#endif
-
-/*
- * __sync_lock_test_and_set() only supports setting the value to 1 on some
- * platforms, so we only provide an __atomic implementation for
- * pg_atomic_exchange.
- *
- * We assume the availability of 32-bit __atomic_compare_exchange_n() implies
- * the availability of 32-bit __atomic_exchange_n().
- */
-#if !defined(PG_HAVE_ATOMIC_EXCHANGE_U32) && defined(HAVE_GCC__ATOMIC_INT32_CAS)
-#define PG_HAVE_ATOMIC_EXCHANGE_U32
-static inline uint32
-pg_atomic_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 newval)
-{
-	return __atomic_exchange_n(&ptr->value, newval, __ATOMIC_SEQ_CST);
-}
-#endif
-
-/* if we have 32-bit __sync_val_compare_and_swap, assume we have these too: */
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U32) && defined(HAVE_GCC__SYNC_INT32_CAS)
-#define PG_HAVE_ATOMIC_FETCH_ADD_U32
-static inline uint32
-pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	return __sync_fetch_and_add(&ptr->value, add_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U32) && defined(HAVE_GCC__SYNC_INT32_CAS)
-#define PG_HAVE_ATOMIC_FETCH_SUB_U32
-static inline uint32
-pg_atomic_fetch_sub_u32_impl(volatile pg_atomic_uint32 *ptr, int32 sub_)
-{
-	return __sync_fetch_and_sub(&ptr->value, sub_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_AND_U32) && defined(HAVE_GCC__SYNC_INT32_CAS)
-#define PG_HAVE_ATOMIC_FETCH_AND_U32
-static inline uint32
-pg_atomic_fetch_and_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 and_)
-{
-	return __sync_fetch_and_and(&ptr->value, and_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_OR_U32) && defined(HAVE_GCC__SYNC_INT32_CAS)
-#define PG_HAVE_ATOMIC_FETCH_OR_U32
-static inline uint32
-pg_atomic_fetch_or_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 or_)
-{
-	return __sync_fetch_and_or(&ptr->value, or_);
-}
-#endif
-
-
-#if !defined(PG_DISABLE_64_BIT_ATOMICS)
-
-#if !defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64) && defined(HAVE_GCC__ATOMIC_INT64_CAS)
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
-static inline bool
-pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
-									uint64 *expected, uint64 newval)
-{
-	AssertPointerAlignment(expected, 8);
-	return __atomic_compare_exchange_n(&ptr->value, expected, newval, false,
-									   __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64) && defined(HAVE_GCC__SYNC_INT64_CAS)
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
-static inline bool
-pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
-									uint64 *expected, uint64 newval)
-{
-	bool	ret;
-	uint64	current;
-
-	AssertPointerAlignment(expected, 8);
-	current = __sync_val_compare_and_swap(&ptr->value, *expected, newval);
-	ret = current == *expected;
-	*expected = current;
-	return ret;
-}
-#endif
-
-/*
- * __sync_lock_test_and_set() only supports setting the value to 1 on some
- * platforms, so we only provide an __atomic implementation for
- * pg_atomic_exchange.
- *
- * We assume the availability of 64-bit __atomic_compare_exchange_n() implies
- * the availability of 64-bit __atomic_exchange_n().
- */
-#if !defined(PG_HAVE_ATOMIC_EXCHANGE_U64) && defined(HAVE_GCC__ATOMIC_INT64_CAS)
-#define PG_HAVE_ATOMIC_EXCHANGE_U64
-static inline uint64
-pg_atomic_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 newval)
-{
-	return __atomic_exchange_n(&ptr->value, newval, __ATOMIC_SEQ_CST);
-}
-#endif
-
-/* if we have 64-bit __sync_val_compare_and_swap, assume we have these too: */
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U64) && defined(HAVE_GCC__SYNC_INT64_CAS)
-#define PG_HAVE_ATOMIC_FETCH_ADD_U64
-static inline uint64
-pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-	return __sync_fetch_and_add(&ptr->value, add_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U64) && defined(HAVE_GCC__SYNC_INT64_CAS)
-#define PG_HAVE_ATOMIC_FETCH_SUB_U64
-static inline uint64
-pg_atomic_fetch_sub_u64_impl(volatile pg_atomic_uint64 *ptr, int64 sub_)
-{
-	return __sync_fetch_and_sub(&ptr->value, sub_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_AND_U64) && defined(HAVE_GCC__SYNC_INT64_CAS)
-#define PG_HAVE_ATOMIC_FETCH_AND_U64
-static inline uint64
-pg_atomic_fetch_and_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 and_)
-{
-	return __sync_fetch_and_and(&ptr->value, and_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_OR_U64) && defined(HAVE_GCC__SYNC_INT64_CAS)
-#define PG_HAVE_ATOMIC_FETCH_OR_U64
-static inline uint64
-pg_atomic_fetch_or_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 or_)
-{
-	return __sync_fetch_and_or(&ptr->value, or_);
-}
-#endif
-
-#endif /* !defined(PG_DISABLE_64_BIT_ATOMICS) */
diff --git a/src/include/port/atomics/generic-msvc.h b/src/include/port/atomics/generic-msvc.h
index a6ea5f1c2e7..4cb5eab5be6 100644
--- a/src/include/port/atomics/generic-msvc.h
+++ b/src/include/port/atomics/generic-msvc.h
@@ -1,17 +1,11 @@
 /*-------------------------------------------------------------------------
  *
  * generic-msvc.h
- *	  Atomic operations support when using MSVC
+ *   Compiler barriers when using MSVC
  *
  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * NOTES:
- *
- * Documentation:
- * * Interlocked Variable Access
- *   http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx
- *
  * src/include/port/atomics/generic-msvc.h
  *
  *-------------------------------------------------------------------------
@@ -24,92 +18,4 @@
 #endif
 
 #pragma intrinsic(_ReadWriteBarrier)
-#define pg_compiler_barrier_impl()	_ReadWriteBarrier()
-
-#ifndef pg_memory_barrier_impl
-#define pg_memory_barrier_impl()	MemoryBarrier()
-#endif
-
-#define PG_HAVE_ATOMIC_U32_SUPPORT
-typedef struct pg_atomic_uint32
-{
-	volatile uint32 value;
-} pg_atomic_uint32;
-
-#define PG_HAVE_ATOMIC_U64_SUPPORT
-typedef struct pg_attribute_aligned(8) pg_atomic_uint64
-{
-	volatile uint64 value;
-} pg_atomic_uint64;
-
-
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32
-static inline bool
-pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr,
-									uint32 *expected, uint32 newval)
-{
-	bool	ret;
-	uint32	current;
-	current = InterlockedCompareExchange(&ptr->value, newval, *expected);
-	ret = current == *expected;
-	*expected = current;
-	return ret;
-}
-
-#define PG_HAVE_ATOMIC_EXCHANGE_U32
-static inline uint32
-pg_atomic_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 newval)
-{
-	return InterlockedExchange(&ptr->value, newval);
-}
-
-#define PG_HAVE_ATOMIC_FETCH_ADD_U32
-static inline uint32
-pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	return InterlockedExchangeAdd(&ptr->value, add_);
-}
-
-/*
- * The non-intrinsics versions are only available in vista upwards, so use the
- * intrinsic version. Only supported on >486, but we require XP as a minimum
- * baseline, which doesn't support the 486, so we don't need to add checks for
- * that case.
- */
-#pragma intrinsic(_InterlockedCompareExchange64)
-
-#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
-static inline bool
-pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
-									uint64 *expected, uint64 newval)
-{
-	bool	ret;
-	uint64	current;
-	current = _InterlockedCompareExchange64(&ptr->value, newval, *expected);
-	ret = current == *expected;
-	*expected = current;
-	return ret;
-}
-
-/* Only implemented on 64bit builds */
-#ifdef _WIN64
-
-#pragma intrinsic(_InterlockedExchange64)
-
-#define PG_HAVE_ATOMIC_EXCHANGE_U64
-static inline uint64
-pg_atomic_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 newval)
-{
-	return _InterlockedExchange64(&ptr->value, newval);
-}
-
-#pragma intrinsic(_InterlockedExchangeAdd64)
-
-#define PG_HAVE_ATOMIC_FETCH_ADD_U64
-static inline uint64
-pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-	return _InterlockedExchangeAdd64(&ptr->value, add_);
-}
-
-#endif /* _WIN64 */
+#define pg_compiler_barrier_impl() _ReadWriteBarrier()
diff --git a/src/include/port/atomics/generic.h b/src/include/port/atomics/generic.h
deleted file mode 100644
index 6b61a7b5416..00000000000
--- a/src/include/port/atomics/generic.h
+++ /dev/null
@@ -1,427 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * generic.h
- *	  Implement higher level operations based on some lower level atomic
- *	  operations.
- *
- * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * src/include/port/atomics/generic.h
- *
- *-------------------------------------------------------------------------
- */
-
-/* intentionally no include guards, should only be included by atomics.h */
-#ifndef INSIDE_ATOMICS_H
-#	error "should be included via atomics.h"
-#endif
-
-/*
- * If read or write barriers are undefined, we upgrade them to full memory
- * barriers.
- */
-#if !defined(pg_read_barrier_impl)
-#	define pg_read_barrier_impl pg_memory_barrier_impl
-#endif
-#if !defined(pg_write_barrier_impl)
-#	define pg_write_barrier_impl pg_memory_barrier_impl
-#endif
-
-#ifndef PG_HAVE_SPIN_DELAY
-#define PG_HAVE_SPIN_DELAY
-#define pg_spin_delay_impl()	((void)0)
-#endif
-
-
-/* provide fallback */
-#if !defined(PG_HAVE_ATOMIC_FLAG_SUPPORT) && defined(PG_HAVE_ATOMIC_U32_SUPPORT)
-#define PG_HAVE_ATOMIC_FLAG_SUPPORT
-typedef pg_atomic_uint32 pg_atomic_flag;
-#endif
-
-#ifndef PG_HAVE_ATOMIC_READ_U32
-#define PG_HAVE_ATOMIC_READ_U32
-static inline uint32
-pg_atomic_read_u32_impl(volatile pg_atomic_uint32 *ptr)
-{
-	return ptr->value;
-}
-#endif
-
-#ifndef PG_HAVE_ATOMIC_WRITE_U32
-#define PG_HAVE_ATOMIC_WRITE_U32
-static inline void
-pg_atomic_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val)
-{
-	ptr->value = val;
-}
-#endif
-
-#ifndef PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32
-#define PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32
-static inline void
-pg_atomic_unlocked_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val)
-{
-	ptr->value = val;
-}
-#endif
-
-/*
- * provide fallback for test_and_set using atomic_exchange if available
- */
-#if !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) && defined(PG_HAVE_ATOMIC_EXCHANGE_U32)
-
-#define PG_HAVE_ATOMIC_INIT_FLAG
-static inline void
-pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	pg_atomic_write_u32_impl(ptr, 0);
-}
-
-#define PG_HAVE_ATOMIC_TEST_SET_FLAG
-static inline bool
-pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	return pg_atomic_exchange_u32_impl(ptr, 1) == 0;
-}
-
-#define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
-static inline bool
-pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	return pg_atomic_read_u32_impl(ptr) == 0;
-}
-
-
-#define PG_HAVE_ATOMIC_CLEAR_FLAG
-static inline void
-pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	/* XXX: release semantics suffice? */
-	pg_memory_barrier_impl();
-	pg_atomic_write_u32_impl(ptr, 0);
-}
-
-/*
- * provide fallback for test_and_set using atomic_compare_exchange if
- * available.
- */
-#elif !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
-
-#define PG_HAVE_ATOMIC_INIT_FLAG
-static inline void
-pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	pg_atomic_write_u32_impl(ptr, 0);
-}
-
-#define PG_HAVE_ATOMIC_TEST_SET_FLAG
-static inline bool
-pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	uint32 value = 0;
-	return pg_atomic_compare_exchange_u32_impl(ptr, &value, 1);
-}
-
-#define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
-static inline bool
-pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	return pg_atomic_read_u32_impl(ptr) == 0;
-}
-
-#define PG_HAVE_ATOMIC_CLEAR_FLAG
-static inline void
-pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr)
-{
-	/* XXX: release semantics suffice? */
-	pg_memory_barrier_impl();
-	pg_atomic_write_u32_impl(ptr, 0);
-}
-
-#elif !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG)
-#	error "No pg_atomic_test_and_set provided"
-#endif /* !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) */
-
-
-#ifndef PG_HAVE_ATOMIC_INIT_U32
-#define PG_HAVE_ATOMIC_INIT_U32
-static inline void
-pg_atomic_init_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val_)
-{
-	ptr->value = val_;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_EXCHANGE_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
-#define PG_HAVE_ATOMIC_EXCHANGE_U32
-static inline uint32
-pg_atomic_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 xchg_)
-{
-	uint32 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, xchg_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
-#define PG_HAVE_ATOMIC_FETCH_ADD_U32
-static inline uint32
-pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	uint32 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, old + add_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
-#define PG_HAVE_ATOMIC_FETCH_SUB_U32
-static inline uint32
-pg_atomic_fetch_sub_u32_impl(volatile pg_atomic_uint32 *ptr, int32 sub_)
-{
-	return pg_atomic_fetch_add_u32_impl(ptr, -sub_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_AND_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
-#define PG_HAVE_ATOMIC_FETCH_AND_U32
-static inline uint32
-pg_atomic_fetch_and_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 and_)
-{
-	uint32 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, old & and_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_OR_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
-#define PG_HAVE_ATOMIC_FETCH_OR_U32
-static inline uint32
-pg_atomic_fetch_or_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 or_)
-{
-	uint32 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, old | or_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_ADD_FETCH_U32) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U32)
-#define PG_HAVE_ATOMIC_ADD_FETCH_U32
-static inline uint32
-pg_atomic_add_fetch_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
-{
-	return pg_atomic_fetch_add_u32_impl(ptr, add_) + add_;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_SUB_FETCH_U32) && defined(PG_HAVE_ATOMIC_FETCH_SUB_U32)
-#define PG_HAVE_ATOMIC_SUB_FETCH_U32
-static inline uint32
-pg_atomic_sub_fetch_u32_impl(volatile pg_atomic_uint32 *ptr, int32 sub_)
-{
-	return pg_atomic_fetch_sub_u32_impl(ptr, sub_) - sub_;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_READ_MEMBARRIER_U32) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U32)
-#define PG_HAVE_ATOMIC_READ_MEMBARRIER_U32
-static inline uint32
-pg_atomic_read_membarrier_u32_impl(volatile pg_atomic_uint32 *ptr)
-{
-	return pg_atomic_fetch_add_u32_impl(ptr, 0);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U32) && defined(PG_HAVE_ATOMIC_EXCHANGE_U32)
-#define PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U32
-static inline void
-pg_atomic_write_membarrier_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val)
-{
-	(void) pg_atomic_exchange_u32_impl(ptr, val);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_EXCHANGE_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
-#define PG_HAVE_ATOMIC_EXCHANGE_U64
-static inline uint64
-pg_atomic_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 xchg_)
-{
-	uint64 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, xchg_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#ifndef PG_HAVE_ATOMIC_WRITE_U64
-#define PG_HAVE_ATOMIC_WRITE_U64
-
-#if defined(PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY) && \
-	!defined(PG_HAVE_ATOMIC_U64_SIMULATION)
-
-static inline void
-pg_atomic_write_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val)
-{
-	/*
-	 * On this platform aligned 64bit writes are guaranteed to be atomic,
-	 * except if using the fallback implementation, where can't guarantee the
-	 * required alignment.
-	 */
-	AssertPointerAlignment(ptr, 8);
-	ptr->value = val;
-}
-
-#else
-
-static inline void
-pg_atomic_write_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val)
-{
-	/*
-	 * 64 bit writes aren't safe on all platforms. In the generic
-	 * implementation implement them as an atomic exchange.
-	 */
-	pg_atomic_exchange_u64_impl(ptr, val);
-}
-
-#endif /* PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY && !PG_HAVE_ATOMIC_U64_SIMULATION */
-#endif /* PG_HAVE_ATOMIC_WRITE_U64 */
-
-#ifndef PG_HAVE_ATOMIC_READ_U64
-#define PG_HAVE_ATOMIC_READ_U64
-
-#if defined(PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY) && \
-	!defined(PG_HAVE_ATOMIC_U64_SIMULATION)
-
-static inline uint64
-pg_atomic_read_u64_impl(volatile pg_atomic_uint64 *ptr)
-{
-	/*
-	 * On this platform aligned 64-bit reads are guaranteed to be atomic.
-	 */
-	AssertPointerAlignment(ptr, 8);
-	return ptr->value;
-}
-
-#else
-
-static inline uint64
-pg_atomic_read_u64_impl(volatile pg_atomic_uint64 *ptr)
-{
-	uint64 old = 0;
-
-	/*
-	 * 64-bit reads aren't atomic on all platforms. In the generic
-	 * implementation implement them as a compare/exchange with 0. That'll
-	 * fail or succeed, but always return the old value. Possibly might store
-	 * a 0, but only if the previous value also was a 0 - i.e. harmless.
-	 */
-	pg_atomic_compare_exchange_u64_impl(ptr, &old, 0);
-
-	return old;
-}
-#endif /* PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY && !PG_HAVE_ATOMIC_U64_SIMULATION */
-#endif /* PG_HAVE_ATOMIC_READ_U64 */
-
-#ifndef PG_HAVE_ATOMIC_INIT_U64
-#define PG_HAVE_ATOMIC_INIT_U64
-static inline void
-pg_atomic_init_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val_)
-{
-	ptr->value = val_;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
-#define PG_HAVE_ATOMIC_FETCH_ADD_U64
-static inline uint64
-pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-	uint64 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, old + add_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
-#define PG_HAVE_ATOMIC_FETCH_SUB_U64
-static inline uint64
-pg_atomic_fetch_sub_u64_impl(volatile pg_atomic_uint64 *ptr, int64 sub_)
-{
-	return pg_atomic_fetch_add_u64_impl(ptr, -sub_);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_AND_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
-#define PG_HAVE_ATOMIC_FETCH_AND_U64
-static inline uint64
-pg_atomic_fetch_and_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 and_)
-{
-	uint64 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, old & and_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_FETCH_OR_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
-#define PG_HAVE_ATOMIC_FETCH_OR_U64
-static inline uint64
-pg_atomic_fetch_or_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 or_)
-{
-	uint64 old;
-	old = ptr->value;			/* ok if read is not atomic */
-	while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, old | or_))
-		/* skip */;
-	return old;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_ADD_FETCH_U64) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U64)
-#define PG_HAVE_ATOMIC_ADD_FETCH_U64
-static inline uint64
-pg_atomic_add_fetch_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
-{
-	return pg_atomic_fetch_add_u64_impl(ptr, add_) + add_;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_SUB_FETCH_U64) && defined(PG_HAVE_ATOMIC_FETCH_SUB_U64)
-#define PG_HAVE_ATOMIC_SUB_FETCH_U64
-static inline uint64
-pg_atomic_sub_fetch_u64_impl(volatile pg_atomic_uint64 *ptr, int64 sub_)
-{
-	return pg_atomic_fetch_sub_u64_impl(ptr, sub_) - sub_;
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_READ_MEMBARRIER_U64) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U64)
-#define PG_HAVE_ATOMIC_READ_MEMBARRIER_U64
-static inline uint64
-pg_atomic_read_membarrier_u64_impl(volatile pg_atomic_uint64 *ptr)
-{
-	return pg_atomic_fetch_add_u64_impl(ptr, 0);
-}
-#endif
-
-#if !defined(PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U64) && defined(PG_HAVE_ATOMIC_EXCHANGE_U64)
-#define PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U64
-static inline void
-pg_atomic_write_membarrier_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val)
-{
-	(void) pg_atomic_exchange_u64_impl(ptr, val);
-}
-#endif
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 23bce72ae64..3b2c109e67b 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -3862,6 +3862,8 @@ pending_label
 pgParameterStatus
 pgoff_t
 pg_atomic_flag
+pg_atomic_uint8
+pg_atomic_uint16
 pg_atomic_uint32
 pg_atomic_uint64
 pg_be_sasl_mech
-- 
2.50.1 (Apple Git-155)



  [application/octet-stream] v2-0004-Use-atomics-API-to-implement-spinlocks.patch (35.8K, 5-v2-0004-Use-atomics-API-to-implement-spinlocks.patch)
  download | inline diff:
From 4727999c79932e728582ccbfe13e9c5ae0620ffe Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Wed, 31 Jul 2024 13:11:35 +1200
Subject: [PATCH v2 4/5] Use atomics API to implement spinlocks.

Since our spinlock API pre-dates our C11-inspired atomics API by
decades, it had its own hand-crafted operations written in assembler.

Use the modern atomics API instead, to simplify and de-duplicate.  We
couldn't have done this until fairly recently, because that would have
been be circular: atomics were simulated with spinlocks in
--disable-atomics builds.  Commit 81385261 removed that option, so now
we can delete most of the system-specific spinlock code and use
pg_atomic_flag.

The remaining architecture-specific knowledge is moved into
src/include/port/spin_delay.h:

* implementation of pg_spin_delay()
* whether it is believed to be a good idea to perform a relaxed load
  before attempting test-and-set while spinning (carried forward from
  the old hand-crafted code)

WIP!
---
 src/backend/port/meson.build      |   2 +-
 src/backend/port/tas/dummy.s      |   0
 src/backend/storage/lmgr/s_lock.c | 128 +-----
 src/include/port/spin_delay.h     |  91 ++++
 src/include/storage/s_lock.h      | 737 ------------------------------
 src/include/storage/spin.h        |  70 ++-
 src/test/regress/regress.c        |  25 +-
 7 files changed, 176 insertions(+), 877 deletions(-)
 delete mode 100644 src/backend/port/tas/dummy.s
 create mode 100644 src/include/port/spin_delay.h
 delete mode 100644 src/include/storage/s_lock.h

diff --git a/src/backend/port/meson.build b/src/backend/port/meson.build
index 09d54e01d13..45438fcec17 100644
--- a/src/backend/port/meson.build
+++ b/src/backend/port/meson.build
@@ -30,4 +30,4 @@ if host_system == 'windows'
 endif
 
 # autoconf generates the file there, ensure we get a conflict
-generated_sources_ac += {'src/backend/port': ['pg_sema.c', 'pg_shmem.c', 'tas.s']}
+generated_sources_ac += {'src/backend/port': ['pg_sema.c', 'pg_shmem.c']}
diff --git a/src/backend/port/tas/dummy.s b/src/backend/port/tas/dummy.s
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/src/backend/storage/lmgr/s_lock.c b/src/backend/storage/lmgr/s_lock.c
index d26e192f4bc..a2fc129c688 100644
--- a/src/backend/storage/lmgr/s_lock.c
+++ b/src/backend/storage/lmgr/s_lock.c
@@ -51,7 +51,9 @@
 #include <unistd.h>
 
 #include "common/pg_prng.h"
-#include "storage/s_lock.h"
+#include "port/atomics.h"
+#include "port/spin_delay.h"
+#include "storage/spin.h"
 #include "utils/wait_event.h"
 
 #define MIN_SPINS_PER_DELAY 10
@@ -92,7 +94,7 @@ s_lock_stuck(const char *file, int line, const char *func)
 }
 
 /*
- * s_lock(lock) - platform-independent portion of waiting for a spinlock.
+ * s_lock(lock) - out-of-line portion of waiting for a spinlock.
  */
 int
 s_lock(volatile slock_t *lock, const char *file, int line, const char *func)
@@ -101,8 +103,25 @@ s_lock(volatile slock_t *lock, const char *file, int line, const char *func)
 
 	init_spin_delay(&delayStatus, file, line, func);
 
-	while (TAS_SPIN(lock))
+	for (;;)
 	{
+		bool		try_to_set;
+
+#ifdef PG_SPIN_TRY_RELAXED
+
+		/*
+		 * It is known to be more efficient to test the lock with a relaxed
+		 * load first, while spinning, on this platform.
+		 */
+		try_to_set = pg_atomic_unlocked_test_flag(lock);
+#else
+		try_to_set = true;
+#endif
+
+		/* Try to get the lock. */
+		if (try_to_set && pg_atomic_test_set_flag(lock))
+			break;
+
 		perform_spin_delay(&delayStatus);
 	}
 
@@ -111,14 +130,6 @@ s_lock(volatile slock_t *lock, const char *file, int line, const char *func)
 	return delayStatus.delays;
 }
 
-#ifdef USE_DEFAULT_S_UNLOCK
-void
-s_unlock(volatile slock_t *lock)
-{
-	*lock = 0;
-}
-#endif
-
 /*
  * Wait while spinning on a contended spinlock.
  */
@@ -126,7 +137,7 @@ void
 perform_spin_delay(SpinDelayStatus *status)
 {
 	/* CPU-specific delay each time through the loop */
-	SPIN_DELAY();
+	pg_spin_delay();
 
 	/* Block the process every spins_per_delay tries */
 	if (++(status->spins) >= spins_per_delay)
@@ -229,96 +240,3 @@ update_spins_per_delay(int shared_spins_per_delay)
 	 */
 	return (shared_spins_per_delay * 15 + spins_per_delay) / 16;
 }
-
-
-/*****************************************************************************/
-#if defined(S_LOCK_TEST)
-
-/*
- * test program for verifying a port's spinlock support.
- */
-
-struct test_lock_struct
-{
-	char		pad1;
-	slock_t		lock;
-	char		pad2;
-};
-
-volatile struct test_lock_struct test_lock;
-
-int
-main()
-{
-	pg_prng_seed(&pg_global_prng_state, (uint64) time(NULL));
-
-	test_lock.pad1 = test_lock.pad2 = 0x44;
-
-	S_INIT_LOCK(&test_lock.lock);
-
-	if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
-	{
-		printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
-		return 1;
-	}
-
-	if (!S_LOCK_FREE(&test_lock.lock))
-	{
-		printf("S_LOCK_TEST: failed, lock not initialized\n");
-		return 1;
-	}
-
-	S_LOCK(&test_lock.lock);
-
-	if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
-	{
-		printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
-		return 1;
-	}
-
-	if (S_LOCK_FREE(&test_lock.lock))
-	{
-		printf("S_LOCK_TEST: failed, lock not locked\n");
-		return 1;
-	}
-
-	S_UNLOCK(&test_lock.lock);
-
-	if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
-	{
-		printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
-		return 1;
-	}
-
-	if (!S_LOCK_FREE(&test_lock.lock))
-	{
-		printf("S_LOCK_TEST: failed, lock not unlocked\n");
-		return 1;
-	}
-
-	S_LOCK(&test_lock.lock);
-
-	if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
-	{
-		printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
-		return 1;
-	}
-
-	if (S_LOCK_FREE(&test_lock.lock))
-	{
-		printf("S_LOCK_TEST: failed, lock not re-locked\n");
-		return 1;
-	}
-
-	printf("S_LOCK_TEST: this will print %d stars and then\n", NUM_DELAYS);
-	printf("             exit with a 'stuck spinlock' message\n");
-	printf("             if S_LOCK() and TAS() are working.\n");
-	fflush(stdout);
-
-	s_lock(&test_lock.lock, __FILE__, __LINE__, __func__);
-
-	printf("S_LOCK_TEST: failed, lock not locked\n");
-	return 1;
-}
-
-#endif							/* S_LOCK_TEST */
diff --git a/src/include/port/spin_delay.h b/src/include/port/spin_delay.h
new file mode 100644
index 00000000000..c583698af8e
--- /dev/null
+++ b/src/include/port/spin_delay.h
@@ -0,0 +1,91 @@
+/*-------------------------------------------------------------------------
+ *
+ * spin_delay.h
+ *	   Implementation of architecture-specific spinlock delay.
+ *
+ * Note to implementors: the default implementation does nothing.
+ *
+ * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *	  src/include/port/spin_delay.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SPIN_DELAY_H
+#define SPIN_DELAY_H
+
+static pg_attribute_always_inline void
+pg_spin_delay(void)
+{
+#if defined(__GNUC__) || defined(__INTEL_COMPILER)
+#ifdef __i386__					/* 32-bit i386 */
+	/*
+	 * This sequence is equivalent to the PAUSE instruction ("rep" is ignored
+	 * by old IA32 processors if the following instruction is not a string
+	 * operation); the IA-32 Architecture Software Developer's Manual, Vol. 3,
+	 * Section 7.7.2 describes why using PAUSE in the inner loop of a spin
+	 * lock is necessary for good performance:
+	 *
+	 * The PAUSE instruction improves the performance of IA-32 processors
+	 * supporting Hyper-Threading Technology when executing spin-wait loops
+	 * and other routines where one thread is accessing a shared lock or
+	 * semaphore in a tight polling loop. When executing a spin-wait loop, the
+	 * processor can suffer a severe performance penalty when exiting the loop
+	 * because it detects a possible memory order violation and flushes the
+	 * core processor's pipeline. The PAUSE instruction provides a hint to the
+	 * processor that the code sequence is a spin-wait loop. The processor
+	 * uses this hint to avoid the memory order violation and prevent the
+	 * pipeline flush. In addition, the PAUSE instruction de-pipelines the
+	 * spin-wait loop to prevent it from consuming execution resources
+	 * excessively.
+	 */
+	__asm__ __volatile__(
+						 " rep; nop			\n");
+#endif							/* __i386__ */
+#ifdef __x86_64__				/* AMD Opteron, Intel EM64T */
+
+	/*
+	 * Adding a PAUSE in the spin delay loop is demonstrably a no-op on
+	 * Opteron, but it may be of some use on EM64T, so we keep it.
+	 */
+	__asm__ __volatile__(
+						 " rep; nop			\n");
+#endif							/* __x86_64__ */
+#if defined(__aarch64__)
+
+	/*
+	 * Using an ISB instruction to delay in spinlock loops appears beneficial
+	 * on high-core-count ARM64 processors.  It seems mostly a wash for
+	 * smaller gear, and ISB doesn't exist at all on pre-v7 ARM chips.
+	 */
+	__asm__ __volatile__(
+						 " isb;				\n");
+#endif							/* __aarch64__ */
+#endif							/* defined(__GNUC__) ||
+								 * defined(__INTEL_COMPILER) */
+
+#ifdef _MSC_VER
+
+	/*
+	 * If using Visual C++ on Win64, inline assembly is unavailable.  Use a
+	 * _mm_pause intrinsic instead of rep nop.
+	 */
+#if defined(_WIN64)
+	_mm_pause();
+#else
+	/* See comment for gcc code. Same code, MASM syntax */
+	__asm		rep nop;
+#endif
+#endif							/* _MSC_VER */
+}
+
+/* Architectures on which a relaxed load is recommended while spinning. */
+#if defined(__i386__) || defined(__x86_64__) || \
+	defined(_M_IX86) || defined(_M_AMD64) || \
+	defined(__ppc__) || defined(__powerpc__) || \
+	defined(__ppc64__) || defined(__powerpc64__)
+#define PG_SPIN_TRY_RELAXED
+#endif
+
+#endif							/* SPIN_DELAY_H */
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
deleted file mode 100644
index 7f8f566bd40..00000000000
--- a/src/include/storage/s_lock.h
+++ /dev/null
@@ -1,737 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * s_lock.h
- *	   Implementation of spinlocks.
- *
- *	NOTE: none of the macros in this file are intended to be called directly.
- *	Call them through the macros in spin.h.
- *
- *	The following hardware-dependent macros must be provided for each
- *	supported platform:
- *
- *	void S_INIT_LOCK(slock_t *lock)
- *		Initialize a spinlock (to the unlocked state).
- *
- *	int S_LOCK(slock_t *lock)
- *		Acquire a spinlock, waiting if necessary.
- *		Time out and abort() if unable to acquire the lock in a
- *		"reasonable" amount of time --- typically ~ 1 minute.
- *		Should return number of "delays"; see s_lock.c
- *
- *	void S_UNLOCK(slock_t *lock)
- *		Unlock a previously acquired lock.
- *
- *	bool S_LOCK_FREE(slock_t *lock)
- *		Tests if the lock is free. Returns true if free, false if locked.
- *		This does *not* change the state of the lock.
- *
- *	void SPIN_DELAY(void)
- *		Delay operation to occur inside spinlock wait loop.
- *
- *	Note to implementors: there are default implementations for all these
- *	macros at the bottom of the file.  Check if your platform can use
- *	these or needs to override them.
- *
- *  Usually, S_LOCK() is implemented in terms of even lower-level macros
- *	TAS() and TAS_SPIN():
- *
- *	int TAS(slock_t *lock)
- *		Atomic test-and-set instruction.  Attempt to acquire the lock,
- *		but do *not* wait.	Returns 0 if successful, nonzero if unable
- *		to acquire the lock.
- *
- *	int TAS_SPIN(slock_t *lock)
- *		Like TAS(), but this version is used when waiting for a lock
- *		previously found to be contended.  By default, this is the
- *		same as TAS(), but on some architectures it's better to poll a
- *		contended lock using an unlocked instruction and retry the
- *		atomic test-and-set only when it appears free.
- *
- *	TAS() and TAS_SPIN() are NOT part of the API, and should never be called
- *	directly.
- *
- *	CAUTION: on some platforms TAS() and/or TAS_SPIN() may sometimes report
- *	failure to acquire a lock even when the lock is not locked.  For example,
- *	on Alpha TAS() will "fail" if interrupted.  Therefore a retry loop must
- *	always be used, even if you are certain the lock is free.
- *
- *	It is the responsibility of these macros to make sure that the compiler
- *	does not re-order accesses to shared memory to precede the actual lock
- *	acquisition, or follow the lock release.  Prior to PostgreSQL 9.5, this
- *	was the caller's responsibility, which meant that callers had to use
- *	volatile-qualified pointers to refer to both the spinlock itself and the
- *	shared data being accessed within the spinlocked critical section.  This
- *	was notationally awkward, easy to forget (and thus error-prone), and
- *	prevented some useful compiler optimizations.  For these reasons, we
- *	now require that the macros themselves prevent compiler re-ordering,
- *	so that the caller doesn't need to take special precautions.
- *
- *	On platforms with weak memory ordering, the TAS(), TAS_SPIN(), and
- *	S_UNLOCK() macros must further include hardware-level memory fence
- *	instructions to prevent similar re-ordering at the hardware level.
- *	TAS() and TAS_SPIN() must guarantee that loads and stores issued after
- *	the macro are not executed until the lock has been obtained.  Conversely,
- *	S_UNLOCK() must guarantee that loads and stores issued before the macro
- *	have been executed before the lock is released.
- *
- *	On most supported platforms, TAS() uses a tas() function written
- *	in assembly language to execute a hardware atomic-test-and-set
- *	instruction.  Equivalent OS-supplied mutex routines could be used too.
- *
- *
- * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *	  src/include/storage/s_lock.h
- *
- *-------------------------------------------------------------------------
- */
-#ifndef S_LOCK_H
-#define S_LOCK_H
-
-#ifdef FRONTEND
-#error "s_lock.h may not be included from frontend code"
-#endif
-
-#if defined(__GNUC__) || defined(__INTEL_COMPILER)
-/*************************************************************************
- * All the gcc inlines
- * Gcc consistently defines the CPU as __cpu__.
- * Other compilers use __cpu or __cpu__ so we test for both in those cases.
- */
-
-/*----------
- * Standard gcc asm format (assuming "volatile slock_t *lock"):
-
-	__asm__ __volatile__(
-		"	instruction	\n"
-		"	instruction	\n"
-		"	instruction	\n"
-:		"=r"(_res), "+m"(*lock)		// return register, in/out lock value
-:		"r"(lock)					// lock pointer, in input register
-:		"memory", "cc");			// show clobbered registers here
-
- * The output-operands list (after first colon) should always include
- * "+m"(*lock), whether or not the asm code actually refers to this
- * operand directly.  This ensures that gcc believes the value in the
- * lock variable is used and set by the asm code.  Also, the clobbers
- * list (after third colon) should always include "memory"; this prevents
- * gcc from thinking it can cache the values of shared-memory fields
- * across the asm code.  Add "cc" if your asm code changes the condition
- * code register, and also list any temp registers the code uses.
- *----------
- */
-
-
-#ifdef __i386__		/* 32-bit i386 */
-#define HAS_TEST_AND_SET
-
-typedef unsigned char slock_t;
-
-#define TAS(lock) tas(lock)
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	slock_t		_res = 1;
-
-	/*
-	 * Use a non-locking test before asserting the bus lock.  Note that the
-	 * extra test appears to be a small loss on some x86 platforms and a small
-	 * win on others; it's by no means clear that we should keep it.
-	 *
-	 * When this was last tested, we didn't have separate TAS() and TAS_SPIN()
-	 * macros.  Nowadays it probably would be better to do a non-locking test
-	 * in TAS_SPIN() but not in TAS(), like on x86_64, but no-one's done the
-	 * testing to verify that.  Without some empirical evidence, better to
-	 * leave it alone.
-	 */
-	__asm__ __volatile__(
-		"	cmpb	$0,%1	\n"
-		"	jne		1f		\n"
-		"	lock			\n"
-		"	xchgb	%0,%1	\n"
-		"1: \n"
-:		"+q"(_res), "+m"(*lock)
-:		/* no inputs */
-:		"memory", "cc");
-	return (int) _res;
-}
-
-#define SPIN_DELAY() spin_delay()
-
-static __inline__ void
-spin_delay(void)
-{
-	/*
-	 * This sequence is equivalent to the PAUSE instruction ("rep" is
-	 * ignored by old IA32 processors if the following instruction is
-	 * not a string operation); the IA-32 Architecture Software
-	 * Developer's Manual, Vol. 3, Section 7.7.2 describes why using
-	 * PAUSE in the inner loop of a spin lock is necessary for good
-	 * performance:
-	 *
-	 *     The PAUSE instruction improves the performance of IA-32
-	 *     processors supporting Hyper-Threading Technology when
-	 *     executing spin-wait loops and other routines where one
-	 *     thread is accessing a shared lock or semaphore in a tight
-	 *     polling loop. When executing a spin-wait loop, the
-	 *     processor can suffer a severe performance penalty when
-	 *     exiting the loop because it detects a possible memory order
-	 *     violation and flushes the core processor's pipeline. The
-	 *     PAUSE instruction provides a hint to the processor that the
-	 *     code sequence is a spin-wait loop. The processor uses this
-	 *     hint to avoid the memory order violation and prevent the
-	 *     pipeline flush. In addition, the PAUSE instruction
-	 *     de-pipelines the spin-wait loop to prevent it from
-	 *     consuming execution resources excessively.
-	 */
-	__asm__ __volatile__(
-		" rep; nop			\n");
-}
-
-#endif	 /* __i386__ */
-
-
-#ifdef __x86_64__		/* AMD Opteron, Intel EM64T */
-#define HAS_TEST_AND_SET
-
-typedef unsigned char slock_t;
-
-#define TAS(lock) tas(lock)
-
-/*
- * On Intel EM64T, it's a win to use a non-locking test before the xchg proper,
- * but only when spinning.
- *
- * See also Implementing Scalable Atomic Locks for Multi-Core Intel(tm) EM64T
- * and IA32, by Michael Chynoweth and Mary R. Lee. As of this writing, it is
- * available at:
- * http://software.intel.com/en-us/articles/implementing-scalable-atomic-locks-for-multi-core-intel-em64t-and-ia32-architectures
- */
-#define TAS_SPIN(lock)    (*(lock) ? 1 : TAS(lock))
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	slock_t		_res = 1;
-
-	__asm__ __volatile__(
-		"	lock			\n"
-		"	xchgb	%0,%1	\n"
-:		"+q"(_res), "+m"(*lock)
-:		/* no inputs */
-:		"memory", "cc");
-	return (int) _res;
-}
-
-#define SPIN_DELAY() spin_delay()
-
-static __inline__ void
-spin_delay(void)
-{
-	/*
-	 * Adding a PAUSE in the spin delay loop is demonstrably a no-op on
-	 * Opteron, but it may be of some use on EM64T, so we keep it.
-	 */
-	__asm__ __volatile__(
-		" rep; nop			\n");
-}
-
-#endif	 /* __x86_64__ */
-
-
-/*
- * On ARM and ARM64, we use __sync_lock_test_and_set(int *, int) if available.
- *
- * We use the int-width variant of the builtin because it works on more chips
- * than other widths.
- */
-#if defined(__arm__) || defined(__arm) || defined(__aarch64__)
-#ifdef HAVE_GCC__SYNC_INT32_TAS
-#define HAS_TEST_AND_SET
-
-#define TAS(lock) tas(lock)
-
-typedef int slock_t;
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	return __sync_lock_test_and_set(lock, 1);
-}
-
-#define S_UNLOCK(lock) __sync_lock_release(lock)
-
-#if defined(__aarch64__)
-
-/*
- * On ARM64, it's a win to use a non-locking test before the TAS proper.  It
- * may be a win on 32-bit ARM, too, but nobody's tested it yet.
- */
-#define TAS_SPIN(lock)	(*(lock) ? 1 : TAS(lock))
-
-#define SPIN_DELAY() spin_delay()
-
-static __inline__ void
-spin_delay(void)
-{
-	/*
-	 * Using an ISB instruction to delay in spinlock loops appears beneficial
-	 * on high-core-count ARM64 processors.  It seems mostly a wash for smaller
-	 * gear, and ISB doesn't exist at all on pre-v7 ARM chips.
-	 */
-	__asm__ __volatile__(
-		" isb;				\n");
-}
-
-#endif	 /* __aarch64__ */
-#endif	 /* HAVE_GCC__SYNC_INT32_TAS */
-#endif	 /* __arm__ || __arm || __aarch64__ */
-
-
-/* S/390 and S/390x Linux (32- and 64-bit zSeries) */
-#if defined(__s390__) || defined(__s390x__)
-#define HAS_TEST_AND_SET
-
-typedef unsigned int slock_t;
-
-#define TAS(lock)	   tas(lock)
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	int			_res = 0;
-
-	__asm__	__volatile__(
-		"	cs 	%0,%3,0(%2)		\n"
-:		"+d"(_res), "+m"(*lock)
-:		"a"(lock), "d"(1)
-:		"memory", "cc");
-	return _res;
-}
-
-#endif	 /* __s390__ || __s390x__ */
-
-
-#if defined(__sparc__)		/* Sparc */
-/*
- * Solaris has always run sparc processors in TSO (total store) mode, but
- * linux didn't use to and the *BSDs still don't. So, be careful about
- * acquire/release semantics. The CPU will treat superfluous members as
- * NOPs, so it's just code space.
- */
-#define HAS_TEST_AND_SET
-
-typedef unsigned char slock_t;
-
-#define TAS(lock) tas(lock)
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	slock_t		_res;
-
-	/*
-	 * "cas" would be better than "ldstub", but it is only present on
-	 * sparcv8plus and later, while some platforms still support sparcv7 or
-	 * sparcv8.  Also, "cas" requires that the system be running in TSO mode.
-	 */
-	__asm__ __volatile__(
-		"	ldstub	[%2], %0	\n"
-:		"=r"(_res), "+m"(*lock)
-:		"r"(lock)
-:		"memory");
-#if defined(__sparcv7) || defined(__sparc_v7__)
-	/*
-	 * No stbar or membar available, luckily no actually produced hardware
-	 * requires a barrier.
-	 */
-#elif defined(__sparcv8) || defined(__sparc_v8__)
-	/* stbar is available (and required for both PSO, RMO), membar isn't */
-	__asm__ __volatile__ ("stbar	 \n":::"memory");
-#else
-	/*
-	 * #LoadStore (RMO) | #LoadLoad (RMO) together are the appropriate acquire
-	 * barrier for sparcv8+ upwards.
-	 */
-	__asm__ __volatile__ ("membar #LoadStore | #LoadLoad \n":::"memory");
-#endif
-	return (int) _res;
-}
-
-#if defined(__sparcv7) || defined(__sparc_v7__)
-/*
- * No stbar or membar available, luckily no actually produced hardware
- * requires a barrier.  We fall through to the default gcc definition of
- * S_UNLOCK in this case.
- */
-#elif defined(__sparcv8) || defined(__sparc_v8__)
-/* stbar is available (and required for both PSO, RMO), membar isn't */
-#define S_UNLOCK(lock)	\
-do \
-{ \
-	__asm__ __volatile__ ("stbar	 \n":::"memory"); \
-	*((volatile slock_t *) (lock)) = 0; \
-} while (0)
-#else
-/*
- * #LoadStore (RMO) | #StoreStore (RMO, PSO) together are the appropriate
- * release barrier for sparcv8+ upwards.
- */
-#define S_UNLOCK(lock)	\
-do \
-{ \
-	__asm__ __volatile__ ("membar #LoadStore | #StoreStore \n":::"memory"); \
-	*((volatile slock_t *) (lock)) = 0; \
-} while (0)
-#endif
-
-#endif	 /* __sparc__ */
-
-
-/* PowerPC */
-#if defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__)
-#define HAS_TEST_AND_SET
-
-typedef unsigned int slock_t;
-
-#define TAS(lock) tas(lock)
-
-/* On PPC, it's a win to use a non-locking test before the lwarx */
-#define TAS_SPIN(lock)	(*(lock) ? 1 : TAS(lock))
-
-/*
- * The second operand of addi can hold a constant zero or a register number,
- * hence constraint "=&b" to avoid allocating r0.  "b" stands for "address
- * base register"; most operands having this register-or-zero property are
- * address bases, e.g. the second operand of lwax.
- *
- * NOTE: per the Enhanced PowerPC Architecture manual, v1.0 dated 7-May-2002,
- * an isync is a sufficient synchronization barrier after a lwarx/stwcx loop.
- * But if the spinlock is in ordinary memory, we can use lwsync instead for
- * better performance.
- */
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	slock_t _t;
-	int _res;
-
-	__asm__ __volatile__(
-"	lwarx   %0,0,%3,1	\n"
-"	cmpwi   %0,0		\n"
-"	bne     1f			\n"
-"	addi    %0,%0,1		\n"
-"	stwcx.  %0,0,%3		\n"
-"	beq     2f			\n"
-"1: \n"
-"	li      %1,1		\n"
-"	b       3f			\n"
-"2: \n"
-"	lwsync				\n"
-"	li      %1,0		\n"
-"3: \n"
-:	"=&b"(_t), "=r"(_res), "+m"(*lock)
-:	"r"(lock)
-:	"memory", "cc");
-	return _res;
-}
-
-/*
- * PowerPC S_UNLOCK is almost standard but requires a "sync" instruction.
- * But we can use lwsync instead for better performance.
- */
-#define S_UNLOCK(lock)	\
-do \
-{ \
-	__asm__ __volatile__ ("	lwsync \n" ::: "memory"); \
-	*((volatile slock_t *) (lock)) = 0; \
-} while (0)
-
-#endif /* powerpc */
-
-
-#if defined(__mips__) && !defined(__sgi)	/* non-SGI MIPS */
-#define HAS_TEST_AND_SET
-
-typedef unsigned int slock_t;
-
-#define TAS(lock) tas(lock)
-
-/*
- * Original MIPS-I processors lacked the LL/SC instructions, but if we are
- * so unfortunate as to be running on one of those, we expect that the kernel
- * will handle the illegal-instruction traps and emulate them for us.  On
- * anything newer (and really, MIPS-I is extinct) LL/SC is the only sane
- * choice because any other synchronization method must involve a kernel
- * call.  Unfortunately, many toolchains still default to MIPS-I as the
- * codegen target; if the symbol __mips shows that that's the case, we
- * have to force the assembler to accept LL/SC.
- *
- * R10000 and up processors require a separate SYNC, which has the same
- * issues as LL/SC.
- */
-#if __mips < 2
-#define MIPS_SET_MIPS2	"       .set mips2          \n"
-#else
-#define MIPS_SET_MIPS2
-#endif
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	volatile slock_t *_l = lock;
-	int			_res;
-	int			_tmp;
-
-	__asm__ __volatile__(
-		"       .set push           \n"
-		MIPS_SET_MIPS2
-		"       .set noreorder      \n"
-		"       .set nomacro        \n"
-		"       ll      %0, %2      \n"
-		"       or      %1, %0, 1   \n"
-		"       sc      %1, %2      \n"
-		"       xori    %1, 1       \n"
-		"       or      %0, %0, %1  \n"
-		"       sync                \n"
-		"       .set pop              "
-:		"=&r" (_res), "=&r" (_tmp), "+R" (*_l)
-:		/* no inputs */
-:		"memory");
-	return _res;
-}
-
-/* MIPS S_UNLOCK is almost standard but requires a "sync" instruction */
-#define S_UNLOCK(lock)	\
-do \
-{ \
-	__asm__ __volatile__( \
-		"       .set push           \n" \
-		MIPS_SET_MIPS2 \
-		"       .set noreorder      \n" \
-		"       .set nomacro        \n" \
-		"       sync                \n" \
-		"       .set pop              " \
-:		/* no outputs */ \
-:		/* no inputs */	\
-:		"memory"); \
-	*((volatile slock_t *) (lock)) = 0; \
-} while (0)
-
-#endif /* __mips__ && !__sgi */
-
-
-
-/*
- * If we have no platform-specific knowledge, but we found that the compiler
- * provides __sync_lock_test_and_set(), use that.  Prefer the int-width
- * version over the char-width version if we have both, on the rather dubious
- * grounds that that's known to be more likely to work in the ARM ecosystem.
- * (But we dealt with ARM above.)
- */
-#if !defined(HAS_TEST_AND_SET)
-
-#if defined(HAVE_GCC__SYNC_INT32_TAS)
-#define HAS_TEST_AND_SET
-
-#define TAS(lock) tas(lock)
-
-typedef int slock_t;
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	return __sync_lock_test_and_set(lock, 1);
-}
-
-#define S_UNLOCK(lock) __sync_lock_release(lock)
-
-#elif defined(HAVE_GCC__SYNC_CHAR_TAS)
-#define HAS_TEST_AND_SET
-
-#define TAS(lock) tas(lock)
-
-typedef char slock_t;
-
-static __inline__ int
-tas(volatile slock_t *lock)
-{
-	return __sync_lock_test_and_set(lock, 1);
-}
-
-#define S_UNLOCK(lock) __sync_lock_release(lock)
-
-#endif	 /* HAVE_GCC__SYNC_INT32_TAS */
-
-#endif	/* !defined(HAS_TEST_AND_SET) */
-
-
-/*
- * Default implementation of S_UNLOCK() for gcc/icc.
- *
- * Note that this implementation is unsafe for any platform that can reorder
- * a memory access (either load or store) after a following store.  That
- * happens not to be possible on x86 and most legacy architectures (some are
- * single-processor!), but many modern systems have weaker memory ordering.
- * Those that do must define their own version of S_UNLOCK() rather than
- * relying on this one.
- */
-#if !defined(S_UNLOCK)
-#define S_UNLOCK(lock)	\
-	do { __asm__ __volatile__("" : : : "memory");  *(lock) = 0; } while (0)
-#endif
-
-#endif	/* defined(__GNUC__) || defined(__INTEL_COMPILER) */
-
-
-/*
- * ---------------------------------------------------------------------
- * Platforms that use non-gcc inline assembly:
- * ---------------------------------------------------------------------
- */
-
-#if !defined(HAS_TEST_AND_SET)	/* We didn't trigger above, let's try here */
-
-#ifdef _MSC_VER
-typedef LONG slock_t;
-
-#define HAS_TEST_AND_SET
-#define TAS(lock) (InterlockedCompareExchange(lock, 1, 0))
-
-#define SPIN_DELAY() spin_delay()
-
-/* If using Visual C++ on Win64, inline assembly is unavailable.
- * Use a _mm_pause intrinsic instead of rep nop.
- */
-#if defined(_WIN64)
-static __forceinline void
-spin_delay(void)
-{
-	_mm_pause();
-}
-#else
-static __forceinline void
-spin_delay(void)
-{
-	/* See comment for gcc code. Same code, MASM syntax */
-	__asm rep nop;
-}
-#endif
-
-#include <intrin.h>
-#pragma intrinsic(_ReadWriteBarrier)
-
-#define S_UNLOCK(lock)	\
-	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
-
-#endif
-
-
-#endif	/* !defined(HAS_TEST_AND_SET) */
-
-
-/* Blow up if we didn't have any way to do spinlocks */
-#ifndef HAS_TEST_AND_SET
-#error PostgreSQL does not have spinlock support on this platform.  Please report this to [email protected].
-#endif
-
-
-/*
- * Default Definitions - override these above as needed.
- */
-
-#if !defined(S_LOCK)
-#define S_LOCK(lock) \
-	(TAS(lock) ? s_lock((lock), __FILE__, __LINE__, __func__) : 0)
-#endif	 /* S_LOCK */
-
-#if !defined(S_LOCK_FREE)
-#define S_LOCK_FREE(lock)	(*(lock) == 0)
-#endif	 /* S_LOCK_FREE */
-
-#if !defined(S_UNLOCK)
-/*
- * Our default implementation of S_UNLOCK is essentially *(lock) = 0.  This
- * is unsafe if the platform can reorder a memory access (either load or
- * store) after a following store; platforms where this is possible must
- * define their own S_UNLOCK.  But CPU reordering is not the only concern:
- * if we simply defined S_UNLOCK() as an inline macro, the compiler might
- * reorder instructions from inside the critical section to occur after the
- * lock release.  Since the compiler probably can't know what the external
- * function s_unlock is doing, putting the same logic there should be adequate.
- * A sufficiently-smart globally optimizing compiler could break that
- * assumption, though, and the cost of a function call for every spinlock
- * release may hurt performance significantly, so we use this implementation
- * only for platforms where we don't know of a suitable intrinsic.  For the
- * most part, those are relatively obscure platform/compiler combinations to
- * which the PostgreSQL project does not have access.
- */
-#define USE_DEFAULT_S_UNLOCK
-extern void s_unlock(volatile slock_t *lock);
-#define S_UNLOCK(lock)		s_unlock(lock)
-#endif	 /* S_UNLOCK */
-
-#if !defined(S_INIT_LOCK)
-#define S_INIT_LOCK(lock)	S_UNLOCK(lock)
-#endif	 /* S_INIT_LOCK */
-
-#if !defined(SPIN_DELAY)
-#define SPIN_DELAY()	((void) 0)
-#endif	 /* SPIN_DELAY */
-
-#if !defined(TAS)
-extern int	tas(volatile slock_t *lock);		/* in port/.../tas.s, or
-												 * s_lock.c */
-
-#define TAS(lock)		tas(lock)
-#endif	 /* TAS */
-
-#if !defined(TAS_SPIN)
-#define TAS_SPIN(lock)	TAS(lock)
-#endif	 /* TAS_SPIN */
-
-
-/*
- * Platform-independent out-of-line support routines
- */
-extern int s_lock(volatile slock_t *lock, const char *file, int line, const char *func);
-
-/* Support for dynamic adjustment of spins_per_delay */
-#define DEFAULT_SPINS_PER_DELAY  100
-
-extern void set_spins_per_delay(int shared_spins_per_delay);
-extern int	update_spins_per_delay(int shared_spins_per_delay);
-
-/*
- * Support for spin delay which is useful in various places where
- * spinlock-like procedures take place.
- */
-typedef struct
-{
-	int			spins;
-	int			delays;
-	int			cur_delay;
-	const char *file;
-	int			line;
-	const char *func;
-} SpinDelayStatus;
-
-static inline void
-init_spin_delay(SpinDelayStatus *status,
-				const char *file, int line, const char *func)
-{
-	status->spins = 0;
-	status->delays = 0;
-	status->cur_delay = 0;
-	status->file = file;
-	status->line = line;
-	status->func = func;
-}
-
-#define init_local_spin_delay(status) init_spin_delay(status, __FILE__, __LINE__, __func__)
-extern void perform_spin_delay(SpinDelayStatus *status);
-extern void finish_spin_delay(SpinDelayStatus *status);
-
-#endif	 /* S_LOCK_H */
diff --git a/src/include/storage/spin.h b/src/include/storage/spin.h
index 33e2ab87572..eece7026d3b 100644
--- a/src/include/storage/spin.h
+++ b/src/include/storage/spin.h
@@ -14,9 +14,11 @@
  *		Acquire a spinlock, waiting if necessary.
  *		Time out and abort() if unable to acquire the lock in a
  *		"reasonable" amount of time --- typically ~ 1 minute.
+ *		Acquire (including read barrier) semantics.
  *
  *	void SpinLockRelease(volatile slock_t *lock)
  *		Unlock a previously acquired lock.
+ *		Release (including write barrier) semantics.
  *
  *	bool SpinLockFree(slock_t *lock)
  *		Tests if the lock is free. Returns true if free, false if locked.
@@ -35,11 +37,6 @@
  *	for a CHECK_FOR_INTERRUPTS() to occur while holding a spinlock, and so
  *	it is not necessary to do HOLD/RESUME_INTERRUPTS() in these macros.
  *
- *	These macros are implemented in terms of hardware-dependent macros
- *	supplied by s_lock.h.  There is not currently any extra functionality
- *	added by this header, but there has been in the past and may someday
- *	be again.
- *
  *
  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
@@ -51,15 +48,68 @@
 #ifndef SPIN_H
 #define SPIN_H
 
-#include "storage/s_lock.h"
+#ifdef FRONTEND
+#error "spin.h may not be included from frontend code"
+#endif
+
+#include "port/atomics.h"
+
+/* Support for dynamic adjustment of spins_per_delay */
+#define DEFAULT_SPINS_PER_DELAY  100
+
+typedef pg_atomic_flag slock_t;
+
+/*
+ * Support for spin delay which is useful in various places where
+ * spinlock-like procedures take place.
+ */
+typedef struct
+{
+	int			spins;
+	int			delays;
+	int			cur_delay;
+	const char *file;
+	int			line;
+	const char *func;
+} SpinDelayStatus;
+
+static inline void
+init_spin_delay(SpinDelayStatus *status,
+				const char *file, int line, const char *func)
+{
+	status->spins = 0;
+	status->delays = 0;
+	status->cur_delay = 0;
+	status->file = file;
+	status->line = line;
+	status->func = func;
+}
 
+#define init_local_spin_delay(status) init_spin_delay(status, __FILE__, __LINE__, __func__)
+extern void perform_spin_delay(SpinDelayStatus *status);
+extern void finish_spin_delay(SpinDelayStatus *status);
+extern void set_spins_per_delay(int shared_spins_per_delay);
+extern int	update_spins_per_delay(int shared_spins_per_delay);
 
-#define SpinLockInit(lock)	S_INIT_LOCK(lock)
+/* Out-of-line part of spinlock acquisition. */
+extern int	s_lock(volatile slock_t *lock,
+				   const char *file, int line,
+				   const char *func);
 
-#define SpinLockAcquire(lock) S_LOCK(lock)
+static inline void
+SpinLockInit(volatile slock_t *lock)
+{
+	pg_atomic_init_flag(lock);
+}
 
-#define SpinLockRelease(lock) S_UNLOCK(lock)
+#define SpinLockAcquire(lock)						\
+	(pg_atomic_test_set_flag(lock) ? 0 :			\
+	 s_lock((lock), __FILE__, __LINE__, __func__))
 
-#define SpinLockFree(lock)	S_LOCK_FREE(lock)
+static inline void
+SpinLockRelease(volatile slock_t *lock)
+{
+	pg_atomic_clear_flag(lock);
+}
 
 #endif							/* SPIN_H */
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index a2db6080876..dd4034e8eda 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -658,32 +658,9 @@ test_spinlock(void)
 		SpinLockAcquire(&struct_w_lock.lock);
 		SpinLockRelease(&struct_w_lock.lock);
 
-		/* test basic operations via underlying S_* API */
-		S_INIT_LOCK(&struct_w_lock.lock);
-		S_LOCK(&struct_w_lock.lock);
-		S_UNLOCK(&struct_w_lock.lock);
-
 		/* and that "contended" acquisition works */
 		s_lock(&struct_w_lock.lock, "testfile", 17, "testfunc");
-		S_UNLOCK(&struct_w_lock.lock);
-
-		/*
-		 * Check, using TAS directly, that a single spin cycle doesn't block
-		 * when acquiring an already acquired lock.
-		 */
-#ifdef TAS
-		S_LOCK(&struct_w_lock.lock);
-
-		if (!TAS(&struct_w_lock.lock))
-			elog(ERROR, "acquired already held spinlock");
-
-#ifdef TAS_SPIN
-		if (!TAS_SPIN(&struct_w_lock.lock))
-			elog(ERROR, "acquired already held spinlock");
-#endif							/* defined(TAS_SPIN) */
-
-		S_UNLOCK(&struct_w_lock.lock);
-#endif							/* defined(TAS) */
+		SpinLockRelease(&struct_w_lock.lock);
 
 		/*
 		 * Verify that after all of this the non-lock contents are still
-- 
2.50.1 (Apple Git-155)



  [application/octet-stream] v2-0005-Remove-configure-meson-checks-for-atomics.patch (16.1K, 6-v2-0005-Remove-configure-meson-checks-for-atomics.patch)
  download | inline diff:
From 7a55ded353250beb7b77d902813788505b79dbda Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Mon, 10 Nov 2025 23:03:00 +1300
Subject: [PATCH v2 5/5] Remove configure/meson checks for atomics.

These are now unreferenced, but this was kept separate from the two
patches that did that to disentangle them.
---
 config/c-compiler.m4        |  99 ------------------
 configure                   | 200 ------------------------------------
 configure.ac                |  10 --
 meson.build                 |  63 ------------
 src/backend/Makefile        |   2 +-
 src/backend/port/.gitignore |   1 -
 src/include/pg_config.h.in  |  20 ----
 7 files changed, 1 insertion(+), 394 deletions(-)

diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 236a59e8536..e05570255b3 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -446,105 +446,6 @@ AC_DEFUN([PGAC_PROG_CC_LDFLAGS_OPT],
 [PGAC_PROG_CC_LD_VARFLAGS_OPT(LDFLAGS, [$1], [$2])
 ])# PGAC_PROG_CC_LDFLAGS_OPT
 
-
-# PGAC_HAVE_GCC__SYNC_CHAR_TAS
-# ----------------------------
-# Check if the C compiler understands __sync_lock_test_and_set(char),
-# and define HAVE_GCC__SYNC_CHAR_TAS
-#
-# NB: There are platforms where test_and_set is available but compare_and_swap
-# is not, so test this separately.
-# NB: Some platforms only do 32bit tas, others only do 8bit tas. Test both.
-AC_DEFUN([PGAC_HAVE_GCC__SYNC_CHAR_TAS],
-[AC_CACHE_CHECK(for builtin __sync char locking functions, pgac_cv_gcc_sync_char_tas,
-[AC_LINK_IFELSE([AC_LANG_PROGRAM([],
-  [char lock = 0;
-   __sync_lock_test_and_set(&lock, 1);
-   __sync_lock_release(&lock);])],
-  [pgac_cv_gcc_sync_char_tas="yes"],
-  [pgac_cv_gcc_sync_char_tas="no"])])
-if test x"$pgac_cv_gcc_sync_char_tas" = x"yes"; then
-  AC_DEFINE(HAVE_GCC__SYNC_CHAR_TAS, 1, [Define to 1 if you have __sync_lock_test_and_set(char *) and friends.])
-fi])# PGAC_HAVE_GCC__SYNC_CHAR_TAS
-
-# PGAC_HAVE_GCC__SYNC_INT32_TAS
-# -----------------------------
-# Check if the C compiler understands __sync_lock_test_and_set(),
-# and define HAVE_GCC__SYNC_INT32_TAS
-AC_DEFUN([PGAC_HAVE_GCC__SYNC_INT32_TAS],
-[AC_CACHE_CHECK(for builtin __sync int32 locking functions, pgac_cv_gcc_sync_int32_tas,
-[AC_LINK_IFELSE([AC_LANG_PROGRAM([],
-  [int lock = 0;
-   __sync_lock_test_and_set(&lock, 1);
-   __sync_lock_release(&lock);])],
-  [pgac_cv_gcc_sync_int32_tas="yes"],
-  [pgac_cv_gcc_sync_int32_tas="no"])])
-if test x"$pgac_cv_gcc_sync_int32_tas" = x"yes"; then
-  AC_DEFINE(HAVE_GCC__SYNC_INT32_TAS, 1, [Define to 1 if you have __sync_lock_test_and_set(int *) and friends.])
-fi])# PGAC_HAVE_GCC__SYNC_INT32_TAS
-
-# PGAC_HAVE_GCC__SYNC_INT32_CAS
-# -----------------------------
-# Check if the C compiler understands __sync_compare_and_swap() for 32bit
-# types, and define HAVE_GCC__SYNC_INT32_CAS if so.
-AC_DEFUN([PGAC_HAVE_GCC__SYNC_INT32_CAS],
-[AC_CACHE_CHECK(for builtin __sync int32 atomic operations, pgac_cv_gcc_sync_int32_cas,
-[AC_LINK_IFELSE([AC_LANG_PROGRAM([],
-  [int val = 0;
-   __sync_val_compare_and_swap(&val, 0, 37);])],
-  [pgac_cv_gcc_sync_int32_cas="yes"],
-  [pgac_cv_gcc_sync_int32_cas="no"])])
-if test x"$pgac_cv_gcc_sync_int32_cas" = x"yes"; then
-  AC_DEFINE(HAVE_GCC__SYNC_INT32_CAS, 1, [Define to 1 if you have __sync_val_compare_and_swap(int *, int, int).])
-fi])# PGAC_HAVE_GCC__SYNC_INT32_CAS
-
-# PGAC_HAVE_GCC__SYNC_INT64_CAS
-# -----------------------------
-# Check if the C compiler understands __sync_compare_and_swap() for 64bit
-# types, and define HAVE_GCC__SYNC_INT64_CAS if so.
-AC_DEFUN([PGAC_HAVE_GCC__SYNC_INT64_CAS],
-[AC_CACHE_CHECK(for builtin __sync int64 atomic operations, pgac_cv_gcc_sync_int64_cas,
-[AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <stdint.h>],
-  [int64_t lock = 0;
-   __sync_val_compare_and_swap(&lock, 0, (int64_t) 37);])],
-  [pgac_cv_gcc_sync_int64_cas="yes"],
-  [pgac_cv_gcc_sync_int64_cas="no"])])
-if test x"$pgac_cv_gcc_sync_int64_cas" = x"yes"; then
-  AC_DEFINE(HAVE_GCC__SYNC_INT64_CAS, 1, [Define to 1 if you have __sync_val_compare_and_swap(int64_t *, int64_t, int64_t).])
-fi])# PGAC_HAVE_GCC__SYNC_INT64_CAS
-
-# PGAC_HAVE_GCC__ATOMIC_INT32_CAS
-# -------------------------------
-# Check if the C compiler understands __atomic_compare_exchange_n() for 32bit
-# types, and define HAVE_GCC__ATOMIC_INT32_CAS if so.
-AC_DEFUN([PGAC_HAVE_GCC__ATOMIC_INT32_CAS],
-[AC_CACHE_CHECK(for builtin __atomic int32 atomic operations, pgac_cv_gcc_atomic_int32_cas,
-[AC_LINK_IFELSE([AC_LANG_PROGRAM([],
-  [int val = 0;
-   int expect = 0;
-   __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);])],
-  [pgac_cv_gcc_atomic_int32_cas="yes"],
-  [pgac_cv_gcc_atomic_int32_cas="no"])])
-if test x"$pgac_cv_gcc_atomic_int32_cas" = x"yes"; then
-  AC_DEFINE(HAVE_GCC__ATOMIC_INT32_CAS, 1, [Define to 1 if you have __atomic_compare_exchange_n(int *, int *, int).])
-fi])# PGAC_HAVE_GCC__ATOMIC_INT32_CAS
-
-# PGAC_HAVE_GCC__ATOMIC_INT64_CAS
-# -------------------------------
-# Check if the C compiler understands __atomic_compare_exchange_n() for 64bit
-# types, and define HAVE_GCC__ATOMIC_INT64_CAS if so.
-AC_DEFUN([PGAC_HAVE_GCC__ATOMIC_INT64_CAS],
-[AC_CACHE_CHECK(for builtin __atomic int64 atomic operations, pgac_cv_gcc_atomic_int64_cas,
-[AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <stdint.h>],
-  [int64_t val = 0;
-   int64_t expect = 0;
-   __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);])],
-  [pgac_cv_gcc_atomic_int64_cas="yes"],
-  [pgac_cv_gcc_atomic_int64_cas="no"])])
-if test x"$pgac_cv_gcc_atomic_int64_cas" = x"yes"; then
-  AC_DEFINE(HAVE_GCC__ATOMIC_INT64_CAS, 1, [Define to 1 if you have __atomic_compare_exchange_n(int64 *, int64 *, int64).])
-fi])# PGAC_HAVE_GCC__ATOMIC_INT64_CAS
-
 # PGAC_SSE42_CRC32_INTRINSICS
 # ---------------------------
 # Check if the compiler supports the x86 CRC instructions added in SSE 4.2,
diff --git a/configure b/configure
index 3a0ed11fa8e..bd7dee3fdf3 100755
--- a/configure
+++ b/configure
@@ -17167,206 +17167,6 @@ _ACEOF
   fi
 fi
 
-# Check for various atomic operations now that we have checked how to declare
-# 64bit integers.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __sync char locking functions" >&5
-$as_echo_n "checking for builtin __sync char locking functions... " >&6; }
-if ${pgac_cv_gcc_sync_char_tas+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-char lock = 0;
-   __sync_lock_test_and_set(&lock, 1);
-   __sync_lock_release(&lock);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  pgac_cv_gcc_sync_char_tas="yes"
-else
-  pgac_cv_gcc_sync_char_tas="no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_gcc_sync_char_tas" >&5
-$as_echo "$pgac_cv_gcc_sync_char_tas" >&6; }
-if test x"$pgac_cv_gcc_sync_char_tas" = x"yes"; then
-
-$as_echo "#define HAVE_GCC__SYNC_CHAR_TAS 1" >>confdefs.h
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __sync int32 locking functions" >&5
-$as_echo_n "checking for builtin __sync int32 locking functions... " >&6; }
-if ${pgac_cv_gcc_sync_int32_tas+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-int lock = 0;
-   __sync_lock_test_and_set(&lock, 1);
-   __sync_lock_release(&lock);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  pgac_cv_gcc_sync_int32_tas="yes"
-else
-  pgac_cv_gcc_sync_int32_tas="no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_gcc_sync_int32_tas" >&5
-$as_echo "$pgac_cv_gcc_sync_int32_tas" >&6; }
-if test x"$pgac_cv_gcc_sync_int32_tas" = x"yes"; then
-
-$as_echo "#define HAVE_GCC__SYNC_INT32_TAS 1" >>confdefs.h
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __sync int32 atomic operations" >&5
-$as_echo_n "checking for builtin __sync int32 atomic operations... " >&6; }
-if ${pgac_cv_gcc_sync_int32_cas+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-int val = 0;
-   __sync_val_compare_and_swap(&val, 0, 37);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  pgac_cv_gcc_sync_int32_cas="yes"
-else
-  pgac_cv_gcc_sync_int32_cas="no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_gcc_sync_int32_cas" >&5
-$as_echo "$pgac_cv_gcc_sync_int32_cas" >&6; }
-if test x"$pgac_cv_gcc_sync_int32_cas" = x"yes"; then
-
-$as_echo "#define HAVE_GCC__SYNC_INT32_CAS 1" >>confdefs.h
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __sync int64 atomic operations" >&5
-$as_echo_n "checking for builtin __sync int64 atomic operations... " >&6; }
-if ${pgac_cv_gcc_sync_int64_cas+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdint.h>
-int
-main ()
-{
-int64_t lock = 0;
-   __sync_val_compare_and_swap(&lock, 0, (int64_t) 37);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  pgac_cv_gcc_sync_int64_cas="yes"
-else
-  pgac_cv_gcc_sync_int64_cas="no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_gcc_sync_int64_cas" >&5
-$as_echo "$pgac_cv_gcc_sync_int64_cas" >&6; }
-if test x"$pgac_cv_gcc_sync_int64_cas" = x"yes"; then
-
-$as_echo "#define HAVE_GCC__SYNC_INT64_CAS 1" >>confdefs.h
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __atomic int32 atomic operations" >&5
-$as_echo_n "checking for builtin __atomic int32 atomic operations... " >&6; }
-if ${pgac_cv_gcc_atomic_int32_cas+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-int val = 0;
-   int expect = 0;
-   __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  pgac_cv_gcc_atomic_int32_cas="yes"
-else
-  pgac_cv_gcc_atomic_int32_cas="no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_gcc_atomic_int32_cas" >&5
-$as_echo "$pgac_cv_gcc_atomic_int32_cas" >&6; }
-if test x"$pgac_cv_gcc_atomic_int32_cas" = x"yes"; then
-
-$as_echo "#define HAVE_GCC__ATOMIC_INT32_CAS 1" >>confdefs.h
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __atomic int64 atomic operations" >&5
-$as_echo_n "checking for builtin __atomic int64 atomic operations... " >&6; }
-if ${pgac_cv_gcc_atomic_int64_cas+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdint.h>
-int
-main ()
-{
-int64_t val = 0;
-   int64_t expect = 0;
-   __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  pgac_cv_gcc_atomic_int64_cas="yes"
-else
-  pgac_cv_gcc_atomic_int64_cas="no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_gcc_atomic_int64_cas" >&5
-$as_echo "$pgac_cv_gcc_atomic_int64_cas" >&6; }
-if test x"$pgac_cv_gcc_atomic_int64_cas" = x"yes"; then
-
-$as_echo "#define HAVE_GCC__ATOMIC_INT64_CAS 1" >>confdefs.h
-
-fi
-
-
 # Check for __get_cpuid() and __cpuid()
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __get_cpuid" >&5
 $as_echo_n "checking for __get_cpuid... " >&6; }
diff --git a/configure.ac b/configure.ac
index c2413720a18..e3b75601df7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2019,16 +2019,6 @@ AC_DEFINE_UNQUOTED(MAXIMUM_ALIGNOF, $MAX_ALIGNOF, [Define as the maximum alignme
 # Some compilers offer a 128-bit integer scalar type.
 PGAC_TYPE_128BIT_INT
 
-# Check for various atomic operations now that we have checked how to declare
-# 64bit integers.
-PGAC_HAVE_GCC__SYNC_CHAR_TAS
-PGAC_HAVE_GCC__SYNC_INT32_TAS
-PGAC_HAVE_GCC__SYNC_INT32_CAS
-PGAC_HAVE_GCC__SYNC_INT64_CAS
-PGAC_HAVE_GCC__ATOMIC_INT32_CAS
-PGAC_HAVE_GCC__ATOMIC_INT64_CAS
-
-
 # Check for __get_cpuid() and __cpuid()
 AC_CACHE_CHECK([for __get_cpuid], [pgac_cv__get_cpuid],
 [AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <cpuid.h>],
diff --git a/meson.build b/meson.build
index 04c563378c7..0fb783fcb64 100644
--- a/meson.build
+++ b/meson.build
@@ -2224,69 +2224,6 @@ if llvm.found()
 endif
 
 
-
-###############################################################
-# Atomics
-###############################################################
-
-atomic_checks = [
-  {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
-   'desc': '__sync_lock_test_and_set(char)',
-   'test': '''
-char lock = 0;
-__sync_lock_test_and_set(&lock, 1);
-__sync_lock_release(&lock);'''},
-
-  {'name': 'HAVE_GCC__SYNC_INT32_TAS',
-   'desc': '__sync_lock_test_and_set(int32)',
-   'test': '''
-int lock = 0;
-__sync_lock_test_and_set(&lock, 1);
-__sync_lock_release(&lock);'''},
-
-  {'name': 'HAVE_GCC__SYNC_INT32_CAS',
-   'desc': '__sync_val_compare_and_swap(int32)',
-   'test': '''
-int val = 0;
-__sync_val_compare_and_swap(&val, 0, 37);'''},
-
-  {'name': 'HAVE_GCC__SYNC_INT64_CAS',
-   'desc': '__sync_val_compare_and_swap(int64)',
-   'test': '''
-int64_t val = 0;
-__sync_val_compare_and_swap(&val, 0, 37);'''},
-
-  {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
-   'desc': ' __atomic_compare_exchange_n(int32)',
-   'test': '''
-int val = 0;
-int expect = 0;
-__atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
-
-  {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
-   'desc': ' __atomic_compare_exchange_n(int64)',
-   'test': '''
-int64_t val = 0;
-int64_t expect = 0;
-__atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
-]
-
-foreach check : atomic_checks
-  test = '''
-#include <stdint.h>
-int main(void)
-{
-@0@
-}'''.format(check['test'])
-
-  cdata.set(check['name'],
-    cc.links(test,
-      name: check['desc'],
-      args: test_c_args) ? 1 : false
-  )
-endforeach
-
-
 ###############################################################
 # Check for the availability of XSAVE intrinsics.
 ###############################################################
diff --git a/src/backend/Makefile b/src/backend/Makefile
index 7344c8c7f5c..b0d97dc2fa2 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -265,7 +265,7 @@ endif
 
 distclean: clean
 # generated by configure
-	rm -f port/tas.s port/pg_sema.c port/pg_shmem.c
+	rm -f port/pg_sema.c port/pg_shmem.c
 
 
 ##########################################################################
diff --git a/src/backend/port/.gitignore b/src/backend/port/.gitignore
index 4ef36b82c77..6c5067a4a9f 100644
--- a/src/backend/port/.gitignore
+++ b/src/backend/port/.gitignore
@@ -1,3 +1,2 @@
 /pg_sema.c
 /pg_shmem.c
-/tas.s
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index b0b0cfdaf79..ad5663a8915 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -149,26 +149,6 @@
 /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
 #undef HAVE_FSEEKO
 
-/* Define to 1 if you have __atomic_compare_exchange_n(int *, int *, int). */
-#undef HAVE_GCC__ATOMIC_INT32_CAS
-
-/* Define to 1 if you have __atomic_compare_exchange_n(int64 *, int64 *,
-   int64). */
-#undef HAVE_GCC__ATOMIC_INT64_CAS
-
-/* Define to 1 if you have __sync_lock_test_and_set(char *) and friends. */
-#undef HAVE_GCC__SYNC_CHAR_TAS
-
-/* Define to 1 if you have __sync_val_compare_and_swap(int *, int, int). */
-#undef HAVE_GCC__SYNC_INT32_CAS
-
-/* Define to 1 if you have __sync_lock_test_and_set(int *) and friends. */
-#undef HAVE_GCC__SYNC_INT32_TAS
-
-/* Define to 1 if you have __sync_val_compare_and_swap(int64_t *, int64_t,
-   int64_t). */
-#undef HAVE_GCC__SYNC_INT64_CAS
-
 /* Define to 1 if you have the `getauxval' function. */
 #undef HAVE_GETAUXVAL
 
-- 
2.50.1 (Apple Git-155)



^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-10 13:57 ` Re: Trying out <stdatomic.h> Heikki Linnakangas <[email protected]>
  2025-11-13 11:35   ` Re: Trying out <stdatomic.h> Thomas Munro <[email protected]>
@ 2025-11-19 11:23     ` Peter Eisentraut <[email protected]>
  2025-11-20 07:12       ` Re: Trying out <stdatomic.h> Thomas Munro <[email protected]>
  1 sibling, 1 reply; 19+ messages in thread

From: Peter Eisentraut @ 2025-11-19 11:23 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; Heikki Linnakangas <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>

On 13.11.25 12:35, Thomas Munro wrote:
> It passes with VS 2022 on CI.  I had to skip some assertions about
> macros promising lock-free implementation, that it doesn't define in C
> mode yet.  They are definitely lock-free though[1], and the macros are
> defined for C++, and the same under the covers...  Perhaps
> feature/conformance macros won't be defined until a few remaining
> pieces (things we don't care about) are accessible from C?  (I see
> that Visual Studio 2026 has also just shipped a couple of days ago,
> not investigated.)

Note also that we still have buildfarm members with gcc <4.9, which is 
required for stdatomic.h/_Atomic there.

We could most likely resolve to get rid of them when the time comes, but 
let's not forget to plan that.






^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-10 13:57 ` Re: Trying out <stdatomic.h> Heikki Linnakangas <[email protected]>
  2025-11-13 11:35   ` Re: Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-19 11:23     ` Re: Trying out <stdatomic.h> Peter Eisentraut <[email protected]>
@ 2025-11-20 07:12       ` Thomas Munro <[email protected]>
  0 siblings, 0 replies; 19+ messages in thread

From: Thomas Munro @ 2025-11-20 07:12 UTC (permalink / raw)
  To: Peter Eisentraut <[email protected]>; +Cc: Heikki Linnakangas <[email protected]>; PostgreSQL Hackers <[email protected]>

On Thu, Nov 20, 2025 at 12:23 AM Peter Eisentraut <[email protected]> wrote:
> On 13.11.25 12:35, Thomas Munro wrote:
> > It passes with VS 2022 on CI.  I had to skip some assertions about
> > macros promising lock-free implementation, that it doesn't define in C
> > mode yet.  They are definitely lock-free though[1], and the macros are
> > defined for C++, and the same under the covers...  Perhaps
> > feature/conformance macros won't be defined until a few remaining
> > pieces (things we don't care about) are accessible from C?  (I see
> > that Visual Studio 2026 has also just shipped a couple of days ago,
> > not investigated.)
>
> Note also that we still have buildfarm members with gcc <4.9, which is
> required for stdatomic.h/_Atomic there.

Those are EOL'd RHEL/Centos 7 and SUSE 12 systems.  A decision to
require GCC 4.9+ might not be fatal to them though, as those distros
had optional newer tool chain packages too.  I'm not sure what
problems could follow from that, probably not much as far as C goes?
C++ ABI questions are always harder but such old systems couldn't
possibly use LLVM as we chop old releases based on distro EOL dates,
and LLVM adopts new language standards (being a compiler project after
all).  (It'll be interesting to see what happens when LLVM requires
C++23, and then RHEL's new rolling LLVM upgrade policy meets its 10
year old stable compiler policy...)

The elephant in the room is Visual Studio.  We have drongo on 2019,
hammerkop on 2022, and CI on 2019 but ready to flip to 2022 whenever
we're ready.  There is no testing for 2026, being only a few days old
(I heard from Bilal that our CI passed when he tried it out FWIW).
2019 fell out of "mainstream" support 1.6 years ago[1], "extended"
support lasts 3.4 more years, and 2017's "extended" support also lasts
1.4 more years, which didn't stop commit 8fd9bb1d from chopping it to
gain some C11 support.  When could we chop 2019 too, to gain more C11
support?

What motivation do people have to use old compilers for new software?
If my google-search-fu is serving me, upgrades are either free
(community edition for individuals, also for organisations working on
open source) or included in various paid subscriptions.  Is there a
technical reason to be more conservative, for example, in terms of
library versions on the target system, something to do with UCRT or
_WIN32_WINNT versions that the EDB installer needs to target before
you can use this stuff?  I can't find anything saying so.  Perhaps
it'd be better to wait until /experimental:c11atomics isn't needed
though.  My impression so far is that that's about conformance with
details we don't care about, not the maturity of the codegen which is
used far and wide in C++, it's just that C conformance is a distant
second priority (1½ decades later), but...  (Not that this project is
finished anyway, more study and validation required.)

[1] https://learn.microsoft.com/en-us/lifecycle/products/visual-studio-2019





^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-10 13:57 ` Re: Trying out <stdatomic.h> Heikki Linnakangas <[email protected]>
  2025-11-13 11:35   ` Re: Trying out <stdatomic.h> Thomas Munro <[email protected]>
@ 2025-11-19 14:03     ` Aleksander Alekseev <[email protected]>
  2025-11-20 07:16       ` Re: Trying out <stdatomic.h> Thomas Munro <[email protected]>
  1 sibling, 1 reply; 19+ messages in thread

From: Aleksander Alekseev @ 2025-11-19 14:03 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; +Cc: Heikki Linnakangas <[email protected]>; PostgreSQL Hackers <[email protected]>

Hi Thomas,

> It passes with VS 2022 on CI.  I had to skip some assertions about
> macros promising lock-free implementation, that it doesn't define in C
> mode yet.  They are definitely lock-free though[1], and the macros are
> defined for C++, and the same under the covers...  Perhaps
> feature/conformance macros won't be defined until a few remaining
> pieces (things we don't care about) are accessible from C?  (I see
> that Visual Studio 2026 has also just shipped a couple of days ago,
> not investigated.)

Thanks for working on this. I checked v2 on Linux x64 with and without
Valgrind and it passed all the tests. I haven't looked at the code
closely yet.


--
Best regards,
Aleksander Alekseev





^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-10 13:57 ` Re: Trying out <stdatomic.h> Heikki Linnakangas <[email protected]>
  2025-11-13 11:35   ` Re: Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-19 14:03     ` Re: Trying out <stdatomic.h> Aleksander Alekseev <[email protected]>
@ 2025-11-20 07:16       ` Thomas Munro <[email protected]>
  0 siblings, 0 replies; 19+ messages in thread

From: Thomas Munro @ 2025-11-20 07:16 UTC (permalink / raw)
  To: Aleksander Alekseev <[email protected]>; +Cc: Heikki Linnakangas <[email protected]>; PostgreSQL Hackers <[email protected]>

On Thu, Nov 20, 2025 at 3:03 AM Aleksander Alekseev
<[email protected]> wrote:
> Thanks for working on this. I checked v2 on Linux x64 with and without
> Valgrind and it passed all the tests. I haven't looked at the code
> closely yet.

Thanks for testing!

The next thing on my TODO list for this is some kind of codegen diff
on a full matrix of targets.





^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
@ 2025-11-23 15:22 ` Greg Burd <[email protected]>
  2025-11-23 21:08   ` Re: Trying out <stdatomic.h> Thomas Munro <[email protected]>
  1 sibling, 1 reply; 19+ messages in thread

From: Greg Burd @ 2025-11-23 15:22 UTC (permalink / raw)
  To: PostgreSQL Hackers <[email protected]>


On Mon, Nov 10, 2025, at 8:17 AM, Thomas Munro wrote:
> Hi,
>
> Here is an experimental patch to try out standard C (and C++) atomics
> to implement port/atomics.h, and also add more types and operations.
> It's mostly just redirecting our names to the standard ones, except
> for our barriers and slightly extended pg_atomic_flag, so there isn't
> much left of the code.
>
> Here also is a semi-independent patch to implement storage/spin.h with
> pg_atomic_flag.  It keeps a small amount of the architecture-specific
> magic, but moves it out to src/port/spin_delay.h.
>
> I'm not saying they're correct, performant or portable yet, that'll
> require studying codegen and performance on a bunch of weird and
> wonderful systems, but they at least passes basic testing on the usual
> suspects and CI systems, except for Windows which needs a newer
> toolchain so I haven't tried yet.  It should hopefully just work™ on
> VS 2022 (same version that provides <threads.h>, about which more
> soon).
>
> All that being the case, it's not far enough along to be a serious
> proposal, but I imagine others will be looking into things like this
> since we pulled the trigger on C11 and I figured I might as well share
> a basic working patch set to avoid duplicated effort...   Hopefully it
> works well enough to kick the tyres and try to find the difficult
> problems, test it out on weird systems, etc etc.
>
> Attachments:
> * v1-0001-Add-some-missing-include-limits.h.patch
> * v1-0002-Redefine-port-atomics.h-on-top-of-stdatomic.h.patch
> * v1-0003-Use-atomics-API-to-implement-spinlocks.patch
> * v1-0004-Remove-configure-meson-checks-for-atomics.patch

Hello Thomas,

First off, thanks for working on this set of changes.  I like your changes in general, except for removing Solaris/Illumos (but I get it).  ;-P

As mentioned on a separate thread about fixing ARM64 support when building with MSVC on Win11 [1] I tried out this patch.  The reply on that thread had an issue with _mm_pause() in spin_delay(), it turns out we need to use __yield() [2].  I went ahead and fixed that, so ignore that patch on the other thread [1].  The new patch attached that layers on top of your work and supports that platform, there was one minor change that was required:


#ifdef _MSC_VER

	/*
	 * If using Visual C++ on Win64, inline assembly is unavailable.  Use a
	 * _mm_pause intrinsic instead of rep nop. For ARM64, use the __yield()
	 * intrinsic which emits the YIELD instruction as a hint to the processor.
	 */
#if defined(_M_ARM64)
	__yield();
#elif defined(_WIN64)
	_mm_pause();
#else
	/* See comment for gcc code. Same code, MASM syntax */
	__asm		rep nop;
#endif
#endif							/* _MSC_VER */


Visual Studio 2026 (Community)
cl (msvc 19.50.35718 "Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35718 for ARM64")
link 14.50.35718.0


tests are passing, best.

-greg

[1] https://www.postgresql.org/message-id/3c576ad7-d2da-4137-b791-5821da7cc370%40app.fastmail.com
[2] https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics?view=msvc-180

Attachments:

  [application/octet-stream] v20251123-0001-WIP-ARM64-MSVC-stdatomic.patch (4.4K, 2-v20251123-0001-WIP-ARM64-MSVC-stdatomic.patch)
  download | inline diff:
From 295161e09c41658841a902c57f99da54395b20dd Mon Sep 17 00:00:00 2001
From: Greg Burd <[email protected]>
Date: Sun, 23 Nov 2025 07:58:47 -0500
Subject: [PATCH v20251123] WIP ARM64/MSVC stdatomic

---
 doc/src/sgml/installation.sgml |  2 +-
 meson.build                    | 15 ++++++++++++++-
 src/include/port/spin_delay.h  |  7 +++++--
 src/port/pg_crc32c_armv8.c     |  2 ++
 src/tools/msvc_gendef.pl       |  8 ++++----
 5 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index fe8d73e1f8c..3f8d512a906 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -3967,7 +3967,7 @@ configure ... LDFLAGS="-R /usr/sfw/lib:/opt/sfw/lib:/usr/local/lib"
    <sect3 id="install-windows-full-64-bit">
     <title>Special Considerations for 64-Bit Windows</title>
     <para>
-     PostgreSQL will only build for the x64 architecture on 64-bit Windows.
+     PostgreSQL will only build for the x64 and ARM64 architectures on 64-bit Windows.
     </para>
     <para>
      Mixing 32- and 64-bit versions in the same build tree is not supported.
diff --git a/meson.build b/meson.build
index 1a2005e75c4..18637180ab1 100644
--- a/meson.build
+++ b/meson.build
@@ -2158,6 +2158,11 @@ endforeach
 
 
 if cc.get_id() == 'msvc'
+  # Add ARM64 architecture flag for Windows 11 ARM64 for correct intrensics
+  if host_machine.system() == 'windows' and host_machine.cpu_family() == 'aarch64'
+    add_project_arguments('/arch:armv9.4', language: ['c', 'cpp'])
+  endif
+
   cflags_warn += [
     # Warnings to disable:
     # from /W1:
@@ -2367,6 +2372,11 @@ if host_cpu == 'x86' or host_cpu == 'x86_64'
   else
 
     prog = '''
+#ifdef _MSC_VER
+#include <intrin.h>
+#else
+#include <arm_acle.h>
+#endif
 #include <nmmintrin.h>
 unsigned int crc;
 
@@ -2450,7 +2460,10 @@ int main(void)
 }
 '''
 
-  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
+  if cc.get_id() == 'msvc'
+    cdata.set('USE_ARMV8_CRC32C', 1)
+    have_optimized_crc = true
+  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
       args: test_c_args)
     # Use ARM CRC Extension unconditionally
     cdata.set('USE_ARMV8_CRC32C', 1)
diff --git a/src/include/port/spin_delay.h b/src/include/port/spin_delay.h
index c583698af8e..f944c8362da 100644
--- a/src/include/port/spin_delay.h
+++ b/src/include/port/spin_delay.h
@@ -69,9 +69,12 @@ pg_spin_delay(void)
 
 	/*
 	 * If using Visual C++ on Win64, inline assembly is unavailable.  Use a
-	 * _mm_pause intrinsic instead of rep nop.
+	 * _mm_pause intrinsic instead of rep nop. For ARM64, use the __yield()
+	 * intrinsic which emits the YIELD instruction as a hint to the processor.
 	 */
-#if defined(_WIN64)
+#if defined(_M_ARM64)
+	__yield();
+#elif defined(_WIN64)
 	_mm_pause();
 #else
 	/* See comment for gcc code. Same code, MASM syntax */
diff --git a/src/port/pg_crc32c_armv8.c b/src/port/pg_crc32c_armv8.c
index 5ba070bb99d..6a155ddde1e 100644
--- a/src/port/pg_crc32c_armv8.c
+++ b/src/port/pg_crc32c_armv8.c
@@ -14,7 +14,9 @@
  */
 #include "c.h"
 
+#ifndef _MSC_VER
 #include <arm_acle.h>
+#endif
 
 #include "port/pg_crc32c.h"
 
diff --git a/src/tools/msvc_gendef.pl b/src/tools/msvc_gendef.pl
index 868aad51b09..c92c94c4775 100644
--- a/src/tools/msvc_gendef.pl
+++ b/src/tools/msvc_gendef.pl
@@ -118,9 +118,9 @@ sub writedef
 	{
 		my $isdata = $def->{$f} eq 'data';
 
-		# Strip the leading underscore for win32, but not x64
+		# Strip the leading underscore for win32, but not x64 and aarch64
 		$f =~ s/^_//
-		  unless ($arch eq "x86_64");
+		  unless ($arch eq "x86_64" || $arch eq "aarch64");
 
 		# Emit just the name if it's a function symbol, or emit the name
 		# decorated with the DATA option for variables.
@@ -141,7 +141,7 @@ sub writedef
 sub usage
 {
 	die("Usage: msvc_gendef.pl --arch <arch> --deffile <deffile> --tempdir <tempdir> files-or-directories\n"
-		  . "    arch: x86 | x86_64\n"
+		  . "    arch: x86 | x86_64 | aarch64\n"
 		  . "    deffile: path of the generated file\n"
 		  . "    tempdir: directory for temporary files\n"
 		  . "    files or directories: object files or directory containing object files\n"
@@ -158,7 +158,7 @@ GetOptions(
 	'tempdir:s' => \$tempdir,) or usage();
 
 usage("arch: $arch")
-  unless ($arch eq 'x86' || $arch eq 'x86_64');
+  unless ($arch eq 'x86' || $arch eq 'x86_64' || $arch eq 'aarch64');
 
 my @files;
 
-- 
2.52.0.windows.1



^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-23 15:22 ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
@ 2025-11-23 21:08   ` Thomas Munro <[email protected]>
  2025-11-23 21:17     ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
  0 siblings, 1 reply; 19+ messages in thread

From: Thomas Munro @ 2025-11-23 21:08 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>

On Mon, Nov 24, 2025 at 4:23 AM Greg Burd <[email protected]> wrote:
> As mentioned on a separate thread about fixing ARM64 support when building with MSVC on Win11 [1] I tried out this patch.  The reply on that thread had an issue with _mm_pause() in spin_delay(), it turns out we need to use __yield() [2].  I went ahead and fixed that, so ignore that patch on the other thread [1].  The new patch attached that layers on top of your work and supports that platform, there was one minor change that was required:
>
>
> #ifdef _MSC_VER
>
>         /*
>          * If using Visual C++ on Win64, inline assembly is unavailable.  Use a
>          * _mm_pause intrinsic instead of rep nop. For ARM64, use the __yield()
>          * intrinsic which emits the YIELD instruction as a hint to the processor.
>          */
> #if defined(_M_ARM64)
>         __yield();
> #elif defined(_WIN64)
>         _mm_pause();
> #else
>         /* See comment for gcc code. Same code, MASM syntax */
>         __asm           rep nop;
> #endif
> #endif                                                  /* _MSC_VER */

That makes more intuitive sense... but I didn't know that people *do*
sometimes prefer instruction synchronisation barriers for spinlock
delays:

https://stackoverflow.com/questions/70810121/why-does-hintspin-loop-use-isb-on-aarch64

When reading your patch I was pretty confused by that, because it said
it was fixing a barrier problem and apparently doing so in an
unprincipled place.  I guess we really need to research the best delay
mechanism for our needs on this architecture, independently of the
compiler being used, and then write matching GCC and Visual Studio
versions of that?  I think there were some threads about spinlock
performance on Linux + Graviton with graphs and theories...

> tests are passing, best.

Great news!  Thanks.  It sounds like if I could supply the missing
credible evidence of codegen quality on... all the computers, then I
think we'd be down to just: when can we pull the trigger and require
Visual Studio 2022 and do we trust /experimental:c11atomics?

FTR I had earlier shared some version of this patch with Dave when he
was trying to get his Windows/ARM system going, but I think my earlier
version was probably too broken.  Sorry Dave.  At that stage I was
also trying to do it as an option but keeping the existing stuff
around.  Since then we adopted C11, so this is the all-in version.  I
also hadn't understood a key part of the C11 memory model that your
RISC-V animal taught me and that c5d34f4a fixed, and you can see in
this patch set too, and I'm not sure if Visual Studio is like GCC or
Clang in that respect.  It crossed my mind that this might even be
related to the problem you've noticed with barriers being missing, but
I haven't looked into that.  BTW I believe we could actually change
our code NOT to rely on that, ie to follow the C11 memory model better
and declare eg PgAioHandle::status as atomic_uint8 or whatever (other
non-atomic access would be considered dependent and do the right thing
IIUC), but I'm not sure if it's necessary and that research project
can wait.





^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-23 15:22 ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
  2025-11-23 21:08   ` Re: Trying out <stdatomic.h> Thomas Munro <[email protected]>
@ 2025-11-23 21:17     ` Greg Burd <[email protected]>
  2026-03-23 11:57       ` Re: Trying out <stdatomic.h> Peter Eisentraut <[email protected]>
  0 siblings, 1 reply; 19+ messages in thread

From: Greg Burd @ 2025-11-23 21:17 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>


On Nov 23 2025, at 4:08 pm, Thomas Munro <[email protected]> wrote:

> On Mon, Nov 24, 2025 at 4:23 AM Greg Burd <[email protected]> wrote:
>> As mentioned on a separate thread about fixing ARM64 support when
>> building with MSVC on Win11 [1] I tried out this patch.  The reply on
>> that thread had an issue with _mm_pause() in spin_delay(), it turns
>> out we need to use __yield() [2].  I went ahead and fixed that, so
>> ignore that patch on the other thread [1].  The new patch attached
>> that layers on top of your work and supports that platform, there was
>> one minor change that was required:
>>  
>>  
>> #ifdef _MSC_VER
>>  
>>         /*
>>          * If using Visual C++ on Win64, inline assembly is
>> unavailable.  Use a
>>          * _mm_pause intrinsic instead of rep nop. For ARM64, use the __yield()
>>          * intrinsic which emits the YIELD instruction as a hint to
>> the processor.
>>          */
>> #if defined(_M_ARM64)
>>         __yield();
>> #elif defined(_WIN64)
>>         _mm_pause();
>> #else
>>         /* See comment for gcc code. Same code, MASM syntax */
>>         __asm           rep nop;
>> #endif
>> #endif                                                  /* _MSC_VER */
>  
> That makes more intuitive sense... but I didn't know that people *do*
> sometimes prefer instruction synchronisation barriers for spinlock
> delays:
>  
> https://stackoverflow.com/questions/70810121/why-does-hintspin-loop-use-isb-on-aarch64
>  
> When reading your patch I was pretty confused by that, because it said
> it was fixing a barrier problem and apparently doing so in an
> unprincipled place.  I guess we really need to research the best delay
> mechanism for our needs on this architecture, independently of the
> compiler being used, and then write matching GCC and Visual Studio
> versions of that?  I think there were some threads about spinlock
> performance on Linux + Graviton with graphs and theories...

Interesting, I think I was rushing to get past that compile issue rather
than optimizing.  This sounds like yet another place where we should
choose based on arch and it seems hint::spin_loop() does.

>> tests are passing, best.
>  
> Great news!  Thanks.  It sounds like if I could supply the missing
> credible evidence of codegen quality on... all the computers, then I
> think we'd be down to just: when can we pull the trigger and require
> Visual Studio 2022 and do we trust /experimental:c11atomics?

I'm in favor of the stdatomic approach.  I can't speak to codegen
quality on *all the platforms* or how *experimental* c11 atomics are
when using MSVC.

> FTR I had earlier shared some version of this patch with Dave when he
> was trying to get his Windows/ARM system going, but I think my earlier
> version was probably too broken.  Sorry Dave.  At that stage I was
> also trying to do it as an option but keeping the existing stuff
> around.  Since then we adopted C11, so this is the all-in version.  I
> also hadn't understood a key part of the C11 memory model that your
> RISC-V animal taught me and that c5d34f4a fixed, and you can see in
> this patch set too, and I'm not sure if Visual Studio is like GCC or
> Clang in that respect.

Thanks for that work on RISC-V, I appreciate that!  Much more digging to
be done to answer those questions for sure.

> It crossed my mind that this might even be
> related to the problem you've noticed with barriers being missing, but
> I haven't looked into that.  BTW I believe we could actually change
> our code NOT to rely on that, ie to follow the C11 memory model better
> and declare eg PgAioHandle::status as atomic_uint8 or whatever (other
> non-atomic access would be considered dependent and do the right thing
> IIUC), but I'm not sure if it's necessary and that research project
> can wait.

Interesting.  Yeah, let's do one thing and then move to the next, but I
do like the idea.

best.

-greg





^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-23 15:22 ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
  2025-11-23 21:08   ` Re: Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-23 21:17     ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
@ 2026-03-23 11:57       ` Peter Eisentraut <[email protected]>
  2026-03-23 12:50         ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
  0 siblings, 1 reply; 19+ messages in thread

From: Peter Eisentraut @ 2026-03-23 11:57 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>

On 21.03.26 19:39, Greg Burd wrote:
> I think that $subject is interesting because it presents an opportunity to reduce the code we maintain and potentially improve performance.  This thread has languished a bit on the list, so I picked it up.  I've tried it out on my local systems (greenfly, unicorn, icarus, macOS, and a Fedora x86_64 laptop I use as my daily driver) using clang, gcc, and MSVC.  It seems to work, I still need to measure performance.
> 
> tested:
>    - Linux x86_64 (GCC 14.3.0)
>    - Linux RISC-V (GCC 13.3.0, Clang 20.1.2)
>    - FreeBSD x86_64 (Clang 19.1.7)
>    - Windows ARM64 (MSVC 2022)
> 
> I realize we're close to the end of the v19 cycle, but one last look couldn't hurt could it?  Attached is "v3" of his patch set.  Is anyone else interested in this? :)

We currently require MSVC 2019, so before this could be accepted, this 
requirement would need to be adjusted (including documentation, 
buildfarm updates, etc.).  Maybe a bit late for that.





^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-23 15:22 ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
  2025-11-23 21:08   ` Re: Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-23 21:17     ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
  2026-03-23 11:57       ` Re: Trying out <stdatomic.h> Peter Eisentraut <[email protected]>
@ 2026-03-23 12:50         ` Greg Burd <[email protected]>
  2026-03-23 14:24           ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
  0 siblings, 1 reply; 19+ messages in thread

From: Greg Burd @ 2026-03-23 12:50 UTC (permalink / raw)
  To: Peter Eisentraut <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>


On Mon, Mar 23, 2026, at 7:57 AM, Peter Eisentraut wrote:
> On 21.03.26 19:39, Greg Burd wrote:
>> I think that $subject is interesting because it presents an opportunity to reduce the code we maintain and potentially improve performance.  This thread has languished a bit on the list, so I picked it up.  I've tried it out on my local systems (greenfly, unicorn, icarus, macOS, and a Fedora x86_64 laptop I use as my daily driver) using clang, gcc, and MSVC.  It seems to work, I still need to measure performance.
>> 
>> tested:
>>    - Linux x86_64 (GCC 14.3.0)
>>    - Linux RISC-V (GCC 13.3.0, Clang 20.1.2)
>>    - FreeBSD x86_64 (Clang 19.1.7)
>>    - Windows ARM64 (MSVC 2022)
>> 
>> I realize we're close to the end of the v19 cycle, but one last look couldn't hurt could it?  Attached is "v3" of his patch set.  Is anyone else interested in this? :)
>
> We currently require MSVC 2019, so before this could be accepted, this 
> requirement would need to be adjusted (including documentation, 
> buildfarm updates, etc.).

Fair point, it does seem that's the minimum supported version (2022).

I'm not a Microsoft marketplace or tools expert, so I can't gauge how hard it is to require 2022 or if that'd impact too many users of PG today on that platform who choose to use MSVC over gcc or clang.

I have even less insight into what Azure uses for the host OS (Linux, FreeBSD or Windows) running Postgres for their services, but lets say it's Windows and they have a requirement for MSVC when compiling.  I'd bet they could switch to 2022 without too much trouble.  Are there others out there that deploy/depend/use PG on Windows and have a strong bias for MSVC (vs clang or gcc)?  I have no idea.

> Maybe a bit late for that.

It is late, and this isn't a small set of changes.  I'd be curious to know if, other than the buildfarm animals that are Wnidows with MSVC < 2022, the rest would work with this change or not.  I'd also like to get some objective data on performance.

Would it be wasted effort for me to get this patch into a form that could be committed, tested on the farm, then rolled back if needed (a single patch)?  Is that even a thing we'd consider trying out?

Maybe the effort is worth it and we consider this again at the start of v20 development?

best.

-greg





^ permalink  raw  reply  [nested|flat] 19+ messages in thread

* Re: Trying out <stdatomic.h>
  2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-23 15:22 ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
  2025-11-23 21:08   ` Re: Trying out <stdatomic.h> Thomas Munro <[email protected]>
  2025-11-23 21:17     ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
  2026-03-23 11:57       ` Re: Trying out <stdatomic.h> Peter Eisentraut <[email protected]>
  2026-03-23 12:50         ` Re: Trying out <stdatomic.h> Greg Burd <[email protected]>
@ 2026-03-23 14:24           ` Greg Burd <[email protected]>
  0 siblings, 0 replies; 19+ messages in thread

From: Greg Burd @ 2026-03-23 14:24 UTC (permalink / raw)
  To: Tom Lane <[email protected]>; +Cc: Peter Eisentraut <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>


On Mon, Mar 23, 2026, at 10:13 AM, Tom Lane wrote:
> "Greg Burd" <[email protected]> writes:
>> On Mon, Mar 23, 2026, at 7:57 AM, Peter Eisentraut wrote:
>>> We currently require MSVC 2019, so before this could be accepted, this 
>>> requirement would need to be adjusted (including documentation, 
>>> buildfarm updates, etc.).
>

Hi Tom, thanks for chiming in. :)

>> Fair point, it does seem that's the minimum supported version (2022).
>
> I don't really see why we'd need to do that?  I would expect any such
> patch to cope gracefully with the lack of <stdatomic.h>, so it could
> continue to support older MSVC by falling back to the older code
> paths.  For MSVC in particular, we'd not even need to maintain the
> older code paths for arches other than x86 and ARM.

Fair, and I agree.

> But even disregarding Windows, I'd look with great suspicion on a
> patch that proposes to rip out all that handwritten code in favor of
> requiring <stdatomic.h>.  That'd be putting a great deal of trust in
> code that's not under our control and frankly we have no reason to
> trust yet, especially not from the standpoint of performance rather
> than just minimum functionality.

Yes, I 100% agree.  That is a valid concern.

> Note that the thread title is
> "Trying out <stdatomic.h>", not "We're marrying <stdatomic.h>
> sight-unseen, and there will be no divorce".

This made me laugh, thank you. :)

> So I want to see a
> patch that treats <stdatomic.h> as an alternative implementation,
> not The Only Way.

Got it.

> As for timing, this is the sort of patch that we usually feel should
> go in near the start of a dev cycle, not near the end.  So I counsel
> making sure that it's in shape for commit early in v20, but not
> expecting that it will get in now, even temporarily.  There are too
> many irons in the fire at this phase of the cycle, and too little
> room to disambiguate "Greg broke it" from "somebody else broke it".

Yep, that's prudent and you're right to point out that the breaking the farm isn't really a good way to test at this stage.

> 			regards, tom lane

best.

-greg





^ permalink  raw  reply  [nested|flat] 19+ messages in thread


end of thread, other threads:[~2026-03-23 14:24 UTC | newest]

Thread overview: 19+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2025-11-10 13:17 Trying out <stdatomic.h> Thomas Munro <[email protected]>
2025-11-10 13:57 ` Heikki Linnakangas <[email protected]>
2025-11-10 15:19   ` Tom Lane <[email protected]>
2025-11-10 20:25     ` Thomas Munro <[email protected]>
2025-11-23 15:02     ` Greg Burd <[email protected]>
2025-11-23 17:02       ` Tom Lane <[email protected]>
2025-11-23 18:17         ` Álvaro Herrera <[email protected]>
2025-11-23 20:16         ` Thomas Munro <[email protected]>
2025-11-13 11:35   ` Thomas Munro <[email protected]>
2025-11-19 11:23     ` Peter Eisentraut <[email protected]>
2025-11-20 07:12       ` Thomas Munro <[email protected]>
2025-11-19 14:03     ` Aleksander Alekseev <[email protected]>
2025-11-20 07:16       ` Thomas Munro <[email protected]>
2025-11-23 15:22 ` Greg Burd <[email protected]>
2025-11-23 21:08   ` Thomas Munro <[email protected]>
2025-11-23 21:17     ` Greg Burd <[email protected]>
2026-03-23 11:57       ` Peter Eisentraut <[email protected]>
2026-03-23 12:50         ` Greg Burd <[email protected]>
2026-03-23 14:24           ` Greg Burd <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox