[PATCH] S390: Remove support for lock elision.
Stefan Liebler
stli@linux.ibm.com
Tue Jul 1 09:39:04 GMT 2025
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.
---
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
--
2.47.1
More information about the Libc-alpha
mailing list