588 lines
19 KiB
Diff
588 lines
19 KiB
Diff
|
|
From 1cdbe579482c07e9f4bb3baa4864da2d3e7eb837 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Andi Kleen <ak@linux.intel.com>
|
||
|
|
Date: Sat, 10 Nov 2012 00:51:26 -0800i
|
||
|
|
Subject: [PATCH 6/9] build extra lipthreadcond so
|
||
|
|
|
||
|
|
add elsion functions which moved to libc in glibc-2.34.
|
||
|
|
Some attributes are changed and cannot be directly referenced.
|
||
|
|
|
||
|
|
|
||
|
|
---
|
||
|
|
nptl_2_17/lll_timedlock_wait_2_17.c | 59 +++++++++++++++++++++++++++++
|
||
|
|
nptl_2_17/elision-conf_2_17.c | 138 +++++++++++++++++++++++++++++++
|
||
|
|
nptl_2_17/elision-lock_2_17.c | 107 ++++++++++++++++++++++++
|
||
|
|
nptl_2_17/elision-timed_2_17.c | 27 ++++++
|
||
|
|
nptl_2_17/elision-trylock_2_17.c | 75 +++++++++++++++++
|
||
|
|
nptl_2_17/elision-unlock_2_17.c | 34 ++++++++
|
||
|
|
nptl_2_17/hle_2_17.h | 75 +++++++++++++++++
|
||
|
|
6 files changed, 515
|
||
|
|
insertions(+)
|
||
|
|
create mode 100644 nptl_2_17/lll_timedlock_wait_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/elision-conf_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/elision-lock_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/elision-timed_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/elision-trylock_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/elision-unlock_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/hle_2_17.h
|
||
|
|
|
||
|
|
diff --git a/nptl_2_17/lll_timedlock_wait_2_17.c b/nptl_2_17/lll_timedlock_wait_2_17.c
|
||
|
|
new file mode 100644
|
||
|
|
index 00000000..91bf9637
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/nptl_2_17/lll_timedlock_wait_2_17.c
|
||
|
|
@@ -0,0 +1,59 @@
|
||
|
|
+/* Timed low level locking for pthread library. Generic futex-using version.
|
||
|
|
+ Copyright (C) 2003-2018 Free Software Foundation, Inc.
|
||
|
|
+ This file is part of the GNU C Library.
|
||
|
|
+ Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
|
||
|
|
+
|
||
|
|
+ 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include <atomic.h>
|
||
|
|
+#include <errno.h>
|
||
|
|
+#include <lowlevellock.h>
|
||
|
|
+#include <sys/time.h>
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+int
|
||
|
|
+__lll_timedlock_wait (int *futex, const struct timespec *abstime, int private)
|
||
|
|
+{
|
||
|
|
+ /* Reject invalid timeouts. */
|
||
|
|
+ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
|
||
|
|
+ return EINVAL;
|
||
|
|
+
|
||
|
|
+ /* Try locking. */
|
||
|
|
+ while (atomic_exchange_acq (futex, 2) != 0)
|
||
|
|
+ {
|
||
|
|
+ struct timeval tv;
|
||
|
|
+
|
||
|
|
+ /* Get the current time. */
|
||
|
|
+ (void) __gettimeofday (&tv, NULL);
|
||
|
|
+
|
||
|
|
+ /* Compute relative timeout. */
|
||
|
|
+ struct timespec rt;
|
||
|
|
+ rt.tv_sec = abstime->tv_sec - tv.tv_sec;
|
||
|
|
+ rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
|
||
|
|
+ if (rt.tv_nsec < 0)
|
||
|
|
+ {
|
||
|
|
+ rt.tv_nsec += 1000000000;
|
||
|
|
+ --rt.tv_sec;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (rt.tv_sec < 0)
|
||
|
|
+ return ETIMEDOUT;
|
||
|
|
+
|
||
|
|
+ /* If *futex == 2, wait until woken or timeout. */
|
||
|
|
+ lll_futex_timed_wait (futex, 2, &rt, private);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
diff --git a/nptl_2_17/elision-conf_2_17.c b/nptl_2_17/elision-conf_2_17.c
|
||
|
|
new file mode 100644
|
||
|
|
index 00000000..22af2944
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/nptl_2_17/elision-conf_2_17.c
|
||
|
|
@@ -0,0 +1,138 @@
|
||
|
|
+/* elision-conf.c: Lock elision tunable parameters.
|
||
|
|
+ Copyright (C) 2013-2018 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "config.h"
|
||
|
|
+#include <pthreadP.h>
|
||
|
|
+#include <init-arch.h>
|
||
|
|
+#include <elision-conf.h>
|
||
|
|
+#include <unistd.h>
|
||
|
|
+
|
||
|
|
+#if HAVE_TUNABLES
|
||
|
|
+# define TUNABLE_NAMESPACE elision
|
||
|
|
+#endif
|
||
|
|
+#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 we retry 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. */
|
||
|
|
+ .retry_try_xbegin = 3,
|
||
|
|
+ /* Same as SKIP_LOCK_INTERNAL_ABORT but for trylock. */
|
||
|
|
+ .skip_trylock_internal_abort = 3,
|
||
|
|
+ };
|
||
|
|
+
|
||
|
|
+/* Force elision for all new locks. This is used to decide whether existing
|
||
|
|
+ DEFAULT locks should be automatically upgraded to elision in
|
||
|
|
+ pthread_mutex_lock(). Disabled for suid programs. Only used when elision
|
||
|
|
+ is available. */
|
||
|
|
+
|
||
|
|
+int __pthread_force_elision attribute_hidden = 0;
|
||
|
|
+
|
||
|
|
+#if HAVE_TUNABLES
|
||
|
|
+static inline void
|
||
|
|
+__always_inline
|
||
|
|
+do_set_elision_enable (int32_t elision_enable)
|
||
|
|
+{
|
||
|
|
+ /* Enable elision if it's avaliable 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 = HAS_CPU_FEATURE (RTM) ? 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 (retry_try_xbegin, int32_t);
|
||
|
|
+TUNABLE_CALLBACK_FNDECL (skip_trylock_internal_abort, int32_t);
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+/* Initialize elision. */
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+elision_init (int argc __attribute__ ((unused)),
|
||
|
|
+ char **argv __attribute__ ((unused)),
|
||
|
|
+ char **environ)
|
||
|
|
+{
|
||
|
|
+#if HAVE_TUNABLES
|
||
|
|
+ /* 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 (tries, int32_t,
|
||
|
|
+ TUNABLE_CALLBACK (set_elision_retry_try_xbegin));
|
||
|
|
+ TUNABLE_GET (skip_trylock_internal_abort, int32_t,
|
||
|
|
+ TUNABLE_CALLBACK (set_elision_skip_trylock_internal_abort));
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+ if (!__pthread_force_elision)
|
||
|
|
+ __elision_aconf.retry_try_xbegin = 0; /* Disable elision on rwlocks. */
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+#ifdef SHARED
|
||
|
|
+# define INIT_SECTION ".init_array"
|
||
|
|
+#else
|
||
|
|
+# define INIT_SECTION ".preinit_array"
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+void (*const __pthread_init_array []) (int, char **, char **)
|
||
|
|
+ __attribute__ ((section (INIT_SECTION), aligned (sizeof (void *)))) =
|
||
|
|
+{
|
||
|
|
+ &elision_init
|
||
|
|
+};
|
||
|
|
diff --git a/nptl_2_17/elision-lock_2_17.c b/nptl_2_17/elision-lock_2_17.c
|
||
|
|
new file mode 100644
|
||
|
|
index 00000000..e6dbbc21
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/nptl_2_17/elision-lock_2_17.c
|
||
|
|
@@ -0,0 +1,107 @@
|
||
|
|
+/* elision-lock.c: Elided pthread mutex lock.
|
||
|
|
+ Copyright (C) 2011-2018 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include <pthread_2_17.h>
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include "lowlevellock.h"
|
||
|
|
+#include "hle_2_17.h"
|
||
|
|
+#include <elision-conf.h>
|
||
|
|
+
|
||
|
|
+#if !defined(LLL_LOCK) && !defined(EXTRAARG)
|
||
|
|
+/* Make sure the configuration code is always linked in for static
|
||
|
|
+ libraries. */
|
||
|
|
+#include "elision-conf_2_17.c"
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+#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)
|
||
|
|
+ {
|
||
|
|
+ unsigned status;
|
||
|
|
+ int try_xbegin;
|
||
|
|
+
|
||
|
|
+ for (try_xbegin = aconf.retry_try_xbegin;
|
||
|
|
+ try_xbegin > 0;
|
||
|
|
+ try_xbegin--)
|
||
|
|
+ {
|
||
|
|
+ if ((status = _xbegin()) == _XBEGIN_STARTED)
|
||
|
|
+ {
|
||
|
|
+ if (*futex == 0)
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+ /* Lock was busy. Fall back to normal locking.
|
||
|
|
+ Could also _xend here but xabort with 0xff code
|
||
|
|
+ is more visible in the profiler. */
|
||
|
|
+ _xabort (_ABORT_LOCK_BUSY);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!(status & _XABORT_RETRY))
|
||
|
|
+ {
|
||
|
|
+ if ((status & _XABORT_EXPLICIT)
|
||
|
|
+ && _XABORT_CODE (status) == _ABORT_LOCK_BUSY)
|
||
|
|
+ {
|
||
|
|
+ /* Right now we skip here. Better would be to wait a bit
|
||
|
|
+ and retry. This likely needs some spinning. See
|
||
|
|
+ above for why relaxed MO is sufficient. */
|
||
|
|
+ if (atomic_load_relaxed (adapt_count)
|
||
|
|
+ != aconf.skip_lock_busy)
|
||
|
|
+ atomic_store_relaxed (adapt_count, aconf.skip_lock_busy);
|
||
|
|
+ }
|
||
|
|
+ /* Internal abort. There is no chance for retry.
|
||
|
|
+ Use the normal locking and next time use lock.
|
||
|
|
+ Be careful to avoid writing to the lock. See above for why
|
||
|
|
+ relaxed MO is sufficient. */
|
||
|
|
+ else if (atomic_load_relaxed (adapt_count)
|
||
|
|
+ != aconf.skip_lock_internal_abort)
|
||
|
|
+ atomic_store_relaxed (adapt_count,
|
||
|
|
+ aconf.skip_lock_internal_abort);
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ /* Use a normal lock until the threshold counter runs out.
|
||
|
|
+ Lost updates possible. */
|
||
|
|
+ atomic_store_relaxed (adapt_count,
|
||
|
|
+ atomic_load_relaxed (adapt_count) - 1);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* Use a normal lock here. */
|
||
|
|
+ return LLL_LOCK ((*futex), private);
|
||
|
|
+}
|
||
|
|
diff --git a/nptl_2_17/elision-timed_2_17.c b/nptl_2_17/elision-timed_2_17.c
|
||
|
|
new file mode 100644
|
||
|
|
index 00000000..5050f2d1
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/nptl_2_17/elision-timed_2_17.c
|
||
|
|
@@ -0,0 +1,27 @@
|
||
|
|
+/* elision-timed.c: Lock elision timed lock.
|
||
|
|
+ Copyright (C) 2013-2018 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include <time.h>
|
||
|
|
+#include <elision-conf.h>
|
||
|
|
+#include "lowlevellock.h"
|
||
|
|
+#include <old_macros_2_17.h>
|
||
|
|
+#define __lll_lock_elision __lll_timedlock_elision
|
||
|
|
+#define EXTRAARG const struct timespec *t,
|
||
|
|
+#undef LLL_LOCK
|
||
|
|
+#define LLL_LOCK(a, b) lll_timedlock(a, t, b)
|
||
|
|
+#include "elision-lock_2_17.c"
|
||
|
|
diff --git a/nptl_2_17/elision-trylock_2_17.c b/nptl_2_17/elision-trylock_2_17.c
|
||
|
|
new file mode 100644
|
||
|
|
index 00000000..70d8f8b9
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/nptl_2_17/elision-trylock_2_17.c
|
||
|
|
@@ -0,0 +1,75 @@
|
||
|
|
+/* elision-trylock.c: Lock eliding trylock for pthreads.
|
||
|
|
+ Copyright (C) 2013-2018 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include <pthread_2_17.h>
|
||
|
|
+
|
||
|
|
+#include <lowlevellock.h>
|
||
|
|
+#include "hle_2_17.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
|
||
|
|
+ trylock. Sorry. After the abort the code is re-executed
|
||
|
|
+ non transactional and if the lock was already locked
|
||
|
|
+ return an error. */
|
||
|
|
+ _xabort (_ABORT_NESTED_TRYLOCK);
|
||
|
|
+
|
||
|
|
+ /* Only try a transaction if it's worth it. See __lll_lock_elision for
|
||
|
|
+ why we need atomic accesses. Relaxed MO is sufficient because this is
|
||
|
|
+ just a hint. */
|
||
|
|
+ if (atomic_load_relaxed (adapt_count) <= 0)
|
||
|
|
+ {
|
||
|
|
+ unsigned status;
|
||
|
|
+
|
||
|
|
+ if ((status = _xbegin()) == _XBEGIN_STARTED)
|
||
|
|
+ {
|
||
|
|
+ if (*futex == 0)
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+ /* Lock was busy. Fall back to normal locking.
|
||
|
|
+ Could also _xend here but xabort with 0xff code
|
||
|
|
+ is more visible in the profiler. */
|
||
|
|
+ _xabort (_ABORT_LOCK_BUSY);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!(status & _XABORT_RETRY))
|
||
|
|
+ {
|
||
|
|
+ /* Internal abort. No chance for retry. For future
|
||
|
|
+ locks don't try speculation for some time. See above for MO. */
|
||
|
|
+ if (atomic_load_relaxed (adapt_count)
|
||
|
|
+ != aconf.skip_lock_internal_abort)
|
||
|
|
+ atomic_store_relaxed (adapt_count, aconf.skip_lock_internal_abort);
|
||
|
|
+ }
|
||
|
|
+ /* Could do some retries here. */
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ /* Lost updates are possible but harmless (see above). */
|
||
|
|
+ atomic_store_relaxed (adapt_count,
|
||
|
|
+ atomic_load_relaxed (adapt_count) - 1);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return lll_trylock (*futex);
|
||
|
|
+}
|
||
|
|
diff --git a/nptl_2_17/elision-unlock_2_17.c b/nptl_2_17/elision-unlock_2_17.c
|
||
|
|
new file mode 100644
|
||
|
|
index 00000000..b5d38c5f
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/nptl_2_17/elision-unlock_2_17.c
|
||
|
|
@@ -0,0 +1,34 @@
|
||
|
|
+/* elision-unlock.c: Commit an elided pthread lock.
|
||
|
|
+ Copyright (C) 2013-2018 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include "lowlevellock.h"
|
||
|
|
+#include "hle_2_17.h"
|
||
|
|
+#include <old_macros_2_17.h>
|
||
|
|
+
|
||
|
|
+int
|
||
|
|
+__lll_unlock_elision(int *lock, int private)
|
||
|
|
+{
|
||
|
|
+ /* When the lock was free we're in a transaction.
|
||
|
|
+ When you crash here you unlocked a free lock. */
|
||
|
|
+ if (*lock == 0)
|
||
|
|
+ _xend();
|
||
|
|
+ else
|
||
|
|
+ lll_unlock ((*lock), private);
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
diff --git a/nptl_2_17/hle_2_17.h b/nptl_2_17/hle_2_17.h
|
||
|
|
new file mode 100644
|
||
|
|
index 00000000..4a7b9e3b
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/nptl_2_17/hle_2_17.h
|
||
|
|
@@ -0,0 +1,75 @@
|
||
|
|
+/* Shared RTM header. Emulate TSX intrinsics for compilers and assemblers
|
||
|
|
+ that do not support the intrinsics and instructions yet. */
|
||
|
|
+#ifndef _HLE_H
|
||
|
|
+#define _HLE_H 1
|
||
|
|
+
|
||
|
|
+#ifdef __ASSEMBLER__
|
||
|
|
+
|
||
|
|
+.macro XBEGIN target
|
||
|
|
+ .byte 0xc7,0xf8
|
||
|
|
+ .long \target-1f
|
||
|
|
+1:
|
||
|
|
+.endm
|
||
|
|
+
|
||
|
|
+.macro XEND
|
||
|
|
+ .byte 0x0f,0x01,0xd5
|
||
|
|
+.endm
|
||
|
|
+
|
||
|
|
+.macro XABORT code
|
||
|
|
+ .byte 0xc6,0xf8,\code
|
||
|
|
+.endm
|
||
|
|
+
|
||
|
|
+.macro XTEST
|
||
|
|
+ .byte 0x0f,0x01,0xd6
|
||
|
|
+.endm
|
||
|
|
+
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+/* Official RTM intrinsics interface matching gcc/icc, but works
|
||
|
|
+ on older gcc compatible compilers and binutils.
|
||
|
|
+ We should somehow detect if the compiler supports it, because
|
||
|
|
+ it may be able to generate slightly better code. */
|
||
|
|
+
|
||
|
|
+#define _XBEGIN_STARTED (~0u)
|
||
|
|
+#define _XABORT_EXPLICIT (1 << 0)
|
||
|
|
+#define _XABORT_RETRY (1 << 1)
|
||
|
|
+#define _XABORT_CONFLICT (1 << 2)
|
||
|
|
+#define _XABORT_CAPACITY (1 << 3)
|
||
|
|
+#define _XABORT_DEBUG (1 << 4)
|
||
|
|
+#define _XABORT_NESTED (1 << 5)
|
||
|
|
+#define _XABORT_CODE(x) (((x) >> 24) & 0xff)
|
||
|
|
+
|
||
|
|
+#define _ABORT_LOCK_BUSY 0xff
|
||
|
|
+#define _ABORT_LOCK_IS_LOCKED 0xfe
|
||
|
|
+#define _ABORT_NESTED_TRYLOCK 0xfd
|
||
|
|
+
|
||
|
|
+#ifndef __ASSEMBLER__
|
||
|
|
+
|
||
|
|
+#define __force_inline __attribute__((__always_inline__)) inline
|
||
|
|
+
|
||
|
|
+static __force_inline int _xbegin(void)
|
||
|
|
+{
|
||
|
|
+ int ret = _XBEGIN_STARTED;
|
||
|
|
+ asm volatile (".byte 0xc7,0xf8 ; .long 0" : "+a" (ret) :: "memory");
|
||
|
|
+ return ret;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static __force_inline void _xend(void)
|
||
|
|
+{
|
||
|
|
+ asm volatile (".byte 0x0f,0x01,0xd5" ::: "memory");
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static __force_inline void _xabort(const unsigned int status)
|
||
|
|
+{
|
||
|
|
+ asm volatile (".byte 0xc6,0xf8,%P0" :: "i" (status) : "memory");
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static __force_inline int _xtest(void)
|
||
|
|
+{
|
||
|
|
+ unsigned char out;
|
||
|
|
+ asm volatile (".byte 0x0f,0x01,0xd6 ; setnz %0" : "=r" (out) :: "memory");
|
||
|
|
+ return out;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+#endif
|
||
|
|
+#endif
|
||
|
|
--
|
||
|
|
2.30.0
|
||
|
|
|