Skip to content

Commit d8a5164

Browse files
gburdmacdice
andcommitted
[NOT FOR MERGE... yet.] Remove traditional atomics; use C11 stdatomic.h exclusively
*** NOT FOR MERGE in this cycle. *** This commit is included to show the intended long-term destination of the series, and to let reviewers and the buildfarm exercise the stdatomic-only end state -- but it is deliberately NOT proposed for commit yet. The plan is to ship the earlier patches (which add C11 <stdatomic.h> as a *selectable* implementation alongside the traditional platform-specific code), let the stdatomic path prove itself in the field across the buildfarm and at least one release, and only THEN remove the traditional implementation via a commit like this one. Removing the battle-tested arch-*/generic-* code on day one is not being asked for here; keeping both paths until stdatomic has earned trust is. Everything below describes what this (eventual) removal commit does. This collapses the dual-path atomics into a single stdatomic-only implementation, mirroring the destination state of the series. Rather than selecting between C11 <stdatomic.h> and the platform-specific implementations at build time, stdatomic.h is now the sole backend for PostgreSQL's atomic operations and USE_STDATOMIC_H is effectively always-on. The platform-specific implementation files are deleted outright: - src/include/port/atomics/arch-arm.h - src/include/port/atomics/arch-ppc.h - src/include/port/atomics/arch-x86.h - src/include/port/atomics/generic.h - src/include/port/atomics/generic-gcc.h - src/include/port/atomics/generic-msvc.h - src/include/port/atomics/fallback.h atomics.h drops its #ifdef USE_STDATOMIC_H / #else conditional and the now-dead includes of the arch-*/generic-*/fallback headers, keeping only the stdatomic_impl.h include and the common public-API layer of static inline pg_atomic_* wrappers. storage/spin.h and s_lock.c lose their traditional-spinlock (#else) branches, so only the pg_atomic_flag-based spinlock path remains; the s_lock.h includes that served only that path are removed. Detection is retained but now hard-errors when a working C11 stdatomic.h is unavailable, in both meson.build and configure.ac, instead of silently falling back. The only remaining hand-written platform hint is the CPU spin-delay instruction in src/include/port/spin_delay.h, which stdatomic.h does not cover; it is intentionally left in place along with spin_delay_status.h and stdatomic_impl.h. This depends on the prior commits in the series (build-time detection, stdatomic_impl.h, conditional wire-up, documentation, and the test_atomics module). Co-authored-by: Thomas Munro <tmunro@postgresql.org>
1 parent 04bc909 commit d8a5164

21 files changed

Lines changed: 97 additions & 2671 deletions

File tree

‎configure‎

Lines changed: 15 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,6 @@ LLVM_LIBS
759759
CLANG
760760
LLVM_CONFIG
761761
AWK
762-
with_stdatomic
763762
with_llvm
764763
have_cxx
765764
ac_ct_CXX
@@ -858,7 +857,6 @@ with_segsize
858857
with_segsize_blocks
859858
with_wal_blocksize
860859
with_llvm
861-
with_stdatomic
862860
enable_depend
863861
enable_cassert
864862
with_icu
@@ -1578,8 +1576,6 @@ Optional Packages:
15781576
--with-wal-blocksize=BLOCKSIZE
15791577
set WAL block size in kB [8]
15801578
--with-llvm build with LLVM based JIT support
1581-
--with-stdatomic[=yes/no/auto]
1582-
use C11 stdatomic.h for atomic operations [auto]
15831579
--without-icu build without ICU support
15841580
--with-tcl build Tcl modules (PL/Tcl)
15851581
--with-tclconfig=DIR tclConfig.sh is in DIR
@@ -4925,22 +4921,9 @@ fi
49254921
#
49264922
# C11 stdatomic.h
49274923
#
4928-
# Accepts --with-stdatomic={yes,no,auto}. "auto" (the default) uses
4929-
# stdatomic.h if a compile test succeeds; "yes" requires it; "no" forces the
4930-
# traditional platform-specific atomics. The actual detection runs later,
4931-
# after the compiler and 64-bit integer handling have been configured.
4932-
4933-
# Check whether --with-stdatomic was given.
4934-
if test "${with_stdatomic+set}" = set; then :
4935-
withval=$with_stdatomic; case $withval in
4936-
yes | no | auto) ;;
4937-
*) as_fn_error $? "invalid argument to --with-stdatomic; use yes, no, or auto" "$LINENO" 5 ;;
4938-
esac
4939-
else
4940-
with_stdatomic=no
4941-
fi
4942-
4943-
4924+
# stdatomic.h is the sole atomics implementation. The actual detection runs
4925+
# later, after the compiler and 64-bit integer handling have been configured;
4926+
# a missing or broken header is a hard error there.
49444927
for ac_prog in gawk mawk nawk awk
49454928
do
49464929
# Extract the first word of "$ac_prog", so it can be a program name with args.
@@ -17742,11 +17725,11 @@ $as_echo "#define HAVE_GCC__ATOMIC_INT64_CAS 1" >>confdefs.h
1774217725
fi
1774317726

1774417727

17745-
# Decide whether to use C11 stdatomic.h (see --with-stdatomic above). The
17746-
# probe mirrors the one used by the meson build: it must compile 32-bit
17747-
# fetch_add, a seq_cst thread fence, and a 64-bit compare-exchange.
17748-
if test "$with_stdatomic" != no; then
17749-
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working C11 stdatomic.h" >&5
17728+
# Require a working C11 stdatomic.h: it is the sole atomics implementation,
17729+
# so a missing or broken header is a hard error. The probe mirrors the one
17730+
# used by the meson build: it must compile 32-bit fetch_add, a seq_cst thread
17731+
# fence, and a 64-bit compare-exchange.
17732+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working C11 stdatomic.h" >&5
1775017733
$as_echo_n "checking for working C11 stdatomic.h... " >&6; }
1775117734
if ${pgac_cv_stdatomic+:} false; then :
1775217735
$as_echo_n "(cached) " >&6
@@ -17758,11 +17741,11 @@ int
1775817741
main ()
1775917742
{
1776017743
_Atomic int x = 0;
17761-
atomic_fetch_add(&x, 1);
17762-
atomic_thread_fence(memory_order_seq_cst);
17763-
_Atomic(unsigned long long) y = 0;
17764-
unsigned long long expected = 0;
17765-
atomic_compare_exchange_strong(&y, &expected, 42);
17744+
atomic_fetch_add(&x, 1);
17745+
atomic_thread_fence(memory_order_seq_cst);
17746+
_Atomic(unsigned long long) y = 0;
17747+
unsigned long long expected = 0;
17748+
atomic_compare_exchange_strong(&y, &expected, 42);
1776617749

1776717750
;
1776817751
return 0;
@@ -17777,19 +17760,14 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
1777717760
fi
1777817761
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_stdatomic" >&5
1777917762
$as_echo "$pgac_cv_stdatomic" >&6; }
17780-
else
17781-
pgac_cv_stdatomic=no
17782-
fi
1778317763

17784-
if test "$with_stdatomic" = yes && test "$pgac_cv_stdatomic" != yes; then
17785-
as_fn_error $? "--with-stdatomic=yes was given, but a working C11 stdatomic.h could not be found" "$LINENO" 5
17764+
if test "$pgac_cv_stdatomic" != yes; then
17765+
as_fn_error $? "a working C11 stdatomic.h is required (it is the only atomics implementation)" "$LINENO" 5
1778617766
fi
1778717767

17788-
if test "$pgac_cv_stdatomic" = yes; then
1778917768

1779017769
$as_echo "#define USE_STDATOMIC_H 1" >>confdefs.h
1779117770

17792-
fi
1779317771

1779417772

1779517773
# Check for __get_cpuid() and __cpuid()

‎configure.ac‎

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -447,19 +447,9 @@ AC_SUBST(with_llvm)
447447
#
448448
# C11 stdatomic.h
449449
#
450-
# Accepts --with-stdatomic={yes,no,auto}. "auto" (the default) uses
451-
# stdatomic.h if a compile test succeeds; "yes" requires it; "no" forces the
452-
# traditional platform-specific atomics. The actual detection runs later,
453-
# after the compiler and 64-bit integer handling have been configured.
454-
AC_ARG_WITH(stdatomic,
455-
[AS_HELP_STRING([--with-stdatomic@<:@=yes/no/auto@:>@],
456-
[use C11 stdatomic.h for atomic operations @<:@auto@:>@])],
457-
[case $withval in
458-
yes | no | auto) ;;
459-
*) AC_MSG_ERROR([invalid argument to --with-stdatomic; use yes, no, or auto]) ;;
460-
esac],
461-
[with_stdatomic=no])
462-
AC_SUBST(with_stdatomic)
450+
# stdatomic.h is the sole atomics implementation. The actual detection runs
451+
# later, after the compiler and 64-bit integer handling have been configured;
452+
# a missing or broken header is a hard error there.
463453
dnl must use AS_IF here, else AC_REQUIRES inside PGAC_LLVM_SUPPORT malfunctions
464454
AS_IF([test "$with_llvm" = yes], [
465455
PGAC_LLVM_SUPPORT()
@@ -2118,33 +2108,28 @@ PGAC_HAVE_GCC__ATOMIC_INT32_CAS
21182108
PGAC_HAVE_GCC__ATOMIC_INT64_CAS
21192109

21202110

2121-
# Decide whether to use C11 stdatomic.h (see --with-stdatomic above). The
2122-
# probe mirrors the one used by the meson build: it must compile 32-bit
2123-
# fetch_add, a seq_cst thread fence, and a 64-bit compare-exchange.
2124-
if test "$with_stdatomic" != no; then
2125-
AC_CACHE_CHECK([for working C11 stdatomic.h], [pgac_cv_stdatomic],
2126-
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <stdatomic.h>],
2127-
[[_Atomic int x = 0;
2128-
atomic_fetch_add(&x, 1);
2129-
atomic_thread_fence(memory_order_seq_cst);
2130-
_Atomic(unsigned long long) y = 0;
2131-
unsigned long long expected = 0;
2132-
atomic_compare_exchange_strong(&y, &expected, 42);
2133-
]])],
2134-
[pgac_cv_stdatomic=yes],
2135-
[pgac_cv_stdatomic=no])])
2136-
else
2137-
pgac_cv_stdatomic=no
2138-
fi
2111+
# Require a working C11 stdatomic.h: it is the sole atomics implementation,
2112+
# so a missing or broken header is a hard error. The probe mirrors the one
2113+
# used by the meson build: it must compile 32-bit fetch_add, a seq_cst thread
2114+
# fence, and a 64-bit compare-exchange.
2115+
AC_CACHE_CHECK([for working C11 stdatomic.h], [pgac_cv_stdatomic],
2116+
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <stdatomic.h>],
2117+
[[_Atomic int x = 0;
2118+
atomic_fetch_add(&x, 1);
2119+
atomic_thread_fence(memory_order_seq_cst);
2120+
_Atomic(unsigned long long) y = 0;
2121+
unsigned long long expected = 0;
2122+
atomic_compare_exchange_strong(&y, &expected, 42);
2123+
]])],
2124+
[pgac_cv_stdatomic=yes],
2125+
[pgac_cv_stdatomic=no])])
21392126

2140-
if test "$with_stdatomic" = yes && test "$pgac_cv_stdatomic" != yes; then
2141-
AC_MSG_ERROR([--with-stdatomic=yes was given, but a working C11 stdatomic.h could not be found])
2127+
if test "$pgac_cv_stdatomic" != yes; then
2128+
AC_MSG_ERROR([a working C11 stdatomic.h is required (it is the only atomics implementation)])
21422129
fi
21432130

2144-
if test "$pgac_cv_stdatomic" = yes; then
2145-
AC_DEFINE([USE_STDATOMIC_H], 1,
2146-
[Define to 1 to use C11 stdatomic.h for atomic operations. (--with-stdatomic)])
2147-
fi
2131+
AC_DEFINE([USE_STDATOMIC_H], 1,
2132+
[Define to 1 to use C11 stdatomic.h for atomic operations. (--with-stdatomic)])
21482133

21492134

21502135
# Check for __get_cpuid() and __cpuid()

‎meson.build‎

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,6 @@ int main(void) {
692692
'''
693693

694694
has_stdatomic = false
695-
use_stdatomic = get_option('use_stdatomic')
696695

697696
if cc.get_id() == 'msvc'
698697
msvc_ver = cc.version()
@@ -730,30 +729,16 @@ else
730729
endif
731730
endif
732731

733-
# Process the use_stdatomic option
734-
if use_stdatomic == 'yes'
735-
if not has_stdatomic
736-
error('stdatomic.h was requested with -Duse_stdatomic=yes but is not available or not working')
737-
endif
738-
cdata.set('USE_STDATOMIC_H', 1)
739-
message('Using C11 stdatomic.h for atomic operations (forced by -Duse_stdatomic=yes)')
740-
if cc.get_id() == 'msvc'
741-
# MSVC needs C11 mode plus the experimental atomics switch for <stdatomic.h>.
742-
cflags += ['/std:c11', '/experimental:c11atomics']
743-
endif
744-
elif use_stdatomic == 'no'
745-
message('Using traditional platform-specific atomics (forced by -Duse_stdatomic=no)')
746-
# Do not set USE_STDATOMIC_H
747-
elif use_stdatomic == 'auto'
748-
if has_stdatomic
749-
cdata.set('USE_STDATOMIC_H', 1)
750-
message('Using C11 stdatomic.h for atomic operations (auto-detected)')
751-
if cc.get_id() == 'msvc'
752-
cflags += ['/std:c11', '/experimental:c11atomics']
753-
endif
754-
else
755-
message('Using traditional platform-specific atomics (stdatomic.h not available)')
756-
endif
732+
# stdatomic.h is the sole atomics implementation, so a missing or broken
733+
# header is a hard error.
734+
if not has_stdatomic
735+
error('a working C11 stdatomic.h is required (it is the only atomics implementation)')
736+
endif
737+
cdata.set('USE_STDATOMIC_H', 1)
738+
message('Using C11 stdatomic.h for atomic operations')
739+
if cc.get_id() == 'msvc'
740+
# MSVC needs C11 mode plus the experimental atomics switch for <stdatomic.h>.
741+
cflags += ['/std:c11', '/experimental:c11atomics']
757742
endif
758743

759744
postgres_inc = [include_directories(postgres_inc_d)]

‎meson_options.txt‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,6 @@ option('PG_TEST_EXTRA', type: 'string', value: '',
5252
option('PG_GIT_REVISION', type: 'string', value: 'HEAD',
5353
description: 'git revision to be packaged by pgdist target')
5454

55-
option('use_stdatomic', type: 'combo',
56-
choices: ['auto', 'yes', 'no'],
57-
value: 'no',
58-
description: 'Use C11 stdatomic.h for atomic operations (auto, yes, no)')
59-
6055

6156
# Compilation options
6257

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
/lwlocknames.h
2-
/s_lock_test

‎src/backend/storage/lmgr/Makefile‎

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,8 @@ OBJS = \
2424

2525
include $(top_srcdir)/src/backend/common.mk
2626

27-
s_lock_test: s_lock.c $(top_builddir)/src/common/libpgcommon.a $(top_builddir)/src/port/libpgport.a
28-
$(CC) $(CPPFLAGS) $(CFLAGS) -DS_LOCK_TEST=1 $(srcdir)/s_lock.c \
29-
-L $(top_builddir)/src/common -lpgcommon \
30-
-L $(top_builddir)/src/port -lpgport -lm -o s_lock_test
31-
3227
lwlocknames.h: ../../../include/storage/lwlocklist.h ../../utils/activity/wait_event_names.txt generate-lwlocknames.pl
3328
$(PERL) $(srcdir)/generate-lwlocknames.pl $^
3429

35-
check: s_lock_test
36-
./s_lock_test
37-
3830
clean:
39-
rm -f s_lock_test
4031
rm -f lwlocknames.h

‎src/backend/storage/lmgr/README‎

Lines changed: 19 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -50,41 +50,28 @@ The rest of this README file discusses the regular lock manager in detail.
5050
Atomic Operations
5151
=================
5252

53-
PostgreSQL's atomic operations (see src/include/port/atomics.h) can be
54-
implemented using either C11 stdatomic.h or traditional platform-specific
55-
code. The implementation is selected at build time via the USE_STDATOMIC_H
56-
preprocessor definition:
57-
58-
* C11 stdatomic.h implementation (USE_STDATOMIC_H defined):
59-
Uses the standard C11 <stdatomic.h> header for all atomic operations.
60-
This provides better portability and potentially better compiler
61-
optimizations. Available on:
53+
PostgreSQL's atomic operations (see src/include/port/atomics.h) are
54+
implemented on top of the standard C11 <stdatomic.h> header, which is the
55+
sole atomics implementation. A working stdatomic.h is required at build
56+
time; the USE_STDATOMIC_H preprocessor symbol is always defined. Available
57+
on:
6258
- MSVC 2022+ (requires /experimental:c11atomics flag)
6359
- GCC 4.9+ and Clang 3.1+ (no special flags needed)
6460

65-
* Traditional implementation (USE_STDATOMIC_H not defined):
66-
Uses platform-specific implementations that have been battle-tested
67-
in PostgreSQL for many years:
68-
- Architecture-specific: arch-x86.h, arch-arm.h, arch-ppc.h
69-
- Compiler intrinsics: generic-gcc.h, generic-msvc.h
70-
- Fallback implementations: generic.h, fallback.h
61+
There is no build option to select the atomics implementation: stdatomic.h
62+
is probed unconditionally and a missing or non-working header is a hard
63+
configure/build error, since there is no other implementation to fall back
64+
to.
7165

72-
Both implementations provide the same public API and observable semantics.
73-
The choice is made at build configuration time:
66+
Several internal properties of the implementation are worth noting; none of
67+
them affect the public API:
7468

75-
meson setup build -Duse_stdatomic=auto # Auto-detect (default)
76-
meson setup build -Duse_stdatomic=yes # Force stdatomic.h
77-
meson setup build -Duse_stdatomic=no # Force traditional
78-
79-
The two implementations differ internally in several ways that do not affect
80-
the public API:
81-
82-
* Memory ordering. pg_atomic_read_u32/u64() use seq_cst ordering under
83-
stdatomic.h; pg_atomic_write_u32/u64() use relaxed. The seq_cst read was
69+
* Memory ordering. pg_atomic_read_u32/u64() use seq_cst ordering;
70+
pg_atomic_write_u32/u64() use relaxed. The seq_cst read is
8471
required for correctness on weak-memory hardware (e.g. RISC-V), where the
8572
weaker relaxed and acquire orderings let a concurrent reader miss a tuple
8673
in a parallel hash join. The write stays relaxed: a plain atomic store
87-
matches the traditional "no barrier" contract for pg_atomic_write and, on
74+
matches the "no barrier" contract for pg_atomic_write and, on
8875
ARM64, avoids the store-release (STLR) serialization that would penalize
8976
contended writes to hot shared state. The pg_atomic_unlocked_write_*
9077
variant also uses relaxed ordering, consistent with its "no guarantees"
@@ -96,23 +83,15 @@ the public API:
9683
the thread fence (atomic_thread_fence), because a bare thread fence orders
9784
only atomic accesses and would let the compiler reorder plain loads/stores
9885
across it, whereas PostgreSQL's barrier contract must order non-atomic
99-
accesses too. This matches the traditional generic-gcc.h barriers.
86+
accesses too.
10087

101-
* Spinlock flag polarity. The stdatomic.h pg_atomic_flag uses 1=unlocked,
102-
0=locked (fetch_and-based test-and-set), the inverse of the traditional
103-
0=unlocked, 1=locked (exchange-based). This is an internal detail with no
88+
* Spinlock flag polarity. The pg_atomic_flag uses 1=unlocked,
89+
0=locked (fetch_and-based test-and-set). This is an internal detail with no
10490
external visibility beyond raw values seen in a debugger.
10591

106-
* Binary compatibility. The atomic types are _Atomic(...) under stdatomic.h
107-
and volatile-struct under the traditional path. The two are not binary
108-
compatible, so objects and shared memory cannot be mixed between builds;
109-
the implementation is fixed at build time, so this is not a concern in
110-
practice.
111-
112-
* Platform reach. Under stdatomic.h, 64-bit atomics are available on 32-bit
92+
* Platform reach. 64-bit atomics are available on 32-bit
11393
ARM (compiler/runtime may emulate them with locks), atomics are usable from
114-
frontend programs, and the headers are C++-compatible. The traditional
115-
path disables 64-bit atomics on ARM32 and is backend-only.
94+
frontend programs, and the headers are C++-compatible.
11695

11796
For more information on memory barriers and atomic operations, see
11897
src/backend/storage/lmgr/README.barrier.

0 commit comments

Comments
 (0)