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