From 3ada5198498ff861edd0c1afa2211a471f369ec1 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Thu, 14 Mar 2024 07:07:38 +0000
Subject: [PATCH v14 1/4] Add monotonic advancement functions for atomics

This commit adds functions for monotonically advancing the given
atomic variable with full barrier semantics.

An upcoming commit uses 64-bit monotonic function. But this commit
also adds 32-bit version just for the sake of completeness.
---
 src/include/port/atomics.h | 56 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/src/include/port/atomics.h b/src/include/port/atomics.h
index ff47782cdb..53e1a337a4 100644
--- a/src/include/port/atomics.h
+++ b/src/include/port/atomics.h
@@ -438,6 +438,35 @@ pg_atomic_sub_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
 	return pg_atomic_sub_fetch_u32_impl(ptr, sub_);
 }
 
+/*
+ * Monotonically advance the given variable using only atomic operations until
+ * it's at least the target value.
+ *
+ * Full barrier semantics (even when value is unchanged).
+ */
+static inline void
+pg_atomic_monotonic_advance_u32(volatile pg_atomic_uint32 *ptr, uint32 target_)
+{
+	uint32		currval;
+
+	AssertPointerAlignment(ptr, 4);
+
+	currval = pg_atomic_read_u32_impl(ptr);
+	if (currval >= target_)
+	{
+		pg_memory_barrier();
+		return;
+	}
+
+	AssertPointerAlignment(&currval, 4);
+
+	while (currval < target_)
+	{
+		if (pg_atomic_compare_exchange_u32_impl(ptr, &currval, target_))
+			break;
+	}
+}
+
 /* ----
  * The 64 bit operations have the same semantics as their 32bit counterparts
  * if they are available. Check the corresponding 32bit function for
@@ -570,6 +599,33 @@ pg_atomic_sub_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 sub_)
 	return pg_atomic_sub_fetch_u64_impl(ptr, sub_);
 }
 
+static inline void
+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);
+	if (currval >= target_)
+	{
+		pg_memory_barrier();
+		return;
+	}
+
+#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
+	AssertPointerAlignment(&currval, 8);
+#endif
+
+	while (currval < target_)
+	{
+		if (pg_atomic_compare_exchange_u64_impl(ptr, &currval, target_))
+			break;
+	}
+}
+
 #undef INSIDE_ATOMICS_H
 
 #endif							/* ATOMICS_H */
-- 
2.34.1

