]> git.ipfire.org Git - thirdparty/glibc.git/blob - nptl/sysdeps/x86_64/tls.h
(THREAD_GETMEM): Makr asms volatile. (THREAD_GETMEM_NC): Likewise.
[thirdparty/glibc.git] / 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.
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 #include <asm/prctl.h> /* For ARCH_SET_FS. */
24 #ifndef __ASSEMBLER__
25 # include <stddef.h>
26 # include <stdint.h>
27 # include <stdlib.h>
28
29
30 /* Type for the dtv. */
31 typedef union dtv
32 {
33 size_t counter;
34 void *pointer;
35 } dtv_t;
36
37
38 typedef struct
39 {
40 void *tcb; /* Pointer to the TCB. Not necessary the
41 thread descriptor used by libpthread. */
42 dtv_t *dtv;
43 void *self; /* Pointer to the thread descriptor. */
44 } tcbhead_t;
45 #else /* __ASSEMBLER__ */
46 # include <tcb-offsets.h>
47 #endif
48
49
50 /* We require TLS support in the tools. */
51 #ifndef HAVE_TLS_SUPPORT
52 # error "TLS support is required."
53 #endif
54
55 /* Signal that TLS support is available. */
56 #define USE_TLS 1
57
58 /* Alignment requirement for the stack. */
59 #define STACK_ALIGN 16
60
61
62 #ifndef __ASSEMBLER__
63 /* Get system call information. */
64 # include <sysdep.h>
65
66
67 /* Get the thread descriptor definition. */
68 # include <nptl/descr.h>
69
70 /* This is the size of the initial TCB. */
71 # define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
72
73 /* Alignment requirements for the initial TCB. */
74 # define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
75
76 /* This is the size of the TCB. */
77 # define TLS_TCB_SIZE sizeof (struct pthread)
78
79 /* Alignment requirements for the TCB. */
80 # define TLS_TCB_ALIGN __alignof__ (struct pthread)
81
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
85
86
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
91
92 /* Install new dtv for current thread. */
93 # define INSTALL_NEW_DTV(dtvp) \
94 ({ struct pthread *__pd; \
95 THREAD_SETMEM (__pd, dtv, (dtvp)); })
96
97 /* Return dtv of given thread descriptor. */
98 # define GET_DTV(descr) \
99 (((tcbhead_t *) (descr))->dtv)
100
101
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))
107
108
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.
112
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; \
118 int _result; \
119 \
120 _head->tcb = _thrdescr; \
121 /* For now the thread descriptor is at the same address. */ \
122 _head->self = _thrdescr; \
123 \
124 /* It is a simple syscall to set the %fs value for the thread. */ \
125 asm volatile ("syscall" \
126 : "=a" (_result) \
127 : "0" ((unsigned long int) __NR_arch_prctl), \
128 "D" ((unsigned long int) ARCH_SET_FS), \
129 "S" (_thrdescr) \
130 : "memory", "cc", "r11", "cx"); \
131 \
132 _result ? "cannot set %fs base address for thread-local storage" : 0; \
133 })
134
135
136 /* Return the address of the dtv for the current thread. */
137 # define THREAD_DTV() \
138 ({ struct pthread *__pd; \
139 THREAD_GETMEM (__pd, dtv); })
140
141
142 /* Return the thread descriptor for the current thread.
143
144 The contained asm must *not* be marked volatile since otherwise
145 assignments like
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))); \
152 __self;})
153
154
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" \
160 : "=q" (__value) \
161 : "0" (0), "i" (offsetof (struct pthread, member))); \
162 else if (sizeof (__value) == 4) \
163 asm volatile ("movl %%fs:%P1,%0" \
164 : "=r" (__value) \
165 : "i" (offsetof (struct pthread, member))); \
166 else \
167 { \
168 if (sizeof (__value) != 8) \
169 /* There should not be any value with a size other than 1, \
170 4 or 8. */ \
171 abort (); \
172 \
173 asm volatile ("movq %%fs:%P1,%q0" \
174 : "=r" (__value) \
175 : "i" (offsetof (struct pthread, member))); \
176 } \
177 __value; })
178
179
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" \
185 : "=q" (__value) \
186 : "0" (0), "i" (offsetof (struct pthread, member[0])), \
187 "r" (idx)); \
188 else if (sizeof (__value) == 4) \
189 asm volatile ("movl %%fs:%P1(,%q2,4),%0" \
190 : "=r" (__value) \
191 : "i" (offsetof (struct pthread, member[0])), "r" (idx));\
192 else \
193 { \
194 if (sizeof (__value) != 8) \
195 /* There should not be any value with a size other than 1, \
196 4 or 8. */ \
197 abort (); \
198 \
199 asm volatile ("movq %%fs:%P1(,%q2,8),%q0" \
200 : "=r" (__value) \
201 : "i" (offsetof (struct pthread, member[0])), \
202 "r" (idx)); \
203 } \
204 __value; })
205
206
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" : \
211 : "iq" (value), \
212 "i" (offsetof (struct pthread, member))); \
213 else if (sizeof (descr->member) == 4) \
214 asm volatile ("movl %0,%%fs:%P1" : \
215 : "ir" (value), \
216 "i" (offsetof (struct pthread, member))); \
217 else \
218 { \
219 if (sizeof (descr->member) != 8) \
220 /* There should not be any value with a size other than 1, \
221 4 or 8. */ \
222 abort (); \
223 \
224 asm volatile ("movq %q0,%%fs:%P1" : \
225 : "ir" ((unsigned long int) value), \
226 "i" (offsetof (struct pthread, member))); \
227 }})
228
229
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)" : \
234 : "iq" (value), \
235 "i" (offsetof (struct pthread, member[0])), \
236 "r" (idx)); \
237 else if (sizeof (descr->member[0]) == 4) \
238 asm volatile ("movl %0,%%fs:%P1(,%q2,4)" : \
239 : "ir" (value), \
240 "i" (offsetof (struct pthread, member[0])), \
241 "r" (idx)); \
242 else \
243 { \
244 if (sizeof (descr->member[0]) != 8) \
245 /* There should not be any value with a size other than 1, \
246 4 or 8. */ \
247 abort (); \
248 \
249 asm volatile ("movq %q0,%%fs:%P1(,%q2,8)" : \
250 : "r" ((unsigned long int) value), \
251 "i" (offsetof (struct pthread, member[0])), \
252 "r" (idx)); \
253 }})
254
255
256 #endif /* __ASSEMBLER__ */
257
258 #endif /* tls.h */