[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