]> git.ipfire.org Git - thirdparty/glibc.git/blame - nptl/sysdeps/x86_64/tls.h
Update.
[thirdparty/glibc.git] / nptl / sysdeps / x86_64 / tls.h
CommitLineData
a3931336 1/* Definition for thread-local data handling. nptl/x86_64 version.
c6180643 2 Copyright (C) 2002, 2003 Free Software Foundation, Inc.
a3931336
UD
3 This file is part of the GNU C Library.
4
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.
9
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.
14
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
18 02111-1307 USA. */
19
20#ifndef _TLS_H
21#define _TLS_H 1
22
23#ifndef __ASSEMBLER__
24# include <stddef.h>
25# include <stdint.h>
33b5d0cc 26# include <stdlib.h>
a3931336
UD
27
28
29/* Type for the dtv. */
30typedef union dtv
31{
32 size_t counter;
33 void *pointer;
34} dtv_t;
35
36
37typedef struct
38{
39 void *tcb; /* Pointer to the TCB. Not necessary the
40 thread descriptor used by libpthread. */
41 dtv_t *dtv;
42 void *self; /* Pointer to the thread descriptor. */
43} tcbhead_t;
44#endif
45
46
47/* We require TLS support in the tools. */
48#ifndef HAVE_TLS_SUPPORT
49# error "TLS support is required."
50#endif
51
52/* Signal that TLS support is available. */
53#define USE_TLS 1
54
55/* Alignment requirement for the stack. */
56#define STACK_ALIGN 16
57
58
59#ifndef __ASSEMBLER__
60/* Get system call information. */
61# include <sysdep.h>
62
a3931336
UD
63
64/* Get the thread descriptor definition. */
65# include <nptl/descr.h>
66
67/* This is the size of the initial TCB. */
68# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
69
70/* Alignment requirements for the initial TCB. */
71# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
72
73/* This is the size of the TCB. */
74# define TLS_TCB_SIZE sizeof (struct pthread)
75
76/* Alignment requirements for the TCB. */
77# define TLS_TCB_ALIGN __alignof__ (struct pthread)
78
79/* The TCB can have any size and the memory following the address the
80 thread pointer points to is unspecified. Allocate the TCB there. */
81# define TLS_TCB_AT_TP 1
82
83
84/* Install the dtv pointer. The pointer passed is to the element with
85 index -1 which contain the length. */
86# define INSTALL_DTV(descr, dtvp) \
d4f64e1a 87 ((tcbhead_t *) (descr))->dtv = (dtvp) + 1
a3931336
UD
88
89/* Install new dtv for current thread. */
d4f64e1a 90# define INSTALL_NEW_DTV(dtvp) \
a3931336 91 ({ struct pthread *__pd; \
d4f64e1a 92 THREAD_SETMEM (__pd, dtv, (dtvp)); })
a3931336
UD
93
94/* Return dtv of given thread descriptor. */
95# define GET_DTV(descr) \
96 (((tcbhead_t *) (descr))->dtv)
97
98
c6180643
UD
99/* Macros to load from and store into segment registers. */
100# define TLS_GET_FS() \
101 ({ int __seg; __asm ("movl %%fs, %0" : "=q" (__seg)); __seg; })
102# define TLS_SET_FS(val) \
103 __asm ("movl %0, %%fs" :: "q" (val))
104
105
a3931336
UD
106/* Code to initially initialize the thread pointer. This might need
107 special attention since 'errno' is not yet available and if the
108 operation can cause a failure 'errno' must not be touched.
109
110 We have to make the syscall for both uses of the macro since the
111 address might be (and probably is) different. */
112# define TLS_INIT_TP(thrdescr, secondcall) \
113 ({ void *_thrdescr = (thrdescr); \
114 tcbhead_t *_head = _thrdescr; \
115 int _result; \
116 \
117 _head->tcb = _thrdescr; \
118 /* For now the thread descriptor is at the same address. */ \
119 _head->self = _thrdescr; \
120 \
121 /* It is a simple syscall to set the %fs value for the thread. */ \
122 asm volatile ("syscall" \
123 : "=a" (_result) \
124 : "0" ((unsigned long int) __NR_arch_prctl), \
125 "D" ((unsigned long int) ARCH_SET_FS), \
126 "S" (_descr) \
127 : "memory", "cc", "r11", "cx"); \
128 \
fde89ad0
RM
129 _result ? "cannot set %fs base address for thread-local storage" : 0; \
130 })
a3931336
UD
131
132
133/* Return the address of the dtv for the current thread. */
134# define THREAD_DTV() \
135 ({ struct pthread *__pd; \
d4f64e1a 136 THREAD_GETMEM (__pd, dtv); })
a3931336
UD
137
138
139/* Return the thread descriptor for the current thread.
140
141 The contained asm must *not* be marked volatile since otherwise
142 assignments like
143 pthread_descr self = thread_self();
144 do not get optimized away. */
145# define THREAD_SELF \
146 ({ struct pthread *__self; \
147 asm ("movq %%fs:%c1,%0" : "=r" (__self) \
d4f64e1a 148 : "i" (offsetof (struct pthread, self))); \
a3931336
UD
149 __self;})
150
151
152/* Read member of the thread descriptor directly. */
153# define THREAD_GETMEM(descr, member) \
154 ({ __typeof (descr->member) __value; \
155 if (sizeof (__value) == 1) \
156 asm ("movb %%fs:%P2,%b0" \
157 : "=q" (__value) \
158 : "0" (0), "i" (offsetof (struct pthread, member))); \
159 else if (sizeof (__value) == 4) \
160 asm ("movl %%fs:%P1,%0" \
161 : "=r" (__value) \
162 : "i" (offsetof (struct pthread, member))); \
163 else \
164 { \
165 if (sizeof (__value) != 8) \
166 /* There should not be any value with a size other than 1, \
167 4 or 8. */ \
168 abort (); \
169 \
170 asm ("movq %%fs:%P1,%0" \
171 : "=r" (__value) \
172 : "i" (offsetof (struct pthread, member))); \
173 } \
174 __value; })
175
176
177/* Same as THREAD_GETMEM, but the member offset can be non-constant. */
178# define THREAD_GETMEM_NC(descr, member, idx) \
179 ({ __typeof (descr->member[0]) __value; \
180 if (sizeof (__value) == 1) \
181 asm ("movb %%fs:%P2(%3),%b0" \
182 : "=q" (__value) \
183 : "0" (0), "i" (offsetof (struct pthread, member[0])), \
184 "r" (idx)); \
185 else if (sizeof (__value) == 4) \
186 asm ("movl %%fs:%P1(,%2,4),%0" \
187 : "=r" (__value) \
188 : "i" (offsetof (struct pthread, member[0])), "r" (idx)); \
189 else \
190 { \
191 if (sizeof (__value) != 8) \
192 /* There should not be any value with a size other than 1, \
193 4 or 8. */ \
194 abort (); \
195 \
196 asm ("movq %%fs:%P1(,%2,8),%0" \
197 : "=r" (__value) \
198 : "i" (offsetof (struct pthread, member[0])), "r" (idx)); \
199 } \
200 __value; })
201
202
203/* Same as THREAD_SETMEM, but the member offset can be non-constant. */
204# define THREAD_SETMEM(descr, member, value) \
205 ({ if (sizeof (descr->member) == 1) \
206 asm volatile ("movb %0,%%fs:%P1" : \
207 : "iq" (value), \
208 "i" (offsetof (struct pthread, member))); \
209 else if (sizeof (descr->member) == 4) \
210 asm volatile ("movl %0,%%fs:%P1" : \
211 : "ir" (value), \
212 "i" (offsetof (struct pthread, member))); \
213 else \
214 { \
215 if (sizeof (descr->member) != 8) \
216 /* There should not be any value with a size other than 1, \
217 4 or 8. */ \
218 abort (); \
219 \
220 asm volatile ("movq %0,%%fs:%P1" : \
221 : "ir" ((unsigned long int) value), \
222 "i" (offsetof (struct pthread, member))); \
223 }})
224
225
226/* Set member of the thread descriptor directly. */
227# define THREAD_SETMEM_NC(descr, member, idx, value) \
228 ({ if (sizeof (descr->member[0]) == 1) \
229 asm volatile ("movb %0,%%fs:%P1(%2)" : \
230 : "iq" (value), \
231 "i" (offsetof (struct pthread, member[0])), \
232 "r" (idx)); \
233 else if (sizeof (descr->member[0]) == 4) \
234 asm volatile ("movl %0,%%fs:%P1(,%2,4)" : \
235 : "ir" (value), \
236 "i" (offsetof (struct pthread, member[0])), \
237 "r" (idx)); \
238 else \
239 { \
240 if (sizeof (descr->member[0]) != 8) \
241 /* There should not be any value with a size other than 1, \
242 4 or 8. */ \
243 abort (); \
244 \
245 asm volatile ("movq %0,%%fs:%P1(,%2,8)" : \
246 : "r" ((unsigned long int) value), \
247 "i" (offsetof (struct pthread, member[0])), \
248 "r" (idx)); \
249 }})
250
251
252#endif /* __ASSEMBLER__ */
253
254#endif /* tls.h */