glibc/sysdeps/powerpc/powerpc32/sysdep.h
Adhemerval Zanella f0458cf4f9 powerpc: Only enable TLE with PPC_FEATURE2_HTM_NOSC
Linux from 3.9 through 4.2 does not abort HTM transaction on syscalls,
instead it suspend and resume it when leaving the kernel.  The
side-effects of the syscall will always remain visible, even if the
transaction is aborted.  This is an issue when transaction is used along
with futex syscall, on pthread_cond_wait for instance, where the futex
call might succeed but the transaction is rolled back leading the
pthread_cond object in an inconsistent state.

Glibc used to prevent it by always aborting a transaction before issuing
a syscall.  Linux 4.2 also decided to abort active transaction in
syscalls which makes the glibc workaround superfluous.  Worse, glibc
transaction abortion leads to a performance issue on recent kernels
where the HTM state is saved/restore lazily (v4.9).  By aborting a
transaction on every syscalls, regardless whether a transaction has being
initiated before, GLIBS makes the kernel always save/restore HTM state
(it can not even lazily disable it after a certain number of syscall
iterations).

Because of this shortcoming, Transactional Lock Elision is just enabled
when it has been explicitly set (either by tunables of by a configure
switch) and if kernel aborts HTM transactions on syscalls
(PPC_FEATURE2_HTM_NOSC).  It is reported that using simple benchmark [1],
the context-switch is about 5% faster by not issuing a tabort in every
syscall in newer kernels.

Checked on powerpc64le-linux-gnu with 4.4.0 kernel (Ubuntu 16.04).

	* NEWS: Add note about new TLE support on powerpc64le.
	* sysdeps/powerpc/nptl/tcb-offsets.sym (TM_CAPABLE): Remove.
	* sysdeps/powerpc/nptl/tls.h (tcbhead_t): Rename tm_capable to
	__ununsed1.
	(TLS_INIT_TP, TLS_DEFINE_INIT_TP): Remove tm_capable setup.
	(THREAD_GET_TM_CAPABLE, THREAD_SET_TM_CAPABLE): Remove macros.
	* sysdeps/powerpc/powerpc32/sysdep.h,
	sysdeps/powerpc/powerpc64/sysdep.h (ABORT_TRANSACTION_IMPL,
	ABORT_TRANSACTION): Remove macros.
	* sysdeps/powerpc/sysdep.h (ABORT_TRANSACTION): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/elision-conf.c (elision_init): Set
	__pthread_force_elision iff PPC_FEATURE2_HTM_NOSC is set.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h,
	sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
	sysdeps/unix/sysv/linux/powerpc/syscall.S (ABORT_TRANSACTION): Remove
	usage.
	* sysdeps/unix/sysv/linux/powerpc/not-errno.h: Remove file.

Reported-by: Breno Leitão <leitao@debian.org>
2018-09-21 10:18:03 -07:00

161 lines
4.5 KiB
C

/* Assembly macros for 32-bit PowerPC.
Copyright (C) 1999-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 <sysdeps/powerpc/sysdep.h>
#ifdef __ASSEMBLER__
/* If compiled for profiling, call `_mcount' at the start of each
function. */
#ifdef PROF
/* The mcount code relies on a the return address being on the stack
to locate our caller and so it can restore it; so store one just
for its benefit. */
# define CALL_MCOUNT \
mflr r0; \
stw r0,4(r1); \
cfi_offset (lr, 4); \
bl JUMPTARGET(_mcount);
#else /* PROF */
# define CALL_MCOUNT /* Do nothing. */
#endif /* PROF */
#define ENTRY(name) \
.globl C_SYMBOL_NAME(name); \
.type C_SYMBOL_NAME(name),@function; \
.align ALIGNARG(2); \
C_LABEL(name) \
cfi_startproc; \
CALL_MCOUNT
#define ENTRY_TOCLESS(name) ENTRY(name)
/* helper macro for accessing the 32-bit powerpc GOT. */
#define SETUP_GOT_ACCESS(regname,GOT_LABEL) \
bcl 20,31,GOT_LABEL ; \
GOT_LABEL: ; \
mflr (regname)
#define EALIGN_W_0 /* No words to insert. */
#define EALIGN_W_1 nop
#define EALIGN_W_2 nop;nop
#define EALIGN_W_3 nop;nop;nop
#define EALIGN_W_4 EALIGN_W_3;nop
#define EALIGN_W_5 EALIGN_W_4;nop
#define EALIGN_W_6 EALIGN_W_5;nop
#define EALIGN_W_7 EALIGN_W_6;nop
/* EALIGN is like ENTRY, but does alignment to 'words'*4 bytes
past a 2^align boundary. */
#ifdef PROF
# define EALIGN(name, alignt, words) \
.globl C_SYMBOL_NAME(name); \
.type C_SYMBOL_NAME(name),@function; \
.align ALIGNARG(2); \
C_LABEL(name) \
cfi_startproc; \
CALL_MCOUNT \
b 0f; \
.align ALIGNARG(alignt); \
EALIGN_W_##words; \
0:
#else /* PROF */
# define EALIGN(name, alignt, words) \
.globl C_SYMBOL_NAME(name); \
.type C_SYMBOL_NAME(name),@function; \
.align ALIGNARG(alignt); \
EALIGN_W_##words; \
C_LABEL(name) \
cfi_startproc;
#endif
#undef END
#define END(name) \
cfi_endproc; \
ASM_SIZE_DIRECTIVE(name)
#define DO_CALL(syscall) \
li 0,syscall; \
sc
#undef JUMPTARGET
#ifdef PIC
# define JUMPTARGET(name) name##@plt
#else
# define JUMPTARGET(name) name
#endif
#if defined SHARED && defined PIC && !defined NO_HIDDEN
# undef HIDDEN_JUMPTARGET
# define HIDDEN_JUMPTARGET(name) __GI_##name##@local
#endif
#define PSEUDO(name, syscall_name, args) \
.section ".text"; \
ENTRY (name) \
DO_CALL (SYS_ify (syscall_name));
#define PSEUDO_RET \
bnslr+; \
b __syscall_error@local
#define ret PSEUDO_RET
#undef PSEUDO_END
#define PSEUDO_END(name) \
END (name)
#define PSEUDO_NOERRNO(name, syscall_name, args) \
.section ".text"; \
ENTRY (name) \
DO_CALL (SYS_ify (syscall_name));
#define PSEUDO_RET_NOERRNO \
blr
#define ret_NOERRNO PSEUDO_RET_NOERRNO
#undef PSEUDO_END_NOERRNO
#define PSEUDO_END_NOERRNO(name) \
END (name)
#define PSEUDO_ERRVAL(name, syscall_name, args) \
.section ".text"; \
ENTRY (name) \
DO_CALL (SYS_ify (syscall_name));
#define PSEUDO_RET_ERRVAL \
blr
#define ret_ERRVAL PSEUDO_RET_ERRVAL
#undef PSEUDO_END_ERRVAL
#define PSEUDO_END_ERRVAL(name) \
END (name)
/* Local labels stripped out by the linker. */
#undef L
#define L(x) .L##x
#define XGLUE(a,b) a##b
#define GLUE(a,b) XGLUE (a,b)
#define GENERATE_GOT_LABEL(name) GLUE (.got_label, name)
/* Label in text section. */
#define C_TEXT(name) name
#endif /* __ASSEMBLER__ */