bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

asyncsafe-spin: Fix link error on various platforms


From: Bruno Haible
Subject: asyncsafe-spin: Fix link error on various platforms
Date: Sun, 21 Jan 2024 16:16:05 +0100

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






reply via email to

[Prev in Thread] Current Thread [Next in Thread]