git: 0f8941fedce6 - main - tools/regression: Expand stdatomic conformance tests

From: Warner Losh <imp_at_FreeBSD.org>
Date: Sat, 20 Jun 2026 00:24:59 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=0f8941fedce6c622f0fa71464b7790225aefa3e6

commit 0f8941fedce6c622f0fa71464b7790225aefa3e6
Author:     Faraz Vahedi <kfv@kfv.io>
AuthorDate: 2026-05-08 11:40:02 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2026-06-20 00:23:29 +0000

    tools/regression: Expand stdatomic conformance tests
    
    Extend the existing test utility to cover recent stdatomic
    changes and improve validation of interface semantics,
    compile-time assertions, and behavioural conformance.
    
    Signed-off-by: Faraz Vahedi <kfv@kfv.io>
    Reviewed by: imp
    Pull Request: https://github.com/freebsd/freebsd-src/pull/2185
---
 tools/regression/include/stdatomic/logic.c | 109 +++++++++++++++++++++++++++++
 1 file changed, 109 insertions(+)

diff --git a/tools/regression/include/stdatomic/logic.c b/tools/regression/include/stdatomic/logic.c
index e5534851417d..46ac85c57b0c 100644
--- a/tools/regression/include/stdatomic/logic.c
+++ b/tools/regression/include/stdatomic/logic.c
@@ -27,6 +27,8 @@
 #include <sys/cdefs.h>
 #include <assert.h>
 #include <stdatomic.h>
+#include <stdbool.h>
+#include <stddef.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
@@ -42,8 +44,111 @@
  * especially useful for the smaller integer types, as it may be the
  * case that these operations are implemented by processing entire words
  * (e.g. on MIPS).
+ *
+ * Before the randomised loop, a small surface check exercises lock-free
+ * macros, fences, atomic_flag, atomic_bool, pointer fetch_add/fetch_sub
+ * stride, kill_dependency, atomic_is_lock_free, and when available
+ * ATOMIC_VAR_INIT / ATOMIC_FLAG_INIT (pre-C23).
  */
 
+#define	CHECK_LOCK_FREE(name)						\
+	_Static_assert((name) == 0 || (name) == 1 || (name) == 2,	\
+	    #name " out of range")
+
+CHECK_LOCK_FREE(ATOMIC_BOOL_LOCK_FREE);
+CHECK_LOCK_FREE(ATOMIC_CHAR_LOCK_FREE);
+CHECK_LOCK_FREE(ATOMIC_SHORT_LOCK_FREE);
+CHECK_LOCK_FREE(ATOMIC_INT_LOCK_FREE);
+CHECK_LOCK_FREE(ATOMIC_LONG_LOCK_FREE);
+CHECK_LOCK_FREE(ATOMIC_LLONG_LOCK_FREE);
+CHECK_LOCK_FREE(ATOMIC_POINTER_LOCK_FREE);
+#ifdef ATOMIC_CHAR8_T_LOCK_FREE
+CHECK_LOCK_FREE(ATOMIC_CHAR8_T_LOCK_FREE);
+#endif
+#ifdef ATOMIC_CHAR16_T_LOCK_FREE
+CHECK_LOCK_FREE(ATOMIC_CHAR16_T_LOCK_FREE);
+#endif
+#ifdef ATOMIC_CHAR32_T_LOCK_FREE
+CHECK_LOCK_FREE(ATOMIC_CHAR32_T_LOCK_FREE);
+#endif
+#ifdef ATOMIC_WCHAR_T_LOCK_FREE
+CHECK_LOCK_FREE(ATOMIC_WCHAR_T_LOCK_FREE);
+#endif
+
+#if defined(__STDC_VERSION_STDATOMIC_H__)
+_Static_assert(__STDC_VERSION_STDATOMIC_H__ == 202311L,
+    "__STDC_VERSION_STDATOMIC_H__");
+#endif
+
+static void
+test_surface(void)
+{
+	atomic_flag f = ATOMIC_FLAG_INIT;
+	atomic_int probe;
+	atomic_bool b;
+	_Atomic(int *) ap;
+	int arr[4];
+	int dep;
+	static const memory_order k_orders[] = {
+		memory_order_relaxed,
+		memory_order_consume,
+		memory_order_acquire,
+		memory_order_release,
+		memory_order_acq_rel,
+		memory_order_seq_cst,
+	};
+	size_t k;
+
+	dep = kill_dependency(123);
+	assert(dep == 123);
+
+	atomic_init(&probe, 0);
+	assert(atomic_is_lock_free(&probe) ==
+	    atomic_is_lock_free((atomic_int *)NULL));
+
+	for (k = 0; k < sizeof(k_orders) / sizeof(k_orders[0]); k++) {
+		atomic_thread_fence(k_orders[k]);
+		atomic_signal_fence(k_orders[k]);
+	}
+
+	assert(atomic_flag_test_and_set_explicit(&f,
+	    memory_order_seq_cst) == 0);
+	assert(atomic_flag_test_and_set_explicit(&f,
+	    memory_order_acquire) != 0);
+	atomic_flag_clear_explicit(&f, memory_order_relaxed);
+
+	atomic_init(&b, false);
+	atomic_store_explicit(&b, true, memory_order_relaxed);
+	assert(atomic_load_explicit(&b, memory_order_relaxed) == true);
+
+	memset(arr, 0, sizeof(arr));
+	atomic_init(&ap, &arr[3]);
+	atomic_fetch_sub_explicit(&ap, 2, memory_order_relaxed);
+	assert(ap == &arr[1]);
+	atomic_fetch_add_explicit(&ap, 1, memory_order_relaxed);
+	assert(ap == &arr[2]);
+}
+
+#ifdef ATOMIC_VAR_INIT
+static void
+test_atomic_var_init(void)
+{
+	atomic_int x = ATOMIC_VAR_INIT(42);
+
+	assert(atomic_load_explicit(&x, memory_order_relaxed) == 42);
+	atomic_store_explicit(&x, 7, memory_order_relaxed);
+	assert(atomic_load_explicit(&x, memory_order_relaxed) == 7);
+
+	{
+		atomic_flag f = ATOMIC_FLAG_INIT;
+
+		assert(atomic_flag_test_and_set_explicit(&f,
+		    memory_order_seq_cst) == 0);
+		atomic_flag_clear_explicit(&f, memory_order_relaxed);
+	}
+}
+#endif
+
 static inline intmax_t
 rndnum(void)
 {
@@ -111,6 +216,10 @@ main(void)
 {
 	int i;
 
+	test_surface();
+#ifdef ATOMIC_VAR_INIT
+	test_atomic_var_init();
+#endif
 	for (i = 0; i < 1000; i++) {
 		TEST_TYPE(int8_t);
 		TEST_TYPE(uint8_t);