]> sourceware.org Git - glibc.git/blame - nptl/sysdeps/i386/tls.h
(TLS_INIT_TP): Include \n in error message.
[glibc.git] / nptl / sysdeps / i386 / tls.h
CommitLineData
117c452c 1/* Definition for thread-local data handling. nptl/i386 version.
a1f8ec97 2 Copyright (C) 2002, 2003 Free Software Foundation, Inc.
76a50749
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
097eca29 23#include <dl-sysdep.h>
76a50749
UD
24#ifndef __ASSEMBLER__
25# include <stddef.h>
26# include <stdint.h>
33b5d0cc 27# include <stdlib.h>
9ae0909b 28# include <list.h>
76a50749
UD
29
30
31/* Type for the dtv. */
32typedef union dtv
33{
34 size_t counter;
35 void *pointer;
36} dtv_t;
37
38
39typedef struct
40{
41 void *tcb; /* Pointer to the TCB. Not necessary the
42 thread descriptor used by libpthread. */
43 dtv_t *dtv;
44 void *self; /* Pointer to the thread descriptor. */
9ae0909b 45 int multiple_threads;
df45b31e 46 uintptr_t sysinfo;
76a50749 47} tcbhead_t;
3b7ed871 48
d4f64e1a
RM
49# define TLS_MULTIPLE_THREADS_IN_TCB 1
50
3b7ed871
UD
51#else /* __ASSEMBLER__ */
52# include <tcb-offsets.h>
76a50749
UD
53#endif
54
55
56/* We require TLS support in the tools. */
57#ifndef HAVE_TLS_SUPPORT
58# error "TLS support is required."
59#endif
60
61/* Signal that TLS support is available. */
62#define USE_TLS 1
63
9ae0909b 64/* Alignment requirement for the stack. For IA-32 this is governed by
76a50749
UD
65 the SSE memory functions. */
66#define STACK_ALIGN 16
67
76a50749
UD
68#ifndef __ASSEMBLER__
69/* Get system call information. */
70# include <sysdep.h>
71
72/* The old way: using LDT. */
73
74/* Structure passed to `modify_ldt', 'set_thread_area', and 'clone' calls. */
75struct user_desc
76{
77 unsigned int entry_number;
78 unsigned long int base_addr;
79 unsigned int limit;
80 unsigned int seg_32bit:1;
81 unsigned int contents:2;
82 unsigned int read_exec_only:1;
83 unsigned int limit_in_pages:1;
84 unsigned int seg_not_present:1;
85 unsigned int useable:1;
86 unsigned int empty:25;
87};
88
89/* Initializing bit fields is slow. We speed it up by using a union. */
90union user_desc_init
91{
92 struct user_desc desc;
93 unsigned int vals[4];
94};
95
96
97/* Get the thread descriptor definition. */
98# include <nptl/descr.h>
99
100/* This is the size of the initial TCB. */
101# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
102
103/* Alignment requirements for the initial TCB. */
104# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
105
106/* This is the size of the TCB. */
107# define TLS_TCB_SIZE sizeof (struct pthread)
108
109/* Alignment requirements for the TCB. */
110# define TLS_TCB_ALIGN __alignof__ (struct pthread)
111
112/* The TCB can have any size and the memory following the address the
113 thread pointer points to is unspecified. Allocate the TCB there. */
114# define TLS_TCB_AT_TP 1
115
116
117/* Install the dtv pointer. The pointer passed is to the element with
118 index -1 which contain the length. */
119# define INSTALL_DTV(descr, dtvp) \
d4f64e1a 120 ((tcbhead_t *) (descr))->dtv = (dtvp) + 1
76a50749
UD
121
122/* Install new dtv for current thread. */
d4f64e1a 123# define INSTALL_NEW_DTV(dtvp) \
76a50749 124 ({ struct pthread *__pd; \
55c11fbd 125 THREAD_SETMEM (__pd, header.dtv, (dtvp)); })
76a50749
UD
126
127/* Return dtv of given thread descriptor. */
128# define GET_DTV(descr) \
129 (((tcbhead_t *) (descr))->dtv)
130
131
132/* Macros to load from and store into segment registers. */
133# ifndef TLS_GET_GS
134# define TLS_GET_GS() \
135 ({ int __seg; __asm ("movw %%gs, %w0" : "=q" (__seg)); __seg & 0xffff; })
136# endif
137# ifndef TLS_SET_GS
138# define TLS_SET_GS(val) \
139 __asm ("movw %w0, %%gs" :: "q" (val))
140# endif
141
142
143# ifndef __NR_set_thread_area
144# define __NR_set_thread_area 243
145# endif
146# ifndef TLS_FLAG_WRITABLE
147# define TLS_FLAG_WRITABLE 0x00000001
148# endif
149
150// XXX Enable for the real world.
151#if 0
152# ifndef __ASSUME_SET_THREAD_AREA
153# error "we need set_thread_area"
154# endif
155#endif
156
157# ifdef __PIC__
158# define TLS_EBX_ARG "r"
159# define TLS_LOAD_EBX "xchgl %3, %%ebx\n\t"
160# else
161# define TLS_EBX_ARG "b"
162# define TLS_LOAD_EBX
163# endif
164
a1f8ec97 165#if defined NEED_DL_SYSINFO
df45b31e
UD
166# define INIT_SYSINFO \
167 _head->sysinfo = GL(dl_sysinfo)
168#else
169# define INIT_SYSINFO
170#endif
171
bd4f43b4 172#ifndef LOCK_PREFIX
b22d701b 173# ifdef UP
bd4f43b4 174# define LOCK_PREFIX /* nothing */
b22d701b 175# else
bd4f43b4 176# define LOCK_PREFIX "lock;"
b22d701b
UD
177# endif
178#endif
179
76a50749
UD
180/* Code to initially initialize the thread pointer. This might need
181 special attention since 'errno' is not yet available and if the
182 operation can cause a failure 'errno' must not be touched. */
183# define TLS_INIT_TP(thrdescr, secondcall) \
184 ({ void *_thrdescr = (thrdescr); \
185 tcbhead_t *_head = _thrdescr; \
186 union user_desc_init _segdescr; \
187 int _result; \
188 \
189 _head->tcb = _thrdescr; \
190 /* For now the thread descriptor is at the same address. */ \
191 _head->self = _thrdescr; \
df45b31e
UD
192 /* New syscall handling support. */ \
193 INIT_SYSINFO; \
76a50749
UD
194 \
195 /* The 'entry_number' field. Let the kernel pick a value. */ \
196 if (secondcall) \
197 _segdescr.vals[0] = TLS_GET_GS () >> 3; \
198 else \
199 _segdescr.vals[0] = -1; \
200 /* The 'base_addr' field. Pointer to the TCB. */ \
201 _segdescr.vals[1] = (unsigned long int) _thrdescr; \
202 /* The 'limit' field. We use 4GB which is 0xfffff pages. */ \
203 _segdescr.vals[2] = 0xfffff; \
204 /* Collapsed value of the bitfield: \
205 .seg_32bit = 1 \
206 .contents = 0 \
207 .read_exec_only = 0 \
208 .limit_in_pages = 1 \
209 .seg_not_present = 0 \
210 .useable = 1 */ \
211 _segdescr.vals[3] = 0x51; \
212 \
213 /* Install the TLS. */ \
214 asm volatile (TLS_LOAD_EBX \
215 "int $0x80\n\t" \
216 TLS_LOAD_EBX \
217 : "=a" (_result), "=m" (_segdescr.desc.entry_number) \
218 : "0" (__NR_set_thread_area), \
219 TLS_EBX_ARG (&_segdescr.desc), "m" (_segdescr.desc)); \
220 \
221 if (_result == 0) \
222 /* We know the index in the GDT, now load the segment register. \
223 The use of the GDT is described by the value 3 in the lower \
224 three bits of the segment descriptor value. \
225 \
226 Note that we have to do this even if the numeric value of \
227 the descriptor does not change. Loading the segment register \
228 causes the segment information from the GDT to be loaded \
229 which is necessary since we have changed it. */ \
230 TLS_SET_GS (_segdescr.desc.entry_number * 8 + 3); \
231 \
fde89ad0 232 _result == 0 ? NULL \
e55674c6 233 : "set_thread_area failed when setting up thread-local storage\n"; })
76a50749
UD
234
235
236/* Return the address of the dtv for the current thread. */
237# define THREAD_DTV() \
238 ({ struct pthread *__pd; \
55c11fbd 239 THREAD_GETMEM (__pd, header.dtv); })
76a50749
UD
240
241
242/* Return the thread descriptor for the current thread.
243
244 The contained asm must *not* be marked volatile since otherwise
245 assignments like
246 pthread_descr self = thread_self();
247 do not get optimized away. */
248# define THREAD_SELF \
249 ({ struct pthread *__self; \
250 asm ("movl %%gs:%c1,%0" : "=r" (__self) \
55c11fbd 251 : "i" (offsetof (struct pthread, header.self))); \
76a50749
UD
252 __self;})
253
9a7178d6
UD
254/* Identifier for the current thread. THREAD_SELF is usable but
255 sometimes more expensive than necessary. It is fine here. */
256# define THREAD_ID THREAD_SELF
257
76a50749
UD
258
259/* Read member of the thread descriptor directly. */
260# define THREAD_GETMEM(descr, member) \
261 ({ __typeof (descr->member) __value; \
262 if (sizeof (__value) == 1) \
fd1a0d0c
UD
263 asm volatile ("movb %%gs:%P2,%b0" \
264 : "=q" (__value) \
265 : "0" (0), "i" (offsetof (struct pthread, member))); \
76a50749 266 else if (sizeof (__value) == 4) \
fd1a0d0c
UD
267 asm volatile ("movl %%gs:%P1,%0" \
268 : "=r" (__value) \
269 : "i" (offsetof (struct pthread, member))); \
76a50749
UD
270 else \
271 { \
272 if (sizeof (__value) != 8) \
273 /* There should not be any value with a size other than 1, \
274 4 or 8. */ \
275 abort (); \
276 \
fd1a0d0c
UD
277 asm volatile ("movl %%gs:%P1,%%eax\n\t" \
278 "movl %%gs:%P2,%%edx" \
279 : "=A" (__value) \
280 : "i" (offsetof (struct pthread, member)), \
281 "i" (offsetof (struct pthread, member) + 4)); \
76a50749
UD
282 } \
283 __value; })
284
285
286/* Same as THREAD_GETMEM, but the member offset can be non-constant. */
117c452c
UD
287# define THREAD_GETMEM_NC(descr, member, idx) \
288 ({ __typeof (descr->member[0]) __value; \
76a50749 289 if (sizeof (__value) == 1) \
fd1a0d0c
UD
290 asm volatile ("movb %%gs:%P2(%3),%b0" \
291 : "=q" (__value) \
292 : "0" (0), "i" (offsetof (struct pthread, member[0])), \
293 "r" (idx)); \
76a50749 294 else if (sizeof (__value) == 4) \
fd1a0d0c
UD
295 asm volatile ("movl %%gs:%P1(,%2,4),%0" \
296 : "=r" (__value) \
297 : "i" (offsetof (struct pthread, member[0])), \
298 "r" (idx)); \
76a50749
UD
299 else \
300 { \
301 if (sizeof (__value) != 8) \
302 /* There should not be any value with a size other than 1, \
303 4 or 8. */ \
304 abort (); \
305 \
fd1a0d0c
UD
306 asm volatile ("movl %%gs:%P1(,%2,8),%%eax\n\t" \
307 "movl %%gs:4+%P1(,%2,8),%%edx" \
308 : "=&A" (__value) \
309 : "i" (offsetof (struct pthread, member[0])), \
310 "r" (idx)); \
76a50749
UD
311 } \
312 __value; })
313
314
315/* Same as THREAD_SETMEM, but the member offset can be non-constant. */
316# define THREAD_SETMEM(descr, member, value) \
117c452c 317 ({ if (sizeof (descr->member) == 1) \
5a03acfe 318 asm volatile ("movb %b0,%%gs:%P1" : \
76a50749
UD
319 : "iq" (value), \
320 "i" (offsetof (struct pthread, member))); \
117c452c 321 else if (sizeof (descr->member) == 4) \
76a50749
UD
322 asm volatile ("movl %0,%%gs:%P1" : \
323 : "ir" (value), \
324 "i" (offsetof (struct pthread, member))); \
325 else \
326 { \
117c452c 327 if (sizeof (descr->member) != 8) \
76a50749
UD
328 /* There should not be any value with a size other than 1, \
329 4 or 8. */ \
330 abort (); \
331 \
117c452c 332 asm volatile ("movl %%eax,%%gs:%P1\n\t" \
76a50749
UD
333 "movl %%edx,%%gs:%P2" : \
334 : "A" (value), \
335 "i" (offsetof (struct pthread, member)), \
336 "i" (offsetof (struct pthread, member) + 4)); \
337 }})
338
339
340/* Set member of the thread descriptor directly. */
117c452c
UD
341# define THREAD_SETMEM_NC(descr, member, idx, value) \
342 ({ if (sizeof (descr->member[0]) == 1) \
5a03acfe 343 asm volatile ("movb %b0,%%gs:%P1(%2)" : \
76a50749 344 : "iq" (value), \
117c452c
UD
345 "i" (offsetof (struct pthread, member)), \
346 "r" (idx)); \
347 else if (sizeof (descr->member[0]) == 4) \
348 asm volatile ("movl %0,%%gs:%P1(,%2,4)" : \
76a50749 349 : "ir" (value), \
117c452c
UD
350 "i" (offsetof (struct pthread, member)), \
351 "r" (idx)); \
76a50749
UD
352 else \
353 { \
117c452c 354 if (sizeof (descr->member[0]) != 8) \
76a50749
UD
355 /* There should not be any value with a size other than 1, \
356 4 or 8. */ \
357 abort (); \
358 \
117c452c
UD
359 asm volatile ("movl %%eax,%%gs:%P1(,%2,8)\n\t" \
360 "movl %%edx,%%gs:4+%P1(,%2,8)" : \
76a50749 361 : "A" (value), \
117c452c
UD
362 "i" (offsetof (struct pthread, member)), \
363 "r" (idx)); \
76a50749
UD
364 }})
365
366
b22d701b
UD
367/* Atomic compare and exchange on TLS, returning old value. */
368#define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, newval, oldval) \
369 ({ __typeof (descr->member) __ret; \
370 __typeof (oldval) __old = (oldval); \
371 if (sizeof (descr->member) == 4) \
bd4f43b4 372 asm volatile (LOCK_PREFIX "cmpxchgl %2, %%gs:%P3" \
b22d701b
UD
373 : "=a" (__ret) \
374 : "0" (__old), "r" (newval), \
375 "i" (offsetof (struct pthread, member))); \
376 else \
377 /* Not necessary for other sizes in the moment. */ \
378 abort (); \
379 __ret; })
380
381
382/* Atomic set bit. */
383#define THREAD_ATOMIC_BIT_SET(descr, member, bit) \
384 (void) ({ if (sizeof ((descr)->member) == 4) \
bd4f43b4 385 asm volatile (LOCK_PREFIX "orl %1, %%gs:%P0" \
b22d701b
UD
386 :: "i" (offsetof (struct pthread, member)), \
387 "ir" (1 << (bit))); \
388 else \
389 /* Not necessary for other sizes in the moment. */ \
390 abort (); })
391
392
e22a221d
UD
393/* Call the user-provided thread function. */
394#define CALL_THREAD_FCT(descr) \
395 ({ void *__res; \
396 int __ignore1, __ignore2; \
f877b338 397 asm volatile ("pushl %%gs:%P4\n\t" \
e22a221d 398 "call *%%gs:%P3\n\t" \
f877b338 399 "addl $4, %%esp" \
e22a221d
UD
400 : "=a" (__res), "=c" (__ignore1), "=d" (__ignore2) \
401 : "i" (offsetof (struct pthread, start_routine)), \
402 "i" (offsetof (struct pthread, arg))); \
403 __res; })
404
405
76a50749
UD
406#endif /* __ASSEMBLER__ */
407
408#endif /* tls.h */
This page took 0.114301 seconds and 5 git commands to generate.