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