blob: 4c9b68099025a670ce5995e75bc8fb115571662d [file] [log] [blame]
yuezonghe824eb0c2024-06-27 02:32:26 -07001/* Definition for thread-local data handling. linuxthreads/i386 version.
2 Copyright (C) 2002, 2003, 2004, 2005 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
22
23# include <pt-machine.h>
24
25#ifndef __ASSEMBLER__
26# include <stdbool.h>
27# include <stddef.h>
28# include <stdint.h>
29
30/* Type for the dtv. */
31typedef union dtv
32{
33 size_t counter;
34 struct
35 {
36 void *val;
37 bool is_static;
38 } pointer;
39} dtv_t;
40
41
42typedef struct
43{
44 void *tcb; /* Pointer to the TCB. Not necessary the
45 thread descriptor used by libpthread. */
46 dtv_t *dtv;
47 void *self; /* Pointer to the thread descriptor. */
48 int multiple_threads;
49 uintptr_t sysinfo;
50} tcbhead_t;
51
52#else /* __ASSEMBLER__ */
53# include <tcb-offsets.h>
54#endif
55
56/* We can support TLS only if the floating-stack support is available.
57 However, we want to compile in the support and test at runtime whether
58 the running kernel can support it or not. To avoid bothering with the
59 TLS support code at all, use configure --without-tls.
60
61 We need USE_TLS to be consistently defined, for ldsodefs.h conditionals.
62 But some of the code below can cause problems in building libpthread
63 (e.g. useldt.h will defined FLOATING_STACKS when it shouldn't). */
64
65#if defined HAVE_TLS_SUPPORT \
66 && (defined FLOATING_STACKS || !defined IS_IN_libpthread)
67
68/* Signal that TLS support is available. */
69# define USE_TLS 1
70
71# ifndef __ASSEMBLER__
72/* Get system call information. */
73# include <sysdep.h>
74
75
76/* Get the thread descriptor definition. */
77# include <linuxthreads/descr.h>
78
79/* This is the size of the initial TCB. */
80# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
81
82/* Alignment requirements for the initial TCB. */
83# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
84
85/* This is the size of the TCB. */
86# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct)
87
88/* Alignment requirements for the TCB. */
89# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
90
91/* The TCB can have any size and the memory following the address the
92 thread pointer points to is unspecified. Allocate the TCB there. */
93# define TLS_TCB_AT_TP 1
94
95
96/* Install the dtv pointer. The pointer passed is to the element with
97 index -1 which contain the length. */
98# define INSTALL_DTV(descr, dtvp) \
99 ((tcbhead_t *) (descr))->dtv = (dtvp) + 1
100
101/* Install new dtv for current thread. */
102# define INSTALL_NEW_DTV(dtv) \
103 ({ struct _pthread_descr_struct *__descr; \
104 THREAD_SETMEM (__descr, p_header.data.dtvp, (dtv)); })
105
106/* Return dtv of given thread descriptor. */
107# define GET_DTV(descr) \
108 (((tcbhead_t *) (descr))->dtv)
109
110# ifdef __PIC__
111# define TLS_EBX_ARG "r"
112# define TLS_LOAD_EBX "xchgl %3, %%ebx\n\t"
113# else
114# define TLS_EBX_ARG "b"
115# define TLS_LOAD_EBX
116# endif
117
118# if !defined IS_IN_libpthread && !defined DO_MODIFY_LDT
119# include "useldt.h" /* For the structure. */
120# endif
121# if __ASSUME_LDT_WORKS > 0
122# define TLS_DO_MODIFY_LDT_KERNEL_CHECK(doit) (doit) /* Nothing to check. */
123# else
124# define TLS_DO_MODIFY_LDT_KERNEL_CHECK(doit) \
125 (__builtin_expect (GLRO(dl_osversion) < 131939, 0) \
126 ? "kernel too old for thread-local storage support\n" \
127 : (doit))
128# endif
129
130# define TLS_DO_MODIFY_LDT(descr, nr) \
131TLS_DO_MODIFY_LDT_KERNEL_CHECK( \
132({ \
133 struct modify_ldt_ldt_s ldt_entry = \
134 { nr, (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \
135 1, 0, 0, 1, 0, 1, 0 }; \
136 int result; \
137 __asm__ __volatile__ (TLS_LOAD_EBX \
138 "int $0x80\n\t" \
139 TLS_LOAD_EBX \
140 : "=a" (result) \
141 : "0" (__NR_modify_ldt), \
142 /* The extra argument with the "m" constraint is necessary \
143 to let the compiler know that we are accessing LDT_ENTRY \
144 here. */ \
145 "m" (ldt_entry), TLS_EBX_ARG (1), "c" (&ldt_entry), \
146 "d" (sizeof (ldt_entry))); \
147 __builtin_expect (result, 0) == 0 \
148 ? ({ __asm__ ("movw %w0, %%gs" : : "q" ((nr) * 8 + 7)); NULL; }) \
149 : "cannot set up LDT for thread-local storage\n"; \
150}))
151
152# define TLS_DO_SET_THREAD_AREA(descr, secondcall) \
153({ \
154 struct modify_ldt_ldt_s ldt_entry = \
155 { -1, (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \
156 1, 0, 0, 1, 0, 1, 0 }; \
157 int result; \
158 if (secondcall) \
159 ldt_entry.entry_number = ({ int _gs; \
160 __asm__ ("movw %%gs, %w0" : "=q" (_gs)); \
161 (_gs & 0xffff) >> 3; }); \
162 __asm__ __volatile__ (TLS_LOAD_EBX \
163 "int $0x80\n\t" \
164 TLS_LOAD_EBX \
165 : "=a" (result), "=m" (ldt_entry.entry_number) \
166 : "0" (__NR_set_thread_area), \
167 /* The extra argument with the "m" constraint is necessary \
168 to let the compiler know that we are accessing LDT_ENTRY \
169 here. */ \
170 TLS_EBX_ARG (&ldt_entry), "m" (ldt_entry)); \
171 if (__builtin_expect (result, 0) == 0) \
172 __asm__ ("movw %w0, %%gs" : : "q" (ldt_entry.entry_number * 8 + 3)); \
173 result; \
174})
175
176# ifdef __ASSUME_SET_THREAD_AREA_SYSCALL
177# define TLS_SETUP_GS_SEGMENT(descr, secondcall) \
178 (TLS_DO_SET_THREAD_AREA (descr, secondcall) \
179 ? "set_thread_area failed when setting up thread-local storage\n" : NULL)
180# elif defined __NR_set_thread_area
181# define TLS_SETUP_GS_SEGMENT(descr, secondcall) \
182 (TLS_DO_SET_THREAD_AREA (descr, secondcall) \
183 ? TLS_DO_MODIFY_LDT (descr, 0) : NULL)
184# else
185# define TLS_SETUP_GS_SEGMENT(descr, secondcall) \
186 TLS_DO_MODIFY_LDT ((descr), 0)
187# endif
188
189#if defined NEED_DL_SYSINFO
190# define INIT_SYSINFO \
191 head->sysinfo = GLRO(dl_sysinfo)
192#else
193# define INIT_SYSINFO
194#endif
195
196/* Code to initially initialize the thread pointer. This might need
197 special attention since 'errno' is not yet available and if the
198 operation can cause a failure 'errno' must not be touched.
199
200 The value of this macro is null if successful, or an error string. */
201# define TLS_INIT_TP(descr, secondcall) \
202 ({ \
203 void *_descr = (descr); \
204 tcbhead_t *head = _descr; \
205 \
206 head->tcb = _descr; \
207 /* For now the thread descriptor is at the same address. */ \
208 head->self = _descr; \
209 \
210 INIT_SYSINFO; \
211 TLS_SETUP_GS_SEGMENT (_descr, secondcall); \
212 })
213
214/* Indicate that dynamic linker shouldn't try to initialize TLS even
215 when no PT_TLS segments are found in the program and libraries
216 it is linked against. */
217# define TLS_INIT_TP_EXPENSIVE 1
218
219/* Return the address of the dtv for the current thread. */
220# define THREAD_DTV() \
221 ({ struct _pthread_descr_struct *__descr; \
222 THREAD_GETMEM (__descr, p_header.data.dtvp); })
223
224# endif /* HAVE_TLS_SUPPORT && (FLOATING_STACKS || !IS_IN_libpthread) */
225#endif /* __ASSEMBLER__ */
226
227#endif /* tls.h */