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