On 2026-08-09 07:52, Arsen Arsenović wrote:
one could just cross their fingers on platforms lacking
stdatomic, since the odds of the bug actually manifesting observably is
quite low, and use stdatomic only a best effort basis - i.e. use it if
present, and have no atomic handling (as is the case today) otherwise.

I took a look at the only Gnulib module that uses _Atomic, namely hamt. It uses 
_Atomic in the way you suggest, i.e., use _Atomic only on a best effort basis. 
Unfortunately I found two problems with how hamt uses _Atomic. First, it 
misspelled __STDC_NO_ATOMICS__, a bug that nobody has reported since hamt was 
added to Gnulib in 2021. Second, hamt worried only about GCC and Clang, I 
suppose under the theory it wasn't worth investigating which other compilers 
supported _Atomic.

I attempted to fix these problems by installing the attached patches. Still, 
this is dicey, as with older platforms one might need to compile with special 
options. For example, on Solaris 10 sparc when compiling with Oracle Developer 
Studio 12.6, one now needs to compile with 'cc -xatomic=studio' to get hamt to 
work. It's a bit of a mess dealing with these old platforms, a mess that I 
suppose old-platform builders will have to deal with somehow.

Luckily, Gnulib's hamt module is so rarely used that this isn't much of a 
practical problem. Still, it appears that using _Atomic is dicey, at least in 
the Gnulib world which ports to older platforms. It's not clear to me whether 
or when Gnulib-using code should use _Atomic instead of Gnulib's simple-atomic 
module, for example.

Come to think of it, should we remove the hamt module from Gnulib? As I vaguely 
recall it was added under the theory that some package might find it useful, 
but it's been five years now, and as far as I know nobody is using it. I'll cc 
this to its original contributor Marc Nieper-Wißkirchen to give him a heads-up 
about the situation, and am retitling this email's subject line accordingly.
From f4b6627bac4641411662cb47730925ad337fb144 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Sun, 9 Aug 2026 17:23:49 -0500
Subject: [PATCH] hamt: port to non-_Atomic C platforms
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* lib/hamt.h (GL_HAMT_THREAD_SAFE):
Fix misspelling of ‘__STDC_NO_ATOMICS__’.
---
 ChangeLog  | 6 ++++++
 lib/hamt.h | 2 +-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index beaeff585c..fade982eb5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2026-08-09  Paul Eggert  <[email protected]>
+
+	hamt: port to non-_Atomic C platforms
+	* lib/hamt.h (GL_HAMT_THREAD_SAFE):
+	Fix misspelling of ‘__STDC_NO_ATOMICS__’.
+
 2026-08-09  Collin Funk  <[email protected]>
 
 	fts: Pacify -Wuseless-cast warnings when GNULIB_FTS_DEBUG is defined.
diff --git a/lib/hamt.h b/lib/hamt.h
index 24ff6b7611..cb68a74f26 100644
--- a/lib/hamt.h
+++ b/lib/hamt.h
@@ -65,7 +65,7 @@ _GL_INLINE_HEADER_BEGIN
 
 #if (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4 && !defined __clang \
      || __clang_major__ >= 4) \
-    && __STDC_VERSION__ >= 201112L && !defined __STD_NO_ATOMICS__ \
+    && __STDC_VERSION__ >= 201112L && !defined __STDC_NO_ATOMICS__ \
     && !defined __cplusplus
 # define GL_HAMT_THREAD_SAFE 1
 #else
-- 
2.53.0

From 7370e33b8ba15e3d270cc045383ad6c022e4def5 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Mon, 10 Aug 2026 23:31:02 -0700
Subject: [PATCH] hamt: improve _Atomic port
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* lib/hamt.h (HAVE_C11__ATOMIC): New macro.  It improves on the
old GL_HAMT_THREAD_SAFE, by dealing with Apple’s renumbering of
Clang versions, and by adding support for MSVC 19.35+, nvc 21.3+,
and IBM XL C 17.1+.
(GL_HAMT_THREAD_SAFE): Remove.  All uses replaced by ...
(GL_HAMT_ATOMIC): ... this new macro.
---
 ChangeLog  |  8 ++++++++
 lib/hamt.h | 50 +++++++++++++++++++++++++++++++++-----------------
 2 files changed, 41 insertions(+), 17 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index e258e18d2b..83e47ae6b3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2026-08-10  Paul Eggert  <[email protected]>
 
+	hamt: improve _Atomic port
+	* lib/hamt.h (HAVE_C11__ATOMIC): New macro.  It improves on the
+	old GL_HAMT_THREAD_SAFE, by dealing with Apple’s renumbering of
+	Clang versions, and by adding support for MSVC 19.35+, nvc 21.3+,
+	and IBM XL C 17.1+.
+	(GL_HAMT_THREAD_SAFE): Remove.  All uses replaced by ...
+	(GL_HAMT_ATOMIC): ... this new macro.
+
 	canonicalize-lgpl: sync from glibc
 	Merge into lib/canonicalize-lgpl.c the changes of glibc
 	stdlib/canonicalize.c through glibc commit
diff --git a/lib/hamt.h b/lib/hamt.h
index cb68a74f26..8430313811 100644
--- a/lib/hamt.h
+++ b/lib/hamt.h
@@ -56,20 +56,39 @@ _GL_INLINE_HEADER_BEGIN
 # define _GL_HAMT_INLINE _GL_INLINE
 #endif
 
-/* The GL_HAMT_THREAD_SAFE flag is set if the implementation of hamts
-   is thread-safe as long as two threads do not simultaneously access
-   the same hamt.  This is non-trivial as different hamts may share
-   some structure.
-   We can define it only when the compiler supports _Atomic.  For GCC,
-   it is supported starting with GCC 4.9.  For clang, with clang 4.  */
-
-#if (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4 && !defined __clang \
-     || __clang_major__ >= 4) \
-    && __STDC_VERSION__ >= 201112L && !defined __STDC_NO_ATOMICS__ \
-    && !defined __cplusplus
-# define GL_HAMT_THREAD_SAFE 1
+/* Whether the _Atomic type specifier (e.g., '_Atomic (int)') conforms to C11.
+   Unless __STDC_NO_ATOMICS__ is defined, it reportedly works for C
+   in Xcode 8+, Clang 4+, MSVC 19.35+, nvc 21.3+, GCC 4.9+, and IBM XL C 17.1+,
+   all regardless of which -std option is used; although earlier
+   versions of these compilers may pretend to support C11 atomics,
+   there are bugs.  There are also bugs in pgcc.  Check for the
+   compilers in that order, as some compilers pretend to be others and
+   this order prevents false matches.  If it is not one of these
+   compilers, fall back on checking the version of the C standard.  */
+#ifndef HAVE_C11__ATOMIC
+# if (!defined __STDC_NO_ATOMICS__ && !defined __cplusplus \
+      && (defined __apple_build_version__ ? 8000000 <= __apple_build_version__ \
+          : defined __clang__ ? 4 <= __clang_major__ \
+          : defined _MSC_VER ? 1935 <= _MSC_VER \
+          : defined __NVCOMPILER \
+          ? 21 < __NVCOMPILER_MAJOR__ + (3 <= __NVCOMPILER_MINOR__) \
+          : defined __GNUC__ ? 4 < __GNUC__ + (9 <= __GNUC_MINOR__) \
+          : (!defined __xlC__ && !defined __PGI \
+             && defined __STDC_VERSION__ && 201112 <= __STDC_VERSION__)))
+#  define HAVE_C11__ATOMIC 1
+# else
+#  define HAVE_C11__ATOMIC 0
+# endif
+#endif
+
+/* The atomic type corresponding to T, if available; otherwise, just T.  */
+#if HAVE_C11__ATOMIC
+# define GL_HAMT_ATOMIC(t) _Atomic (t)
+#elif defined __cplusplus && 201103 <= __cplusplus
+# include <atomic>
+# define GL_HAMT_ATOMIC(t) ::std::atomic<t>
 #else
-# define GL_HAMT_THREAD_SAFE 0
+# define GL_HAMT_ATOMIC(t) t
 #endif
 
 #include <stddef.h>
@@ -98,10 +117,7 @@ extern "C" {
    containing it is freed.  */
 typedef struct
 {
-#if GL_HAMT_THREAD_SAFE
-  _Atomic
-#endif
-  size_t ref_count;
+  GL_HAMT_ATOMIC (size_t) ref_count;
 } Hamt_entry;
 
 /* Initialize *ELT, which has to point to a structure as described
-- 
2.53.0

Reply via email to