| File: | src/lib/libc/thread/rthread_libc.c |
| Warning: | line 107, column 28 Access to field 'k' results in a dereference of a null pointer (loaded from variable 'tt') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: rthread_libc.c,v 1.4 2021/01/06 19:54:17 otto Exp $ */ | |||
| 2 | ||||
| 3 | /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ | |||
| 4 | ||||
| 5 | #include <pthread.h> | |||
| 6 | #include <stdlib.h> | |||
| 7 | #include <string.h> | |||
| 8 | ||||
| 9 | #include "rthread.h" | |||
| 10 | #include "rthread_cb.h" | |||
| 11 | ||||
| 12 | /* | |||
| 13 | * A thread tag is a pointer to a structure of this type. An opaque | |||
| 14 | * tag is used to decouple libc from the thread library. | |||
| 15 | */ | |||
| 16 | struct _thread_tag { | |||
| 17 | pthread_mutex_t m; /* the tag's mutex */ | |||
| 18 | pthread_key_t k; /* a key for private data */ | |||
| 19 | }; | |||
| 20 | ||||
| 21 | /* | |||
| 22 | * local mutex to protect against tag creation races. | |||
| 23 | */ | |||
| 24 | static pthread_mutex_t _thread_tag_mutex = PTHREAD_MUTEX_INITIALIZER((void *)0); | |||
| 25 | ||||
| 26 | /* | |||
| 27 | * Initialize a thread tag structure once. This function is called | |||
| 28 | * if the tag is null. Allocation and initialization are controlled | |||
| 29 | * by a mutex. If the tag is not null when the mutex is obtained | |||
| 30 | * the caller lost a race -- some other thread initialized the tag. | |||
| 31 | * This function will never return NULL. | |||
| 32 | */ | |||
| 33 | static void | |||
| 34 | _thread_tag_init(void **tag, void (*dt)(void *)) | |||
| 35 | { | |||
| 36 | struct _thread_tag *tt; | |||
| 37 | int result; | |||
| 38 | ||||
| 39 | result = pthread_mutex_lock(&_thread_tag_mutex); | |||
| 40 | if (result == 0) { | |||
| 41 | if (*tag == NULL((void *)0)) { | |||
| 42 | tt = malloc(sizeof *tt); | |||
| 43 | if (tt != NULL((void *)0)) { | |||
| 44 | result = pthread_mutex_init(&tt->m, NULL((void *)0)); | |||
| 45 | result |= pthread_key_create(&tt->k, dt ? dt : | |||
| 46 | free); | |||
| 47 | *tag = tt; | |||
| 48 | } | |||
| 49 | } | |||
| 50 | result |= pthread_mutex_unlock(&_thread_tag_mutex); | |||
| 51 | } | |||
| 52 | if (result != 0) | |||
| 53 | _rthread_debug(1, "tag init failure"); | |||
| 54 | } | |||
| 55 | ||||
| 56 | /* | |||
| 57 | * lock the mutex associated with the given tag | |||
| 58 | */ | |||
| 59 | void | |||
| 60 | _thread_tag_lock(void **tag) | |||
| 61 | { | |||
| 62 | struct _thread_tag *tt; | |||
| 63 | ||||
| 64 | if (__isthreaded) { | |||
| 65 | if (*tag == NULL((void *)0)) | |||
| 66 | _thread_tag_init(tag, NULL((void *)0)); | |||
| 67 | tt = *tag; | |||
| 68 | if (pthread_mutex_lock(&tt->m) != 0) | |||
| 69 | _rthread_debug(1, "tag mutex lock failure"); | |||
| 70 | } | |||
| 71 | } | |||
| 72 | ||||
| 73 | /* | |||
| 74 | * unlock the mutex associated with the given tag | |||
| 75 | */ | |||
| 76 | void | |||
| 77 | _thread_tag_unlock(void **tag) | |||
| 78 | { | |||
| 79 | struct _thread_tag *tt; | |||
| 80 | ||||
| 81 | if (__isthreaded) { | |||
| 82 | if (*tag == NULL((void *)0)) | |||
| 83 | _thread_tag_init(tag, NULL((void *)0)); | |||
| 84 | tt = *tag; | |||
| 85 | if (pthread_mutex_unlock(&tt->m) != 0) | |||
| 86 | _rthread_debug(1, "tag mutex unlock failure"); | |||
| 87 | } | |||
| 88 | } | |||
| 89 | ||||
| 90 | /* | |||
| 91 | * return the thread specific data for the given tag. If there | |||
| 92 | * is no data for this thread allocate and initialize it from 'storage' | |||
| 93 | * or clear it for non-main threads. | |||
| 94 | * On any error return 'err'. | |||
| 95 | */ | |||
| 96 | void * | |||
| 97 | _thread_tag_storage(void **tag, void *storage, size_t sz, void (*dt)(void *), | |||
| 98 | void *err) | |||
| 99 | { | |||
| 100 | struct _thread_tag *tt; | |||
| 101 | void *ret; | |||
| 102 | ||||
| 103 | if (*tag == NULL((void *)0)) | |||
| ||||
| 104 | _thread_tag_init(tag, dt); | |||
| 105 | tt = *tag; | |||
| 106 | ||||
| 107 | ret = pthread_getspecific(tt->k); | |||
| ||||
| 108 | if (ret == NULL((void *)0)) { | |||
| 109 | ret = calloc(1, sz); | |||
| 110 | if (ret == NULL((void *)0)) | |||
| 111 | ret = err; | |||
| 112 | else { | |||
| 113 | if (pthread_setspecific(tt->k, ret) == 0) { | |||
| 114 | if (pthread_self() == &_initial_thread) | |||
| 115 | memcpy(ret, storage, sz); | |||
| 116 | } else { | |||
| 117 | free(ret); | |||
| 118 | ret = err; | |||
| 119 | } | |||
| 120 | } | |||
| 121 | } | |||
| 122 | return ret; | |||
| 123 | } | |||
| 124 | ||||
| 125 | void | |||
| 126 | _thread_mutex_lock(void **mutex) | |||
| 127 | { | |||
| 128 | pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex; | |||
| 129 | ||||
| 130 | if (pthread_mutex_lock(pmutex) != 0) | |||
| 131 | _rthread_debug(1, "mutex lock failure"); | |||
| 132 | } | |||
| 133 | ||||
| 134 | void | |||
| 135 | _thread_mutex_unlock(void **mutex) | |||
| 136 | { | |||
| 137 | pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex; | |||
| 138 | ||||
| 139 | if (pthread_mutex_unlock(pmutex) != 0) | |||
| 140 | _rthread_debug(1, "mutex unlock failure"); | |||
| 141 | } | |||
| 142 | ||||
| 143 | void | |||
| 144 | _thread_mutex_destroy(void **mutex) | |||
| 145 | { | |||
| 146 | pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex; | |||
| 147 | ||||
| 148 | if (pthread_mutex_destroy(pmutex) != 0) | |||
| 149 | _rthread_debug(1, "mutex destroy failure"); | |||
| 150 | } | |||
| 151 | ||||
| 152 | /* | |||
| 153 | * the malloc lock | |||
| 154 | */ | |||
| 155 | #ifndef FUTEX1 | |||
| 156 | #define MALLOC_LOCK_INITIALIZER(n){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 } { \ | |||
| 157 | _SPINLOCK_UNLOCKED(0), \ | |||
| 158 | TAILQ_HEAD_INITIALIZER(malloc_lock[n].lockers){ ((void *)0), &(malloc_lock[n].lockers).tqh_first }, \ | |||
| 159 | PTHREAD_MUTEX_DEFAULTPTHREAD_MUTEX_STRICT_NP, \ | |||
| 160 | NULL((void *)0), \ | |||
| 161 | 0, \ | |||
| 162 | -1 } | |||
| 163 | #else | |||
| 164 | #define MALLOC_LOCK_INITIALIZER(n){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 } { \ | |||
| 165 | _SPINLOCK_UNLOCKED(0), \ | |||
| 166 | PTHREAD_MUTEX_DEFAULTPTHREAD_MUTEX_STRICT_NP, \ | |||
| 167 | NULL((void *)0), \ | |||
| 168 | 0, \ | |||
| 169 | -1 } | |||
| 170 | #endif | |||
| 171 | ||||
| 172 | static struct pthread_mutex malloc_lock[_MALLOC_MUTEXES32] = { | |||
| 173 | MALLOC_LOCK_INITIALIZER(0){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 174 | MALLOC_LOCK_INITIALIZER(1){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 175 | MALLOC_LOCK_INITIALIZER(2){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 176 | MALLOC_LOCK_INITIALIZER(3){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 177 | MALLOC_LOCK_INITIALIZER(4){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 178 | MALLOC_LOCK_INITIALIZER(5){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 179 | MALLOC_LOCK_INITIALIZER(6){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 180 | MALLOC_LOCK_INITIALIZER(7){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 181 | MALLOC_LOCK_INITIALIZER(8){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 182 | MALLOC_LOCK_INITIALIZER(9){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 183 | MALLOC_LOCK_INITIALIZER(10){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 184 | MALLOC_LOCK_INITIALIZER(11){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 185 | MALLOC_LOCK_INITIALIZER(12){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 186 | MALLOC_LOCK_INITIALIZER(13){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 187 | MALLOC_LOCK_INITIALIZER(14){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 188 | MALLOC_LOCK_INITIALIZER(15){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 189 | MALLOC_LOCK_INITIALIZER(16){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 190 | MALLOC_LOCK_INITIALIZER(17){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 191 | MALLOC_LOCK_INITIALIZER(18){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 192 | MALLOC_LOCK_INITIALIZER(19){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 193 | MALLOC_LOCK_INITIALIZER(20){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 194 | MALLOC_LOCK_INITIALIZER(21){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 195 | MALLOC_LOCK_INITIALIZER(22){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 196 | MALLOC_LOCK_INITIALIZER(23){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 197 | MALLOC_LOCK_INITIALIZER(24){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 198 | MALLOC_LOCK_INITIALIZER(25){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 199 | MALLOC_LOCK_INITIALIZER(26){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 200 | MALLOC_LOCK_INITIALIZER(27){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 201 | MALLOC_LOCK_INITIALIZER(28){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 202 | MALLOC_LOCK_INITIALIZER(29){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 203 | MALLOC_LOCK_INITIALIZER(30){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }, | |||
| 204 | MALLOC_LOCK_INITIALIZER(31){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 } | |||
| 205 | }; | |||
| 206 | ||||
| 207 | static pthread_mutex_t malloc_mutex[_MALLOC_MUTEXES32] = { | |||
| 208 | &malloc_lock[0], | |||
| 209 | &malloc_lock[1], | |||
| 210 | &malloc_lock[2], | |||
| 211 | &malloc_lock[3], | |||
| 212 | &malloc_lock[4], | |||
| 213 | &malloc_lock[5], | |||
| 214 | &malloc_lock[6], | |||
| 215 | &malloc_lock[7], | |||
| 216 | &malloc_lock[8], | |||
| 217 | &malloc_lock[9], | |||
| 218 | &malloc_lock[10], | |||
| 219 | &malloc_lock[11], | |||
| 220 | &malloc_lock[12], | |||
| 221 | &malloc_lock[13], | |||
| 222 | &malloc_lock[14], | |||
| 223 | &malloc_lock[15], | |||
| 224 | &malloc_lock[16], | |||
| 225 | &malloc_lock[17], | |||
| 226 | &malloc_lock[18], | |||
| 227 | &malloc_lock[19], | |||
| 228 | &malloc_lock[20], | |||
| 229 | &malloc_lock[21], | |||
| 230 | &malloc_lock[22], | |||
| 231 | &malloc_lock[23], | |||
| 232 | &malloc_lock[24], | |||
| 233 | &malloc_lock[25], | |||
| 234 | &malloc_lock[26], | |||
| 235 | &malloc_lock[27], | |||
| 236 | &malloc_lock[28], | |||
| 237 | &malloc_lock[29], | |||
| 238 | &malloc_lock[30], | |||
| 239 | &malloc_lock[31] | |||
| 240 | }; | |||
| 241 | ||||
| 242 | void | |||
| 243 | _thread_malloc_lock(int i) | |||
| 244 | { | |||
| 245 | pthread_mutex_lock(&malloc_mutex[i]); | |||
| 246 | } | |||
| 247 | ||||
| 248 | void | |||
| 249 | _thread_malloc_unlock(int i) | |||
| 250 | { | |||
| 251 | pthread_mutex_unlock(&malloc_mutex[i]); | |||
| 252 | } | |||
| 253 | ||||
| 254 | static void | |||
| 255 | _thread_malloc_reinit(void) | |||
| 256 | { | |||
| 257 | int i; | |||
| 258 | ||||
| 259 | for (i = 0; i < _MALLOC_MUTEXES32; i++) { | |||
| 260 | malloc_lock[i].lock = _SPINLOCK_UNLOCKED(0); | |||
| 261 | #ifndef FUTEX1 | |||
| 262 | TAILQ_INIT(&malloc_lock[i].lockers)do { (&malloc_lock[i].lockers)->tqh_first = ((void *)0 ); (&malloc_lock[i].lockers)->tqh_last = &(&malloc_lock [i].lockers)->tqh_first; } while (0); | |||
| 263 | #endif | |||
| 264 | malloc_lock[i].owner = NULL((void *)0); | |||
| 265 | malloc_lock[i].count = 0; | |||
| 266 | } | |||
| 267 | } | |||
| 268 | ||||
| 269 | /* | |||
| 270 | * atexit lock | |||
| 271 | */ | |||
| 272 | static _atomic_lock_t atexit_lock = _SPINLOCK_UNLOCKED(0); | |||
| 273 | ||||
| 274 | void | |||
| 275 | _thread_atexit_lock(void) | |||
| 276 | { | |||
| 277 | _spinlock(&atexit_lock); | |||
| 278 | } | |||
| 279 | ||||
| 280 | void | |||
| 281 | _thread_atexit_unlock(void) | |||
| 282 | { | |||
| 283 | _spinunlock(&atexit_lock); | |||
| 284 | } | |||
| 285 | ||||
| 286 | /* | |||
| 287 | * atfork lock | |||
| 288 | */ | |||
| 289 | static _atomic_lock_t atfork_lock = _SPINLOCK_UNLOCKED(0); | |||
| 290 | ||||
| 291 | void | |||
| 292 | _thread_atfork_lock(void) | |||
| 293 | { | |||
| 294 | _spinlock(&atfork_lock); | |||
| 295 | } | |||
| 296 | ||||
| 297 | void | |||
| 298 | _thread_atfork_unlock(void) | |||
| 299 | { | |||
| 300 | _spinunlock(&atfork_lock); | |||
| 301 | } | |||
| 302 | ||||
| 303 | /* | |||
| 304 | * arc4random lock | |||
| 305 | */ | |||
| 306 | static _atomic_lock_t arc4_lock = _SPINLOCK_UNLOCKED(0); | |||
| 307 | ||||
| 308 | void | |||
| 309 | _thread_arc4_lock(void) | |||
| 310 | { | |||
| 311 | _spinlock(&arc4_lock); | |||
| 312 | } | |||
| 313 | ||||
| 314 | void | |||
| 315 | _thread_arc4_unlock(void) | |||
| 316 | { | |||
| 317 | _spinunlock(&arc4_lock); | |||
| 318 | } | |||
| 319 | ||||
| 320 | pid_t | |||
| 321 | _thread_dofork(pid_t (*sys_fork)(void)) | |||
| 322 | { | |||
| 323 | int i; | |||
| 324 | pid_t newid; | |||
| 325 | ||||
| 326 | _thread_atexit_lock(); | |||
| 327 | for (i = 0; i < _MALLOC_MUTEXES32; i++) | |||
| 328 | _thread_malloc_lock(i); | |||
| 329 | _thread_arc4_lock(); | |||
| 330 | ||||
| 331 | newid = sys_fork(); | |||
| 332 | ||||
| 333 | _thread_arc4_unlock(); | |||
| 334 | if (newid == 0) | |||
| 335 | _thread_malloc_reinit(); | |||
| 336 | else | |||
| 337 | for (i = 0; i < _MALLOC_MUTEXES32; i++) | |||
| 338 | _thread_malloc_unlock(i); | |||
| 339 | _thread_atexit_unlock(); | |||
| 340 | ||||
| 341 | return newid; | |||
| 342 | } | |||
| 343 |