[PATCH] S390: Remove support for lock elision.
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Wed Jul 2 15:53:15 GMT 2025
On 01/07/25 06:39, Stefan Liebler wrote:
> The support for TX lock elision of pthread mutexes on s390x is now removed.
>
> As already announced back in 2022 with z16, the used non-constrained
> transactions are now not usable anymore on z17
> (https://www.ibm.com/support/pages/system/files/inline-files/Tech%20Bytes%20May%202025%20zVM%207.4%20and%20IBM%20z17.pdf):
> z16 Statement of Direction:
> Removal of support of the transactional execution and constrained transactional
> execution facility: In a future IBM Z hardware system family, the transactional
> execution and constrained transactional execution facility will no longer be
> supported. Users of the facility on current servers should always check the
> facility indications before use.
>
> z17 Support:
> Reduced support for transactional execution (TX) - Non-constrained transactions
> will result in unconditionally aborting with condition code 1 (CC1) and no TDB
> stored.
I wonder if we still want to support it for x86 and powerpc. If I
recall correctly, x86 results are mixed and on some chips TSX was
disabled in firmware to avoid some odd issues. On POWER the kernel
added PPC_FEATURE2_HTM_NOSC to avoid some odd ssues as well.
> ---
> manual/tunables.texi | 5 +-
> sysdeps/s390/configure | 38 ----
> sysdeps/s390/configure.ac | 26 ---
> sysdeps/unix/sysv/linux/s390/Makefile | 8 -
> sysdeps/unix/sysv/linux/s390/elision-conf.c | 118 -----------
> sysdeps/unix/sysv/linux/s390/elision-conf.h | 40 ----
> sysdeps/unix/sysv/linux/s390/elision-lock.c | 120 -----------
> sysdeps/unix/sysv/linux/s390/elision-timed.c | 27 ---
> .../unix/sysv/linux/s390/elision-trylock.c | 98 ---------
> sysdeps/unix/sysv/linux/s390/elision-unlock.c | 62 ------
> sysdeps/unix/sysv/linux/s390/htm.h | 187 ------------------
> 11 files changed, 2 insertions(+), 727 deletions(-)
> delete mode 100644 sysdeps/unix/sysv/linux/s390/elision-conf.c
> delete mode 100644 sysdeps/unix/sysv/linux/s390/elision-conf.h
> delete mode 100644 sysdeps/unix/sysv/linux/s390/elision-lock.c
> delete mode 100644 sysdeps/unix/sysv/linux/s390/elision-timed.c
> delete mode 100644 sysdeps/unix/sysv/linux/s390/elision-trylock.c
> delete mode 100644 sysdeps/unix/sysv/linux/s390/elision-unlock.c
> delete mode 100644 sysdeps/unix/sysv/linux/s390/htm.h
>
> diff --git a/manual/tunables.texi b/manual/tunables.texi
> index d11ca7ed7c..1ba41f97f5 100644
> --- a/manual/tunables.texi
> +++ b/manual/tunables.texi
> @@ -405,8 +405,7 @@ The @code{glibc.elision.enable} tunable enables lock elision if the feature is
> supported by the hardware. If elision is not supported by the hardware this
> tunable has no effect.
>
> -Elision tunables are supported for 64-bit Intel, IBM POWER, and z System
> -architectures.
> +Elision tunables are supported for 64-bit Intel, and IBM POWER architectures.
> @end deftp
>
> @deftp Tunable glibc.elision.skip_lock_busy
> @@ -432,7 +431,7 @@ to try to elide a lock with transactions, that only failed due to a different
> thread's memory accesses, before falling back to regular lock.
> Expressed in number of lock elision attempts.
>
> -This tunable is supported only on IBM POWER, and z System architectures.
> +This tunable is supported only on IBM POWER architecture.
>
> The default value of this tunable is @samp{3}.
> @end deftp
> diff --git a/sysdeps/s390/configure b/sysdeps/s390/configure
> index 97f52524fb..e3766aa801 100644
> --- a/sysdeps/s390/configure
> +++ b/sysdeps/s390/configure
> @@ -1,44 +1,6 @@
> # This file is generated from configure.ac by Autoconf. DO NOT EDIT!
> # Local configure fragment for sysdeps/s390.
>
> -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __builtin_tbegin" >&5
> -printf %s "checking for __builtin_tbegin... " >&6; }
> -if test ${libc_cv_gcc_builtin_tbegin+y}
> -then :
> - printf %s "(cached) " >&6
> -else case e in #(
> - e) cat > conftest.c <<\EOF
> -#include <htmintrin.h>
> -void testtransaction ()
> -{
> - if (__builtin_tbegin (0) == _HTM_TBEGIN_STARTED)
> - {
> - __builtin_tend ();
> - }
> -}
> -EOF
> -if { ac_try='${CC-cc} -mhtm -O2 -S conftest.c -o - | grep -w tbegin > /dev/null'
> - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
> - (eval $ac_try) 2>&5
> - ac_status=$?
> - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> - test $ac_status = 0; }; } ;
> -then
> - libc_cv_gcc_builtin_tbegin=yes
> -else
> - libc_cv_gcc_builtin_tbegin=no
> -fi
> -rm -f conftest* ;;
> -esac
> -fi
> -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_gcc_builtin_tbegin" >&5
> -printf "%s\n" "$libc_cv_gcc_builtin_tbegin" >&6; }
> -
> -if test "$libc_cv_gcc_builtin_tbegin" = no ; then
> - critic_missing="$critic_missing The used GCC has no support for __builtin_tbegin, which is needed for lock-elision on target S390."
> -fi
> -
> -
>
> { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for S390 vector instruction support" >&5
> printf %s "checking for S390 vector instruction support... " >&6; }
> diff --git a/sysdeps/s390/configure.ac b/sysdeps/s390/configure.ac
> index 496866b850..4265bfd9f4 100644
> --- a/sysdeps/s390/configure.ac
> +++ b/sysdeps/s390/configure.ac
> @@ -1,32 +1,6 @@
> GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
> # Local configure fragment for sysdeps/s390.
>
> -AC_CACHE_CHECK(for __builtin_tbegin, libc_cv_gcc_builtin_tbegin, [dnl
> -cat > conftest.c <<\EOF
> -#include <htmintrin.h>
> -void testtransaction ()
> -{
> - if (__builtin_tbegin (0) == _HTM_TBEGIN_STARTED)
> - {
> - __builtin_tend ();
> - }
> -}
> -EOF
> -dnl
> -dnl test, if the tbegin instruction is used by __builtin_tbegin
> -if AC_TRY_COMMAND([${CC-cc} -mhtm -O2 -S conftest.c -o - | grep -w tbegin > /dev/null]) ;
> -then
> - libc_cv_gcc_builtin_tbegin=yes
> -else
> - libc_cv_gcc_builtin_tbegin=no
> -fi
> -rm -f conftest* ])
> -
> -if test "$libc_cv_gcc_builtin_tbegin" = no ; then
> - critic_missing="$critic_missing The used GCC has no support for __builtin_tbegin, which is needed for lock-elision on target S390."
> -fi
> -
> -
> AC_CACHE_CHECK([for S390 vector instruction support], libc_cv_asm_s390_vx, [
> AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
> void testvecinsn ()
> diff --git a/sysdeps/unix/sysv/linux/s390/Makefile b/sysdeps/unix/sysv/linux/s390/Makefile
> index 3de9579e23..d5433f1dd9 100644
> --- a/sysdeps/unix/sysv/linux/s390/Makefile
> +++ b/sysdeps/unix/sysv/linux/s390/Makefile
> @@ -11,14 +11,6 @@ ifeq ($(subdir),stdlib)
> gen-as-const-headers += ucontext_i.sym
> endif
>
> -ifeq ($(subdir),nptl)
> -elision-CFLAGS = -mhtm -msoft-float
> -CFLAGS-elision-lock.c = $(elision-CFLAGS)
> -CFLAGS-elision-timed.c = $(elision-CFLAGS)
> -CFLAGS-elision-trylock.c = $(elision-CFLAGS)
> -CFLAGS-elision-unlock.c = $(elision-CFLAGS)
> -endif
> -
> ifeq ($(subdir),misc)
> tests += tst-ptrace-singleblock
> endif
> diff --git a/sysdeps/unix/sysv/linux/s390/elision-conf.c b/sysdeps/unix/sysv/linux/s390/elision-conf.c
> deleted file mode 100644
> index 32b9b3a17d..0000000000
> --- a/sysdeps/unix/sysv/linux/s390/elision-conf.c
> +++ /dev/null
> @@ -1,118 +0,0 @@
> -/* Lock elision tunable parameters.
> - Copyright (C) 2014-2025 Free Software Foundation, Inc.
> - This file is part of the GNU C Library.
> -
> - The GNU C Library is free software; you can redistribute it and/or
> - modify it under the terms of the GNU Lesser General Public
> - License as published by the Free Software Foundation; either
> - version 2.1 of the License, or (at your option) any later version.
> -
> - The GNU C Library is distributed in the hope that it will be useful,
> - but WITHOUT ANY WARRANTY; without even the implied warranty of
> - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - Lesser General Public License for more details.
> -
> - You should have received a copy of the GNU Lesser General Public
> - License along with the GNU C Library; if not, see
> - <https://www.gnu.org/licenses/>. */
> -
> -#include <config.h>
> -#include <pthreadP.h>
> -#include <elision-conf.h>
> -#include <unistd.h>
> -#include <ldsodefs.h>
> -#include <sys/auxv.h>
> -
> -#define TUNABLE_NAMESPACE elision
> -#include <elf/dl-tunables.h>
> -
> -/* Reasonable initial tuning values, may be revised in the future.
> - This is a conservative initial value. */
> -
> -struct elision_config __elision_aconf =
> - {
> - /* How often to not attempt to use elision if a transaction aborted
> - because the lock is already acquired. Expressed in number of lock
> - acquisition attempts. */
> - .skip_lock_busy = 3,
> - /* How often to not attempt to use elision if a transaction aborted due
> - to reasons other than other threads' memory accesses. Expressed in
> - number of lock acquisition attempts. */
> - .skip_lock_internal_abort = 3,
> - /* How often to not attempt to use elision if a lock used up all retries
> - without success. Expressed in number of lock acquisition attempts. */
> - .skip_lock_out_of_tbegin_retries = 3,
> - /* How often we try using elision if there is chance for the transaction
> - to finish execution (e.g., it wasn't aborted due to the lock being
> - already acquired. */
> - .try_tbegin = 3,
> - /* Same as SKIP_LOCK_INTERNAL_ABORT but for trylock. */
> - .skip_trylock_internal_abort = 3,
> - };
> -
> -static inline void
> -__always_inline
> -do_set_elision_enable (int32_t elision_enable)
> -{
> - /* Enable elision if it's available in hardware. It's not necessary to check
> - if __libc_enable_secure isn't enabled since elision_enable will be set
> - according to the default, which is disabled. */
> - if (elision_enable == 1)
> - __pthread_force_elision = (GLRO (dl_hwcap) & HWCAP_S390_TE) ? 1 : 0;
> -}
> -
> -/* The pthread->elision_enable tunable is 0 or 1 indicating that elision
> - should be disabled or enabled respectively. The feature will only be used
> - if it's supported by the hardware. */
> -
> -void
> -TUNABLE_CALLBACK (set_elision_enable) (tunable_val_t *valp)
> -{
> - int32_t elision_enable = (int32_t) valp->numval;
> - do_set_elision_enable (elision_enable);
> -}
> -
> -#define TUNABLE_CALLBACK_FNDECL(__name, __type) \
> -static inline void \
> -__always_inline \
> -do_set_elision_ ## __name (__type value) \
> -{ \
> - __elision_aconf.__name = value; \
> -} \
> -void \
> -TUNABLE_CALLBACK (set_elision_ ## __name) (tunable_val_t *valp) \
> -{ \
> - __type value = (__type) (valp)->numval; \
> - do_set_elision_ ## __name (value); \
> -}
> -
> -TUNABLE_CALLBACK_FNDECL (skip_lock_busy, int32_t);
> -TUNABLE_CALLBACK_FNDECL (skip_lock_internal_abort, int32_t);
> -TUNABLE_CALLBACK_FNDECL (skip_lock_out_of_tbegin_retries, int32_t);
> -TUNABLE_CALLBACK_FNDECL (try_tbegin, int32_t);
> -TUNABLE_CALLBACK_FNDECL (skip_trylock_internal_abort, int32_t);
> -
> -/* Initialize elison. */
> -
> -void
> -__lll_elision_init (void)
> -{
> - /* Elision depends on tunables and must be explicitly turned on by setting
> - the appropriate tunable on a supported platform. */
> -
> - TUNABLE_GET (enable, int32_t,
> - TUNABLE_CALLBACK (set_elision_enable));
> - TUNABLE_GET (skip_lock_busy, int32_t,
> - TUNABLE_CALLBACK (set_elision_skip_lock_busy));
> - TUNABLE_GET (skip_lock_internal_abort, int32_t,
> - TUNABLE_CALLBACK (set_elision_skip_lock_internal_abort));
> - TUNABLE_GET (skip_lock_after_retries, int32_t,
> - TUNABLE_CALLBACK (set_elision_skip_lock_out_of_tbegin_retries));
> - TUNABLE_GET (tries, int32_t,
> - TUNABLE_CALLBACK (set_elision_try_tbegin));
> - TUNABLE_GET (skip_trylock_internal_abort, int32_t,
> - TUNABLE_CALLBACK (set_elision_skip_trylock_internal_abort));
> -
> - if (!__pthread_force_elision)
> - __elision_aconf.try_tbegin = 0; /* Disable elision on rwlocks. */
> -}
> diff --git a/sysdeps/unix/sysv/linux/s390/elision-conf.h b/sysdeps/unix/sysv/linux/s390/elision-conf.h
> deleted file mode 100644
> index 90845de01e..0000000000
> --- a/sysdeps/unix/sysv/linux/s390/elision-conf.h
> +++ /dev/null
> @@ -1,40 +0,0 @@
> -/* Lock elision tunable parameters.
> - Copyright (C) 2014-2025 Free Software Foundation, Inc.
> - This file is part of the GNU C Library.
> -
> - The GNU C Library is free software; you can redistribute it and/or
> - modify it under the terms of the GNU Lesser General Public
> - License as published by the Free Software Foundation; either
> - version 2.1 of the License, or (at your option) any later version.
> -
> - The GNU C Library is distributed in the hope that it will be useful,
> - but WITHOUT ANY WARRANTY; without even the implied warranty of
> - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - Lesser General Public License for more details.
> -
> - You should have received a copy of the GNU Lesser General Public
> - License along with the GNU C Library; if not, see
> - <https://www.gnu.org/licenses/>. */
> -#ifndef _ELISION_CONF_H
> -#define _ELISION_CONF_H 1
> -
> -#include <pthread.h>
> -#include <time.h>
> -
> -#define ENABLE_ELISION_SUPPORT 1
> -#define ELISION_UNLOCK_NEEDS_ADAPT_COUNT 1
> -
> -/* Should make sure there is no false sharing on this. */
> -
> -struct elision_config
> -{
> - int skip_lock_busy;
> - int skip_lock_internal_abort;
> - int skip_lock_out_of_tbegin_retries;
> - int try_tbegin;
> - int skip_trylock_internal_abort;
> -};
> -
> -extern struct elision_config __elision_aconf attribute_hidden;
> -
> -#endif
> diff --git a/sysdeps/unix/sysv/linux/s390/elision-lock.c b/sysdeps/unix/sysv/linux/s390/elision-lock.c
> deleted file mode 100644
> index b22e6cd938..0000000000
> --- a/sysdeps/unix/sysv/linux/s390/elision-lock.c
> +++ /dev/null
> @@ -1,120 +0,0 @@
> -/* Elided pthread mutex lock.
> - Copyright (C) 2014-2025 Free Software Foundation, Inc.
> - This file is part of the GNU C Library.
> -
> - The GNU C Library is free software; you can redistribute it and/or
> - modify it under the terms of the GNU Lesser General Public
> - License as published by the Free Software Foundation; either
> - version 2.1 of the License, or (at your option) any later version.
> -
> - The GNU C Library is distributed in the hope that it will be useful,
> - but WITHOUT ANY WARRANTY; without even the implied warranty of
> - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - Lesser General Public License for more details.
> -
> - You should have received a copy of the GNU Lesser General Public
> - License along with the GNU C Library; if not, see
> - <https://www.gnu.org/licenses/>. */
> -
> -#include <pthread.h>
> -#include <pthreadP.h>
> -#include <lowlevellock.h>
> -#include <htm.h>
> -#include <elision-conf.h>
> -#include <stdint.h>
> -
> -#ifndef EXTRAARG
> -#define EXTRAARG
> -#endif
> -#ifndef LLL_LOCK
> -#define LLL_LOCK(a,b) lll_lock(a,b), 0
> -#endif
> -
> -#define aconf __elision_aconf
> -
> -/* Adaptive lock using transactions.
> - By default the lock region is run as a transaction, and when it
> - aborts or the lock is busy the lock adapts itself. */
> -
> -int
> -__lll_lock_elision (int *futex, short *adapt_count, EXTRAARG int private)
> -{
> - /* adapt_count can be accessed concurrently; these accesses can be both
> - inside of transactions (if critical sections are nested and the outer
> - critical section uses lock elision) and outside of transactions. Thus,
> - we need to use atomic accesses to avoid data races. However, the
> - value of adapt_count is just a hint, so relaxed MO accesses are
> - sufficient. */
> - if (atomic_load_relaxed (adapt_count) <= 0 && aconf.try_tbegin > 0)
> - {
> - /* Start a transaction and retry it automatically if it aborts with
> - _HTM_TBEGIN_TRANSIENT. This macro calls tbegin at most retry_cnt
> - + 1 times. The second argument is considered as retry_cnt. */
> - int status = __libc_tbegin_retry ((void *) 0, aconf.try_tbegin - 1);
> - if (__glibc_likely (status == _HTM_TBEGIN_STARTED))
> - {
> - /* Check the futex to make sure nobody has touched it in the
> - mean time. This forces the futex into the cache and makes
> - sure the transaction aborts if another thread acquires the lock
> - concurrently. */
> - if (__glibc_likely (atomic_load_relaxed (futex) == 0))
> - /* Lock was free. Return to user code in a transaction. */
> - return 0;
> -
> - /* Lock was busy. Fall back to normal locking.
> - This can be the case if e.g. adapt_count was decremented to zero
> - by a former release and another thread has been waken up and
> - acquired it. */
> - if (__glibc_likely (__libc_tx_nesting_depth () <= 1))
> - {
> - /* In a non-nested transaction there is no need to abort,
> - which is expensive. Simply end the started transaction. */
> - __libc_tend ();
> - /* Don't try to use transactions for the next couple of times.
> - See above for why relaxed MO is sufficient. */
> - if (aconf.skip_lock_busy > 0)
> - atomic_store_relaxed (adapt_count, aconf.skip_lock_busy);
> - }
> - else /* nesting depth is > 1 */
> - {
> - /* A nested transaction will abort eventually because it
> - cannot make any progress before *futex changes back to 0.
> - So we may as well abort immediately.
> - This persistently aborts the outer transaction to force
> - the outer mutex use the default lock instead of retrying
> - with transactions until the try_tbegin of the outer mutex
> - is zero.
> - The adapt_count of this inner mutex is not changed,
> - because using the default lock with the inner mutex
> - would abort the outer transaction. */
> - __libc_tabort (_HTM_FIRST_USER_ABORT_CODE | 1);
> - __builtin_unreachable ();
> - }
> - }
> - else if (status != _HTM_TBEGIN_TRANSIENT)
> - {
> - /* A persistent abort (cc 1 or 3) indicates that a retry is
> - probably futile. Use the normal locking now and for the
> - next couple of calls.
> - Be careful to avoid writing to the lock. See above for why
> - relaxed MO is sufficient. */
> - if (aconf.skip_lock_internal_abort > 0)
> - atomic_store_relaxed (adapt_count,
> - aconf.skip_lock_internal_abort);
> - }
> - else
> - {
> - /* The transaction failed for some retries with
> - _HTM_TBEGIN_TRANSIENT. Use the normal locking now and for the
> - next couple of calls. */
> - if (aconf.skip_lock_out_of_tbegin_retries > 0)
> - atomic_store_relaxed (adapt_count,
> - aconf.skip_lock_out_of_tbegin_retries);
> - }
> - }
> -
> - /* Use normal locking as fallback path if the transaction does not
> - succeed. */
> - return LLL_LOCK ((*futex), private);
> -}
> -libc_hidden_def (__lll_lock_elision)
> diff --git a/sysdeps/unix/sysv/linux/s390/elision-timed.c b/sysdeps/unix/sysv/linux/s390/elision-timed.c
> deleted file mode 100644
> index 2611e9cf9b..0000000000
> --- a/sysdeps/unix/sysv/linux/s390/elision-timed.c
> +++ /dev/null
> @@ -1,27 +0,0 @@
> -/* Lock elision timed lock.
> - Copyright (C) 2014-2025 Free Software Foundation, Inc.
> - This file is part of the GNU C Library.
> -
> - The GNU C Library is free software; you can redistribute it and/or
> - modify it under the terms of the GNU Lesser General Public
> - License as published by the Free Software Foundation; either
> - version 2.1 of the License, or (at your option) any later version.
> -
> - The GNU C Library is distributed in the hope that it will be useful,
> - but WITHOUT ANY WARRANTY; without even the implied warranty of
> - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - Lesser General Public License for more details.
> -
> - You should have received a copy of the GNU Lesser General Public
> - License along with the GNU C Library; if not, see
> - <https://www.gnu.org/licenses/>. */
> -
> -#include <time.h>
> -#include <elision-conf.h>
> -#include <lowlevellock.h>
> -#include "futex-internal.h"
> -#define __lll_lock_elision __lll_clocklock_elision
> -#define EXTRAARG clockid_t clockid, const struct __timespec64 *t,
> -#undef LLL_LOCK
> -#define LLL_LOCK(a, b) __futex_clocklock64 (&(a), clockid, t, b)
> -#include "elision-lock.c"
> diff --git a/sysdeps/unix/sysv/linux/s390/elision-trylock.c b/sysdeps/unix/sysv/linux/s390/elision-trylock.c
> deleted file mode 100644
> index 1aa99d806c..0000000000
> --- a/sysdeps/unix/sysv/linux/s390/elision-trylock.c
> +++ /dev/null
> @@ -1,98 +0,0 @@
> -/* Elided pthread mutex trylock.
> - Copyright (C) 2014-2025 Free Software Foundation, Inc.
> - This file is part of the GNU C Library.
> -
> - The GNU C Library is free software; you can redistribute it and/or
> - modify it under the terms of the GNU Lesser General Public
> - License as published by the Free Software Foundation; either
> - version 2.1 of the License, or (at your option) any later version.
> -
> - The GNU C Library is distributed in the hope that it will be useful,
> - but WITHOUT ANY WARRANTY; without even the implied warranty of
> - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - Lesser General Public License for more details.
> -
> - You should have received a copy of the GNU Lesser General Public
> - License along with the GNU C Library; if not, see
> - <https://www.gnu.org/licenses/>. */
> -
> -#include <pthread.h>
> -#include <pthreadP.h>
> -#include <lowlevellock.h>
> -#include <htm.h>
> -#include <elision-conf.h>
> -
> -#define aconf __elision_aconf
> -
> -/* Try to elide a futex trylock. FUTEX is the futex variable. ADAPT_COUNT is
> - the adaptation counter in the mutex. */
> -
> -int
> -__lll_trylock_elision (int *futex, short *adapt_count)
> -{
> - /* Implement POSIX semantics by forbiding nesting elided trylocks.
> - Sorry. After the abort the code is re-executed
> - non transactional and if the lock was already locked
> - return an error. */
> - if (__libc_tx_nesting_depth () > 0)
> - {
> - /* Note that this abort may terminate an outermost transaction that
> - was created outside glibc.
> - This persistently aborts the current transactions to force
> - them to use the default lock instead of retrying transactions
> - until their try_tbegin is zero.
> - */
> - __libc_tabort (_HTM_FIRST_USER_ABORT_CODE | 1);
> - __builtin_unreachable ();
> - }
> -
> - /* adapt_count can be accessed concurrently; these accesses can be both
> - inside of transactions (if critical sections are nested and the outer
> - critical section uses lock elision) and outside of transactions. Thus,
> - we need to use atomic accesses to avoid data races. However, the
> - value of adapt_count is just a hint, so relaxed MO accesses are
> - sufficient. */
> - if (atomic_load_relaxed (adapt_count) <= 0 && aconf.try_tbegin > 0)
> - {
> - int status = __libc_tbegin ((void *) 0);
> - if (__glibc_likely (status == _HTM_TBEGIN_STARTED))
> - {
> - /* Check the futex to make sure nobody has touched it in the
> - mean time. This forces the futex into the cache and makes
> - sure the transaction aborts if another thread acquires the lock
> - concurrently. */
> - if (__glibc_likely (atomic_load_relaxed (futex) == 0))
> - /* Lock was free. Return to user code in a transaction. */
> - return 0;
> -
> - /* Lock was busy. Fall back to normal locking.
> - This can be the case if e.g. adapt_count was decremented to zero
> - by a former release and another thread has been waken up and
> - acquired it.
> - Since we are in a non-nested transaction there is no need to abort,
> - which is expensive. Simply end the started transaction. */
> - __libc_tend ();
> - /* Note: Changing the adapt_count here might abort a transaction on a
> - different CPU, but that could happen anyway when the futex is
> - acquired, so there's no need to check the nesting depth here.
> - See above for why relaxed MO is sufficient. */
> - if (aconf.skip_lock_busy > 0)
> - atomic_store_relaxed (adapt_count, aconf.skip_lock_busy);
> - }
> - else if (status != _HTM_TBEGIN_TRANSIENT)
> - {
> - /* A persistent abort (cc 1 or 3) indicates that a retry is
> - probably futile. Use the normal locking now and for the
> - next couple of calls.
> - Be careful to avoid writing to the lock. */
> - if (aconf.skip_trylock_internal_abort > 0)
> - *adapt_count = aconf.skip_trylock_internal_abort;
> - }
> - /* Could do some retries here. */
> - }
> -
> - /* Use normal locking as fallback path if the transaction does not
> - succeed. */
> - return lll_trylock (*futex);
> -}
> -libc_hidden_def (__lll_trylock_elision)
> diff --git a/sysdeps/unix/sysv/linux/s390/elision-unlock.c b/sysdeps/unix/sysv/linux/s390/elision-unlock.c
> deleted file mode 100644
> index 11e96abd5f..0000000000
> --- a/sysdeps/unix/sysv/linux/s390/elision-unlock.c
> +++ /dev/null
> @@ -1,62 +0,0 @@
> -/* Commit an elided pthread lock.
> - Copyright (C) 2014-2025 Free Software Foundation, Inc.
> - This file is part of the GNU C Library.
> -
> - The GNU C Library is free software; you can redistribute it and/or
> - modify it under the terms of the GNU Lesser General Public
> - License as published by the Free Software Foundation; either
> - version 2.1 of the License, or (at your option) any later version.
> -
> - The GNU C Library is distributed in the hope that it will be useful,
> - but WITHOUT ANY WARRANTY; without even the implied warranty of
> - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - Lesser General Public License for more details.
> -
> - You should have received a copy of the GNU Lesser General Public
> - License along with the GNU C Library; if not, see
> - <https://www.gnu.org/licenses/>. */
> -
> -#include <pthreadP.h>
> -#include <lowlevellock.h>
> -#include <htm.h>
> -
> -int
> -__lll_unlock_elision(int *futex, short *adapt_count, int private)
> -{
> - /* If the lock is free, we elided the lock earlier. This does not
> - necessarily mean that we are in a transaction, because the user code may
> - have closed the transaction, but that is impossible to detect reliably.
> - Relaxed MO access to futex is sufficient because a correct program
> - will only release a lock it has acquired; therefore, it must either
> - changed the futex word's value to something !=0 or it must have used
> - elision; these are actions by the same thread, so these actions are
> - sequenced-before the relaxed load (and thus also happens-before the
> - relaxed load). Therefore, relaxed MO is sufficient. */
> - if (atomic_load_relaxed (futex) == 0)
> - {
> - __libc_tend ();
> - }
> - else
> - {
> - /* Update the adapt_count while unlocking before completing the critical
> - section. adapt_count is accessed concurrently outside of a
> - transaction or a critical section (e.g. in elision-lock.c). So we need
> - to use atomic accesses. However, the value of adapt_count is just a
> - hint, so relaxed MO accesses are sufficient.
> - If adapt_count would be decremented while locking, multiple
> - CPUs, trying to lock the acquired mutex, will decrement adapt_count to
> - zero and another CPU will try to start a transaction, which will be
> - immediately aborted as the mutex is locked.
> - The update of adapt_count is done before releasing the lock as POSIX'
> - mutex destruction requirements disallow accesses to the mutex after it
> - has been released and thus could have been acquired or destroyed by
> - another thread. */
> - short adapt_count_val = atomic_load_relaxed (adapt_count);
> - if (adapt_count_val > 0)
> - atomic_store_relaxed (adapt_count, adapt_count_val - 1);
> -
> - lll_unlock ((*futex), private);
> - }
> - return 0;
> -}
> -libc_hidden_def (__lll_unlock_elision)
> diff --git a/sysdeps/unix/sysv/linux/s390/htm.h b/sysdeps/unix/sysv/linux/s390/htm.h
> deleted file mode 100644
> index bf1a89c1a5..0000000000
> --- a/sysdeps/unix/sysv/linux/s390/htm.h
> +++ /dev/null
> @@ -1,187 +0,0 @@
> -/* Shared HTM header. Work around false transactional execution facility
> - intrinsics.
> -
> - Copyright (C) 2016-2025 Free Software Foundation, Inc.
> - This file is part of the GNU C Library.
> -
> - The GNU C Library is free software; you can redistribute it and/or
> - modify it under the terms of the GNU Lesser General Public
> - License as published by the Free Software Foundation; either
> - version 2.1 of the License, or (at your option) any later version.
> -
> - The GNU C Library is distributed in the hope that it will be useful,
> - but WITHOUT ANY WARRANTY; without even the implied warranty of
> - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - Lesser General Public License for more details.
> -
> - You should have received a copy of the GNU Lesser General Public
> - License along with the GNU C Library; if not, see
> - <https://www.gnu.org/licenses/>. */
> -
> -#ifndef _HTM_H
> -#define _HTM_H 1
> -
> -#include <htmintrin.h>
> -
> -#ifdef __s390x__
> -# define TX_FPRS_BYTES 64
> -# define TX_SAVE_FPRS \
> - " std %%f8, 0(%[R_FPRS])\n\t" \
> - " std %%f9, 8(%[R_FPRS])\n\t" \
> - " std %%f10, 16(%[R_FPRS])\n\t" \
> - " std %%f11, 24(%[R_FPRS])\n\t" \
> - " std %%f12, 32(%[R_FPRS])\n\t" \
> - " std %%f13, 40(%[R_FPRS])\n\t" \
> - " std %%f14, 48(%[R_FPRS])\n\t" \
> - " std %%f15, 56(%[R_FPRS])\n\t"
> -
> -# define TX_RESTORE_FPRS \
> - " ld %%f8, 0(%[R_FPRS])\n\t" \
> - " ld %%f9, 8(%[R_FPRS])\n\t" \
> - " ld %%f10, 16(%[R_FPRS])\n\t" \
> - " ld %%f11, 24(%[R_FPRS])\n\t" \
> - " ld %%f12, 32(%[R_FPRS])\n\t" \
> - " ld %%f13, 40(%[R_FPRS])\n\t" \
> - " ld %%f14, 48(%[R_FPRS])\n\t" \
> - " ld %%f15, 56(%[R_FPRS])\n\t"
> -
> -#else
> -
> -# define TX_FPRS_BYTES 16
> -# define TX_SAVE_FPRS \
> - " std %%f4, 0(%[R_FPRS])\n\t" \
> - " std %%f6, 8(%[R_FPRS])\n\t"
> -
> -# define TX_RESTORE_FPRS \
> - " ld %%f4, 0(%[R_FPRS])\n\t" \
> - " ld %%f6, 8(%[R_FPRS])\n\t"
> -
> -#endif /* ! __s390x__ */
> -
> -/* Use own inline assembly instead of __builtin_tbegin, as tbegin
> - has to filter program interruptions which can't be done with the builtin.
> - Now the fprs have to be saved / restored here, too.
> - The fpc is also not saved / restored with the builtin.
> - The used inline assembly does not clobber the volatile fprs / vrs!
> - Clobbering the latter ones would force the compiler to save / restore
> - the call saved fprs as those overlap with the vrs, but they only need to be
> - restored if the transaction fails but not if the transaction is successfully
> - started. Thus the user of the tbegin macros in this header file has to
> - compile the file / function with -msoft-float. It prevents gcc from using
> - fprs / vrs. */
> -#define __libc_tbegin(tdb) __libc_tbegin_base(tdb,,,)
> -
> -#define __libc_tbegin_retry_output_regs , [R_TX_CNT] "+&d" (__tx_cnt)
> -#define __libc_tbegin_retry_input_regs(retry_cnt) , [R_RETRY] "d" (retry_cnt)
> -#define __libc_tbegin_retry_abort_path_insn \
> - /* If tbegin returned _HTM_TBEGIN_TRANSIENT, retry immediately so \
> - that max tbegin_cnt transactions are tried. Otherwise return and \
> - let the caller of this macro do the fallback path. */ \
> - " jnh 1f\n\t" /* cc 1/3: jump to fallback path. */ \
> - /* tbegin returned _HTM_TBEGIN_TRANSIENT: retry with transaction. */ \
> - " crje %[R_TX_CNT], %[R_RETRY], 1f\n\t" /* Reached max retries? */ \
> - " ahi %[R_TX_CNT], 1\n\t" \
> - " ppa %[R_TX_CNT], 0, 1\n\t" /* Transaction-Abort Assist. */ \
> - " j 2b\n\t" /* Loop to tbegin. */
> -
> -/* Same as __libc_tbegin except if tbegin aborts with _HTM_TBEGIN_TRANSIENT.
> - Then this macros restores the fpc, fprs and automatically retries up to
> - retry_cnt tbegins. Further saving of the state is omitted as it is already
> - saved. This macro calls tbegin at most as retry_cnt + 1 times. */
> -#define __libc_tbegin_retry(tdb, retry_cnt) \
> - ({ int __ret; \
> - int __tx_cnt = 0; \
> - __ret = __libc_tbegin_base(tdb, \
> - __libc_tbegin_retry_abort_path_insn, \
> - __libc_tbegin_retry_output_regs, \
> - __libc_tbegin_retry_input_regs(retry_cnt)); \
> - __ret; \
> - })
> -
> -#define __libc_tbegin_base(tdb, abort_path_insn, output_regs, input_regs) \
> - ({ int __ret; \
> - int __fpc; \
> - char __fprs[TX_FPRS_BYTES]; \
> - __asm__ __volatile__ (".machine push\n\t" \
> - ".machinemode \"zarch_nohighgprs\"\n\t" \
> - ".machine \"all\"\n\t" \
> - /* Save state at the outermost transaction. \
> - As extracting nesting depth is expensive \
> - on at least zEC12, save fprs at inner \
> - transactions, too. \
> - The fpc and fprs are saved here as they \
> - are not saved by tbegin. There exist no \
> - call-saved vrs, thus they are not saved \
> - here. */ \
> - " efpc %[R_FPC]\n\t" \
> - TX_SAVE_FPRS \
> - /* Begin transaction: save all gprs, allow \
> - ar modification and fp operations. Some \
> - program-interruptions (e.g. a null \
> - pointer access) are filtered and the \
> - transaction will abort. In this case \
> - the normal lock path will execute it \
> - again and result in a core dump which does \
> - now show at tbegin but the real executed \
> - instruction. \
> - However it is not guaranteed that this \
> - retry operate on the same data and thus \
> - may not end in an program-interruption. \
> - Note: This could also be used to probe \
> - memory for being accessible! */ \
> - "2: tbegin 0, 0xFF0E\n\t" \
> - /* Branch away in abort case (this is the \
> - preferred sequence. See PoP in chapter 5 \
> - Transactional-Execution Facility \
> - Operation). */ \
> - " jnz 0f\n\t" \
> - /* Transaction has successfully started. */ \
> - " lhi %[R_RET], 0\n\t" \
> - " j 1f\n\t" \
> - /* Transaction has aborted. Now we are at \
> - the outermost transaction. Restore fprs \
> - and fpc. */ \
> - "0: ipm %[R_RET]\n\t" \
> - " srl %[R_RET], 28\n\t" \
> - " sfpc %[R_FPC]\n\t" \
> - TX_RESTORE_FPRS \
> - abort_path_insn \
> - "1:\n\t" \
> - ".machine pop\n" \
> - : [R_RET] "=&d" (__ret), \
> - [R_FPC] "=&d" (__fpc) \
> - output_regs \
> - : [R_FPRS] "a" (__fprs) \
> - input_regs \
> - : "cc", "memory"); \
> - __ret; \
> - })
> -
> -/* These builtins are usable in context of glibc lock elision code without any
> - changes. Use them. */
> -#define __libc_tend() \
> - ({ __asm__ __volatile__ (".machine push\n\t" \
> - ".machinemode \"zarch_nohighgprs\"\n\t" \
> - ".machine \"all\"\n\t"); \
> - int __ret = __builtin_tend (); \
> - __asm__ __volatile__ (".machine pop"); \
> - __ret; \
> - })
> -
> -#define __libc_tabort(abortcode) \
> - __asm__ __volatile__ (".machine push\n\t" \
> - ".machinemode \"zarch_nohighgprs\"\n\t" \
> - ".machine \"all\"\n\t"); \
> - __builtin_tabort (abortcode); \
> - __asm__ __volatile__ (".machine pop")
> -
> -#define __libc_tx_nesting_depth() \
> - ({ __asm__ __volatile__ (".machine push\n\t" \
> - ".machinemode \"zarch_nohighgprs\"\n\t" \
> - ".machine \"all\"\n\t"); \
> - int __ret = __builtin_tx_nesting_depth (); \
> - __asm__ __volatile__ (".machine pop"); \
> - __ret; \
> - })
> -
> -#endif
More information about the Libc-alpha
mailing list