]>
git.ipfire.org Git - thirdparty/glibc.git/blob - nptl/sysdeps/x86_64/tls.h
1 /* Definition for thread-local data handling. nptl/x86_64 version.
2 Copyright (C) 2002, 2003 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23 #include <asm/prctl.h> /* For ARCH_SET_FS. */
30 /* Type for the dtv. */
40 void *tcb
; /* Pointer to the TCB. Not necessary the
41 thread descriptor used by libpthread. */
43 void *self
; /* Pointer to the thread descriptor. */
45 #else /* __ASSEMBLER__ */
46 # include <tcb-offsets.h>
50 /* We require TLS support in the tools. */
51 #ifndef HAVE_TLS_SUPPORT
52 # error "TLS support is required."
55 /* Signal that TLS support is available. */
58 /* Alignment requirement for the stack. */
59 #define STACK_ALIGN 16
63 /* Get system call information. */
67 /* Get the thread descriptor definition. */
68 # include <nptl/descr.h>
70 /* This is the size of the initial TCB. */
71 # define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
73 /* Alignment requirements for the initial TCB. */
74 # define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
76 /* This is the size of the TCB. */
77 # define TLS_TCB_SIZE sizeof (struct pthread)
79 /* Alignment requirements for the TCB. */
80 # define TLS_TCB_ALIGN __alignof__ (struct pthread)
82 /* The TCB can have any size and the memory following the address the
83 thread pointer points to is unspecified. Allocate the TCB there. */
84 # define TLS_TCB_AT_TP 1
87 /* Install the dtv pointer. The pointer passed is to the element with
88 index -1 which contain the length. */
89 # define INSTALL_DTV(descr, dtvp) \
90 ((tcbhead_t *) (descr))->dtv = (dtvp) + 1
92 /* Install new dtv for current thread. */
93 # define INSTALL_NEW_DTV(dtvp) \
94 ({ struct pthread *__pd; \
95 THREAD_SETMEM (__pd, dtv, (dtvp)); })
97 /* Return dtv of given thread descriptor. */
98 # define GET_DTV(descr) \
99 (((tcbhead_t *) (descr))->dtv)
102 /* Macros to load from and store into segment registers. */
103 # define TLS_GET_FS() \
104 ({ int __seg; __asm ("movl %%fs, %0" : "=q" (__seg)); __seg; })
105 # define TLS_SET_FS(val) \
106 __asm ("movl %0, %%fs" :: "q" (val))
109 /* Code to initially initialize the thread pointer. This might need
110 special attention since 'errno' is not yet available and if the
111 operation can cause a failure 'errno' must not be touched.
113 We have to make the syscall for both uses of the macro since the
114 address might be (and probably is) different. */
115 # define TLS_INIT_TP(thrdescr, secondcall) \
116 ({ void *_thrdescr = (thrdescr); \
117 tcbhead_t *_head = _thrdescr; \
120 _head->tcb = _thrdescr; \
121 /* For now the thread descriptor is at the same address. */ \
122 _head->self = _thrdescr; \
124 /* It is a simple syscall to set the %fs value for the thread. */ \
125 asm volatile ("syscall" \
127 : "0" ((unsigned long int) __NR_arch_prctl), \
128 "D" ((unsigned long int) ARCH_SET_FS), \
130 : "memory", "cc", "r11", "cx"); \
132 _result ? "cannot set %fs base address for thread-local storage" : 0; \
136 /* Return the address of the dtv for the current thread. */
137 # define THREAD_DTV() \
138 ({ struct pthread *__pd; \
139 THREAD_GETMEM (__pd, dtv); })
142 /* Return the thread descriptor for the current thread.
144 The contained asm must *not* be marked volatile since otherwise
146 pthread_descr self = thread_self();
147 do not get optimized away. */
148 # define THREAD_SELF \
149 ({ struct pthread *__self; \
150 asm ("movq %%fs:%c1,%q0" : "=r" (__self) \
151 : "i" (offsetof (struct pthread, self))); \
155 /* Read member of the thread descriptor directly. */
156 # define THREAD_GETMEM(descr, member) \
157 ({ __typeof (descr->member) __value; \
158 if (sizeof (__value) == 1) \
159 asm volatile ("movb %%fs:%P2,%b0" \
161 : "0" (0), "i" (offsetof (struct pthread, member))); \
162 else if (sizeof (__value) == 4) \
163 asm volatile ("movl %%fs:%P1,%0" \
165 : "i" (offsetof (struct pthread, member))); \
168 if (sizeof (__value) != 8) \
169 /* There should not be any value with a size other than 1, \
173 asm volatile ("movq %%fs:%P1,%q0" \
175 : "i" (offsetof (struct pthread, member))); \
180 /* Same as THREAD_GETMEM, but the member offset can be non-constant. */
181 # define THREAD_GETMEM_NC(descr, member, idx) \
182 ({ __typeof (descr->member[0]) __value; \
183 if (sizeof (__value) == 1) \
184 asm volatile ("movb %%fs:%P2(%q3),%b0" \
186 : "0" (0), "i" (offsetof (struct pthread, member[0])), \
188 else if (sizeof (__value) == 4) \
189 asm volatile ("movl %%fs:%P1(,%q2,4),%0" \
191 : "i" (offsetof (struct pthread, member[0])), "r" (idx));\
194 if (sizeof (__value) != 8) \
195 /* There should not be any value with a size other than 1, \
199 asm volatile ("movq %%fs:%P1(,%q2,8),%q0" \
201 : "i" (offsetof (struct pthread, member[0])), \
207 /* Same as THREAD_SETMEM, but the member offset can be non-constant. */
208 # define THREAD_SETMEM(descr, member, value) \
209 ({ if (sizeof (descr->member) == 1) \
210 asm volatile ("movb %b0,%%fs:%P1" : \
212 "i" (offsetof (struct pthread, member))); \
213 else if (sizeof (descr->member) == 4) \
214 asm volatile ("movl %0,%%fs:%P1" : \
216 "i" (offsetof (struct pthread, member))); \
219 if (sizeof (descr->member) != 8) \
220 /* There should not be any value with a size other than 1, \
224 asm volatile ("movq %q0,%%fs:%P1" : \
225 : "ir" ((unsigned long int) value), \
226 "i" (offsetof (struct pthread, member))); \
230 /* Set member of the thread descriptor directly. */
231 # define THREAD_SETMEM_NC(descr, member, idx, value) \
232 ({ if (sizeof (descr->member[0]) == 1) \
233 asm volatile ("movb %b0,%%fs:%P1(%q2)" : \
235 "i" (offsetof (struct pthread, member[0])), \
237 else if (sizeof (descr->member[0]) == 4) \
238 asm volatile ("movl %0,%%fs:%P1(,%q2,4)" : \
240 "i" (offsetof (struct pthread, member[0])), \
244 if (sizeof (descr->member[0]) != 8) \
245 /* There should not be any value with a size other than 1, \
249 asm volatile ("movq %q0,%%fs:%P1(,%q2,8)" : \
250 : "r" ((unsigned long int) value), \
251 "i" (offsetof (struct pthread, member[0])), \
256 #endif /* __ASSEMBLER__ */