aboutsummaryrefslogtreecommitdiff
path: root/REORG.TODO/sysdeps/powerpc/nptl
diff options
context:
space:
mode:
Diffstat (limited to 'REORG.TODO/sysdeps/powerpc/nptl')
-rw-r--r--REORG.TODO/sysdeps/powerpc/nptl/Makefile20
-rw-r--r--REORG.TODO/sysdeps/powerpc/nptl/bits/pthreadtypes-arch.h79
-rw-r--r--REORG.TODO/sysdeps/powerpc/nptl/elide.h125
-rw-r--r--REORG.TODO/sysdeps/powerpc/nptl/pthread_spin_lock.c43
-rw-r--r--REORG.TODO/sysdeps/powerpc/nptl/pthread_spin_trylock.c41
-rw-r--r--REORG.TODO/sysdeps/powerpc/nptl/pthread_spin_unlock.c27
-rw-r--r--REORG.TODO/sysdeps/powerpc/nptl/pthreaddef.h33
-rw-r--r--REORG.TODO/sysdeps/powerpc/nptl/tcb-offsets.sym32
-rw-r--r--REORG.TODO/sysdeps/powerpc/nptl/tls.h263
9 files changed, 663 insertions, 0 deletions
diff --git a/REORG.TODO/sysdeps/powerpc/nptl/Makefile b/REORG.TODO/sysdeps/powerpc/nptl/Makefile
new file mode 100644
index 0000000000..13fa630f2f
--- /dev/null
+++ b/REORG.TODO/sysdeps/powerpc/nptl/Makefile
@@ -0,0 +1,20 @@
+# Copyright (C) 2003-2017 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/>.
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
diff --git a/REORG.TODO/sysdeps/powerpc/nptl/bits/pthreadtypes-arch.h b/REORG.TODO/sysdeps/powerpc/nptl/bits/pthreadtypes-arch.h
new file mode 100644
index 0000000000..f29119b794
--- /dev/null
+++ b/REORG.TODO/sysdeps/powerpc/nptl/bits/pthreadtypes-arch.h
@@ -0,0 +1,79 @@
+/* Machine-specific pthread type layouts. PowerPC version.
+ Copyright (C) 2003-2017 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/>. */
+
+#ifndef _BITS_PTHREADTYPES_ARCH_H
+#define _BITS_PTHREADTYPES_ARCH_H 1
+
+#include <bits/wordsize.h>
+
+#if __WORDSIZE == 64
+# define __SIZEOF_PTHREAD_MUTEX_T 40
+# define __SIZEOF_PTHREAD_ATTR_T 56
+# define __SIZEOF_PTHREAD_RWLOCK_T 56
+# define __SIZEOF_PTHREAD_BARRIER_T 32
+#else
+# define __SIZEOF_PTHREAD_MUTEX_T 24
+# define __SIZEOF_PTHREAD_ATTR_T 36
+# define __SIZEOF_PTHREAD_RWLOCK_T 32
+# define __SIZEOF_PTHREAD_BARRIER_T 20
+#endif
+#define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+#define __SIZEOF_PTHREAD_COND_T 48
+#define __SIZEOF_PTHREAD_CONDATTR_T 4
+#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+#define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+
+/* Definitions for internal mutex struct. */
+#define __PTHREAD_COMPAT_PADDING_MID
+#define __PTHREAD_COMPAT_PADDING_END
+#define __PTHREAD_MUTEX_LOCK_ELISION 1
+
+#define __LOCK_ALIGNMENT
+#define __ONCE_ALIGNMENT
+
+struct __pthread_rwlock_arch_t
+{
+ unsigned int __readers;
+ unsigned int __writers;
+ unsigned int __wrphase_futex;
+ unsigned int __writers_futex;
+ unsigned int __pad3;
+ unsigned int __pad4;
+#if __WORDSIZE == 64
+ int __cur_writer;
+ int __shared;
+ unsigned char __rwelision;
+ unsigned char __pad1[7];
+ unsigned long int __pad2;
+ /* FLAGS must stay at this position in the structure to maintain
+ binary compatibility. */
+ unsigned int __flags;
+# define __PTHREAD_RWLOCK_ELISION_EXTRA 0, {0, 0, 0, 0, 0, 0, 0 }
+#else
+ unsigned char __rwelision;
+ unsigned char __pad2;
+ unsigned char __shared;
+ /* FLAGS must stay at this position in the structure to maintain
+ binary compatibility. */
+ unsigned char __flags;
+ int __cur_writer;
+# define __PTHREAD_RWLOCK_ELISION_EXTRA 0
+#endif
+};
+
+#endif /* bits/pthreadtypes.h */
diff --git a/REORG.TODO/sysdeps/powerpc/nptl/elide.h b/REORG.TODO/sysdeps/powerpc/nptl/elide.h
new file mode 100644
index 0000000000..1c42814b71
--- /dev/null
+++ b/REORG.TODO/sysdeps/powerpc/nptl/elide.h
@@ -0,0 +1,125 @@
+/* elide.h: Generic lock elision support for powerpc.
+ Copyright (C) 2015-2017 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/>. */
+
+#ifndef ELIDE_PPC_H
+# define ELIDE_PPC_H
+
+#ifdef ENABLE_LOCK_ELISION
+# include <htm.h>
+# include <elision-conf.h>
+
+/* Get the new value of adapt_count according to the elision
+ configurations. Returns true if the system should retry again or false
+ otherwise. */
+static inline bool
+__get_new_count (uint8_t *adapt_count, int attempt)
+{
+ /* A persistent failure indicates that a retry will probably
+ result in another failure. Use normal locking now and
+ for the next couple of calls. */
+ if (_TEXASRU_FAILURE_PERSISTENT (__builtin_get_texasru ()))
+ {
+ if (__elision_aconf.skip_lock_internal_abort > 0)
+ *adapt_count = __elision_aconf.skip_lock_internal_abort;
+ return false;
+ }
+ /* Same logic as above, but for a number of temporary failures in a
+ a row. */
+ else if (attempt <= 1 && __elision_aconf.skip_lock_out_of_tbegin_retries > 0
+ && __elision_aconf.try_tbegin > 0)
+ *adapt_count = __elision_aconf.skip_lock_out_of_tbegin_retries;
+ return true;
+}
+
+/* CONCURRENCY NOTES:
+
+ The evaluation of the macro expression is_lock_free encompasses one or
+ more loads from memory locations that are concurrently modified by other
+ threads. For lock elision to work, this evaluation and the rest of the
+ critical section protected by the lock must be atomic because an
+ execution with lock elision must be equivalent to an execution in which
+ the lock would have been actually acquired and released. Therefore, we
+ evaluate is_lock_free inside of the transaction that represents the
+ critical section for which we want to use lock elision, which ensures
+ the atomicity that we require. */
+
+/* Returns 0 if the lock defined by is_lock_free was elided.
+ ADAPT_COUNT is a per-lock state variable. */
+# define ELIDE_LOCK(adapt_count, is_lock_free) \
+ ({ \
+ int ret = 0; \
+ if (adapt_count > 0) \
+ (adapt_count)--; \
+ else \
+ for (int i = __elision_aconf.try_tbegin; i > 0; i--) \
+ { \
+ if (__libc_tbegin (0)) \
+ { \
+ if (is_lock_free) \
+ { \
+ ret = 1; \
+ break; \
+ } \
+ __libc_tabort (_ABORT_LOCK_BUSY); \
+ } \
+ else \
+ if (!__get_new_count (&adapt_count,i)) \
+ break; \
+ } \
+ ret; \
+ })
+
+# define ELIDE_TRYLOCK(adapt_count, is_lock_free, write) \
+ ({ \
+ int ret = 0; \
+ if (__elision_aconf.try_tbegin > 0) \
+ { \
+ if (write) \
+ __libc_tabort (_ABORT_NESTED_TRYLOCK); \
+ ret = ELIDE_LOCK (adapt_count, is_lock_free); \
+ } \
+ ret; \
+ })
+
+
+static inline bool
+__elide_unlock (int is_lock_free)
+{
+ if (is_lock_free)
+ {
+ /* This code is expected to crash when trying to unlock a lock not
+ held by this thread. More information is available in the
+ __pthread_rwlock_unlock() implementation. */
+ __libc_tend (0);
+ return true;
+ }
+ return false;
+}
+
+# define ELIDE_UNLOCK(is_lock_free) \
+ __elide_unlock (is_lock_free)
+
+# else
+
+# define ELIDE_LOCK(adapt_count, is_lock_free) 0
+# define ELIDE_TRYLOCK(adapt_count, is_lock_free, write) 0
+# define ELIDE_UNLOCK(is_lock_free) 0
+
+#endif /* ENABLE_LOCK_ELISION */
+
+#endif
diff --git a/REORG.TODO/sysdeps/powerpc/nptl/pthread_spin_lock.c b/REORG.TODO/sysdeps/powerpc/nptl/pthread_spin_lock.c
new file mode 100644
index 0000000000..e377feb1cf
--- /dev/null
+++ b/REORG.TODO/sysdeps/powerpc/nptl/pthread_spin_lock.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 2003-2017 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 "pthreadP.h"
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+ unsigned int __tmp;
+
+ asm volatile (
+ "1: lwarx %0,0,%1" MUTEX_HINT_ACQ "\n"
+ " cmpwi 0,%0,0\n"
+ " bne- 2f\n"
+ " stwcx. %2,0,%1\n"
+ " bne- 2f\n"
+ __ARCH_ACQ_INSTR "\n"
+ " .subsection 1\n"
+ "2: lwzx %0,0,%1\n"
+ " cmpwi 0,%0,0\n"
+ " bne 2b\n"
+ " b 1b\n"
+ " .previous"
+ : "=&r" (__tmp)
+ : "r" (lock), "r" (1)
+ : "cr0", "memory");
+ return 0;
+}
diff --git a/REORG.TODO/sysdeps/powerpc/nptl/pthread_spin_trylock.c b/REORG.TODO/sysdeps/powerpc/nptl/pthread_spin_trylock.c
new file mode 100644
index 0000000000..d81d984237
--- /dev/null
+++ b/REORG.TODO/sysdeps/powerpc/nptl/pthread_spin_trylock.c
@@ -0,0 +1,41 @@
+/* Copyright (C) 2003-2017 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 <errno.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+ unsigned int old;
+ int err = EBUSY;
+
+ asm ("1: lwarx %0,0,%2" MUTEX_HINT_ACQ "\n"
+ " cmpwi 0,%0,0\n"
+ " bne 2f\n"
+ " stwcx. %3,0,%2\n"
+ " bne- 1b\n"
+ " li %1,0\n"
+ __ARCH_ACQ_INSTR "\n"
+ "2: "
+ : "=&r" (old), "=&r" (err)
+ : "r" (lock), "r" (1), "1" (err)
+ : "cr0", "memory");
+
+ return err;
+}
diff --git a/REORG.TODO/sysdeps/powerpc/nptl/pthread_spin_unlock.c b/REORG.TODO/sysdeps/powerpc/nptl/pthread_spin_unlock.c
new file mode 100644
index 0000000000..fa30a82491
--- /dev/null
+++ b/REORG.TODO/sysdeps/powerpc/nptl/pthread_spin_unlock.c
@@ -0,0 +1,27 @@
+/* pthread_spin_unlock -- unlock a spin lock. PowerPC version.
+ Copyright (C) 2007-2017 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.h"
+#include <lowlevellock.h>
+
+int
+pthread_spin_unlock (pthread_spinlock_t *lock)
+{
+ atomic_store_release (lock, 0);
+ return 0;
+}
diff --git a/REORG.TODO/sysdeps/powerpc/nptl/pthreaddef.h b/REORG.TODO/sysdeps/powerpc/nptl/pthreaddef.h
new file mode 100644
index 0000000000..e3e407a4c4
--- /dev/null
+++ b/REORG.TODO/sysdeps/powerpc/nptl/pthreaddef.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2003-2017 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/>. */
+
+/* Default stack size. */
+#define ARCH_STACK_DEFAULT_SIZE (4 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning. The ABI requires 16
+ bytes (for both 32-bit and 64-bit PowerPC). */
+#define STACK_ALIGN 16
+
+/* Minimal stack size after allocating thread descriptor and guard size. */
+#define MINIMAL_REST_STACK 4096
+
+/* Alignment requirement for TCB. */
+#define TCB_ALIGNMENT 16
+
+
+/* Location of current stack frame. */
+#define CURRENT_STACK_FRAME __builtin_frame_address (0)
diff --git a/REORG.TODO/sysdeps/powerpc/nptl/tcb-offsets.sym b/REORG.TODO/sysdeps/powerpc/nptl/tcb-offsets.sym
new file mode 100644
index 0000000000..7c9fd33562
--- /dev/null
+++ b/REORG.TODO/sysdeps/powerpc/nptl/tcb-offsets.sym
@@ -0,0 +1,32 @@
+#include <sysdep.h>
+#include <tls.h>
+#include <kernel-features.h>
+
+--
+
+-- Abuse tls.h macros to derive offsets relative to the thread register.
+# undef __thread_register
+# define __thread_register ((void *) 0)
+# define thread_offsetof(mem) ((ptrdiff_t) THREAD_SELF + offsetof (struct pthread, mem))
+
+
+#if TLS_MULTIPLE_THREADS_IN_TCB
+MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads)
+#endif
+TID thread_offsetof (tid)
+POINTER_GUARD (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
+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))
+#ifdef __powerpc64__
+TCB_AT_PLATFORM (offsetof (tcbhead_t, at_platform) - TLS_TCB_OFFSET - sizeof(tcbhead_t))
+#endif
+TM_CAPABLE (offsetof (tcbhead_t, tm_capable) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
+#ifndef __powerpc64__
+TCB_AT_PLATFORM (offsetof (tcbhead_t, at_platform) - TLS_TCB_OFFSET - sizeof(tcbhead_t))
+PADDING (offsetof (tcbhead_t, padding) - TLS_TCB_OFFSET - sizeof(tcbhead_t))
+#endif
+TCB_HWCAP (offsetof (tcbhead_t, hwcap) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
+#ifndef __ASSUME_PRIVATE_FUTEX
+PRIVATE_FUTEX_OFFSET thread_offsetof (header.private_futex)
+#endif
diff --git a/REORG.TODO/sysdeps/powerpc/nptl/tls.h b/REORG.TODO/sysdeps/powerpc/nptl/tls.h
new file mode 100644
index 0000000000..7556e7c8b8
--- /dev/null
+++ b/REORG.TODO/sysdeps/powerpc/nptl/tls.h
@@ -0,0 +1,263 @@
+/* Definition for thread-local data handling. NPTL/PowerPC version.
+ Copyright (C) 2003-2017 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/>. */
+
+#ifndef _TLS_H
+#define _TLS_H 1
+
+# include <dl-sysdep.h>
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+# include <dl-dtv.h>
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif /* __ASSEMBLER__ */
+
+
+#ifndef __ASSEMBLER__
+
+# include <hwcapinfo.h>
+
+/* Get system call information. */
+# include <sysdep.h>
+
+/* The TP points to the start of the thread blocks. */
+# define TLS_DTV_AT_TP 1
+# define TLS_TCB_AT_TP 0
+
+/* We use the multiple_threads field in the pthread struct */
+#define TLS_MULTIPLE_THREADS_IN_TCB 1
+
+/* Get the thread descriptor definition. */
+# include <nptl/descr.h>
+
+
+/* The stack_guard is accessed directly by GCC -fstack-protector code,
+ so it is a part of public ABI. The dtv and pointer_guard fields
+ are private. */
+typedef struct
+{
+ /* Reservation for HWCAP data. To be accessed by GCC in
+ __builtin_cpu_supports(), so it is a part of public ABI. */
+ uint64_t hwcap;
+ /* Reservation for AT_PLATFORM data. To be accessed by GCC in
+ __builtin_cpu_is(), so it is a part of public ABI. Since there
+ are different ABIs for 32 and 64 bit, we put this field in a
+ previously empty padding space for powerpc64. */
+#ifndef __powerpc64__
+ /* Padding to maintain alignment. */
+ uint32_t padding;
+ uint32_t at_platform;
+#endif
+ /* Indicate if HTM capable (ISA 2.07). */
+ uint32_t tm_capable;
+ /* Reservation for AT_PLATFORM data - powerpc64. */
+#ifdef __powerpc64__
+ uint32_t at_platform;
+#endif
+ /* Reservation for Dynamic System Optimizer ABI. */
+ uintptr_t dso_slot2;
+ uintptr_t dso_slot1;
+ /* Reservation for tar register (ISA 2.07). */
+ uintptr_t tar_save;
+ /* GCC split stack support. */
+ void *__private_ss;
+ /* Reservation for the Event-Based Branching ABI. */
+ uintptr_t ebb_handler;
+ uintptr_t ebb_ctx_pointer;
+ uintptr_t ebb_reserved1;
+ uintptr_t ebb_reserved2;
+ uintptr_t pointer_guard;
+ uintptr_t stack_guard;
+ dtv_t *dtv;
+} tcbhead_t;
+
+/* This is the size of the initial TCB. */
+# define TLS_INIT_TCB_SIZE 0
+
+/* Alignment requirements for the initial TCB. */
+# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread)
+
+/* This is the size of the TCB. */
+# define TLS_TCB_SIZE 0
+
+/* Alignment requirements for the TCB. */
+# define TLS_TCB_ALIGN __alignof__ (struct pthread)
+
+/* This is the size we need before TCB. */
+# define TLS_PRE_TCB_SIZE \
+ (sizeof (struct pthread) \
+ + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+# ifndef __powerpc64__
+/* Register r2 (tp) is reserved by the ABI as "thread pointer". */
+register void *__thread_register __asm__ ("r2");
+# define PT_THREAD_POINTER PT_R2
+# else
+/* Register r13 (tp) is reserved by the ABI as "thread pointer". */
+register void *__thread_register __asm__ ("r13");
+# define PT_THREAD_POINTER PT_R13
+# endif
+
+/* The following assumes that TP (R2 or R13) points to the end of the
+ TCB + 0x7000 (per the ABI). This implies that TCB address is
+ TP - 0x7000. As we define TLS_DTV_AT_TP we can
+ assume that the pthread struct is allocated immediately ahead of the
+ TCB. This implies that the pthread_descr address is
+ TP - (TLS_PRE_TCB_SIZE + 0x7000). */
+# define TLS_TCB_OFFSET 0x7000
+
+/* Install the dtv pointer. The pointer passed is to the element with
+ index -1 which contain the length. */
+# define INSTALL_DTV(tcbp, dtvp) \
+ ((tcbhead_t *) (tcbp))[-1].dtv = dtvp + 1
+
+/* Install new dtv for current thread. */
+# define INSTALL_NEW_DTV(dtv) (THREAD_DTV() = (dtv))
+
+/* Return dtv of given thread descriptor. */
+# define GET_DTV(tcbp) (((tcbhead_t *) (tcbp))[-1].dtv)
+
+/* Code to initially initialize the thread pointer. This might need
+ 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; \
+ THREAD_SET_TM_CAPABLE (__tcb_hwcap & PPC_FEATURE2_HAS_HTM ? 1 : 0); \
+ THREAD_SET_HWCAP (__tcb_hwcap); \
+ THREAD_SET_AT_PLATFORM (__tcb_platform); \
+ 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; \
+ (((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].tm_capable) = \
+ THREAD_GET_TM_CAPABLE (); \
+ (((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].hwcap) = \
+ THREAD_GET_HWCAP (); \
+ (((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].at_platform) = \
+ THREAD_GET_AT_PLATFORM ();
+
+/* Return the address of the dtv for the current thread. */
+# define THREAD_DTV() \
+ (((tcbhead_t *) (__thread_register - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread. */
+# define THREAD_SELF \
+ ((struct pthread *) (__thread_register \
+ - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF. */
+# define DB_THREAD_SELF \
+ REGISTER (32, 32, PT_THREAD_POINTER * 4, \
+ - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) \
+ REGISTER (64, 64, PT_THREAD_POINTER * 8, \
+ - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+/* Read member of the thread descriptor directly. */
+# define THREAD_GETMEM(descr, member) ((void)(descr), (THREAD_SELF)->member)
+
+/* Same as THREAD_GETMEM, but the member offset can be non-constant. */
+# define THREAD_GETMEM_NC(descr, member, idx) \
+ ((void)(descr), (THREAD_SELF)->member[idx])
+
+/* Set member of the thread descriptor directly. */
+# define THREAD_SETMEM(descr, member, value) \
+ ((void)(descr), (THREAD_SELF)->member = (value))
+
+/* Same as THREAD_SETMEM, but the member offset can be non-constant. */
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+ ((void)(descr), (THREAD_SELF)->member[idx] = (value))
+
+/* Set the stack guard field in TCB head. */
+# define THREAD_SET_STACK_GUARD(value) \
+ (((tcbhead_t *) ((char *) __thread_register \
+ - TLS_TCB_OFFSET))[-1].stack_guard = (value))
+# define THREAD_COPY_STACK_GUARD(descr) \
+ (((tcbhead_t *) ((char *) (descr) \
+ + TLS_PRE_TCB_SIZE))[-1].stack_guard \
+ = ((tcbhead_t *) ((char *) __thread_register \
+ - TLS_TCB_OFFSET))[-1].stack_guard)
+
+/* Set the stack guard field in TCB head. */
+# define THREAD_GET_POINTER_GUARD() \
+ (((tcbhead_t *) ((char *) __thread_register \
+ - TLS_TCB_OFFSET))[-1].pointer_guard)
+# define THREAD_SET_POINTER_GUARD(value) \
+ (THREAD_GET_POINTER_GUARD () = (value))
+# define THREAD_COPY_POINTER_GUARD(descr) \
+ (((tcbhead_t *) ((char *) (descr) \
+ + 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))
+
+/* hwcap field in TCB head. */
+# define THREAD_GET_HWCAP() \
+ (((tcbhead_t *) ((char *) __thread_register \
+ - TLS_TCB_OFFSET))[-1].hwcap)
+# define THREAD_SET_HWCAP(value) \
+ (THREAD_GET_HWCAP () = (value))
+
+/* at_platform field in TCB head. */
+# define THREAD_GET_AT_PLATFORM() \
+ (((tcbhead_t *) ((char *) __thread_register \
+ - TLS_TCB_OFFSET))[-1].at_platform)
+# define THREAD_SET_AT_PLATFORM(value) \
+ (THREAD_GET_AT_PLATFORM () = (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
+
+/* Get and set the global scope generation counter in struct pthread. */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED 1
+#define THREAD_GSCOPE_FLAG_WAIT 2
+#define THREAD_GSCOPE_RESET_FLAG() \
+ do \
+ { int __res \
+ = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag, \
+ THREAD_GSCOPE_FLAG_UNUSED); \
+ if (__res == THREAD_GSCOPE_FLAG_WAIT) \
+ lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \
+ } \
+ while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+ do \
+ { \
+ THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED; \
+ atomic_write_barrier (); \
+ } \
+ while (0)
+#define THREAD_GSCOPE_WAIT() \
+ GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */