From ba3395f8a09a3ae3919f3f811296b05b2cddd17c Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Mon, 6 Jul 2026 01:10:45 +0300
Subject: [PATCH 1/1] Replace pg_atomic_flag with pg_atomic_bool

The pg_atomic_flag operations were different from those that we
support with pg_atomic_u32/u64. I've learned the u32/u64 functions by
now, but whenever I deal with pg_atomic_flag, I need to read the docs
to remind myself what the pg_atomic_flag functions do. However, what I
really just want is to have a "bool" with an atomic-exchange
operation. The pg_atomic_flag operations were slightly different and
unintuitive to me at least:

- pg_atomic_unlocked_test_flag() returned false, if the flag was set
  and true if it was not set. That felt backwards if you thought of it
  as just reading the underlying boolean value.

- Similarly, pg_atomic_test_set_flag() returned true if it was not
  previously set, which was different from what pg_atomic_exchange()
  returns. (None of the callers of pg_atomic_test_set_flag() actually
  looked at the return value, however. They all just wanted to set the
  flag, but there was no pg_atomic_set_flag() function!)

- There was no atomic "test and clear" operation

- There were differences in the barrier semantics compared to the
  pg_atomic_u32 variants. We don't expose "acquire" or "release"
  semantics anywhere else (outside arch-specific headers), we use the
  terms "read" and "write" barriers instead, and it wasn't quite clear
  if they're the same thing.

Replace the pg_atomic_flag type and functions with pg_atomic_bool,
which has functions with same names and semantics as pg_atomic_u32.
Remove the x86-specific implementation, and rely on the fallback that
defines pg_atomic_bool as a wrapper around pg_atomic_u32 on all
platforms.
---
 contrib/pg_stash_advice/pg_stash_advice.c |   8 +-
 contrib/pg_stash_advice/pg_stash_advice.h |   2 +-
 contrib/pg_stash_advice/stashfuncs.c      |   4 +-
 contrib/pg_stash_advice/stashpersist.c    |   4 +-
 src/backend/postmaster/autovacuum.c       |  24 ++--
 src/include/port/atomics.h                | 108 ++++++++--------
 src/include/port/atomics/arch-x86.h       |  33 -----
 src/include/port/atomics/generic-gcc.h    |  67 ----------
 src/include/port/atomics/generic.h        | 150 ++++++++++------------
 src/test/regress/regress.c                |  34 +++--
 src/tools/pgindent/typedefs.list          |   2 +-
 11 files changed, 164 insertions(+), 272 deletions(-)

diff --git a/contrib/pg_stash_advice/pg_stash_advice.c b/contrib/pg_stash_advice/pg_stash_advice.c
index 1858c6a135a..6dbb3f57b6b 100644
--- a/contrib/pg_stash_advice/pg_stash_advice.c
+++ b/contrib/pg_stash_advice/pg_stash_advice.c
@@ -167,7 +167,7 @@ pgsa_advisor(PlannerGlobal *glob, Query *parse,
 		pgsa_attach();
 
 	/* If stash data is still being restored from disk, ignore. */
-	if (pg_atomic_unlocked_test_flag(&pgsa_state->stashes_ready))
+	if (!pg_atomic_read_bool(&pgsa_state->stashes_ready))
 		return NULL;
 
 	/*
@@ -324,7 +324,7 @@ pgsa_attach(void)
 void
 pgsa_check_lockout(void)
 {
-	if (pg_atomic_unlocked_test_flag(&pgsa_state->stashes_ready))
+	if (!pg_atomic_read_bool(&pgsa_state->stashes_ready))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("stash modifications are not allowed because \"%s\" has not been loaded yet",
@@ -579,7 +579,7 @@ pgsa_init_shared_state(void *ptr, void *arg)
 	state->stash_hash = DSHASH_HANDLE_INVALID;
 	state->entry_hash = DSHASH_HANDLE_INVALID;
 	state->bgworker_pid = InvalidPid;
-	pg_atomic_init_flag(&state->stashes_ready);
+	pg_atomic_init_bool(&state->stashes_ready, false);
 	pg_atomic_init_u64(&state->change_count, 0);
 
 	/*
@@ -594,7 +594,7 @@ pgsa_init_shared_state(void *ptr, void *arg)
 	 * which leads to the correct behavior.
 	 */
 	if (!pg_stash_advice_persist)
-		pg_atomic_test_set_flag(&state->stashes_ready);
+		pg_atomic_write_bool(&state->stashes_ready, true);
 }
 
 /*
diff --git a/contrib/pg_stash_advice/pg_stash_advice.h b/contrib/pg_stash_advice/pg_stash_advice.h
index 01aded472f3..e15e09582f8 100644
--- a/contrib/pg_stash_advice/pg_stash_advice.h
+++ b/contrib/pg_stash_advice/pg_stash_advice.h
@@ -65,7 +65,7 @@ typedef struct pgsa_shared_state
 	dshash_table_handle stash_hash;
 	dshash_table_handle entry_hash;
 	pid_t		bgworker_pid;
-	pg_atomic_flag stashes_ready;
+	pg_atomic_bool stashes_ready;
 	pg_atomic_uint64 change_count;
 } pgsa_shared_state;
 
diff --git a/contrib/pg_stash_advice/stashfuncs.c b/contrib/pg_stash_advice/stashfuncs.c
index a70df60579b..2af369e4bc8 100644
--- a/contrib/pg_stash_advice/stashfuncs.c
+++ b/contrib/pg_stash_advice/stashfuncs.c
@@ -99,7 +99,7 @@ pg_get_advice_stashes(PG_FUNCTION_ARGS)
 		pgsa_attach();
 
 	/* If stash data is still being restored from disk, ignore. */
-	if (pg_atomic_unlocked_test_flag(&pgsa_state->stashes_ready))
+	if (!pg_atomic_read_bool(&pgsa_state->stashes_ready))
 		return (Datum) 0;
 
 	/* Tally up the number of entries per stash. */
@@ -163,7 +163,7 @@ pg_get_advice_stash_contents(PG_FUNCTION_ARGS)
 		pgsa_attach();
 
 	/* If stash data is still being restored from disk, ignore. */
-	if (pg_atomic_unlocked_test_flag(&pgsa_state->stashes_ready))
+	if (!pg_atomic_read_bool(&pgsa_state->stashes_ready))
 		return (Datum) 0;
 
 	/* User can pass NULL for all stashes, or the name of a specific stash. */
diff --git a/contrib/pg_stash_advice/stashpersist.c b/contrib/pg_stash_advice/stashpersist.c
index 5bdf4bddaae..c9d7887cb75 100644
--- a/contrib/pg_stash_advice/stashpersist.c
+++ b/contrib/pg_stash_advice/stashpersist.c
@@ -141,10 +141,10 @@ pg_stash_advice_worker_main(Datum main_arg)
 	 * process_shared_preload_libraries() and the data has not yet been
 	 * successfully loaded, load it now.
 	 */
-	if (pg_atomic_unlocked_test_flag(&pgsa_state->stashes_ready))
+	if (!pg_atomic_read_bool(&pgsa_state->stashes_ready))
 	{
 		pgsa_read_from_disk();
-		pg_atomic_test_set_flag(&pgsa_state->stashes_ready);
+		pg_atomic_write_bool(&pgsa_state->stashes_ready, true);
 	}
 
 	/* Note the current change count so we can detect future changes. */
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 127bd9e7da3..287936efbf8 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -244,7 +244,7 @@ typedef struct WorkerInfoData
 	Oid			wi_tableoid;
 	PGPROC	   *wi_proc;
 	TimestampTz wi_launchtime;
-	pg_atomic_flag wi_dobalance;
+	pg_atomic_bool wi_dobalance;
 	bool		wi_sharedrel;
 } WorkerInfoData;
 
@@ -1657,7 +1657,7 @@ FreeWorkerInfo(int code, Datum arg)
 		MyWorkerInfo->wi_sharedrel = false;
 		MyWorkerInfo->wi_proc = NULL;
 		MyWorkerInfo->wi_launchtime = 0;
-		pg_atomic_clear_flag(&MyWorkerInfo->wi_dobalance);
+		pg_atomic_write_bool(&MyWorkerInfo->wi_dobalance, false);
 		dclist_push_head(&AutoVacuumShmem->av_freeWorkers,
 						 &MyWorkerInfo->wi_links);
 		/* not mine anymore */
@@ -1732,7 +1732,7 @@ VacuumUpdateCosts(void)
 
 		elog(DEBUG2,
 			 "Autovacuum VacuumUpdateCosts(db=%u, rel=%u, dobalance=%s, cost_limit=%d, cost_delay=%g active=%s failsafe=%s)",
-			 dboid, tableoid, pg_atomic_unlocked_test_flag(&MyWorkerInfo->wi_dobalance) ? "no" : "yes",
+			 dboid, tableoid, pg_atomic_read_bool(&MyWorkerInfo->wi_dobalance) ? "yes" : "no",
 			 vacuum_cost_limit, vacuum_cost_delay,
 			 vacuum_cost_delay > 0 ? "yes" : "no",
 			 VacuumFailsafeActive ? "yes" : "no");
@@ -1770,7 +1770,7 @@ AutoVacuumUpdateCostLimit(void)
 			vacuum_cost_limit = VacuumCostLimit;
 
 		/* Only balance limit if no cost-related storage parameters specified */
-		if (pg_atomic_unlocked_test_flag(&MyWorkerInfo->wi_dobalance))
+		if (!pg_atomic_read_bool(&MyWorkerInfo->wi_dobalance))
 			return;
 
 		Assert(vacuum_cost_limit > 0);
@@ -1810,7 +1810,7 @@ autovac_recalculate_workers_for_balance(void)
 		WorkerInfo	worker = dlist_container(WorkerInfoData, wi_links, iter.cur);
 
 		if (worker->wi_proc == NULL ||
-			pg_atomic_unlocked_test_flag(&worker->wi_dobalance))
+			!pg_atomic_read_bool(&worker->wi_dobalance))
 			continue;
 
 		nworkers_for_balance++;
@@ -2465,14 +2465,8 @@ do_autovacuum(void)
 		av_storage_param_cost_delay = tab->at_storage_param_vac_cost_delay;
 		av_storage_param_cost_limit = tab->at_storage_param_vac_cost_limit;
 
-		/*
-		 * We only expect this worker to ever set the flag, so don't bother
-		 * checking the return value. We shouldn't have to retry.
-		 */
-		if (tab->at_dobalance)
-			pg_atomic_test_set_flag(&MyWorkerInfo->wi_dobalance);
-		else
-			pg_atomic_clear_flag(&MyWorkerInfo->wi_dobalance);
+		/* We only expect this worker to write the flag */
+		pg_atomic_write_bool(&MyWorkerInfo->wi_dobalance, tab->at_dobalance);
 
 		LWLockAcquire(AutovacuumLock, LW_SHARED);
 		autovac_recalculate_workers_for_balance();
@@ -2578,7 +2572,7 @@ deleted:
 		MyWorkerInfo->wi_tableoid = InvalidOid;
 		MyWorkerInfo->wi_sharedrel = false;
 		LWLockRelease(AutovacuumScheduleLock);
-		pg_atomic_test_set_flag(&MyWorkerInfo->wi_dobalance);
+		pg_atomic_write_bool(&MyWorkerInfo->wi_dobalance, true);
 	}
 
 	list_free_deep(tables_to_process);
@@ -3574,7 +3568,7 @@ AutoVacuumShmemInit(void *arg)
 	{
 		dclist_push_head(&AutoVacuumShmem->av_freeWorkers,
 						 &worker[i].wi_links);
-		pg_atomic_init_flag(&worker[i].wi_dobalance);
+		pg_atomic_init_bool(&worker[i].wi_dobalance, false);
 	}
 
 	pg_atomic_init_u32(&AutoVacuumShmem->av_nworkersForBalance, 0);
diff --git a/src/include/port/atomics.h b/src/include/port/atomics.h
index a605ea81d07..bd75d00a558 100644
--- a/src/include/port/atomics.h
+++ b/src/include/port/atomics.h
@@ -11,7 +11,6 @@
  * 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.
  *
  * There exist generic, hardware independent, implementations for several
@@ -154,55 +153,6 @@
 #define pg_read_barrier()	pg_read_barrier_impl()
 #define pg_write_barrier()	pg_write_barrier_impl()
 
-/*
- * pg_atomic_init_flag - initialize atomic flag.
- *
- * No barrier semantics.
- */
-static inline void
-pg_atomic_init_flag(volatile pg_atomic_flag *ptr)
-{
-	pg_atomic_init_flag_impl(ptr);
-}
-
-/*
- * pg_atomic_test_set_flag - TAS()
- *
- * Returns true if the flag has successfully been set, false otherwise.
- *
- * Acquire (including read barrier) semantics.
- */
-static inline bool
-pg_atomic_test_set_flag(volatile pg_atomic_flag *ptr)
-{
-	return pg_atomic_test_set_flag_impl(ptr);
-}
-
-/*
- * pg_atomic_unlocked_test_flag - Check if the lock is free
- *
- * Returns true if the flag currently is not set, false otherwise.
- *
- * No barrier semantics.
- */
-static inline bool
-pg_atomic_unlocked_test_flag(volatile pg_atomic_flag *ptr)
-{
-	return pg_atomic_unlocked_test_flag_impl(ptr);
-}
-
-/*
- * pg_atomic_clear_flag - release lock set by TAS()
- *
- * Release (including write barrier) semantics.
- */
-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
  *
@@ -611,6 +561,64 @@ pg_atomic_monotonic_advance_u64(volatile pg_atomic_uint64 *ptr, uint64 target)
 	return currval;
 }
 
+/* ----
+ * The 'bool' operations have the same semantics as the u32 counterparts
+ * if they are available. Check the corresponding u32 function for
+ * documentation.
+ *
+ * Note: pg_atomic_bool is currently identical to pg_atomic_u32 on all
+ * platforms, but it's notationally nice to have a distinct type.
+ * ----
+ */
+
+static inline void
+pg_atomic_init_bool(volatile pg_atomic_bool *ptr, bool val)
+{
+	pg_atomic_init_bool_impl(ptr, val);
+}
+
+static inline bool
+pg_atomic_read_bool(volatile pg_atomic_bool *ptr)
+{
+	return pg_atomic_read_bool_impl(ptr);
+}
+
+static inline bool
+pg_atomic_read_membarrier_bool(volatile pg_atomic_bool *ptr)
+{
+	return pg_atomic_read_membarrier_bool_impl(ptr);
+}
+
+static inline void
+pg_atomic_write_bool(volatile pg_atomic_bool *ptr, bool val)
+{
+	pg_atomic_write_bool_impl(ptr, val);
+}
+
+static inline void
+pg_atomic_unlocked_write_bool(volatile pg_atomic_bool *ptr, bool val)
+{
+	pg_atomic_unlocked_write_bool_impl(ptr, val);
+}
+
+static inline void
+pg_atomic_write_membarrier_bool(volatile pg_atomic_bool *ptr, bool val)
+{
+	pg_atomic_write_membarrier_bool_impl(ptr, val);
+}
+
+static inline bool
+pg_atomic_exchange_bool(volatile pg_atomic_bool *ptr, bool newval)
+{
+	return pg_atomic_exchange_bool_impl(ptr, newval);
+}
+
+/*
+ * Note: There is no pg_atomic_compare_exchange_bool(). Because a boolean has
+ * only two possible values, it would be no different from
+ * pg_atomic_exchange_bool().
+ */
+
 #undef INSIDE_ATOMICS_H
 
 #endif							/* ATOMICS_H */
diff --git a/src/include/port/atomics/arch-x86.h b/src/include/port/atomics/arch-x86.h
index 231831dcf59..05d2a2ce7f9 100644
--- a/src/include/port/atomics/arch-x86.h
+++ b/src/include/port/atomics/arch-x86.h
@@ -51,12 +51,6 @@
  */
 #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
 {
@@ -76,33 +70,6 @@ typedef struct pg_atomic_uint64
 } pg_atomic_uint64;
 #endif	/* __x86_64__ */
 
-#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,
diff --git a/src/include/port/atomics/generic-gcc.h b/src/include/port/atomics/generic-gcc.h
index 5bfce82f687..9be820f72b1 100644
--- a/src/include/port/atomics/generic-gcc.h
+++ b/src/include/port/atomics/generic-gcc.h
@@ -61,27 +61,6 @@
 #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))
@@ -107,52 +86,6 @@ typedef struct 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
diff --git a/src/include/port/atomics/generic.h b/src/include/port/atomics/generic.h
index daa772e9a6d..c5a130c76a2 100644
--- a/src/include/port/atomics/generic.h
+++ b/src/include/port/atomics/generic.h
@@ -28,12 +28,6 @@
 #	define pg_write_barrier_impl pg_memory_barrier_impl
 #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
@@ -61,84 +55,6 @@ pg_atomic_unlocked_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 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
@@ -427,4 +343,70 @@ pg_atomic_write_membarrier_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val)
 {
 	(void) pg_atomic_exchange_u64_impl(ptr, val);
 }
+
+
+/* implement pg_atomic_bool over pg_atomic_u32 */
+#if !defined(PG_HAVE_ATOMIC_BOOL_SUPPORT) && defined(PG_HAVE_ATOMIC_U32_SUPPORT)
+#define PG_HAVE_ATOMIC_BOOL_SUPPORT
+typedef pg_atomic_uint32 pg_atomic_bool;
+#endif
+
+#if !defined(PG_HAVE_ATOMIC_INIT_BOOL) && defined(PG_HAVE_ATOMIC_INIT_U32)
+static inline void
+pg_atomic_init_bool_impl(volatile pg_atomic_bool *ptr, bool val)
+{
+	pg_atomic_init_u32_impl(ptr, (uint32) val);
+}
+#endif
+
+#if !defined(PG_HAVE_ATOMIC_READ_BOOL) && defined(PG_HAVE_ATOMIC_READ_U32)
+static inline bool
+pg_atomic_read_bool_impl(volatile pg_atomic_bool *ptr)
+{
+	return (bool) pg_atomic_read_u32_impl(ptr);
+}
+#endif
+
+#if !defined(PG_HAVE_ATOMIC_READ_MEMBARRIER_BOOL) && defined(PG_HAVE_ATOMIC_READ_MEMBARRIER_U32)
+static inline bool
+pg_atomic_read_membarrier_bool_impl(volatile pg_atomic_bool *ptr)
+{
+	return (bool) pg_atomic_read_membarrier_u32_impl(ptr);
+}
+#endif
+
+#if !defined(PG_HAVE_ATOMIC_WRITE_BOOL) && defined(PG_HAVE_ATOMIC_WRITE_U32)
+static inline void
+pg_atomic_write_bool_impl(volatile pg_atomic_bool *ptr, bool val)
+{
+	pg_atomic_write_u32_impl(ptr, (uint32) val);
+}
+#endif
+
+#if !defined(PG_HAVE_ATOMIC_UNLOCKED_WRITE_BOOL) && defined(PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32)
+static inline void
+pg_atomic_unlocked_write_bool_impl(volatile pg_atomic_bool *ptr, bool val)
+{
+	pg_atomic_unlocked_write_u32_impl(ptr, (uint32) val);
+}
+#endif
+
+#if !defined(PG_HAVE_ATOMIC_WRITE_MEMBARRIER_BOOL) && defined(PG_HAVE_ATOMIC_WRITE_MEMBARRIER_U32)
+static inline void
+pg_atomic_write_membarrier_bool_impl(volatile pg_atomic_bool *ptr, bool val)
+{
+	pg_atomic_write_membarrier_u32_impl(ptr, (uint32) val);
+}
+#endif
+
+#if !defined(PG_HAVE_ATOMIC_EXCHANGE_BOOL) && defined(PG_HAVE_ATOMIC_EXCHANGE_U32)
+static inline bool
+pg_atomic_exchange_bool_impl(volatile pg_atomic_bool *ptr, bool newval)
+{
+	return (bool) pg_atomic_exchange_u32_impl(ptr, (uint32) newval);
+}
+#endif
+
+
+
 #endif
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index d5aafdf370c..7287197a1b6 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -63,6 +63,14 @@
 				 #expr, __FILE__, __LINE__); \
 	} while (0)
 
+#define EXPECT_FALSE(expr)	\
+	do { \
+		if ((expr)) \
+			elog(ERROR, \
+				 "%s was unexpectedly true in file \"%s\" line %u", \
+				 #expr, __FILE__, __LINE__); \
+	} while (0)
+
 #define EXPECT_EQ_U32(result_expr, expected_expr)	\
 	do { \
 		uint32		actual_result = (result_expr); \
@@ -503,19 +511,19 @@ wait_pid(PG_FUNCTION_ARGS)
 }
 
 static void
-test_atomic_flag(void)
+test_atomic_bool(void)
 {
-	pg_atomic_flag flag;
-
-	pg_atomic_init_flag(&flag);
-	EXPECT_TRUE(pg_atomic_unlocked_test_flag(&flag));
-	EXPECT_TRUE(pg_atomic_test_set_flag(&flag));
-	EXPECT_TRUE(!pg_atomic_unlocked_test_flag(&flag));
-	EXPECT_TRUE(!pg_atomic_test_set_flag(&flag));
-	pg_atomic_clear_flag(&flag);
-	EXPECT_TRUE(pg_atomic_unlocked_test_flag(&flag));
-	EXPECT_TRUE(pg_atomic_test_set_flag(&flag));
-	pg_atomic_clear_flag(&flag);
+	pg_atomic_bool flag;
+
+	pg_atomic_init_bool(&flag, false);
+	EXPECT_FALSE(pg_atomic_read_bool(&flag));
+	pg_atomic_write_bool(&flag, true);
+	EXPECT_TRUE(pg_atomic_read_bool(&flag));
+
+	EXPECT_TRUE(pg_atomic_exchange_bool(&flag, true));
+	EXPECT_TRUE(pg_atomic_exchange_bool(&flag, false));
+	EXPECT_FALSE(pg_atomic_exchange_bool(&flag, false));
+	EXPECT_FALSE(pg_atomic_exchange_bool(&flag, true));
 }
 
 static void
@@ -710,7 +718,7 @@ PG_FUNCTION_INFO_V1(test_atomic_ops);
 Datum
 test_atomic_ops(PG_FUNCTION_ARGS)
 {
-	test_atomic_flag();
+	test_atomic_bool();
 
 	test_atomic_uint32();
 
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 117e7379f10..4d5f9bbb5cd 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -4020,7 +4020,7 @@ pe_test_vector
 pendingPosition
 pending_label
 pgParameterStatus
-pg_atomic_flag
+pg_atomic_bool
 pg_atomic_uint32
 pg_atomic_uint64
 pg_be_sasl_mech
-- 
2.47.3

