aboutsummaryrefslogtreecommitdiff
path: root/sysdeps
diff options
context:
space:
mode:
authorAdhemerval Zanella <azanella@linux.vnet.ibm.com>2014-11-07 12:34:52 -0500
committerAdhemerval Zanella <azanella@linux.vnet.ibm.com>2015-01-12 06:32:08 -0500
commit56cf2763819d2f721c98f2b8bcc04a3c673837d3 (patch)
tree5d2fde37897779f64b83951c1ef99406fd384055 /sysdeps
parent4b45943a6f62cfc239e79ad8902f5c7f71fd13ec (diff)
downloadglibc-56cf2763819d2f721c98f2b8bcc04a3c673837d3.tar
glibc-56cf2763819d2f721c98f2b8bcc04a3c673837d3.tar.gz
glibc-56cf2763819d2f721c98f2b8bcc04a3c673837d3.tar.bz2
glibc-56cf2763819d2f721c98f2b8bcc04a3c673837d3.zip
powerpc: abort transaction in syscalls
Linux kernel powerpc documentation states issuing a syscall inside a transaction is not recommended and may lead to undefined behavior. It also states syscalls does not abort transactoin neither they run in transactional state. To avoid side-effects being visible outside transactions, GLIBC with lock elision enabled will issue a transaction abort instruction just before all syscalls if hardware supports hardware transactions.
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/powerpc/nptl/tcb-offsets.sym1
-rw-r--r--sysdeps/powerpc/nptl/tls.h19
-rw-r--r--sysdeps/powerpc/powerpc32/sysdep.h16
-rw-r--r--sysdeps/powerpc/powerpc64/sysdep.h16
-rw-r--r--sysdeps/powerpc/sysdep.h22
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h1
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h1
7 files changed, 74 insertions, 2 deletions
diff --git a/sysdeps/powerpc/nptl/tcb-offsets.sym b/sysdeps/powerpc/nptl/tcb-offsets.sym
index f996759027..d955142aff 100644
--- a/sysdeps/powerpc/nptl/tcb-offsets.sym
+++ b/sysdeps/powerpc/nptl/tcb-offsets.sym
@@ -19,6 +19,7 @@ POINTER_GUARD (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (
TAR_SAVE (offsetof (tcbhead_t, tar_save) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
DSO_SLOT1 (offsetof (tcbhead_t, dso_slot1) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
DSO_SLOT2 (offsetof (tcbhead_t, dso_slot2) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
+TM_CAPABLE (offsetof (tcbhead_t, tm_capable) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
#ifndef __ASSUME_PRIVATE_FUTEX
PRIVATE_FUTEX_OFFSET thread_offsetof (header.private_futex)
#endif
diff --git a/sysdeps/powerpc/nptl/tls.h b/sysdeps/powerpc/nptl/tls.h
index 753381f95d..1f3d97a995 100644
--- a/sysdeps/powerpc/nptl/tls.h
+++ b/sysdeps/powerpc/nptl/tls.h
@@ -63,6 +63,8 @@ typedef union dtv
are private. */
typedef struct
{
+ /* Indicate if HTM capable (ISA 2.07). */
+ int tm_capable;
/* Reservation for Dynamic System Optimizer ABI. */
uintptr_t dso_slot2;
uintptr_t dso_slot1;
@@ -130,11 +132,17 @@ register void *__thread_register __asm__ ("r13");
special attention since 'errno' is not yet available and if the
operation can cause a failure 'errno' must not be touched. */
# define TLS_INIT_TP(tcbp) \
- (__thread_register = (void *) (tcbp) + TLS_TCB_OFFSET, NULL)
+ ({ \
+ __thread_register = (void *) (tcbp) + TLS_TCB_OFFSET; \
+ THREAD_SET_TM_CAPABLE (GLRO (dl_hwcap2) & PPC_FEATURE2_HAS_HTM ? 1 : 0); \
+ NULL; \
+ })
/* Value passed to 'clone' for initialization of the thread register. */
# define TLS_DEFINE_INIT_TP(tp, pd) \
- void *tp = (void *) (pd) + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE
+ void *tp = (void *) (pd) + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE; \
+ (((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].tm_capable) = \
+ THREAD_GET_TM_CAPABLE ();
/* Return the address of the dtv for the current thread. */
# define THREAD_DTV() \
@@ -188,6 +196,13 @@ register void *__thread_register __asm__ ("r13");
+ TLS_PRE_TCB_SIZE))[-1].pointer_guard \
= THREAD_GET_POINTER_GUARD())
+/* tm_capable field in TCB head. */
+# define THREAD_GET_TM_CAPABLE() \
+ (((tcbhead_t *) ((char *) __thread_register \
+ - TLS_TCB_OFFSET))[-1].tm_capable)
+# define THREAD_SET_TM_CAPABLE(value) \
+ (THREAD_GET_TM_CAPABLE () = (value))
+
/* l_tls_offset == 0 is perfectly valid on PPC, so we have to use some
different value to mean unset l_tls_offset. */
# define NO_TLS_OFFSET -1
diff --git a/sysdeps/powerpc/powerpc32/sysdep.h b/sysdeps/powerpc/powerpc32/sysdep.h
index ff05e76047..e16fe3e224 100644
--- a/sysdeps/powerpc/powerpc32/sysdep.h
+++ b/sysdeps/powerpc/powerpc32/sysdep.h
@@ -88,7 +88,23 @@ GOT_LABEL: ; \
cfi_endproc; \
ASM_SIZE_DIRECTIVE(name)
+#if ! IS_IN(rtld) && defined (ENABLE_LOCK_ELISION)
+# define ABORT_TRANSACTION \
+ cmpwi 2,0; \
+ beq 1f; \
+ lwz 0,TM_CAPABLE(2); \
+ cmpwi 0,0; \
+ beq 1f; \
+ li 0,_ABORT_SYSCALL; \
+ tabort. 0; \
+ .align 4; \
+1:
+#else
+# define ABORT_TRANSACTION
+#endif
+
#define DO_CALL(syscall) \
+ ABORT_TRANSACTION \
li 0,syscall; \
sc
diff --git a/sysdeps/powerpc/powerpc64/sysdep.h b/sysdeps/powerpc/powerpc64/sysdep.h
index ab9c3d73f4..1f4efe6648 100644
--- a/sysdeps/powerpc/powerpc64/sysdep.h
+++ b/sysdeps/powerpc/powerpc64/sysdep.h
@@ -283,7 +283,23 @@ LT_LABELSUFFIX(name,_name_end): ; \
TRACEBACK_MASK(name,mask) \
END_2(name)
+#if !IS_IN(rtld) && defined (ENABLE_LOCK_ELISION)
+# define ABORT_TRANSACTION \
+ cmpdi 13,0; \
+ beq 1f; \
+ lwz 0,TM_CAPABLE(13); \
+ cmpwi 0,0; \
+ beq 1f; \
+ li 0,_ABORT_SYSCALL; \
+ tabort. 0; \
+ .align 4; \
+1:
+#else
+# define ABORT_TRANSACTION
+#endif
+
#define DO_CALL(syscall) \
+ ABORT_TRANSACTION \
li 0,syscall; \
sc
diff --git a/sysdeps/powerpc/sysdep.h b/sysdeps/powerpc/sysdep.h
index 3d37b1b92e..e32168e8f4 100644
--- a/sysdeps/powerpc/sysdep.h
+++ b/sysdeps/powerpc/sysdep.h
@@ -21,6 +21,10 @@
*/
#define _SYSDEPS_SYSDEP_H 1
#include <bits/hwcap.h>
+#ifdef ENABLE_LOCK_ELISION
+#include <tls.h>
+#include <htm.h>
+#endif
#define PPC_FEATURE_970 (PPC_FEATURE_POWER4 + PPC_FEATURE_HAS_ALTIVEC)
@@ -164,4 +168,22 @@
#define ALIGNARG(log2) log2
#define ASM_SIZE_DIRECTIVE(name) .size name,.-name
+#else
+
+/* Linux kernel powerpc documentation [1] states issuing a syscall inside a
+ transaction is not recommended and may lead to undefined behavior. It
+ also states syscalls do not abort transactions. To avoid such traps,
+ we abort transaction just before syscalls.
+
+ [1] Documentation/powerpc/transactional_memory.txt [Syscalls] */
+#if !IS_IN(rtld) && defined (ENABLE_LOCK_ELISION)
+# define ABORT_TRANSACTION \
+ ({ \
+ if (THREAD_GET_TM_CAPABLE ()) \
+ __builtin_tabort (_ABORT_SYSCALL); \
+ })
+#else
+# define ABORT_TRANSACTION
+#endif
+
#endif /* __ASSEMBLER__ */
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
index 7eaa5bdc45..0b41e8cae0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
@@ -194,6 +194,7 @@
register long int r11 __asm__ ("r11"); \
register long int r12 __asm__ ("r12"); \
LOADARGS_##nr(name, args); \
+ ABORT_TRANSACTION; \
__asm__ __volatile__ \
("sc \n\t" \
"mfcr %0" \
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
index a397769841..324e19ba9a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
@@ -201,6 +201,7 @@
register long int r7 __asm__ ("r7"); \
register long int r8 __asm__ ("r8"); \
LOADARGS_##nr (name, ##args); \
+ ABORT_TRANSACTION; \
__asm__ __volatile__ \
("sc\n\t" \
"mfcr %0\n\t" \