Blame sysdeps/unix/sysv/linux/s390/elision-conf.c

Packit 6c4009
/* Lock elision tunable parameters.
Packit 6c4009
   Copyright (C) 2014-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <config.h>
Packit 6c4009
#include <pthreadP.h>
Packit 6c4009
#include <elision-conf.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <dl-procinfo.h>
Packit 6c4009
Packit 6c4009
#if HAVE_TUNABLES
Packit 6c4009
# define TUNABLE_NAMESPACE elision
Packit 6c4009
#endif
Packit 6c4009
#include <elf/dl-tunables.h>
Packit 6c4009
Packit 6c4009
/* Reasonable initial tuning values, may be revised in the future.
Packit 6c4009
   This is a conservative initial value.  */
Packit 6c4009
Packit 6c4009
struct elision_config __elision_aconf =
Packit 6c4009
  {
Packit 6c4009
    /* How often to not attempt to use elision if a transaction aborted
Packit 6c4009
       because the lock is already acquired.  Expressed in number of lock
Packit 6c4009
       acquisition attempts.  */
Packit 6c4009
    .skip_lock_busy = 3,
Packit 6c4009
    /* How often to not attempt to use elision if a transaction aborted due
Packit 6c4009
       to reasons other than other threads' memory accesses.  Expressed in
Packit 6c4009
       number of lock acquisition attempts.  */
Packit 6c4009
    .skip_lock_internal_abort = 3,
Packit 6c4009
    /* How often to not attempt to use elision if a lock used up all retries
Packit 6c4009
       without success.  Expressed in number of lock acquisition attempts.  */
Packit 6c4009
    .skip_lock_out_of_tbegin_retries = 3,
Packit 6c4009
    /* How often we try using elision if there is chance for the transaction
Packit 6c4009
       to finish execution (e.g., it wasn't aborted due to the lock being
Packit 6c4009
       already acquired.  */
Packit 6c4009
    .try_tbegin = 3,
Packit 6c4009
    /* Same as SKIP_LOCK_INTERNAL_ABORT but for trylock.  */
Packit 6c4009
    .skip_trylock_internal_abort = 3,
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
/* Force elision for all new locks.  This is used to decide whether existing
Packit 6c4009
   DEFAULT locks should be automatically upgraded to elision in
Packit 6c4009
   pthread_mutex_lock().  Disabled for suid programs.  Only used when elision
Packit 6c4009
   is available.  */
Packit 6c4009
Packit 6c4009
int __pthread_force_elision attribute_hidden = 0;
Packit 6c4009
Packit 6c4009
#if HAVE_TUNABLES
Packit 6c4009
static inline void
Packit 6c4009
__always_inline
Packit 6c4009
do_set_elision_enable (int32_t elision_enable)
Packit 6c4009
{
Packit 6c4009
  /* Enable elision if it's avaliable in hardware. It's not necessary to check
Packit 6c4009
     if __libc_enable_secure isn't enabled since elision_enable will be set
Packit 6c4009
     according to the default, which is disabled.  */
Packit 6c4009
  if (elision_enable == 1)
Packit 6c4009
    __pthread_force_elision = (GLRO (dl_hwcap) & HWCAP_S390_TE) ? 1 : 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* The pthread->elision_enable tunable is 0 or 1 indicating that elision
Packit 6c4009
   should be disabled or enabled respectively.  The feature will only be used
Packit 6c4009
   if it's supported by the hardware.  */
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
TUNABLE_CALLBACK (set_elision_enable) (tunable_val_t *valp)
Packit 6c4009
{
Packit 6c4009
  int32_t elision_enable = (int32_t) valp->numval;
Packit 6c4009
  do_set_elision_enable (elision_enable);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define TUNABLE_CALLBACK_FNDECL(__name, __type)			\
Packit 6c4009
static inline void						\
Packit 6c4009
__always_inline							\
Packit 6c4009
do_set_elision_ ## __name (__type value)			\
Packit 6c4009
{								\
Packit 6c4009
  __elision_aconf.__name = value;				\
Packit 6c4009
}								\
Packit 6c4009
void								\
Packit 6c4009
TUNABLE_CALLBACK (set_elision_ ## __name) (tunable_val_t *valp) \
Packit 6c4009
{								\
Packit 6c4009
  __type value = (__type) (valp)->numval;			\
Packit 6c4009
  do_set_elision_ ## __name (value);				\
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
TUNABLE_CALLBACK_FNDECL (skip_lock_busy, int32_t);
Packit 6c4009
TUNABLE_CALLBACK_FNDECL (skip_lock_internal_abort, int32_t);
Packit 6c4009
TUNABLE_CALLBACK_FNDECL (skip_lock_out_of_tbegin_retries, int32_t);
Packit 6c4009
TUNABLE_CALLBACK_FNDECL (try_tbegin, int32_t);
Packit 6c4009
TUNABLE_CALLBACK_FNDECL (skip_trylock_internal_abort, int32_t);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Initialize elison.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
elision_init (int argc __attribute__ ((unused)),
Packit 6c4009
	      char **argv  __attribute__ ((unused)),
Packit 6c4009
	      char **environ)
Packit 6c4009
{
Packit 6c4009
#if HAVE_TUNABLES
Packit 6c4009
  /* Elision depends on tunables and must be explicitly turned on by setting
Packit 6c4009
     the appropriate tunable on a supported platform.  */
Packit 6c4009
Packit 6c4009
  TUNABLE_GET (enable, int32_t,
Packit 6c4009
	       TUNABLE_CALLBACK (set_elision_enable));
Packit 6c4009
  TUNABLE_GET (skip_lock_busy, int32_t,
Packit 6c4009
	       TUNABLE_CALLBACK (set_elision_skip_lock_busy));
Packit 6c4009
  TUNABLE_GET (skip_lock_internal_abort, int32_t,
Packit 6c4009
	       TUNABLE_CALLBACK (set_elision_skip_lock_internal_abort));
Packit 6c4009
  TUNABLE_GET (skip_lock_after_retries, int32_t,
Packit 6c4009
	       TUNABLE_CALLBACK (set_elision_skip_lock_out_of_tbegin_retries));
Packit 6c4009
  TUNABLE_GET (tries, int32_t,
Packit 6c4009
	       TUNABLE_CALLBACK (set_elision_try_tbegin));
Packit 6c4009
  TUNABLE_GET (skip_trylock_internal_abort, int32_t,
Packit 6c4009
	       TUNABLE_CALLBACK (set_elision_skip_trylock_internal_abort));
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  if (!__pthread_force_elision)
Packit 6c4009
    __elision_aconf.try_tbegin = 0; /* Disable elision on rwlocks.  */
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
# define INIT_SECTION ".init_array"
Packit 6c4009
# define MAYBE_CONST
Packit 6c4009
#else
Packit 6c4009
# define INIT_SECTION ".preinit_array"
Packit 6c4009
# define MAYBE_CONST const
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
void (*MAYBE_CONST __pthread_init_array []) (int, char **, char **)
Packit 6c4009
  __attribute__ ((section (INIT_SECTION), aligned (sizeof (void *)))) =
Packit 6c4009
{
Packit 6c4009
  &elision_init
Packit 6c4009
};