public inbox for [email protected]  
help / color / mirror / Atom feed
From: Thomas Munro <[email protected]>
To: Heikki Linnakangas <[email protected]>
Cc: PostgreSQL Hackers <[email protected]>
Subject: Re: Trying out <stdatomic.h>
Date: Fri, 14 Nov 2025 00:35:48 +1300
Message-ID: <CA+hUKG+bub1T9TFLUAJHr+Z519VRgJS5tb10xBxEtJZRH8GXiA@mail.gmail.com> (raw)
In-Reply-To: <[email protected]>
References: <CA+hUKGKFvu3zyvv3aaj5hHs9VtWcjFAmisOwOc7aOZNc5AF3NA@mail.gmail.com>
	<[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)



view thread (19+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected]
  Subject: Re: Trying out <stdatomic.h>
  In-Reply-To: <CA+hUKG+bub1T9TFLUAJHr+Z519VRgJS5tb10xBxEtJZRH8GXiA@mail.gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

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