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 |