]>
Commit | Line | Data |
---|---|---|
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. */ | |
30 | typedef union dtv | |
31 | { | |
32 | size_t counter; | |
33 | void *pointer; | |
34 | } dtv_t; | |
35 | ||
36 | ||
37 | typedef 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 */ |