diff options
Diffstat (limited to 'src/lib/libc/include/thread_private.h')
-rw-r--r-- | src/lib/libc/include/thread_private.h | 427 |
1 files changed, 0 insertions, 427 deletions
diff --git a/src/lib/libc/include/thread_private.h b/src/lib/libc/include/thread_private.h deleted file mode 100644 index 1ec1071161..0000000000 --- a/src/lib/libc/include/thread_private.h +++ /dev/null | |||
@@ -1,427 +0,0 @@ | |||
1 | /* $OpenBSD: thread_private.h,v 1.37 2024/08/18 02:25:51 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 | extern int __isthreaded; | ||
9 | |||
10 | #define _MALLOC_MUTEXES 32 | ||
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 | * tc_thread_release: | ||
61 | * Handles the release of a thread's TIB and struct pthread and the | ||
62 | * notification of other threads...when there are other threads. | ||
63 | * | ||
64 | * tc_thread_key_zero: | ||
65 | * For each thread, zero out the key data associated with the given key. | ||
66 | |||
67 | * If <machine/tcb.h> doesn't define TCB_GET(), then locating the TCB in a | ||
68 | * threaded process requires a syscall (__get_tcb(2)) which is too much | ||
69 | * overhead for single-threaded processes. For those archs, there are two | ||
70 | * additional callbacks, though they are placed first in the struct for | ||
71 | * convenience in ASM: | ||
72 | * | ||
73 | * tc_errnoptr: | ||
74 | * Returns the address of the thread's errno. | ||
75 | * | ||
76 | * tc_tcb: | ||
77 | * Returns the address of the thread's TCB. | ||
78 | */ | ||
79 | |||
80 | struct __sFILE; | ||
81 | struct pthread; | ||
82 | struct thread_callbacks { | ||
83 | int *(*tc_errnoptr)(void); /* MUST BE FIRST */ | ||
84 | void *(*tc_tcb)(void); | ||
85 | __dead void (*tc_canceled)(void); | ||
86 | void (*tc_flockfile)(struct __sFILE *); | ||
87 | int (*tc_ftrylockfile)(struct __sFILE *); | ||
88 | void (*tc_funlockfile)(struct __sFILE *); | ||
89 | void (*tc_malloc_lock)(int); | ||
90 | void (*tc_malloc_unlock)(int); | ||
91 | void (*tc_atexit_lock)(void); | ||
92 | void (*tc_atexit_unlock)(void); | ||
93 | void (*tc_atfork_lock)(void); | ||
94 | void (*tc_atfork_unlock)(void); | ||
95 | void (*tc_arc4_lock)(void); | ||
96 | void (*tc_arc4_unlock)(void); | ||
97 | void (*tc_mutex_lock)(void **); | ||
98 | void (*tc_mutex_unlock)(void **); | ||
99 | void (*tc_mutex_destroy)(void **); | ||
100 | void (*tc_tag_lock)(void **); | ||
101 | void (*tc_tag_unlock)(void **); | ||
102 | void *(*tc_tag_storage)(void **, void *, size_t, void (*)(void *), | ||
103 | void *); | ||
104 | __pid_t (*tc_fork)(void); | ||
105 | __pid_t (*tc_vfork)(void); | ||
106 | void (*tc_thread_release)(struct pthread *); | ||
107 | void (*tc_thread_key_zero)(int); | ||
108 | }; | ||
109 | |||
110 | __BEGIN_PUBLIC_DECLS | ||
111 | /* | ||
112 | * Set the callbacks used by libc | ||
113 | */ | ||
114 | void _thread_set_callbacks(const struct thread_callbacks *_cb, size_t _len); | ||
115 | __END_PUBLIC_DECLS | ||
116 | |||
117 | #ifdef __LIBC__ | ||
118 | __BEGIN_HIDDEN_DECLS | ||
119 | /* the current set */ | ||
120 | extern struct thread_callbacks _thread_cb; | ||
121 | __END_HIDDEN_DECLS | ||
122 | #endif /* __LIBC__ */ | ||
123 | |||
124 | /* | ||
125 | * helper macro to make unique names in the thread namespace | ||
126 | */ | ||
127 | #define __THREAD_NAME(name) __CONCAT(_thread_tagname_,name) | ||
128 | |||
129 | /* | ||
130 | * Macros used in libc to access thread mutex, keys, and per thread storage. | ||
131 | * _THREAD_PRIVATE_KEY and _THREAD_PRIVATE_MUTEX are different macros for | ||
132 | * historical reasons. They do the same thing, define a static variable | ||
133 | * keyed by 'name' that identifies a mutex and a key to identify per thread | ||
134 | * data. | ||
135 | */ | ||
136 | #define _THREAD_PRIVATE_KEY(name) \ | ||
137 | static void *__THREAD_NAME(name) | ||
138 | #define _THREAD_PRIVATE_MUTEX(name) \ | ||
139 | static void *__THREAD_NAME(name) | ||
140 | |||
141 | |||
142 | #ifndef __LIBC__ /* building some sort of reach around */ | ||
143 | |||
144 | #define _THREAD_PRIVATE_MUTEX_LOCK(name) do {} while (0) | ||
145 | #define _THREAD_PRIVATE_MUTEX_UNLOCK(name) do {} while (0) | ||
146 | #define _THREAD_PRIVATE(keyname, storage, error) &(storage) | ||
147 | #define _THREAD_PRIVATE_DT(keyname, storage, dt, error) &(storage) | ||
148 | #define _MUTEX_LOCK(mutex) do {} while (0) | ||
149 | #define _MUTEX_UNLOCK(mutex) do {} while (0) | ||
150 | #define _MUTEX_DESTROY(mutex) do {} while (0) | ||
151 | #define _MALLOC_LOCK(n) do {} while (0) | ||
152 | #define _MALLOC_UNLOCK(n) do {} while (0) | ||
153 | #define _ATEXIT_LOCK() do {} while (0) | ||
154 | #define _ATEXIT_UNLOCK() do {} while (0) | ||
155 | #define _ATFORK_LOCK() do {} while (0) | ||
156 | #define _ATFORK_UNLOCK() do {} while (0) | ||
157 | #define _ARC4_LOCK() do {} while (0) | ||
158 | #define _ARC4_UNLOCK() do {} while (0) | ||
159 | |||
160 | #else /* building libc */ | ||
161 | #define _THREAD_PRIVATE_MUTEX_LOCK(name) \ | ||
162 | do { \ | ||
163 | if (_thread_cb.tc_tag_lock != NULL) \ | ||
164 | _thread_cb.tc_tag_lock(&(__THREAD_NAME(name))); \ | ||
165 | } while (0) | ||
166 | #define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \ | ||
167 | do { \ | ||
168 | if (_thread_cb.tc_tag_unlock != NULL) \ | ||
169 | _thread_cb.tc_tag_unlock(&(__THREAD_NAME(name))); \ | ||
170 | } while (0) | ||
171 | #define _THREAD_PRIVATE(keyname, storage, error) \ | ||
172 | (_thread_cb.tc_tag_storage == NULL ? &(storage) : \ | ||
173 | _thread_cb.tc_tag_storage(&(__THREAD_NAME(keyname)), \ | ||
174 | &(storage), sizeof(storage), NULL, (error))) | ||
175 | |||
176 | #define _THREAD_PRIVATE_DT(keyname, storage, dt, error) \ | ||
177 | (_thread_cb.tc_tag_storage == NULL ? &(storage) : \ | ||
178 | _thread_cb.tc_tag_storage(&(__THREAD_NAME(keyname)), \ | ||
179 | &(storage), sizeof(storage), (dt), (error))) | ||
180 | |||
181 | /* | ||
182 | * Macros used in libc to access mutexes. | ||
183 | */ | ||
184 | #define _MUTEX_LOCK(mutex) \ | ||
185 | do { \ | ||
186 | if (__isthreaded) \ | ||
187 | _thread_cb.tc_mutex_lock(mutex); \ | ||
188 | } while (0) | ||
189 | #define _MUTEX_UNLOCK(mutex) \ | ||
190 | do { \ | ||
191 | if (__isthreaded) \ | ||
192 | _thread_cb.tc_mutex_unlock(mutex); \ | ||
193 | } while (0) | ||
194 | #define _MUTEX_DESTROY(mutex) \ | ||
195 | do { \ | ||
196 | if (__isthreaded) \ | ||
197 | _thread_cb.tc_mutex_destroy(mutex); \ | ||
198 | } while (0) | ||
199 | |||
200 | /* | ||
201 | * malloc lock/unlock prototypes and definitions | ||
202 | */ | ||
203 | #define _MALLOC_LOCK(n) \ | ||
204 | do { \ | ||
205 | if (__isthreaded) \ | ||
206 | _thread_cb.tc_malloc_lock(n); \ | ||
207 | } while (0) | ||
208 | #define _MALLOC_UNLOCK(n) \ | ||
209 | do { \ | ||
210 | if (__isthreaded) \ | ||
211 | _thread_cb.tc_malloc_unlock(n); \ | ||
212 | } while (0) | ||
213 | |||
214 | #define _ATEXIT_LOCK() \ | ||
215 | do { \ | ||
216 | if (__isthreaded) \ | ||
217 | _thread_cb.tc_atexit_lock(); \ | ||
218 | } while (0) | ||
219 | #define _ATEXIT_UNLOCK() \ | ||
220 | do { \ | ||
221 | if (__isthreaded) \ | ||
222 | _thread_cb.tc_atexit_unlock(); \ | ||
223 | } while (0) | ||
224 | |||
225 | #define _ATFORK_LOCK() \ | ||
226 | do { \ | ||
227 | if (__isthreaded) \ | ||
228 | _thread_cb.tc_atfork_lock(); \ | ||
229 | } while (0) | ||
230 | #define _ATFORK_UNLOCK() \ | ||
231 | do { \ | ||
232 | if (__isthreaded) \ | ||
233 | _thread_cb.tc_atfork_unlock(); \ | ||
234 | } while (0) | ||
235 | |||
236 | #define _ARC4_LOCK() \ | ||
237 | do { \ | ||
238 | if (__isthreaded) \ | ||
239 | _thread_cb.tc_arc4_lock(); \ | ||
240 | } while (0) | ||
241 | #define _ARC4_UNLOCK() \ | ||
242 | do { \ | ||
243 | if (__isthreaded) \ | ||
244 | _thread_cb.tc_arc4_unlock(); \ | ||
245 | } while (0) | ||
246 | #endif /* __LIBC__ */ | ||
247 | |||
248 | |||
249 | /* | ||
250 | * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> | ||
251 | * All Rights Reserved. | ||
252 | * | ||
253 | * Permission to use, copy, modify, and distribute this software for any | ||
254 | * purpose with or without fee is hereby granted, provided that the above | ||
255 | * copyright notice and this permission notice appear in all copies. | ||
256 | * | ||
257 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
258 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
259 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
260 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
261 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
262 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
263 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
264 | */ | ||
265 | /* | ||
266 | * Private data structures that back up the typedefs in pthread.h. | ||
267 | * Since only the thread library cares about their size or arrangement, | ||
268 | * it should be possible to switch libraries without relinking. | ||
269 | * | ||
270 | * Do not reorder _atomic_lock_t and sem_t variables in the structs. | ||
271 | * This is due to alignment requirements of certain arches like hppa. | ||
272 | * The current requirement is 16 bytes. | ||
273 | * | ||
274 | * THE MACHINE DEPENDENT CERROR CODE HAS HARD CODED OFFSETS INTO PTHREAD_T! | ||
275 | */ | ||
276 | |||
277 | #include <sys/queue.h> | ||
278 | #include <pthread.h> | ||
279 | #include <semaphore.h> | ||
280 | #include <machine/spinlock.h> | ||
281 | |||
282 | #define _SPINLOCK_UNLOCKED _ATOMIC_LOCK_UNLOCKED | ||
283 | |||
284 | struct __sem { | ||
285 | _atomic_lock_t lock; | ||
286 | volatile int waitcount; | ||
287 | volatile int value; | ||
288 | int shared; | ||
289 | }; | ||
290 | |||
291 | TAILQ_HEAD(pthread_queue, pthread); | ||
292 | |||
293 | #ifdef FUTEX | ||
294 | |||
295 | struct pthread_mutex { | ||
296 | volatile unsigned int lock; | ||
297 | int type; | ||
298 | pthread_t owner; | ||
299 | int count; | ||
300 | int prioceiling; | ||
301 | }; | ||
302 | |||
303 | struct pthread_cond { | ||
304 | volatile unsigned int seq; | ||
305 | clockid_t clock; | ||
306 | struct pthread_mutex *mutex; | ||
307 | }; | ||
308 | |||
309 | struct pthread_rwlock { | ||
310 | volatile unsigned int value; | ||
311 | }; | ||
312 | |||
313 | #else | ||
314 | |||
315 | struct pthread_mutex { | ||
316 | _atomic_lock_t lock; | ||
317 | struct pthread_queue lockers; | ||
318 | int type; | ||
319 | pthread_t owner; | ||
320 | int count; | ||
321 | int prioceiling; | ||
322 | }; | ||
323 | |||
324 | struct pthread_cond { | ||
325 | _atomic_lock_t lock; | ||
326 | struct pthread_queue waiters; | ||
327 | struct pthread_mutex *mutex; | ||
328 | clockid_t clock; | ||
329 | }; | ||
330 | |||
331 | struct pthread_rwlock { | ||
332 | _atomic_lock_t lock; | ||
333 | pthread_t owner; | ||
334 | struct pthread_queue writers; | ||
335 | int readers; | ||
336 | }; | ||
337 | #endif /* FUTEX */ | ||
338 | |||
339 | struct pthread_mutex_attr { | ||
340 | int ma_type; | ||
341 | int ma_protocol; | ||
342 | int ma_prioceiling; | ||
343 | }; | ||
344 | |||
345 | struct pthread_cond_attr { | ||
346 | clockid_t ca_clock; | ||
347 | }; | ||
348 | |||
349 | struct pthread_attr { | ||
350 | void *stack_addr; | ||
351 | size_t stack_size; | ||
352 | size_t guard_size; | ||
353 | int detach_state; | ||
354 | int contention_scope; | ||
355 | int sched_policy; | ||
356 | struct sched_param sched_param; | ||
357 | int sched_inherit; | ||
358 | }; | ||
359 | |||
360 | struct rthread_storage { | ||
361 | int keyid; | ||
362 | struct rthread_storage *next; | ||
363 | void *data; | ||
364 | }; | ||
365 | |||
366 | struct rthread_cleanup_fn { | ||
367 | void (*fn)(void *); | ||
368 | void *arg; | ||
369 | struct rthread_cleanup_fn *next; | ||
370 | }; | ||
371 | |||
372 | struct tib; | ||
373 | struct stack; | ||
374 | struct pthread { | ||
375 | struct __sem donesem; | ||
376 | unsigned int flags; | ||
377 | _atomic_lock_t flags_lock; | ||
378 | struct tib *tib; | ||
379 | void *retval; | ||
380 | void *(*fn)(void *); | ||
381 | void *arg; | ||
382 | char name[32]; | ||
383 | struct stack *stack; | ||
384 | LIST_ENTRY(pthread) threads; | ||
385 | TAILQ_ENTRY(pthread) waiting; | ||
386 | pthread_cond_t blocking_cond; | ||
387 | struct pthread_attr attr; | ||
388 | struct rthread_storage *local_storage; | ||
389 | struct rthread_cleanup_fn *cleanup_fns; | ||
390 | |||
391 | /* cancel received in a delayed cancel block? */ | ||
392 | int delayed_cancel; | ||
393 | }; | ||
394 | /* flags in pthread->flags */ | ||
395 | #define THREAD_DONE 0x001 | ||
396 | #define THREAD_DETACHED 0x002 | ||
397 | |||
398 | /* flags in tib->tib_thread_flags */ | ||
399 | #define TIB_THREAD_ASYNC_CANCEL 0x001 | ||
400 | #define TIB_THREAD_INITIAL_STACK 0x002 /* has stack from exec */ | ||
401 | |||
402 | #define ENTER_DELAYED_CANCEL_POINT(tib, self) \ | ||
403 | (self)->delayed_cancel = 0; \ | ||
404 | ENTER_CANCEL_POINT_INNER(tib, 1, 1) | ||
405 | |||
406 | /* | ||
407 | * Internal functions exported from libc's thread bits for use by libpthread | ||
408 | */ | ||
409 | void _spinlock(volatile _atomic_lock_t *); | ||
410 | int _spinlocktry(volatile _atomic_lock_t *); | ||
411 | void _spinunlock(volatile _atomic_lock_t *); | ||
412 | |||
413 | void _rthread_debug(int, const char *, ...) | ||
414 | __attribute__((__format__ (printf, 2, 3))); | ||
415 | pid_t _thread_dofork(pid_t (*_sys_fork)(void)); | ||
416 | void _thread_finalize(void); | ||
417 | |||
418 | /* | ||
419 | * Threading syscalls not declared in system headers | ||
420 | */ | ||
421 | __dead void __threxit(pid_t *); | ||
422 | int __thrsleep(const volatile void *, clockid_t, | ||
423 | const struct timespec *, volatile void *, const int *); | ||
424 | int __thrwakeup(const volatile void *, int n); | ||
425 | int __thrsigdivert(sigset_t, siginfo_t *, const struct timespec *); | ||
426 | |||
427 | #endif /* _THREAD_PRIVATE_H_ */ | ||