glibc/nptl/sysdeps/x86_64/tls.h
Roland McGrath d4f64e1ad7 2003-03-10 Roland McGrath <roland@redhat.com>
* allocatestack.c (allocate_stack) [!TLS_MULTIPLE_THREADS_IN_TCB]:
	Instead of setting PD->multiple_threads, set globals
	__pthread_multiple_threads and __libc_multiple_threads.
	* sysdeps/pthread/createthread.c (create_thread): Likewise.
	* sysdeps/i386/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Define it.
	* sysdeps/s390/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Likewise.
	* descr.h (struct pthread): Conditionalize first member on
	[!TLS_DTV_AT_TP].  Replace the `header' member with an anonymous union
	containing an anonymous tcbhead_t.  Move `list' member out.
	[TLS_MULTIPLE_THREADS_IN_TCB]: Define a `multiple_threads' member.
	* allocatestack.c: Remove use of `header.data.' prefix.
	* pthread_create.c: Likewise.
	* init.c (__pthread_initialize_minimal_internal): Likewise.
	* sysdeps/pthread/createthread.c (create_thread): Likewise.
	* sysdeps/i386/tls.h (INSTALL_DTV): Add parens.
	(THREAD_SELF, THREAD_DTV, INSTALL_NEW_DTV): No `header.data.' prefix.
	* sysdeps/x86_64/tls.h: Likewise.
	* sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
	(SINGLE_THREAD_P): Likewise.
	* sysdeps/unix/sysv/linux/sh/sysdep-cancel.h
	(SINGLE_THREAD_P): Likewise.
	* sysdeps/i386/tls.h (tcbhead_t): Remove `list' member.
	* sysdeps/s390/tls.h (tcbhead_t): Likewise.
2003-03-10 08:50:36 +00:00

255 lines
8.5 KiB
C

/* Definition for thread-local data handling. nptl/x86_64 version.
Copyright (C) 2002, 2003 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, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _TLS_H
#define _TLS_H 1
#ifndef __ASSEMBLER__
# include <stddef.h>
# include <stdint.h>
# include <stdlib.h>
/* Type for the dtv. */
typedef union dtv
{
size_t counter;
void *pointer;
} dtv_t;
typedef struct
{
void *tcb; /* Pointer to the TCB. Not necessary the
thread descriptor used by libpthread. */
dtv_t *dtv;
void *self; /* Pointer to the thread descriptor. */
} tcbhead_t;
#endif
/* We require TLS support in the tools. */
#ifndef HAVE_TLS_SUPPORT
# error "TLS support is required."
#endif
/* Signal that TLS support is available. */
#define USE_TLS 1
/* Alignment requirement for the stack. */
#define STACK_ALIGN 16
#ifndef __ASSEMBLER__
/* Get system call information. */
# include <sysdep.h>
/* Get the thread descriptor definition. */
# include <nptl/descr.h>
/* This is the size of the initial TCB. */
# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
/* Alignment requirements for the initial TCB. */
# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
/* This is the size of the TCB. */
# define TLS_TCB_SIZE sizeof (struct pthread)
/* Alignment requirements for the TCB. */
# define TLS_TCB_ALIGN __alignof__ (struct pthread)
/* The TCB can have any size and the memory following the address the
thread pointer points to is unspecified. Allocate the TCB there. */
# define TLS_TCB_AT_TP 1
/* Install the dtv pointer. The pointer passed is to the element with
index -1 which contain the length. */
# define INSTALL_DTV(descr, dtvp) \
((tcbhead_t *) (descr))->dtv = (dtvp) + 1
/* Install new dtv for current thread. */
# define INSTALL_NEW_DTV(dtvp) \
({ struct pthread *__pd; \
THREAD_SETMEM (__pd, dtv, (dtvp)); })
/* Return dtv of given thread descriptor. */
# define GET_DTV(descr) \
(((tcbhead_t *) (descr))->dtv)
/* Macros to load from and store into segment registers. */
# define TLS_GET_FS() \
({ int __seg; __asm ("movl %%fs, %0" : "=q" (__seg)); __seg; })
# define TLS_SET_FS(val) \
__asm ("movl %0, %%fs" :: "q" (val))
/* 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.
We have to make the syscall for both uses of the macro since the
address might be (and probably is) different. */
# define TLS_INIT_TP(thrdescr, secondcall) \
({ void *_thrdescr = (thrdescr); \
tcbhead_t *_head = _thrdescr; \
int _result; \
\
_head->tcb = _thrdescr; \
/* For now the thread descriptor is at the same address. */ \
_head->self = _thrdescr; \
\
/* It is a simple syscall to set the %fs value for the thread. */ \
asm volatile ("syscall" \
: "=a" (_result) \
: "0" ((unsigned long int) __NR_arch_prctl), \
"D" ((unsigned long int) ARCH_SET_FS), \
"S" (_descr) \
: "memory", "cc", "r11", "cx"); \
\
_result ? "cannot set %fs base address for thread-local storage" : 0; \
})
/* Return the address of the dtv for the current thread. */
# define THREAD_DTV() \
({ struct pthread *__pd; \
THREAD_GETMEM (__pd, dtv); })
/* Return the thread descriptor for the current thread.
The contained asm must *not* be marked volatile since otherwise
assignments like
pthread_descr self = thread_self();
do not get optimized away. */
# define THREAD_SELF \
({ struct pthread *__self; \
asm ("movq %%fs:%c1,%0" : "=r" (__self) \
: "i" (offsetof (struct pthread, self))); \
__self;})
/* Read member of the thread descriptor directly. */
# define THREAD_GETMEM(descr, member) \
({ __typeof (descr->member) __value; \
if (sizeof (__value) == 1) \
asm ("movb %%fs:%P2,%b0" \
: "=q" (__value) \
: "0" (0), "i" (offsetof (struct pthread, member))); \
else if (sizeof (__value) == 4) \
asm ("movl %%fs:%P1,%0" \
: "=r" (__value) \
: "i" (offsetof (struct pthread, member))); \
else \
{ \
if (sizeof (__value) != 8) \
/* There should not be any value with a size other than 1, \
4 or 8. */ \
abort (); \
\
asm ("movq %%fs:%P1,%0" \
: "=r" (__value) \
: "i" (offsetof (struct pthread, member))); \
} \
__value; })
/* Same as THREAD_GETMEM, but the member offset can be non-constant. */
# define THREAD_GETMEM_NC(descr, member, idx) \
({ __typeof (descr->member[0]) __value; \
if (sizeof (__value) == 1) \
asm ("movb %%fs:%P2(%3),%b0" \
: "=q" (__value) \
: "0" (0), "i" (offsetof (struct pthread, member[0])), \
"r" (idx)); \
else if (sizeof (__value) == 4) \
asm ("movl %%fs:%P1(,%2,4),%0" \
: "=r" (__value) \
: "i" (offsetof (struct pthread, member[0])), "r" (idx)); \
else \
{ \
if (sizeof (__value) != 8) \
/* There should not be any value with a size other than 1, \
4 or 8. */ \
abort (); \
\
asm ("movq %%fs:%P1(,%2,8),%0" \
: "=r" (__value) \
: "i" (offsetof (struct pthread, member[0])), "r" (idx)); \
} \
__value; })
/* Same as THREAD_SETMEM, but the member offset can be non-constant. */
# define THREAD_SETMEM(descr, member, value) \
({ if (sizeof (descr->member) == 1) \
asm volatile ("movb %0,%%fs:%P1" : \
: "iq" (value), \
"i" (offsetof (struct pthread, member))); \
else if (sizeof (descr->member) == 4) \
asm volatile ("movl %0,%%fs:%P1" : \
: "ir" (value), \
"i" (offsetof (struct pthread, member))); \
else \
{ \
if (sizeof (descr->member) != 8) \
/* There should not be any value with a size other than 1, \
4 or 8. */ \
abort (); \
\
asm volatile ("movq %0,%%fs:%P1" : \
: "ir" ((unsigned long int) value), \
"i" (offsetof (struct pthread, member))); \
}})
/* Set member of the thread descriptor directly. */
# define THREAD_SETMEM_NC(descr, member, idx, value) \
({ if (sizeof (descr->member[0]) == 1) \
asm volatile ("movb %0,%%fs:%P1(%2)" : \
: "iq" (value), \
"i" (offsetof (struct pthread, member[0])), \
"r" (idx)); \
else if (sizeof (descr->member[0]) == 4) \
asm volatile ("movl %0,%%fs:%P1(,%2,4)" : \
: "ir" (value), \
"i" (offsetof (struct pthread, member[0])), \
"r" (idx)); \
else \
{ \
if (sizeof (descr->member[0]) != 8) \
/* There should not be any value with a size other than 1, \
4 or 8. */ \
abort (); \
\
asm volatile ("movq %0,%%fs:%P1(,%2,8)" : \
: "r" ((unsigned long int) value), \
"i" (offsetof (struct pthread, member[0])), \
"r" (idx)); \
}})
#endif /* __ASSEMBLER__ */
#endif /* tls.h */