| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: pthread.c,v 1.167 2020/02/16 17:45:11 kamil Exp $ */ | | 1 | /* $NetBSD: pthread.c,v 1.168 2020/04/14 23:35:07 joerg Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2001, 2002, 2003, 2006, 2007, 2008, 2020 | | 4 | * Copyright (c) 2001, 2002, 2003, 2006, 2007, 2008, 2020 |
5 | * The NetBSD Foundation, Inc. | | 5 | * The NetBSD Foundation, Inc. |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * | | 7 | * |
8 | * This code is derived from software contributed to The NetBSD Foundation | | 8 | * This code is derived from software contributed to The NetBSD Foundation |
9 | * by Nathan J. Williams and Andrew Doran. | | 9 | * by Nathan J. Williams and Andrew Doran. |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
| @@ -21,27 +21,27 @@ | | | @@ -21,27 +21,27 @@ |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. | | 30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | #include <sys/cdefs.h> | | 33 | #include <sys/cdefs.h> |
34 | __RCSID("$NetBSD: pthread.c,v 1.167 2020/02/16 17:45:11 kamil Exp $"); | | 34 | __RCSID("$NetBSD: pthread.c,v 1.168 2020/04/14 23:35:07 joerg Exp $"); |
35 | | | 35 | |
36 | #define __EXPOSE_STACK 1 | | 36 | #define __EXPOSE_STACK 1 |
37 | | | 37 | |
38 | #include <sys/param.h> | | 38 | #include <sys/param.h> |
39 | #include <sys/exec_elf.h> | | 39 | #include <sys/exec_elf.h> |
40 | #include <sys/mman.h> | | 40 | #include <sys/mman.h> |
41 | #include <sys/lwp.h> | | 41 | #include <sys/lwp.h> |
42 | #include <sys/lwpctl.h> | | 42 | #include <sys/lwpctl.h> |
43 | #include <sys/resource.h> | | 43 | #include <sys/resource.h> |
44 | #include <sys/sysctl.h> | | 44 | #include <sys/sysctl.h> |
45 | #include <sys/tls.h> | | 45 | #include <sys/tls.h> |
46 | #include <uvm/uvm_param.h> | | 46 | #include <uvm/uvm_param.h> |
47 | | | 47 | |
| @@ -74,28 +74,26 @@ static signed int pthread__cmp(void *, c | | | @@ -74,28 +74,26 @@ static signed int pthread__cmp(void *, c |
74 | static const rb_tree_ops_t pthread__alltree_ops = { | | 74 | static const rb_tree_ops_t pthread__alltree_ops = { |
75 | .rbto_compare_nodes = pthread__cmp, | | 75 | .rbto_compare_nodes = pthread__cmp, |
76 | .rbto_compare_key = pthread__cmp, | | 76 | .rbto_compare_key = pthread__cmp, |
77 | .rbto_node_offset = offsetof(struct __pthread_st, pt_alltree), | | 77 | .rbto_node_offset = offsetof(struct __pthread_st, pt_alltree), |
78 | .rbto_context = NULL | | 78 | .rbto_context = NULL |
79 | }; | | 79 | }; |
80 | | | 80 | |
81 | static void pthread__create_tramp(void *); | | 81 | static void pthread__create_tramp(void *); |
82 | static void pthread__initthread(pthread_t); | | 82 | static void pthread__initthread(pthread_t); |
83 | static void pthread__scrubthread(pthread_t, char *, int); | | 83 | static void pthread__scrubthread(pthread_t, char *, int); |
84 | static void pthread__initmain(pthread_t *); | | 84 | static void pthread__initmain(pthread_t *); |
85 | static void pthread__fork_callback(void); | | 85 | static void pthread__fork_callback(void); |
86 | static void pthread__reap(pthread_t); | | 86 | static void pthread__reap(pthread_t); |
87 | static void pthread__child_callback(void); | | | |
88 | static void pthread__start(void); | | | |
89 | | | 87 | |
90 | void pthread__init(void); | | 88 | void pthread__init(void); |
91 | | | 89 | |
92 | int pthread__started; | | 90 | int pthread__started; |
93 | int __uselibcstub = 1; | | 91 | int __uselibcstub = 1; |
94 | pthread_mutex_t pthread__deadqueue_lock = PTHREAD_MUTEX_INITIALIZER; | | 92 | pthread_mutex_t pthread__deadqueue_lock = PTHREAD_MUTEX_INITIALIZER; |
95 | pthread_queue_t pthread__deadqueue; | | 93 | pthread_queue_t pthread__deadqueue; |
96 | pthread_queue_t pthread__allqueue; | | 94 | pthread_queue_t pthread__allqueue; |
97 | | | 95 | |
98 | static pthread_attr_t pthread_default_attr; | | 96 | static pthread_attr_t pthread_default_attr; |
99 | static lwpctl_t pthread__dummy_lwpctl = { .lc_curcpu = LWPCTL_CPU_NONE }; | | 97 | static lwpctl_t pthread__dummy_lwpctl = { .lc_curcpu = LWPCTL_CPU_NONE }; |
100 | | | 98 | |
101 | enum { | | 99 | enum { |
| @@ -264,56 +262,26 @@ pthread__init(void) | | | @@ -264,56 +262,26 @@ pthread__init(void) |
264 | | | 262 | |
265 | static void | | 263 | static void |
266 | pthread__fork_callback(void) | | 264 | pthread__fork_callback(void) |
267 | { | | 265 | { |
268 | struct __pthread_st *self = pthread__self(); | | 266 | struct __pthread_st *self = pthread__self(); |
269 | | | 267 | |
270 | /* lwpctl state is not copied across fork. */ | | 268 | /* lwpctl state is not copied across fork. */ |
271 | if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &self->pt_lwpctl)) { | | 269 | if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &self->pt_lwpctl)) { |
272 | err(EXIT_FAILURE, "_lwp_ctl"); | | 270 | err(EXIT_FAILURE, "_lwp_ctl"); |
273 | } | | 271 | } |
274 | self->pt_lid = _lwp_self(); | | 272 | self->pt_lid = _lwp_self(); |
275 | } | | 273 | } |
276 | | | 274 | |
277 | static void | | | |
278 | pthread__child_callback(void) | | | |
279 | { | | | |
280 | | | | |
281 | /* | | | |
282 | * Clean up data structures that a forked child process might | | | |
283 | * trip over. Note that if threads have been created (causing | | | |
284 | * this handler to be registered) the standards say that the | | | |
285 | * child will trigger undefined behavior if it makes any | | | |
286 | * pthread_* calls (or any other calls that aren't | | | |
287 | * async-signal-safe), so we don't really have to clean up | | | |
288 | * much. Anything that permits some pthread_* calls to work is | | | |
289 | * merely being polite. | | | |
290 | */ | | | |
291 | pthread__started = 0; | | | |
292 | } | | | |
293 | | | | |
294 | static void | | | |
295 | pthread__start(void) | | | |
296 | { | | | |
297 | | | | |
298 | /* | | | |
299 | * Per-process timers are cleared by fork(); despite the | | | |
300 | * various restrictions on fork() and threads, it's legal to | | | |
301 | * fork() before creating any threads. | | | |
302 | */ | | | |
303 | pthread_atfork(NULL, NULL, pthread__child_callback); | | | |
304 | } | | | |
305 | | | | |
306 | | | | |
307 | /* General-purpose thread data structure sanitization. */ | | 275 | /* General-purpose thread data structure sanitization. */ |
308 | /* ARGSUSED */ | | 276 | /* ARGSUSED */ |
309 | static void | | 277 | static void |
310 | pthread__initthread(pthread_t t) | | 278 | pthread__initthread(pthread_t t) |
311 | { | | 279 | { |
312 | | | 280 | |
313 | t->pt_self = t; | | 281 | t->pt_self = t; |
314 | t->pt_magic = PT_MAGIC; | | 282 | t->pt_magic = PT_MAGIC; |
315 | t->pt_willpark = 0; | | 283 | t->pt_willpark = 0; |
316 | t->pt_unpark = 0; | | 284 | t->pt_unpark = 0; |
317 | t->pt_nwaiters = 0; | | 285 | t->pt_nwaiters = 0; |
318 | t->pt_sleepobj = NULL; | | 286 | t->pt_sleepobj = NULL; |
319 | t->pt_signalled = 0; | | 287 | t->pt_signalled = 0; |
| @@ -414,42 +382,35 @@ pthread_create(pthread_t *thread, const | | | @@ -414,42 +382,35 @@ pthread_create(pthread_t *thread, const |
414 | pthread_attr_t nattr; | | 382 | pthread_attr_t nattr; |
415 | struct pthread_attr_private *p; | | 383 | struct pthread_attr_private *p; |
416 | char * volatile name; | | 384 | char * volatile name; |
417 | unsigned long flag; | | 385 | unsigned long flag; |
418 | void *private_area; | | 386 | void *private_area; |
419 | int ret; | | 387 | int ret; |
420 | | | 388 | |
421 | if (__predict_false(__uselibcstub)) { | | 389 | if (__predict_false(__uselibcstub)) { |
422 | pthread__errorfunc(__FILE__, __LINE__, __func__, | | 390 | pthread__errorfunc(__FILE__, __LINE__, __func__, |
423 | "pthread_create() requires linking with -lpthread"); | | 391 | "pthread_create() requires linking with -lpthread"); |
424 | return __libc_thr_create_stub(thread, attr, startfunc, arg); | | 392 | return __libc_thr_create_stub(thread, attr, startfunc, arg); |
425 | } | | 393 | } |
426 | | | 394 | |
427 | /* | | | |
428 | * It's okay to check this without a lock because there can | | | |
429 | * only be one thread before it becomes true. | | | |
430 | */ | | | |
431 | if (pthread__started == 0) { | | | |
432 | pthread__start(); | | | |
433 | pthread__started = 1; | | | |
434 | } | | | |
435 | | | | |
436 | if (attr == NULL) | | 395 | if (attr == NULL) |
437 | nattr = pthread_default_attr; | | 396 | nattr = pthread_default_attr; |
438 | else if (attr->pta_magic == PT_ATTR_MAGIC) | | 397 | else if (attr->pta_magic == PT_ATTR_MAGIC) |
439 | nattr = *attr; | | 398 | nattr = *attr; |
440 | else | | 399 | else |
441 | return EINVAL; | | 400 | return EINVAL; |
442 | | | 401 | |
| | | 402 | pthread__started = 1; |
| | | 403 | |
443 | /* Fetch misc. attributes from the attr structure. */ | | 404 | /* Fetch misc. attributes from the attr structure. */ |
444 | name = NULL; | | 405 | name = NULL; |
445 | if ((p = nattr.pta_private) != NULL) | | 406 | if ((p = nattr.pta_private) != NULL) |
446 | if (p->ptap_name[0] != '\0') | | 407 | if (p->ptap_name[0] != '\0') |
447 | if ((name = strdup(p->ptap_name)) == NULL) | | 408 | if ((name = strdup(p->ptap_name)) == NULL) |
448 | return ENOMEM; | | 409 | return ENOMEM; |
449 | | | 410 | |
450 | newthread = NULL; | | 411 | newthread = NULL; |
451 | | | 412 | |
452 | /* | | 413 | /* |
453 | * Try to reclaim a dead thread. | | 414 | * Try to reclaim a dead thread. |
454 | */ | | 415 | */ |
455 | if (!PTQ_EMPTY(&pthread__deadqueue)) { | | 416 | if (!PTQ_EMPTY(&pthread__deadqueue)) { |