Hi,

I've always found the pg_atomic_flag functions counterintuitive. I remember by now pretty well how the pg_atomic_u32/u64 functions work, but any time I have to look at the pg_atomic_flag functions, I feel not-like I'm in a foreign land.

I think that's because I think of pg_atomic_flag as an atomic version of "bool". I'd assume there to be functions similar to the u32/u64 functions, like pg_atomic_read_bool() and pg_atomic_write_bool(). But alas, neither of those functions exist. To read the value, you have to use pg_atomic_unlocked_test_flag(), and remember that when the flag is set, it returns *false*, which feels completely backwards to me. It makes more sense with pg_atomic_test_set_flag(), which returns 'false' if the flag was already set and hence was not set again, but it nevertheless just feels wrong to me.

I propose that we replace pg_atomic_flag with pg_atomic_bool, which behaves more like pg_atomic_u32/u64.

We currently only use pg_atomic_bool in two places: in the shared memory structs of pg_stash_advise and autovacuum. I actually considered just removing pg_test_flag altogether and replacing those two uses directly with pg_atomic_u32, but it's still nice to have a distinct boolean type. It's worth noting that the current usage is not very performance critical (not that I'd expect the u32 functions to be any slower).


Thomas's patches to switch to standard C <stdatomic.h> at [1] is also touching this. They keep the the application-facing functions unchanged, but changes the implementation to use the same atomic-exchange instructions as for u32/u64. This is complementary and an independent topic to discuss, although the patches will conflict.

[1] https://www.postgresql.org/message-id/CA%2BhUKGKFvu3zyvv3aaj5hHs9VtWcjFAmisOwOc7aOZNc5AF3NA%40mail.gmail.com

- Heikki
From ba3395f8a09a3ae3919f3f811296b05b2cddd17c Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <[email protected]>
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

Reply via email to