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