xref: /freebsd/lib/libthr/thread/thr_init.c (revision 93ca6ff2958cace3b7b883ed797ea6539881a6a2)
1df57947fSPedro F. Giffuni /*-
2df57947fSPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
3df57947fSPedro F. Giffuni  *
4a091d823SDavid Xu  * Copyright (c) 2003 Daniel M. Eischen <deischen@freebsd.org>
5bb535300SJeff Roberson  * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
6bb535300SJeff Roberson  * All rights reserved.
7bb535300SJeff Roberson  *
8bb535300SJeff Roberson  * Redistribution and use in source and binary forms, with or without
9bb535300SJeff Roberson  * modification, are permitted provided that the following conditions
10bb535300SJeff Roberson  * are met:
11bb535300SJeff Roberson  * 1. Redistributions of source code must retain the above copyright
12bb535300SJeff Roberson  *    notice, this list of conditions and the following disclaimer.
13bb535300SJeff Roberson  * 2. Redistributions in binary form must reproduce the above copyright
14bb535300SJeff Roberson  *    notice, this list of conditions and the following disclaimer in the
15bb535300SJeff Roberson  *    documentation and/or other materials provided with the distribution.
16bb535300SJeff Roberson  * 3. All advertising materials mentioning features or use of this software
17bb535300SJeff Roberson  *    must display the following acknowledgement:
18bb535300SJeff Roberson  *	This product includes software developed by John Birrell.
19bb535300SJeff Roberson  * 4. Neither the name of the author nor the names of any co-contributors
20bb535300SJeff Roberson  *    may be used to endorse or promote products derived from this software
21bb535300SJeff Roberson  *    without specific prior written permission.
22bb535300SJeff Roberson  *
23bb535300SJeff Roberson  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
24bb535300SJeff Roberson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25bb535300SJeff Roberson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26bb535300SJeff Roberson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27bb535300SJeff Roberson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28bb535300SJeff Roberson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29bb535300SJeff Roberson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30bb535300SJeff Roberson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31bb535300SJeff Roberson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32bb535300SJeff Roberson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33bb535300SJeff Roberson  * SUCH DAMAGE.
34bb535300SJeff Roberson  */
35bb535300SJeff Roberson 
3632793011SKonstantin Belousov #include <sys/cdefs.h>
3732793011SKonstantin Belousov __FBSDID("$FreeBSD$");
3832793011SKonstantin Belousov 
39bb535300SJeff Roberson #include "namespace.h"
40ebf7a015SKonstantin Belousov #include <sys/param.h>
41e2879eceSKonstantin Belousov #include <sys/auxv.h>
42a091d823SDavid Xu #include <sys/signalvar.h>
43bb535300SJeff Roberson #include <sys/ioctl.h>
448495e8b1SKonstantin Belousov #include <sys/link_elf.h>
456c8ce3bfSKonstantin Belousov #include <sys/resource.h>
46bb535300SJeff Roberson #include <sys/sysctl.h>
47bb535300SJeff Roberson #include <sys/ttycom.h>
48bb535300SJeff Roberson #include <sys/mman.h>
497b4f8f03SDavid Xu #include <sys/rtprio.h>
50bb535300SJeff Roberson #include <errno.h>
51bb535300SJeff Roberson #include <fcntl.h>
52bb535300SJeff Roberson #include <paths.h>
53bb535300SJeff Roberson #include <pthread.h>
54a091d823SDavid Xu #include <pthread_np.h>
55bb535300SJeff Roberson #include <signal.h>
56bb535300SJeff Roberson #include <stdlib.h>
57bb535300SJeff Roberson #include <string.h>
589572a734SDavid Xu #include <time.h>
59bb535300SJeff Roberson #include <unistd.h>
60bb535300SJeff Roberson #include "un-namespace.h"
61bb535300SJeff Roberson 
62a091d823SDavid Xu #include "libc_private.h"
63bb535300SJeff Roberson #include "thr_private.h"
64bb535300SJeff Roberson 
65f75b1ff6SMark Johnston char		*_usrstack;
66cf905a15SDavid Xu struct pthread	*_thr_initial;
67cf905a15SDavid Xu int		_libthr_debug;
68cf905a15SDavid Xu int		_thread_event_mask;
69cf905a15SDavid Xu struct pthread	*_thread_last_event;
70cf905a15SDavid Xu pthreadlist	_thread_list = TAILQ_HEAD_INITIALIZER(_thread_list);
71cf905a15SDavid Xu pthreadlist 	_thread_gc_list = TAILQ_HEAD_INITIALIZER(_thread_gc_list);
72cf905a15SDavid Xu int		_thread_active_threads = 1;
73cf905a15SDavid Xu atfork_head	_thr_atfork_list = TAILQ_HEAD_INITIALIZER(_thr_atfork_list);
74ada33a6eSDavid Xu struct urwlock	_thr_atfork_lock = DEFAULT_URWLOCK;
75cf905a15SDavid Xu 
76245116caSDavid Xu struct pthread_prio	_thr_priorities[3] = {
777b4f8f03SDavid Xu 	{RTP_PRIO_MIN,  RTP_PRIO_MAX, 0}, /* FIFO */
787b4f8f03SDavid Xu 	{0, 0, 63}, /* OTHER */
797b4f8f03SDavid Xu 	{RTP_PRIO_MIN, RTP_PRIO_MAX, 0}  /* RR */
80245116caSDavid Xu };
81245116caSDavid Xu 
82cf905a15SDavid Xu struct pthread_attr _pthread_attr_default = {
839ad4b644SDavid Xu 	.sched_policy = SCHED_OTHER,
8454dff16bSDavid Xu 	.sched_inherit = PTHREAD_INHERIT_SCHED,
85245116caSDavid Xu 	.prio = 0,
86cf905a15SDavid Xu 	.suspend = THR_CREATE_RUNNING,
876f79c826SDavid Xu 	.flags = PTHREAD_SCOPE_SYSTEM,
88cf905a15SDavid Xu 	.stackaddr_attr = NULL,
89cf905a15SDavid Xu 	.stacksize_attr = THR_STACK_DEFAULT,
90a759db94SDavid Xu 	.guardsize_attr = 0,
91a759db94SDavid Xu 	.cpusetsize = 0,
92a759db94SDavid Xu 	.cpuset = NULL
93cf905a15SDavid Xu };
94cf905a15SDavid Xu 
95cf905a15SDavid Xu struct pthread_mutex_attr _pthread_mutexattr_default = {
96cf905a15SDavid Xu 	.m_type = PTHREAD_MUTEX_DEFAULT,
97cf905a15SDavid Xu 	.m_protocol = PTHREAD_PRIO_NONE,
981bdbd705SKonstantin Belousov 	.m_ceiling = 0,
991bdbd705SKonstantin Belousov 	.m_pshared = PTHREAD_PROCESS_PRIVATE,
1002a339d9eSKonstantin Belousov 	.m_robust = PTHREAD_MUTEX_STALLED,
101cf905a15SDavid Xu };
102cf905a15SDavid Xu 
103bbb64c21SDavid Xu struct pthread_mutex_attr _pthread_mutexattr_adaptive_default = {
104bbb64c21SDavid Xu 	.m_type = PTHREAD_MUTEX_ADAPTIVE_NP,
105bbb64c21SDavid Xu 	.m_protocol = PTHREAD_PRIO_NONE,
1061bdbd705SKonstantin Belousov 	.m_ceiling = 0,
1071bdbd705SKonstantin Belousov 	.m_pshared = PTHREAD_PROCESS_PRIVATE,
1082a339d9eSKonstantin Belousov 	.m_robust = PTHREAD_MUTEX_STALLED,
109bbb64c21SDavid Xu };
110bbb64c21SDavid Xu 
111cf905a15SDavid Xu /* Default condition variable attributes: */
112cf905a15SDavid Xu struct pthread_cond_attr _pthread_condattr_default = {
113cf905a15SDavid Xu 	.c_pshared = PTHREAD_PROCESS_PRIVATE,
114cf905a15SDavid Xu 	.c_clockid = CLOCK_REALTIME
115cf905a15SDavid Xu };
116cf905a15SDavid Xu 
117d99f6dacSDavid Xu int		_thr_is_smp = 0;
11837a6356bSDavid Xu size_t		_thr_guard_default;
11937a6356bSDavid Xu size_t		_thr_stack_default = THR_STACK_DEFAULT;
12037a6356bSDavid Xu size_t		_thr_stack_initial = THR_STACK_INITIAL;
121cf905a15SDavid Xu int		_thr_page_size;
1227416cdabSDavid Xu int		_thr_spinloops;
1237416cdabSDavid Xu int		_thr_yieldloops;
12484ac0fb8SDavid Xu int		_thr_queuefifo = 4;
125cf905a15SDavid Xu int		_gc_count;
126bddd24cdSDavid Xu struct umutex	_mutex_static_lock = DEFAULT_UMUTEX;
127bddd24cdSDavid Xu struct umutex	_cond_static_lock = DEFAULT_UMUTEX;
128bddd24cdSDavid Xu struct umutex	_rwlock_static_lock = DEFAULT_UMUTEX;
129bddd24cdSDavid Xu struct umutex	_keytable_lock = DEFAULT_UMUTEX;
130a9b764e2SDavid Xu struct urwlock	_thr_list_lock = DEFAULT_URWLOCK;
131bddd24cdSDavid Xu struct umutex	_thr_event_lock = DEFAULT_UMUTEX;
132a7b84c65SDavid Xu struct umutex	_suspend_all_lock = DEFAULT_UMUTEX;
133a7b84c65SDavid Xu struct pthread	*_single_thread;
134a7b84c65SDavid Xu int		_suspend_all_cycle;
135a7b84c65SDavid Xu int		_suspend_all_waiters;
136cf905a15SDavid Xu 
137a091d823SDavid Xu int	__pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
138a091d823SDavid Xu int	__pthread_mutex_lock(pthread_mutex_t *);
139a091d823SDavid Xu int	__pthread_mutex_trylock(pthread_mutex_t *);
140a091d823SDavid Xu void	_thread_init_hack(void) __attribute__ ((constructor));
141a091d823SDavid Xu 
142a091d823SDavid Xu static void init_private(void);
143a091d823SDavid Xu static void init_main_thread(struct pthread *thread);
1444dee39feSMike Makonnen 
145bb535300SJeff Roberson /*
146bb535300SJeff Roberson  * All weak references used within libc should be in this table.
147a091d823SDavid Xu  * This is so that static libraries will work.
148bb535300SJeff Roberson  */
14905c3a5eaSDavid Xu 
15005c3a5eaSDavid Xu STATIC_LIB_REQUIRE(_fork);
1519572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_getspecific);
1529572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_key_create);
1539572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_key_delete);
1549572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_mutex_destroy);
1559572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_mutex_init);
1569572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_mutex_lock);
1579572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_mutex_trylock);
1589572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_mutex_unlock);
1599572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_mutexattr_init);
1609572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_mutexattr_destroy);
1619572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_mutexattr_settype);
1629572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_once);
1639572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_setspecific);
16405c3a5eaSDavid Xu STATIC_LIB_REQUIRE(_raise);
16505c3a5eaSDavid Xu STATIC_LIB_REQUIRE(_sem_destroy);
16605c3a5eaSDavid Xu STATIC_LIB_REQUIRE(_sem_getvalue);
16705c3a5eaSDavid Xu STATIC_LIB_REQUIRE(_sem_init);
16805c3a5eaSDavid Xu STATIC_LIB_REQUIRE(_sem_post);
16905c3a5eaSDavid Xu STATIC_LIB_REQUIRE(_sem_timedwait);
17005c3a5eaSDavid Xu STATIC_LIB_REQUIRE(_sem_trywait);
17105c3a5eaSDavid Xu STATIC_LIB_REQUIRE(_sem_wait);
1729572a734SDavid Xu STATIC_LIB_REQUIRE(_sigaction);
1739572a734SDavid Xu STATIC_LIB_REQUIRE(_sigprocmask);
1749572a734SDavid Xu STATIC_LIB_REQUIRE(_sigsuspend);
17505c3a5eaSDavid Xu STATIC_LIB_REQUIRE(_sigtimedwait);
17605c3a5eaSDavid Xu STATIC_LIB_REQUIRE(_sigwait);
17705c3a5eaSDavid Xu STATIC_LIB_REQUIRE(_sigwaitinfo);
17805c3a5eaSDavid Xu STATIC_LIB_REQUIRE(_spinlock);
17905c3a5eaSDavid Xu STATIC_LIB_REQUIRE(_spinunlock);
1809572a734SDavid Xu STATIC_LIB_REQUIRE(_thread_init_hack);
181bb535300SJeff Roberson 
182bb535300SJeff Roberson /*
183bb535300SJeff Roberson  * These are needed when linking statically.  All references within
184bb535300SJeff Roberson  * libgcc (and in the future libc) to these routines are weak, but
185bb535300SJeff Roberson  * if they are not (strongly) referenced by the application or other
186bb535300SJeff Roberson  * libraries, then the actual functions will not be loaded.
187bb535300SJeff Roberson  */
1889572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_once);
1899572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_key_create);
1909572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_key_delete);
1919572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_getspecific);
1929572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_setspecific);
1939572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_mutex_init);
1949572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_mutex_destroy);
1959572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_mutex_lock);
1969572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_mutex_trylock);
1979572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_mutex_unlock);
1989572a734SDavid Xu STATIC_LIB_REQUIRE(_pthread_create);
1999572a734SDavid Xu 
2009572a734SDavid Xu /* Pull in all symbols required by libthread_db */
2019572a734SDavid Xu STATIC_LIB_REQUIRE(_thread_state_running);
202bb535300SJeff Roberson 
203a091d823SDavid Xu #define	DUAL_ENTRY(entry)	\
204a091d823SDavid Xu 	(pthread_func_t)entry, (pthread_func_t)entry
205a091d823SDavid Xu 
206a091d823SDavid Xu static pthread_func_t jmp_table[][2] = {
2070ab1bfc7SKonstantin Belousov 	[PJT_ATFORK] = {DUAL_ENTRY(_thr_atfork)},
2080ab1bfc7SKonstantin Belousov 	[PJT_ATTR_DESTROY] = {DUAL_ENTRY(_thr_attr_destroy)},
2090ab1bfc7SKonstantin Belousov 	[PJT_ATTR_GETDETACHSTATE] = {DUAL_ENTRY(_thr_attr_getdetachstate)},
2100ab1bfc7SKonstantin Belousov 	[PJT_ATTR_GETGUARDSIZE] = {DUAL_ENTRY(_thr_attr_getguardsize)},
2110ab1bfc7SKonstantin Belousov 	[PJT_ATTR_GETINHERITSCHED] = {DUAL_ENTRY(_thr_attr_getinheritsched)},
2120ab1bfc7SKonstantin Belousov 	[PJT_ATTR_GETSCHEDPARAM] = {DUAL_ENTRY(_thr_attr_getschedparam)},
2130ab1bfc7SKonstantin Belousov 	[PJT_ATTR_GETSCHEDPOLICY] = {DUAL_ENTRY(_thr_attr_getschedpolicy)},
2140ab1bfc7SKonstantin Belousov 	[PJT_ATTR_GETSCOPE] = {DUAL_ENTRY(_thr_attr_getscope)},
2150ab1bfc7SKonstantin Belousov 	[PJT_ATTR_GETSTACKADDR] = {DUAL_ENTRY(_thr_attr_getstackaddr)},
2160ab1bfc7SKonstantin Belousov 	[PJT_ATTR_GETSTACKSIZE] = {DUAL_ENTRY(_thr_attr_getstacksize)},
2170ab1bfc7SKonstantin Belousov 	[PJT_ATTR_INIT] = {DUAL_ENTRY(_thr_attr_init)},
2180ab1bfc7SKonstantin Belousov 	[PJT_ATTR_SETDETACHSTATE] = {DUAL_ENTRY(_thr_attr_setdetachstate)},
2190ab1bfc7SKonstantin Belousov 	[PJT_ATTR_SETGUARDSIZE] = {DUAL_ENTRY(_thr_attr_setguardsize)},
2200ab1bfc7SKonstantin Belousov 	[PJT_ATTR_SETINHERITSCHED] = {DUAL_ENTRY(_thr_attr_setinheritsched)},
2210ab1bfc7SKonstantin Belousov 	[PJT_ATTR_SETSCHEDPARAM] = {DUAL_ENTRY(_thr_attr_setschedparam)},
2220ab1bfc7SKonstantin Belousov 	[PJT_ATTR_SETSCHEDPOLICY] = {DUAL_ENTRY(_thr_attr_setschedpolicy)},
2230ab1bfc7SKonstantin Belousov 	[PJT_ATTR_SETSCOPE] = {DUAL_ENTRY(_thr_attr_setscope)},
2240ab1bfc7SKonstantin Belousov 	[PJT_ATTR_SETSTACKADDR] = {DUAL_ENTRY(_thr_attr_setstackaddr)},
2250ab1bfc7SKonstantin Belousov 	[PJT_ATTR_SETSTACKSIZE] = {DUAL_ENTRY(_thr_attr_setstacksize)},
2260ab1bfc7SKonstantin Belousov 	[PJT_CANCEL] = {DUAL_ENTRY(_thr_cancel)},
2270ab1bfc7SKonstantin Belousov 	[PJT_CLEANUP_POP] = {DUAL_ENTRY(_thr_cleanup_pop)},
2280ab1bfc7SKonstantin Belousov 	[PJT_CLEANUP_PUSH] = {DUAL_ENTRY(_thr_cleanup_push)},
2290ab1bfc7SKonstantin Belousov 	[PJT_COND_BROADCAST] = {DUAL_ENTRY(_thr_cond_broadcast)},
2300ab1bfc7SKonstantin Belousov 	[PJT_COND_DESTROY] = {DUAL_ENTRY(_thr_cond_destroy)},
2310ab1bfc7SKonstantin Belousov 	[PJT_COND_INIT] = {DUAL_ENTRY(_thr_cond_init)},
2320ab1bfc7SKonstantin Belousov 	[PJT_COND_SIGNAL] = {DUAL_ENTRY(_thr_cond_signal)},
2330ab1bfc7SKonstantin Belousov 	[PJT_COND_TIMEDWAIT] = {DUAL_ENTRY(_thr_cond_timedwait)},
2340ab1bfc7SKonstantin Belousov 	[PJT_COND_WAIT] = {(pthread_func_t)__thr_cond_wait,
2350ab1bfc7SKonstantin Belousov 	    (pthread_func_t)_thr_cond_wait},
2360ab1bfc7SKonstantin Belousov 	[PJT_DETACH] = {DUAL_ENTRY(_thr_detach)},
2370ab1bfc7SKonstantin Belousov 	[PJT_EQUAL] = {DUAL_ENTRY(_thr_equal)},
2380ab1bfc7SKonstantin Belousov 	[PJT_EXIT] = {DUAL_ENTRY(_Tthr_exit)},
2390ab1bfc7SKonstantin Belousov 	[PJT_GETSPECIFIC] = {DUAL_ENTRY(_thr_getspecific)},
2400ab1bfc7SKonstantin Belousov 	[PJT_JOIN] = {DUAL_ENTRY(_thr_join)},
2410ab1bfc7SKonstantin Belousov 	[PJT_KEY_CREATE] = {DUAL_ENTRY(_thr_key_create)},
2420ab1bfc7SKonstantin Belousov 	[PJT_KEY_DELETE] = {DUAL_ENTRY(_thr_key_delete)},
2430ab1bfc7SKonstantin Belousov 	[PJT_KILL] = {DUAL_ENTRY(_Tthr_kill)},
2440ab1bfc7SKonstantin Belousov 	[PJT_MAIN_NP] = {DUAL_ENTRY(_thr_main_np)},
2450ab1bfc7SKonstantin Belousov 	[PJT_MUTEXATTR_DESTROY] = {DUAL_ENTRY(_thr_mutexattr_destroy)},
2460ab1bfc7SKonstantin Belousov 	[PJT_MUTEXATTR_INIT] = {DUAL_ENTRY(_thr_mutexattr_init)},
2470ab1bfc7SKonstantin Belousov 	[PJT_MUTEXATTR_SETTYPE] = {DUAL_ENTRY(_thr_mutexattr_settype)},
2480ab1bfc7SKonstantin Belousov 	[PJT_MUTEX_DESTROY] = {DUAL_ENTRY(_thr_mutex_destroy)},
2490ab1bfc7SKonstantin Belousov 	[PJT_MUTEX_INIT] = {DUAL_ENTRY(__Tthr_mutex_init)},
2500ab1bfc7SKonstantin Belousov 	[PJT_MUTEX_LOCK] = {DUAL_ENTRY(__Tthr_mutex_lock)},
2510ab1bfc7SKonstantin Belousov 	[PJT_MUTEX_TRYLOCK] = {DUAL_ENTRY(__Tthr_mutex_trylock)},
2520ab1bfc7SKonstantin Belousov 	[PJT_MUTEX_UNLOCK] = {DUAL_ENTRY(_thr_mutex_unlock)},
2530ab1bfc7SKonstantin Belousov 	[PJT_ONCE] = {DUAL_ENTRY(_thr_once)},
2540ab1bfc7SKonstantin Belousov 	[PJT_RWLOCK_DESTROY] = {DUAL_ENTRY(_thr_rwlock_destroy)},
2550ab1bfc7SKonstantin Belousov 	[PJT_RWLOCK_INIT] = {DUAL_ENTRY(_thr_rwlock_init)},
2560ab1bfc7SKonstantin Belousov 	[PJT_RWLOCK_RDLOCK] = {DUAL_ENTRY(_Tthr_rwlock_rdlock)},
2570ab1bfc7SKonstantin Belousov 	[PJT_RWLOCK_TRYRDLOCK] = {DUAL_ENTRY(_Tthr_rwlock_tryrdlock)},
2580ab1bfc7SKonstantin Belousov 	[PJT_RWLOCK_TRYWRLOCK] = {DUAL_ENTRY(_Tthr_rwlock_trywrlock)},
2590ab1bfc7SKonstantin Belousov 	[PJT_RWLOCK_UNLOCK] = {DUAL_ENTRY(_Tthr_rwlock_unlock)},
2600ab1bfc7SKonstantin Belousov 	[PJT_RWLOCK_WRLOCK] = {DUAL_ENTRY(_Tthr_rwlock_wrlock)},
2610ab1bfc7SKonstantin Belousov 	[PJT_SELF] = {DUAL_ENTRY(_Tthr_self)},
2620ab1bfc7SKonstantin Belousov 	[PJT_SETCANCELSTATE] = {DUAL_ENTRY(_thr_setcancelstate)},
2630ab1bfc7SKonstantin Belousov 	[PJT_SETCANCELTYPE] = {DUAL_ENTRY(_thr_setcanceltype)},
2640ab1bfc7SKonstantin Belousov 	[PJT_SETSPECIFIC] = {DUAL_ENTRY(_thr_setspecific)},
2650ab1bfc7SKonstantin Belousov 	[PJT_SIGMASK] = {DUAL_ENTRY(_thr_sigmask)},
2660ab1bfc7SKonstantin Belousov 	[PJT_TESTCANCEL] = {DUAL_ENTRY(_Tthr_testcancel)},
2670ab1bfc7SKonstantin Belousov 	[PJT_CLEANUP_POP_IMP] = {DUAL_ENTRY(__thr_cleanup_pop_imp)},
2680ab1bfc7SKonstantin Belousov 	[PJT_CLEANUP_PUSH_IMP] = {DUAL_ENTRY(__thr_cleanup_push_imp)},
26965174f68SKonstantin Belousov 	[PJT_CANCEL_ENTER] = {DUAL_ENTRY(_Tthr_cancel_enter)},
27065174f68SKonstantin Belousov 	[PJT_CANCEL_LEAVE] = {DUAL_ENTRY(_Tthr_cancel_leave)},
2710ab1bfc7SKonstantin Belousov 	[PJT_MUTEX_CONSISTENT] = {DUAL_ENTRY(_Tthr_mutex_consistent)},
2720ab1bfc7SKonstantin Belousov 	[PJT_MUTEXATTR_GETROBUST] = {DUAL_ENTRY(_thr_mutexattr_getrobust)},
2730ab1bfc7SKonstantin Belousov 	[PJT_MUTEXATTR_SETROBUST] = {DUAL_ENTRY(_thr_mutexattr_setrobust)},
2740ab1bfc7SKonstantin Belousov 	[PJT_GETTHREADID_NP] = {DUAL_ENTRY(_thr_getthreadid_np)},
275412ef5daSKonstantin Belousov 	[PJT_ATTR_GET_NP] = {DUAL_ENTRY(_thr_attr_get_np)},
276a091d823SDavid Xu };
277a091d823SDavid Xu 
278a091d823SDavid Xu static int init_once = 0;
279bb535300SJeff Roberson 
280bb535300SJeff Roberson /*
281a091d823SDavid Xu  * For the shared version of the threads library, the above is sufficient.
282a091d823SDavid Xu  * But for the archive version of the library, we need a little bit more.
283a091d823SDavid Xu  * Namely, we must arrange for this particular module to be pulled in from
284a091d823SDavid Xu  * the archive library at link time.  To accomplish that, we define and
285a091d823SDavid Xu  * initialize a variable, "_thread_autoinit_dummy_decl".  This variable is
286a091d823SDavid Xu  * referenced (as an extern) from libc/stdlib/exit.c. This will always
287a091d823SDavid Xu  * create a need for this module, ensuring that it is present in the
288a091d823SDavid Xu  * executable.
289a091d823SDavid Xu  */
290a091d823SDavid Xu extern int _thread_autoinit_dummy_decl;
291a091d823SDavid Xu int _thread_autoinit_dummy_decl = 0;
292a091d823SDavid Xu 
293a091d823SDavid Xu void
294a091d823SDavid Xu _thread_init_hack(void)
295a091d823SDavid Xu {
296a091d823SDavid Xu 
297a091d823SDavid Xu 	_libpthread_init(NULL);
298a091d823SDavid Xu }
299a091d823SDavid Xu 
300a091d823SDavid Xu 
301a091d823SDavid Xu /*
302a091d823SDavid Xu  * Threaded process initialization.
303a091d823SDavid Xu  *
304a091d823SDavid Xu  * This is only called under two conditions:
305a091d823SDavid Xu  *
306a091d823SDavid Xu  *   1) Some thread routines have detected that the library hasn't yet
307a091d823SDavid Xu  *      been initialized (_thr_initial == NULL && curthread == NULL), or
308a091d823SDavid Xu  *
309a091d823SDavid Xu  *   2) An explicit call to reinitialize after a fork (indicated
310a091d823SDavid Xu  *      by curthread != NULL)
311f2c3dd08SMike Makonnen  */
312f2c3dd08SMike Makonnen void
313a091d823SDavid Xu _libpthread_init(struct pthread *curthread)
314f2c3dd08SMike Makonnen {
315b6751c3fSKonstantin Belousov 	int first, dlopened;
316bb535300SJeff Roberson 
317bb535300SJeff Roberson 	/* Check if this function has already been called: */
3182a339d9eSKonstantin Belousov 	if (_thr_initial != NULL && curthread == NULL)
319a091d823SDavid Xu 		/* Only initialize the threaded application once. */
320bb535300SJeff Roberson 		return;
321bb535300SJeff Roberson 
322bb535300SJeff Roberson 	/*
323a091d823SDavid Xu 	 * Check the size of the jump table to make sure it is preset
324a091d823SDavid Xu 	 * with the correct number of entries.
325a091d823SDavid Xu 	 */
3262a339d9eSKonstantin Belousov 	if (sizeof(jmp_table) != sizeof(pthread_func_t) * PJT_MAX * 2)
327a091d823SDavid Xu 		PANIC("Thread jump table not properly initialized");
328a091d823SDavid Xu 	memcpy(__thr_jtable, jmp_table, sizeof(jmp_table));
3298495e8b1SKonstantin Belousov 	__thr_interpose_libc();
330a091d823SDavid Xu 
331a091d823SDavid Xu 	/* Initialize pthread private data. */
332a091d823SDavid Xu 	init_private();
333a091d823SDavid Xu 
334a091d823SDavid Xu 	/* Set the initial thread. */
335a091d823SDavid Xu 	if (curthread == NULL) {
336a091d823SDavid Xu 		first = 1;
337a091d823SDavid Xu 		/* Create and initialize the initial thread. */
338a091d823SDavid Xu 		curthread = _thr_alloc(NULL);
339a091d823SDavid Xu 		if (curthread == NULL)
340a091d823SDavid Xu 			PANIC("Can't allocate initial thread");
341a091d823SDavid Xu 		init_main_thread(curthread);
3428495e8b1SKonstantin Belousov 	} else {
3438495e8b1SKonstantin Belousov 		first = 0;
344a091d823SDavid Xu 	}
3458495e8b1SKonstantin Belousov 
346bb535300SJeff Roberson 	/*
347a091d823SDavid Xu 	 * Add the thread to the thread list queue.
348bb535300SJeff Roberson 	 */
349a091d823SDavid Xu 	THR_LIST_ADD(curthread);
350a091d823SDavid Xu 	_thread_active_threads = 1;
351a091d823SDavid Xu 
352a091d823SDavid Xu 	/* Setup the thread specific data */
353a091d823SDavid Xu 	_tcb_set(curthread->tcb);
354a091d823SDavid Xu 
355a091d823SDavid Xu 	if (first) {
356a091d823SDavid Xu 		_thr_initial = curthread;
3578495e8b1SKonstantin Belousov 		dlopened = _rtld_is_dlopened(&_thread_autoinit_dummy_decl) != 0;
3588495e8b1SKonstantin Belousov 		_thr_signal_init(dlopened);
3597a4cd8d3SDavid Xu 		if (_thread_event_mask & TD_CREATE)
360d245d9e1SDavid Xu 			_thr_report_creation(curthread, curthread);
361b18943f3SJilles Tjoelker 		/*
362b18943f3SJilles Tjoelker 		 * Always use our rtld lock implementation.
363b18943f3SJilles Tjoelker 		 * It is faster because it postpones signal handlers
364b18943f3SJilles Tjoelker 		 * instead of calling sigprocmask(2).
365b18943f3SJilles Tjoelker 		 */
366b18943f3SJilles Tjoelker 		_thr_rtld_init();
367a091d823SDavid Xu 	}
368bb535300SJeff Roberson }
3693f07b4bcSMike Makonnen 
370a091d823SDavid Xu /*
371a091d823SDavid Xu  * This function and pthread_create() do a lot of the same things.
372a091d823SDavid Xu  * It'd be nice to consolidate the common stuff in one place.
373a091d823SDavid Xu  */
374a091d823SDavid Xu static void
375a091d823SDavid Xu init_main_thread(struct pthread *thread)
376a091d823SDavid Xu {
377e2dc286cSDavid Xu 	struct sched_param sched_param;
3781bdbd705SKonstantin Belousov 	int i;
379e2dc286cSDavid Xu 
380a091d823SDavid Xu 	/* Setup the thread attributes. */
381a091d823SDavid Xu 	thr_self(&thread->tid);
382a091d823SDavid Xu 	thread->attr = _pthread_attr_default;
383a091d823SDavid Xu 	/*
384a091d823SDavid Xu 	 * Set up the thread stack.
385a091d823SDavid Xu 	 *
386a091d823SDavid Xu 	 * Create a red zone below the main stack.  All other stacks
387a091d823SDavid Xu 	 * are constrained to a maximum size by the parameters
388a091d823SDavid Xu 	 * passed to mmap(), but this stack is only limited by
389a091d823SDavid Xu 	 * resource limits, so this stack needs an explicitly mapped
390a091d823SDavid Xu 	 * red zone to protect the thread stack that is just beyond.
391a091d823SDavid Xu 	 */
392f75b1ff6SMark Johnston 	if (mmap(_usrstack - _thr_stack_initial -
393a091d823SDavid Xu 	    _thr_guard_default, _thr_guard_default, 0, MAP_ANON,
394a091d823SDavid Xu 	    -1, 0) == MAP_FAILED)
395a091d823SDavid Xu 		PANIC("Cannot allocate red zone for initial thread");
396bb535300SJeff Roberson 
397a091d823SDavid Xu 	/*
398a091d823SDavid Xu 	 * Mark the stack as an application supplied stack so that it
399a091d823SDavid Xu 	 * isn't deallocated.
400a091d823SDavid Xu 	 *
401a091d823SDavid Xu 	 * XXX - I'm not sure it would hurt anything to deallocate
402a091d823SDavid Xu 	 *       the main thread stack because deallocation doesn't
403a091d823SDavid Xu 	 *       actually free() it; it just puts it in the free
404a091d823SDavid Xu 	 *       stack queue for later reuse.
405a091d823SDavid Xu 	 */
406f75b1ff6SMark Johnston 	thread->attr.stackaddr_attr = _usrstack - _thr_stack_initial;
407a091d823SDavid Xu 	thread->attr.stacksize_attr = _thr_stack_initial;
408a091d823SDavid Xu 	thread->attr.guardsize_attr = _thr_guard_default;
409a091d823SDavid Xu 	thread->attr.flags |= THR_STACK_USER;
410bb535300SJeff Roberson 
411a091d823SDavid Xu 	/*
412a091d823SDavid Xu 	 * Write a magic value to the thread structure
413a091d823SDavid Xu 	 * to help identify valid ones:
414a091d823SDavid Xu 	 */
415a091d823SDavid Xu 	thread->magic = THR_MAGIC;
416a091d823SDavid Xu 
417f08e1bf6SDavid Xu 	thread->cancel_enable = 1;
418f08e1bf6SDavid Xu 	thread->cancel_async = 0;
419a091d823SDavid Xu 
4201bdbd705SKonstantin Belousov 	/* Initialize the mutex queues */
4211bdbd705SKonstantin Belousov 	for (i = 0; i < TMQ_NITEMS; i++)
4221bdbd705SKonstantin Belousov 		TAILQ_INIT(&thread->mq[i]);
423a091d823SDavid Xu 
424a091d823SDavid Xu 	thread->state = PS_RUNNING;
425a091d823SDavid Xu 
426e6747c7cSDavid Xu 	_thr_getscheduler(thread->tid, &thread->attr.sched_policy,
427e6747c7cSDavid Xu 		 &sched_param);
428e2dc286cSDavid Xu 	thread->attr.prio = sched_param.sched_priority;
429e2dc286cSDavid Xu 
4303832fd24SDavid Xu #ifdef _PTHREAD_FORCED_UNWIND
431f75b1ff6SMark Johnston 	thread->unwind_stackend = _usrstack;
4323832fd24SDavid Xu #endif
4333832fd24SDavid Xu 
434a091d823SDavid Xu 	/* Others cleared to zero by thr_alloc() */
435a091d823SDavid Xu }
436a091d823SDavid Xu 
437e03c7f50SKonstantin Belousov bool
438e03c7f50SKonstantin Belousov __thr_get_main_stack_base(char **base)
439e03c7f50SKonstantin Belousov {
440e03c7f50SKonstantin Belousov 	size_t len;
441e03c7f50SKonstantin Belousov 	int mib[2];
442e03c7f50SKonstantin Belousov 
443e03c7f50SKonstantin Belousov 	if (elf_aux_info(AT_USRSTACKBASE, base, sizeof(*base)) == 0)
444e03c7f50SKonstantin Belousov 		return (true);
445e03c7f50SKonstantin Belousov 
446e03c7f50SKonstantin Belousov 	mib[0] = CTL_KERN;
447e03c7f50SKonstantin Belousov 	mib[1] = KERN_USRSTACK;
448e03c7f50SKonstantin Belousov 	len = sizeof(*base);
449e03c7f50SKonstantin Belousov 	if (sysctl(mib, nitems(mib), base, &len, NULL, 0) == 0)
450e03c7f50SKonstantin Belousov 		return (true);
451e03c7f50SKonstantin Belousov 
452e03c7f50SKonstantin Belousov 	return (false);
453e03c7f50SKonstantin Belousov }
454e03c7f50SKonstantin Belousov 
455e03c7f50SKonstantin Belousov bool
456e03c7f50SKonstantin Belousov __thr_get_main_stack_lim(size_t *lim)
457e03c7f50SKonstantin Belousov {
458e03c7f50SKonstantin Belousov 	struct rlimit rlim;
459e03c7f50SKonstantin Belousov 
460e03c7f50SKonstantin Belousov 	if (elf_aux_info(AT_USRSTACKLIM, lim, sizeof(*lim)) == 0)
461e03c7f50SKonstantin Belousov 		return (true);
462e03c7f50SKonstantin Belousov 
463e03c7f50SKonstantin Belousov 	if (getrlimit(RLIMIT_STACK, &rlim) == 0) {
464e03c7f50SKonstantin Belousov 		*lim = rlim.rlim_cur;
465e03c7f50SKonstantin Belousov 		return (true);
466e03c7f50SKonstantin Belousov 	}
467e03c7f50SKonstantin Belousov 
468e03c7f50SKonstantin Belousov 	return (false);
469e03c7f50SKonstantin Belousov }
470e03c7f50SKonstantin Belousov 
471a091d823SDavid Xu static void
472a091d823SDavid Xu init_private(void)
473a091d823SDavid Xu {
47436bcb07aSKonstantin Belousov 	char *env, *env_bigstack, *env_splitstack;
47574c75113SDavid Xu 
476bddd24cdSDavid Xu 	_thr_umutex_init(&_mutex_static_lock);
477bddd24cdSDavid Xu 	_thr_umutex_init(&_cond_static_lock);
478bddd24cdSDavid Xu 	_thr_umutex_init(&_rwlock_static_lock);
479bddd24cdSDavid Xu 	_thr_umutex_init(&_keytable_lock);
480ada33a6eSDavid Xu 	_thr_urwlock_init(&_thr_atfork_lock);
481bddd24cdSDavid Xu 	_thr_umutex_init(&_thr_event_lock);
482a7b84c65SDavid Xu 	_thr_umutex_init(&_suspend_all_lock);
483a091d823SDavid Xu 	_thr_spinlock_init();
484a091d823SDavid Xu 	_thr_list_init();
485d1078b0bSDavid Xu 	_thr_wake_addr_init();
486d1078b0bSDavid Xu 	_sleepq_init();
487a7b84c65SDavid Xu 	_single_thread = NULL;
488a7b84c65SDavid Xu 	_suspend_all_waiters = 0;
489a091d823SDavid Xu 
490a091d823SDavid Xu 	/*
491a091d823SDavid Xu 	 * Avoid reinitializing some things if they don't need to be,
492a091d823SDavid Xu 	 * e.g. after a fork().
493a091d823SDavid Xu 	 */
494a091d823SDavid Xu 	if (init_once == 0) {
49553fd961fSKonstantin Belousov 		__thr_pshared_init();
496381c2d2eSKonstantin Belousov 		__thr_malloc_init();
497e2879eceSKonstantin Belousov 
498bb535300SJeff Roberson 		/* Find the stack top */
499e03c7f50SKonstantin Belousov 		if (!__thr_get_main_stack_base(&_usrstack))
500e03c7f50SKonstantin Belousov 			PANIC("Cannot get kern.usrstack");
50136bcb07aSKonstantin Belousov 		env_bigstack = getenv("LIBPTHREAD_BIGSTACK_MAIN");
50236bcb07aSKonstantin Belousov 		env_splitstack = getenv("LIBPTHREAD_SPLITSTACK_MAIN");
50336bcb07aSKonstantin Belousov 		if (env_bigstack != NULL || env_splitstack == NULL) {
504e03c7f50SKonstantin Belousov 			if (!__thr_get_main_stack_lim(&_thr_stack_initial))
5056c8ce3bfSKonstantin Belousov 				PANIC("Cannot get stack rlimit");
506e2879eceSKonstantin Belousov 		}
507a4f02d5dSEdward Tomasz Napierala 		_thr_is_smp = sysconf(_SC_NPROCESSORS_CONF);
508a4f02d5dSEdward Tomasz Napierala 		if (_thr_is_smp == -1)
509a4f02d5dSEdward Tomasz Napierala 			PANIC("Cannot get _SC_NPROCESSORS_CONF");
510d99f6dacSDavid Xu 		_thr_is_smp = (_thr_is_smp > 1);
511a091d823SDavid Xu 		_thr_page_size = getpagesize();
512a091d823SDavid Xu 		_thr_guard_default = _thr_page_size;
513a091d823SDavid Xu 		_pthread_attr_default.guardsize_attr = _thr_guard_default;
514a091d823SDavid Xu 		_pthread_attr_default.stacksize_attr = _thr_stack_default;
5157416cdabSDavid Xu 		env = getenv("LIBPTHREAD_SPINLOOPS");
5167416cdabSDavid Xu 		if (env)
5177416cdabSDavid Xu 			_thr_spinloops = atoi(env);
5187416cdabSDavid Xu 		env = getenv("LIBPTHREAD_YIELDLOOPS");
5197416cdabSDavid Xu 		if (env)
5207416cdabSDavid Xu 			_thr_yieldloops = atoi(env);
52184ac0fb8SDavid Xu 		env = getenv("LIBPTHREAD_QUEUE_FIFO");
52284ac0fb8SDavid Xu 		if (env)
52384ac0fb8SDavid Xu 			_thr_queuefifo = atoi(env);
524a091d823SDavid Xu 		TAILQ_INIT(&_thr_atfork_list);
525*93ca6ff2SKonstantin Belousov 		env = getenv("LIBPTHREAD_UMTX_MIN_TIMEOUT");
526*93ca6ff2SKonstantin Belousov 		if (env) {
527*93ca6ff2SKonstantin Belousov 			char *endptr;
528*93ca6ff2SKonstantin Belousov 			long mint;
529*93ca6ff2SKonstantin Belousov 
530*93ca6ff2SKonstantin Belousov 			mint = strtol(env, &endptr, 0);
531*93ca6ff2SKonstantin Belousov 			if (*endptr == '\0' && mint >= 0) {
532*93ca6ff2SKonstantin Belousov 				_umtx_op(NULL, UMTX_OP_SET_MIN_TIMEOUT,
533*93ca6ff2SKonstantin Belousov 				    mint, NULL, NULL);
534*93ca6ff2SKonstantin Belousov 			}
535*93ca6ff2SKonstantin Belousov 		}
536a091d823SDavid Xu 	}
537a091d823SDavid Xu 	init_once = 1;
538a091d823SDavid Xu }
539