* asyncsafe-spin: Fix link error on various platforms
@ 2024-01-21 15:16 Bruno Haible
0 siblings, 0 replies; only message in thread
From: Bruno Haible @ 2024-01-21 15:16 UTC (permalink / raw)
To: bug-gnulib
I'm seeing link errors of the 'asyncsafe-spin' unit tests on two platforms:
* On an older Linux/arm system (with glibc, gcc 4.2.3 arm-none-linux-gnueabi):
gcc -std=gnu99 -Wno-error -g -O2 -o test-asyncsafe-spin1 test-asyncsafe-spin1.o libtests.a ../gllib/libgnu.a libtests.a ../gllib/libgnu.a libtests.a
libtests.a(asyncsafe-spin.o): In function `do_lock':
/admin/testdir1/gltests/asyncsafe-spin.c:157: undefined reference to `__sync_val_compare_and_swap_4'
libtests.a(asyncsafe-spin.o): In function `do_unlock':
/admin/testdir1/gltests/asyncsafe-spin.c:165: undefined reference to `__sync_val_compare_and_swap_4'
collect2: ld returned 1 exit status
make[4]: *** [test-asyncsafe-spin1] Error 1
* On OpenBSD 7.4/hppa (with gcc 4.2.1 hppa-unknown-openbsd7.4)
gmake[3]: Entering directory '/home/bruno/testdir1/build/gltests'
gcc -std=gnu99 -Wno-error -g -O2 -L/home/bruno/lib -o test-asyncsafe-spin1 test-asyncsafe-spin1.o libtests.a ../gllib/libgnu.a libtests.a ../gllib/libgnu.a libtests.a
libtests.a(asyncsafe-spin.o): In function `do_lock':
../../gltests/asyncsafe-spin.c:157: undefined reference to `__sync_val_compare_and_swap_4'
libtests.a(asyncsafe-spin.o): In function `do_unlock':
../../gltests/asyncsafe-spin.c:165: undefined reference to `__sync_val_compare_and_swap_4'
collect2: ld returned 1 exit status
gmake[3]: *** [Makefile:3357: test-asyncsafe-spin1] Error 1
The cause is that a use of the compiler built-in __sync_val_compare_and_swap on
these systems does not produce inline code with CAS instructions or loops,
but rather a call to an external function __sync_val_compare_and_swap_4.
And this function is not implemented, neither in libc, nor in libgcc / libgcc_s.so.
The code indicates that such link errors had already been observed on
Solaris/SPARC, on Android/arm, and with older versions of AIX xlc.
A tedious analysis reveals that these link errors will regularly occur on:
- arm, with gcc versions >= 4.1, < 4.7 on all systems except NetBSD,
with gcc versions >= 4.7, < 5 on FreeBSD, OpenBSD, Android,
with gcc versions >= 5 on OpenBSD, Android,
- hppa, hppa64, with gcc versions >= 4.1, < 4.7 on all systems,
with gcc versions >= 4.7, < 13 on NetBSD, OpenBSD,
- i386 (without '-march=i486'), with gcc versions >= 4.1
on all systems except NetBSD,
- sparc (32-bit, for certain CPU models), with gcc versions >= 4.1
on all systems except NetBSD,
- m68k, with gcc versions >= 4.1, < 4.7 on all systems except NetBSD,
- mips, with gcc versions >= 4.1, < 4.3 on all systems.
And also possible on new architectures that are not known yet.
Therefore a configure-time test is the best approach. gdb uses an autoconf
test for this as well.
2024-01-21 Bruno Haible <bruno@clisp.org>
asyncsafe-spin: Fix link error on various platforms.
* m4/atomic-cas.m4: New file.
* lib/asyncsafe-spin.c: Test HAVE_ATOMIC_COMPARE_AND_SWAP_GCC41 instead
of a condition that considers only __sparc__, __ANDROID__, __ibmxl__.
* lib/pthread-spin.c: Likewise.
* lib/simple-atomic.c: Likewise.
* modules/asyncsafe-spin (Files): Add m4/atomic-cas.m4.
(configure.ac): Require gl_ATOMIC_COMPARE_AND_SWAP.
* modules/pthread-spin: Likewise.
* modules/simple-atomic: Likewise.
=============================== m4/atomic-cas.m4 ===============================
# atomic-cas.m4 serial 1
dnl Copyright (C) 2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
# Determines whether the atomic compare-and-swap operations, officially
# supported in GCC >= 4.1 and clang >= 3.0, are actually available.
# These primitives are documented in
# <https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html>
# without platform restrictions. But they are not actually available
# everywhere:
# * On some platforms, __sync_bool_compare_and_swap does not expand
# to standalone inline code, but to a call to a function
# '__sync_bool_compare_and_swap_4' (assuming a 32-bit value).
# This is the case on
# - arm, for all gcc versions
# - hppa, hppa64, for all gcc versions
# - i386 (without '-march=i486'), for all gcc versions
# - sparc (32-bit, for certain CPU models), for all gcc versions
# - m68k, for gcc < 4.7
# - mips, for gcc < 4.3
# This can be seen by compiling this piece of code
# ----------------------------------------------------------------
# int cmpxchg (int* value, int comp_val, int new_val)
# {
# return __sync_val_compare_and_swap (value, comp_val, new_val);
# }
# ----------------------------------------------------------------
# with option -S, using a (native or cross-) compiler.
# * The function __sync_bool_compare_and_swap_4 is meant to be included
# in libgcc. And indeed, libgcc contains the source code for this
# function on
# - arm, for gcc versions >= 4.7, but only for Linux
# and (for gcc >= 5) FreeBSD,
# - hppa, hppa64, for gcc versions >= 4.7, but only for Linux
# and (for gcc >= 13) NetBSD, OpenBSD, hppa64 HP-UX
# - i386, never at all
# - sparc, never at all
# - m68k, for gcc versions >= 4.7, but only for Linux
# - mips, never at all
# * The NetBSD C library provides this function on
# - arm, arm64,
# - i386,
# - sparc,
# - m68k,
# - riscv64.
# Other C libraries (e.g. glibc, musl libc) do not provide this function.
# So, the use of these primitives results in a link error on:
# - arm, with gcc versions >= 4.1, < 4.7 on all systems except NetBSD,
# with gcc versions >= 4.7, < 5 on FreeBSD, OpenBSD, Android,
# with gcc versions >= 5 on OpenBSD, Android,
# - hppa, hppa64, with gcc versions >= 4.1, < 4.7 on all systems,
# with gcc versions >= 4.7, < 13 on NetBSD, OpenBSD,
# - i386 (without '-march=i486'), with gcc versions >= 4.1
# on all systems except NetBSD,
# - sparc (32-bit, for certain CPU models), with gcc versions >= 4.1
# on all systems except NetBSD,
# - m68k, with gcc versions >= 4.1, < 4.7 on all systems except NetBSD,
# - mips, with gcc versions >= 4.1, < 4.3 on all systems.
# Additionally, link errors can occur if - such as on glibc systems - the libgcc
# functions are distributed through glibc, but the glibc version is older than
# the gcc version.
AC_DEFUN([gl_ATOMIC_COMPARE_AND_SWAP],
[
AC_CACHE_CHECK([for __sync_bool_compare_and_swap],
[gl_cv_builtin_sync_bool_compare_and_swap],
[AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[int cmpxchg (int* value, int comp_val, int new_val)
{
return __sync_val_compare_and_swap (value, comp_val, new_val);
}
]],
[[]])
],
[gl_cv_builtin_sync_bool_compare_and_swap=yes],
[gl_cv_builtin_sync_bool_compare_and_swap=no])
])
if test $gl_cv_builtin_sync_bool_compare_and_swap = yes; then
AC_DEFINE([HAVE_ATOMIC_COMPARE_AND_SWAP_GCC41], [1],
[Define to 1 if the GCC 4.1 primitives for atomic compare-and-swap can be used.])
fi
])
================================================================================
diff --git a/lib/asyncsafe-spin.c b/lib/asyncsafe-spin.c
index f16fb54b1c..63352184ae 100644
--- a/lib/asyncsafe-spin.c
+++ b/lib/asyncsafe-spin.c
@@ -134,11 +134,10 @@ do_unlock (asyncsafe_spinlock_t *lock)
# endif
# elif (((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) \
- && !(defined __sun && defined __sparc__) && !defined __ANDROID__) \
- || __clang_major__ >= 3) \
- && !defined __ibmxl__
-/* Use GCC built-ins (available in GCC >= 4.1, except on Solaris/SPARC and
- Android, and clang >= 3.0).
+ || __clang_major__ >= 3) \
+ && HAVE_ATOMIC_COMPARE_AND_SWAP_GCC41)
+/* Use GCC built-ins (available on many platforms with GCC >= 4.1 or
+ clang >= 3.0).
Documentation:
<https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html> */
diff --git a/lib/pthread-spin.c b/lib/pthread-spin.c
index 32073fbc36..26caa72496 100644
--- a/lib/pthread-spin.c
+++ b/lib/pthread-spin.c
@@ -163,10 +163,10 @@ pthread_spin_destroy (pthread_spinlock_t *lock)
}
# elif (((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) \
- && !defined __ANDROID__) \
- || __clang_major__ >= 3) \
- && !defined __ibmxl__
-/* Use GCC built-ins (available in GCC >= 4.1 and clang >= 3.0).
+ || __clang_major__ >= 3) \
+ && HAVE_ATOMIC_COMPARE_AND_SWAP_GCC41)
+/* Use GCC built-ins (available on many platforms with GCC >= 4.1 or
+ clang >= 3.0).
Documentation:
<https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html> */
diff --git a/lib/simple-atomic.c b/lib/simple-atomic.c
index 61fc602367..656b4bdc19 100644
--- a/lib/simple-atomic.c
+++ b/lib/simple-atomic.c
@@ -67,11 +67,10 @@ atomic_compare_and_swap_ptr (uintptr_t volatile *vp,
require to link with -latomic. */
# if (((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) \
- && !(defined __sun && defined __sparc__) && !defined __ANDROID__) \
- || __clang_major__ >= 3) \
- && !defined __ibmxl__
-/* Use GCC built-ins (available in GCC >= 4.1, except on Solaris/SPARC and
- Android, and clang >= 3.0).
+ || __clang_major__ >= 3) \
+ && HAVE_ATOMIC_COMPARE_AND_SWAP_GCC41)
+/* Use GCC built-ins (available on many platforms with GCC >= 4.1 or
+ clang >= 3.0).
Documentation:
<https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html> */
diff --git a/modules/asyncsafe-spin b/modules/asyncsafe-spin
index fc734928db..ffb2429e65 100644
--- a/modules/asyncsafe-spin
+++ b/modules/asyncsafe-spin
@@ -4,6 +4,7 @@ Spin locks for communication between threads and signal handlers.
Files:
lib/asyncsafe-spin.h
lib/asyncsafe-spin.c
+m4/atomic-cas.m4
Depends-on:
signal-h
@@ -15,6 +16,7 @@ sparcv8+
configure.ac:
AC_REQUIRE([AC_C_INLINE])
AC_CHECK_HEADERS_ONCE([pthread.h])
+AC_REQUIRE([gl_ATOMIC_COMPARE_AND_SWAP])
Makefile.am:
lib_SOURCES += asyncsafe-spin.c
diff --git a/modules/pthread-spin b/modules/pthread-spin
index 35e3aa701e..36b6180c90 100644
--- a/modules/pthread-spin
+++ b/modules/pthread-spin
@@ -4,6 +4,7 @@ POSIX spin locks.
Files:
lib/pthread-spin.c
m4/pthread-spin.m4
+m4/atomic-cas.m4
Depends-on:
pthread-h
@@ -15,6 +16,7 @@ gl_PTHREAD_SPIN
gl_CONDITIONAL([GL_COND_OBJ_PTHREAD_SPIN],
[test $HAVE_PTHREAD_SPIN_INIT = 0 || test $REPLACE_PTHREAD_SPIN_INIT = 1])
gl_PTHREAD_MODULE_INDICATOR([pthread-spin])
+AC_REQUIRE([gl_ATOMIC_COMPARE_AND_SWAP])
Makefile.am:
if GL_COND_OBJ_PTHREAD_SPIN
diff --git a/modules/simple-atomic b/modules/simple-atomic
index 5f3f63d109..8558620580 100644
--- a/modules/simple-atomic
+++ b/modules/simple-atomic
@@ -4,6 +4,7 @@ Simple atomic operations for multithreading.
Files:
lib/simple-atomic.h
lib/simple-atomic.c
+m4/atomic-cas.m4
Depends-on:
stdint
@@ -11,6 +12,7 @@ sparcv8+
configure.ac:
AC_CHECK_HEADERS_ONCE([pthread.h])
+AC_REQUIRE([gl_ATOMIC_COMPARE_AND_SWAP])
Makefile.am:
lib_SOURCES += simple-atomic.c
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2024-01-21 15:16 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-01-21 15:16 asyncsafe-spin: Fix link error on various platforms Bruno Haible
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).