xref: /openbsd-src/include/tib.h (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: tib.h,v 1.3 2016/05/07 19:05:21 guenther Exp $	*/
2 /*
3  * Copyright (c) 2011,2014 Philip Guenther <guenther@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /*
19  * Thread Information Block (TIB) and Thread Local Storage (TLS) handling
20  * (the TCB, Thread Control Block, is part of the TIB)
21  */
22 
23 #ifndef	_TIB_H_
24 #define	_TIB_H_
25 
26 #include <sys/types.h>
27 #include <machine/tcb.h>
28 
29 #include <stddef.h>
30 
31 
32 /*
33  * This header defines struct tib and at least eight macros:
34  *	TLS_VARIANT
35  *		Either 1 or 2  (Actually defined by <machine/tcb.h>)
36  *
37  *	TCB_SET(tcb)
38  *		Set the TCB pointer for this thread to 'tcb'
39  *
40  *	TCB_GET()
41  *		Return the TCB pointer for this thread
42  *
43  *	TCB_TO_TIB(tcb)
44  *		Given a TCB pointer, return the matching TIB pointer
45  *
46  *	TIB_TO_TCB(tib)
47  *		Given a TIB pointer, return the matching TCB pointer
48  *
49  *	TIB_INIT(tib, dtv, thread)
50  *		Initializes a TIB for a new thread, using the supplied
51  *		values for its dtv and thread pointers
52  *
53  *	TIB_GET()
54  *		Short-hand for TCB_TO_TIB(TCB_GET())
55  *
56  *	TIB_EXTRA_ALIGN
57  *		On TLS varaint 2 archs, what alignment is sufficient
58  *		for the extra space that will be used for struct pthread?
59  *
60  * The following functions are provided by either ld.so (dynamic) or
61  * libc (static) for allocating and freeing a common memory block that
62  * will hold both the TIB and the pthread structure:
63  *	_dl_allocate_tib(sizeof(struct pthread))
64  *		Allocates a combined TIB and pthread memory region.
65  *		The argument is the amount of space to reserve
66  *		for the pthread structure.  Returns a pointer to
67  *		the TIB inside the allocated block.
68  *
69  * 	_dl_free_tib(tib, sizeof(struct pthread))
70  *		Frees a TIB and pthread block previously allocated
71  *		with _dl_allocate_tib().  Must be passed the return
72  *		value of that previous call.
73  */
74 
75 /*
76  * Regarding <machine/tcb.h>:
77  *  - it must define the TLS_VARIANT macro
78  *  - it may define TCB_OFFSET if the TCB address in the kernel and/or
79  *    register is offset from the actual TCB address.  TCB_OFFSET > 0
80  *    means the kernel/register points to *after* the real data.
81  *  - if there's a faster way to get or set the TCB pointer for the thread
82  *    than the __{get,set}_tcb() syscalls, it should define either or both
83  *    the TCB_{GET,SET} macros to do so.
84  */
85 
86 
87 /* If <machine/tcb.h> doesn't provide a better way, then use the default */
88 #ifdef	TCB_GET
89 # define TCB_HAVE_MD_GET	1
90 #else
91 # define TCB_GET()		__get_tcb()
92 #endif
93 #ifdef	TCB_SET
94 # define TCB_HAVE_MD_SET	1
95 #else
96 # define TCB_SET(tcb)		__set_tcb(tcb)
97 #endif
98 #ifndef TCB_OFFSET
99 # define TCB_OFFSET	0
100 #endif
101 
102 /*
103  * tib_cantcancel values is non-zero is the thread should skip all
104  * cancellation processing
105  */
106 #define CANCEL_DISABLED	1
107 #define CANCEL_DYING	2
108 
109 /*
110  * tib_cancel_point is non-zero if we're in a cancel point; its modified
111  * by the cancel point code and read by the cancellation signal handler
112  */
113 #define CANCEL_POINT		1
114 #define CANCEL_POINT_DELAYED	2
115 
116 
117 #if TLS_VARIANT == 1
118 /*
119  * ABI specifies that the static TLS data starts two words after the
120  * (notional) thread pointer, with the first of those two words being
121  * the TLS dtv pointer.  The other (second) word is reserved for the
122  * implementation, so we place the pointer to the thread structure there,
123  * but we place our actual thread bits before the TCB, at negative offsets
124  * from the TCB pointer.  Ergo, memory is laid out, low to high, as:
125  *
126  *	[pthread structure]
127  *	TIB {
128  *		...cancelation and other int-sized info...
129  *		int errno
130  *		void *locale
131  *		TCB (- TCB_OFFSET) {
132  *			void *dtv
133  *			struct pthread *thread
134  *		}
135  *	}
136  *	static TLS data
137  */
138 
139 struct tib {
140 	int	tib_thread_flags;	/* internal to libpthread */
141 	pid_t	tib_tid;
142 	int	tib_cantcancel;
143 	int	tib_cancel_point;
144 	int	tib_canceled;
145 	int	tib_errno;
146 	void	*tib_locale;
147 	void	*tib_dtv;		/* internal to the runtime linker */
148 	void	*tib_thread;
149 };
150 
151 
152 #elif TLS_VARIANT == 2
153 /*
154  * ABI specifies that the static TLS data occupies the memory before
155  * the TCB pointer, at negative offsets, and that on i386 and amd64
156  * the word the TCB points to contains a pointer to itself.  So,
157  * we place errno and our thread bits after that.  Memory is laid
158  * out, low to high, as:
159  *	static TLS data
160  *	TIB {
161  *		TCB (- TCB_OFFSET) {
162  *			self pointer [i386/amd64 only]
163  *			void *dtv
164  *		}
165  *		struct pthread *thread
166  *		void *locale
167  *		int errno
168  *		...cancelation and other int-sized info...
169  *	}
170  *	[pthread structure]
171  */
172 
173 struct tib {
174 #if defined(__i386) || defined(__amd64)
175 	struct	tib *__tib_self;
176 # define __tib_tcb __tib_self
177 #endif
178 	void	*tib_dtv;		/* internal to the runtime linker */
179 	void	*tib_thread;
180 	void	*tib_locale;
181 	int	tib_errno;
182 	int	tib_canceled;
183 	int	tib_cancel_point;
184 	int	tib_cantcancel;
185 	pid_t	tib_tid;
186 	int	tib_thread_flags;	/* internal to libpthread */
187 #if !defined(__LP64__) && !defined(__i386)
188 	int	__tib_padding;		/* padding for 8byte alignment */
189 #endif
190 };
191 
192 #if defined(__i386) || defined(__amd64)
193 # define _TIB_PREP(tib)	\
194 	((void)((tib)->__tib_self = (tib)))
195 #elif !defined(__LP64__) && !defined(__i386)
196 # define _TIB_PREP(tib)	((void)((tib)->__tib_padding = 0))
197 #endif
198 
199 #define	TIB_EXTRA_ALIGN		sizeof(void *)
200 
201 #else
202 # error "unknown TLS variant"
203 #endif
204 
205 /* nothing to do by default */
206 #ifndef	_TIB_PREP
207 # define _TIB_PREP(tib)	((void)0)
208 #endif
209 
210 #define	TIB_INIT(tib, dtv, thread)	do {		\
211 		(tib)->tib_thread	= (thread);	\
212 		(tib)->tib_locale	= NULL;		\
213 		(tib)->tib_cantcancel	= 0;		\
214 		(tib)->tib_cancel_point	= 0;		\
215 		(tib)->tib_canceled	= 0;		\
216 		(tib)->tib_dtv		= (dtv);	\
217 		(tib)->tib_errno	= 0;		\
218 		_TIB_PREP(tib);				\
219 	} while (0)
220 
221 #ifndef	__tib_tcb
222 # define __tib_tcb		tib_dtv
223 #endif
224 #define	_TIBO_TCB		(offsetof(struct tib, __tib_tcb) + TCB_OFFSET)
225 
226 #define	TCB_TO_TIB(tcb)		((struct tib *)((char *)(tcb) - _TIBO_TCB))
227 #define	TIB_TO_TCB(tib)		((char *)(tib) + _TIBO_TCB)
228 #define	TIB_GET()		TCB_TO_TIB(TCB_GET())
229 
230 
231 __BEGIN_DECLS
232 void	*_dl_allocate_tib(size_t _extra) __dso_public;
233 void	_dl_free_tib(void *_tib, size_t _extra) __dso_public;
234 
235 /* The actual syscalls */
236 void	*__get_tcb(void);
237 void	__set_tcb(void *_tcb);
238 __END_DECLS
239 
240 #endif /* _TIB_H_ */
241