xref: /openbsd-src/lib/libc/include/thread_private.h (revision d59bb9942320b767f2a19aaa7690c8c6e30b724c)
1 /* $OpenBSD: thread_private.h,v 1.29 2016/10/15 18:24:40 guenther Exp $ */
2 
3 /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */
4 
5 #ifndef _THREAD_PRIVATE_H_
6 #define _THREAD_PRIVATE_H_
7 
8 #include <stdio.h>		/* for FILE and __isthreaded */
9 
10 #define _MALLOC_MUTEXES 4
11 void _malloc_init(int);
12 #ifdef __LIBC__
13 PROTO_NORMAL(_malloc_init);
14 #endif /* __LIBC__ */
15 
16 /*
17  * The callbacks needed by libc to handle the threaded case.
18  * NOTE: Bump the version when you change the struct contents!
19  *
20  * tc_canceled:
21  *	If not NULL, what to do when canceled (otherwise _exit(0))
22  *
23  * tc_flockfile, tc_ftrylockfile, and tc_funlockfile:
24  *	If not NULL, these implement the flockfile() family.
25  *	XXX In theory, you should be able to lock a FILE before
26  *	XXX loading libpthread and have that be a real lock on it,
27  *	XXX but that doesn't work without the libc base version
28  *	XXX tracking the recursion count.
29  *
30  * tc_malloc_lock and tc_malloc_unlock:
31  * tc_atexit_lock and tc_atexit_unlock:
32  * tc_atfork_lock and tc_atfork_unlock:
33  * tc_arc4_lock and tc_arc4_unlock:
34  *	The locks used by the malloc, atexit, atfork, and arc4 subsystems.
35  *	These have to be ordered specially in the fork/vfork wrappers
36  *	and may be implemented differently than the general mutexes
37  *	in the callbacks below.
38  *
39  * tc_mutex_lock and tc_mutex_unlock:
40  *	Lock and unlock the given mutex. If the given mutex is NULL
41  *	a mutex is allocated and initialized automatically.
42  *
43  * tc_mutex_destroy:
44  *	Destroy/deallocate the given mutex.
45  *
46  * tc_tag_lock and tc_tag_unlock:
47  *	Lock and unlock the mutex associated with the given tag.
48  *	If the given tag is NULL a tag is allocated and initialized
49  *	automatically.
50  *
51  * tc_tag_storage:
52  *	Returns a pointer to per-thread instance of data associated
53  *	with the given tag.  If the given tag is NULL a tag is
54  *	allocated and initialized automatically.
55  *
56  * tc_fork, tc_vfork:
57  *	If not NULL, they are called instead of the syscall stub, so that
58  *	the thread library can do necessary locking and reinitialization.
59  *
60  *
61  * If <machine/tcb.h> doesn't define TCB_GET(), then locating the TCB in a
62  * threaded process requires a syscall (__get_tcb(2)) which is too much
63  * overhead for single-threaded processes.  For those archs, there are two
64  * additional callbacks, though they are placed first in the struct for
65  * convenience in ASM:
66  *
67  * tc_errnoptr:
68  *	Returns the address of the thread's errno.
69  *
70  * tc_tcb:
71  *	Returns the address of the thread's TCB.
72  */
73 
74 struct thread_callbacks {
75 	int	*(*tc_errnoptr)(void);		/* MUST BE FIRST */
76 	void	*(*tc_tcb)(void);
77 	__dead void	(*tc_canceled)(void);
78 	void	(*tc_flockfile)(FILE *);
79 	int	(*tc_ftrylockfile)(FILE *);
80 	void	(*tc_funlockfile)(FILE *);
81 	void	(*tc_malloc_lock)(int);
82 	void	(*tc_malloc_unlock)(int);
83 	void	(*tc_atexit_lock)(void);
84 	void	(*tc_atexit_unlock)(void);
85 	void	(*tc_atfork_lock)(void);
86 	void	(*tc_atfork_unlock)(void);
87 	void	(*tc_arc4_lock)(void);
88 	void	(*tc_arc4_unlock)(void);
89 	void	(*tc_mutex_lock)(void **);
90 	void	(*tc_mutex_unlock)(void **);
91 	void	(*tc_mutex_destroy)(void **);
92 	void	(*tc_tag_lock)(void **);
93 	void	(*tc_tag_unlock)(void **);
94 	void	*(*tc_tag_storage)(void **, void *, size_t, void *);
95 	__pid_t	(*tc_fork)(void);
96 	__pid_t	(*tc_vfork)(void);
97 };
98 
99 __BEGIN_PUBLIC_DECLS
100 /*
101  *  Set the callbacks used by libc
102  */
103 void	_thread_set_callbacks(const struct thread_callbacks *_cb, size_t _len);
104 __END_PUBLIC_DECLS
105 
106 #ifdef __LIBC__
107 __BEGIN_HIDDEN_DECLS
108 /* the current set */
109 extern struct thread_callbacks _thread_cb;
110 __END_HIDDEN_DECLS
111 #endif /* __LIBC__ */
112 
113 /*
114  * helper macro to make unique names in the thread namespace
115  */
116 #define __THREAD_NAME(name)	__CONCAT(_thread_tagname_,name)
117 
118 /*
119  * Resolver code is special cased in that it uses global keys.
120  */
121 extern void *__THREAD_NAME(_res);
122 extern void *__THREAD_NAME(_res_ext);
123 extern void *__THREAD_NAME(serv_mutex);
124 
125 /*
126  * Macros used in libc to access thread mutex, keys, and per thread storage.
127  * _THREAD_PRIVATE_KEY and _THREAD_PRIVATE_MUTEX are different macros for
128  * historical reasons.   They do the same thing, define a static variable
129  * keyed by 'name' that identifies a mutex and a key to identify per thread
130  * data.
131  */
132 #define _THREAD_PRIVATE_KEY(name)					\
133 	static void *__THREAD_NAME(name)
134 #define _THREAD_PRIVATE_MUTEX(name)					\
135 	static void *__THREAD_NAME(name)
136 
137 
138 #ifndef __LIBC__	/* building some sort of reach around */
139 
140 #define _THREAD_PRIVATE_MUTEX_LOCK(name)		do {} while (0)
141 #define _THREAD_PRIVATE_MUTEX_UNLOCK(name)		do {} while (0)
142 #define _THREAD_PRIVATE(keyname, storage, error)	&(storage)
143 #define _MUTEX_LOCK(mutex)				do {} while (0)
144 #define _MUTEX_UNLOCK(mutex)				do {} while (0)
145 #define _MUTEX_DESTROY(mutex)				do {} while (0)
146 #define _MALLOC_LOCK(n)					do {} while (0)
147 #define _MALLOC_UNLOCK(n)				do {} while (0)
148 #define _ATEXIT_LOCK()					do {} while (0)
149 #define _ATEXIT_UNLOCK()				do {} while (0)
150 #define _ATFORK_LOCK()					do {} while (0)
151 #define _ATFORK_UNLOCK()				do {} while (0)
152 #define _ARC4_LOCK()					do {} while (0)
153 #define _ARC4_UNLOCK()					do {} while (0)
154 
155 #else		/* building libc */
156 #define _THREAD_PRIVATE_MUTEX_LOCK(name)				\
157 	do {								\
158 		if (_thread_cb.tc_tag_lock != NULL)			\
159 			_thread_cb.tc_tag_lock(&(__THREAD_NAME(name)));	\
160 	} while (0)
161 #define _THREAD_PRIVATE_MUTEX_UNLOCK(name)				\
162 	do {								\
163 		if (_thread_cb.tc_tag_unlock != NULL)			\
164 			_thread_cb.tc_tag_unlock(&(__THREAD_NAME(name))); \
165 	} while (0)
166 #define _THREAD_PRIVATE(keyname, storage, error)			\
167 	(_thread_cb.tc_tag_storage == NULL ? &(storage) :		\
168 	    _thread_cb.tc_tag_storage(&(__THREAD_NAME(keyname)),	\
169 		&(storage), sizeof(storage), error))
170 
171 /*
172  * Macros used in libc to access mutexes.
173  */
174 #define _MUTEX_LOCK(mutex)						\
175 	do {								\
176 		if (__isthreaded)					\
177 			_thread_cb.tc_mutex_lock(mutex);		\
178 	} while (0)
179 #define _MUTEX_UNLOCK(mutex)						\
180 	do {								\
181 		if (__isthreaded)					\
182 			_thread_cb.tc_mutex_unlock(mutex);		\
183 	} while (0)
184 #define _MUTEX_DESTROY(mutex)						\
185 	do {								\
186 		if (__isthreaded)					\
187 			_thread_cb.tc_mutex_destroy(mutex);		\
188 	} while (0)
189 
190 /*
191  * malloc lock/unlock prototypes and definitions
192  */
193 #define _MALLOC_LOCK(n)							\
194 	do {								\
195 		if (__isthreaded)					\
196 			_thread_cb.tc_malloc_lock(n);			\
197 	} while (0)
198 #define _MALLOC_UNLOCK(n)						\
199 	do {								\
200 		if (__isthreaded)					\
201 			_thread_cb.tc_malloc_unlock(n);			\
202 	} while (0)
203 
204 #define _ATEXIT_LOCK()							\
205 	do {								\
206 		if (__isthreaded)					\
207 			_thread_cb.tc_atexit_lock();			\
208 	} while (0)
209 #define _ATEXIT_UNLOCK()						\
210 	do {								\
211 		if (__isthreaded)					\
212 			_thread_cb.tc_atexit_unlock();			\
213 	} while (0)
214 
215 #define _ATFORK_LOCK()							\
216 	do {								\
217 		if (__isthreaded)					\
218 			_thread_cb.tc_atfork_lock();			\
219 	} while (0)
220 #define _ATFORK_UNLOCK()						\
221 	do {								\
222 		if (__isthreaded)					\
223 			_thread_cb.tc_atfork_unlock();			\
224 	} while (0)
225 
226 #define _ARC4_LOCK()							\
227 	do {								\
228 		if (__isthreaded)					\
229 			_thread_cb.tc_arc4_lock();			\
230 	} while (0)
231 #define _ARC4_UNLOCK()							\
232 	do {								\
233 		if (__isthreaded)					\
234 			_thread_cb.tc_arc4_unlock();			\
235 	} while (0)
236 #endif /* __LIBC__ */
237 
238 #endif /* _THREAD_PRIVATE_H_ */
239