xref: /freebsd/lib/libthr/thread/thr_init.c (revision bb535300dd871731b2542594a917bc2892479ca0)
1bb535300SJeff Roberson /*
2bb535300SJeff Roberson  * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3bb535300SJeff Roberson  * All rights reserved.
4bb535300SJeff Roberson  *
5bb535300SJeff Roberson  * Redistribution and use in source and binary forms, with or without
6bb535300SJeff Roberson  * modification, are permitted provided that the following conditions
7bb535300SJeff Roberson  * are met:
8bb535300SJeff Roberson  * 1. Redistributions of source code must retain the above copyright
9bb535300SJeff Roberson  *    notice, this list of conditions and the following disclaimer.
10bb535300SJeff Roberson  * 2. Redistributions in binary form must reproduce the above copyright
11bb535300SJeff Roberson  *    notice, this list of conditions and the following disclaimer in the
12bb535300SJeff Roberson  *    documentation and/or other materials provided with the distribution.
13bb535300SJeff Roberson  * 3. All advertising materials mentioning features or use of this software
14bb535300SJeff Roberson  *    must display the following acknowledgement:
15bb535300SJeff Roberson  *	This product includes software developed by John Birrell.
16bb535300SJeff Roberson  * 4. Neither the name of the author nor the names of any co-contributors
17bb535300SJeff Roberson  *    may be used to endorse or promote products derived from this software
18bb535300SJeff Roberson  *    without specific prior written permission.
19bb535300SJeff Roberson  *
20bb535300SJeff Roberson  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21bb535300SJeff Roberson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22bb535300SJeff Roberson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23bb535300SJeff Roberson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24bb535300SJeff Roberson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25bb535300SJeff Roberson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26bb535300SJeff Roberson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27bb535300SJeff Roberson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28bb535300SJeff Roberson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29bb535300SJeff Roberson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30bb535300SJeff Roberson  * SUCH DAMAGE.
31bb535300SJeff Roberson  *
32bb535300SJeff Roberson  * $FreeBSD$
33bb535300SJeff Roberson  */
34bb535300SJeff Roberson 
35bb535300SJeff Roberson /* Allocate space for global thread variables here: */
36bb535300SJeff Roberson #define GLOBAL_PTHREAD_PRIVATE
37bb535300SJeff Roberson 
38bb535300SJeff Roberson #include "namespace.h"
39bb535300SJeff Roberson #include <sys/param.h>
40bb535300SJeff Roberson #include <sys/types.h>
41bb535300SJeff Roberson #include <machine/reg.h>
42bb535300SJeff Roberson 
43bb535300SJeff Roberson #include <sys/ioctl.h>
44bb535300SJeff Roberson #include <sys/mount.h>
45bb535300SJeff Roberson #include <sys/uio.h>
46bb535300SJeff Roberson #include <sys/socket.h>
47bb535300SJeff Roberson #include <sys/event.h>
48bb535300SJeff Roberson #include <sys/stat.h>
49bb535300SJeff Roberson #include <sys/sysctl.h>
50bb535300SJeff Roberson #include <sys/time.h>
51bb535300SJeff Roberson #include <sys/ttycom.h>
52bb535300SJeff Roberson #include <sys/user.h>
53bb535300SJeff Roberson #include <sys/wait.h>
54bb535300SJeff Roberson #include <sys/mman.h>
55bb535300SJeff Roberson #include <dirent.h>
56bb535300SJeff Roberson #include <errno.h>
57bb535300SJeff Roberson #include <fcntl.h>
58bb535300SJeff Roberson #include <paths.h>
59bb535300SJeff Roberson #include <pthread.h>
60bb535300SJeff Roberson #include <signal.h>
61bb535300SJeff Roberson #include <stdio.h>
62bb535300SJeff Roberson #include <stdlib.h>
63bb535300SJeff Roberson #include <string.h>
64bb535300SJeff Roberson #include <unistd.h>
65bb535300SJeff Roberson #include "un-namespace.h"
66bb535300SJeff Roberson 
67bb535300SJeff Roberson #include "thr_private.h"
68bb535300SJeff Roberson 
69bb535300SJeff Roberson /*
70bb535300SJeff Roberson  * All weak references used within libc should be in this table.
71bb535300SJeff Roberson  * This will is so that static libraries will work.
72bb535300SJeff Roberson  *
73bb535300SJeff Roberson  * XXXTHR - Check this list.
74bb535300SJeff Roberson  */
75bb535300SJeff Roberson static void *references[] = {
76bb535300SJeff Roberson 	&_accept,
77bb535300SJeff Roberson 	&_bind,
78bb535300SJeff Roberson 	&_close,
79bb535300SJeff Roberson 	&_connect,
80bb535300SJeff Roberson 	&_dup,
81bb535300SJeff Roberson 	&_dup2,
82bb535300SJeff Roberson 	&_execve,
83bb535300SJeff Roberson 	&_fcntl,
84bb535300SJeff Roberson 	&_flock,
85bb535300SJeff Roberson 	&_flockfile,
86bb535300SJeff Roberson 	&_fstat,
87bb535300SJeff Roberson 	&_fstatfs,
88bb535300SJeff Roberson 	&_fsync,
89bb535300SJeff Roberson 	&_funlockfile,
90bb535300SJeff Roberson 	&_getdirentries,
91bb535300SJeff Roberson 	&_getlogin,
92bb535300SJeff Roberson 	&_getpeername,
93bb535300SJeff Roberson 	&_getsockname,
94bb535300SJeff Roberson 	&_getsockopt,
95bb535300SJeff Roberson 	&_ioctl,
96bb535300SJeff Roberson 	&_kevent,
97bb535300SJeff Roberson 	&_listen,
98bb535300SJeff Roberson 	&_nanosleep,
99bb535300SJeff Roberson 	&_open,
100bb535300SJeff Roberson 	&_pthread_getspecific,
101bb535300SJeff Roberson 	&_pthread_key_create,
102bb535300SJeff Roberson 	&_pthread_key_delete,
103bb535300SJeff Roberson 	&_pthread_mutex_destroy,
104bb535300SJeff Roberson 	&_pthread_mutex_init,
105bb535300SJeff Roberson 	&_pthread_mutex_lock,
106bb535300SJeff Roberson 	&_pthread_mutex_trylock,
107bb535300SJeff Roberson 	&_pthread_mutex_unlock,
108bb535300SJeff Roberson 	&_pthread_mutexattr_init,
109bb535300SJeff Roberson 	&_pthread_mutexattr_destroy,
110bb535300SJeff Roberson 	&_pthread_mutexattr_settype,
111bb535300SJeff Roberson 	&_pthread_once,
112bb535300SJeff Roberson 	&_pthread_setspecific,
113bb535300SJeff Roberson 	&_read,
114bb535300SJeff Roberson 	&_readv,
115bb535300SJeff Roberson 	&_recvfrom,
116bb535300SJeff Roberson 	&_recvmsg,
117bb535300SJeff Roberson 	&_select,
118bb535300SJeff Roberson 	&_sendmsg,
119bb535300SJeff Roberson 	&_sendto,
120bb535300SJeff Roberson 	&_setsockopt,
121bb535300SJeff Roberson 	&_sigaction,
122bb535300SJeff Roberson 	&_sigprocmask,
123bb535300SJeff Roberson 	&_sigsuspend,
124bb535300SJeff Roberson 	&_socket,
125bb535300SJeff Roberson 	&_socketpair,
126bb535300SJeff Roberson 	&_wait4,
127bb535300SJeff Roberson 	&_write,
128bb535300SJeff Roberson 	&_writev
129bb535300SJeff Roberson };
130bb535300SJeff Roberson 
131bb535300SJeff Roberson /*
132bb535300SJeff Roberson  * These are needed when linking statically.  All references within
133bb535300SJeff Roberson  * libgcc (and in the future libc) to these routines are weak, but
134bb535300SJeff Roberson  * if they are not (strongly) referenced by the application or other
135bb535300SJeff Roberson  * libraries, then the actual functions will not be loaded.
136bb535300SJeff Roberson  */
137bb535300SJeff Roberson static void *libgcc_references[] = {
138bb535300SJeff Roberson 	&_pthread_once,
139bb535300SJeff Roberson 	&_pthread_key_create,
140bb535300SJeff Roberson 	&_pthread_key_delete,
141bb535300SJeff Roberson 	&_pthread_getspecific,
142bb535300SJeff Roberson 	&_pthread_setspecific,
143bb535300SJeff Roberson 	&_pthread_mutex_init,
144bb535300SJeff Roberson 	&_pthread_mutex_destroy,
145bb535300SJeff Roberson 	&_pthread_mutex_lock,
146bb535300SJeff Roberson 	&_pthread_mutex_trylock,
147bb535300SJeff Roberson 	&_pthread_mutex_unlock
148bb535300SJeff Roberson };
149bb535300SJeff Roberson 
150bb535300SJeff Roberson int _pthread_guard_default;
151bb535300SJeff Roberson int _pthread_page_size;
152bb535300SJeff Roberson 
153bb535300SJeff Roberson /*
154bb535300SJeff Roberson  * Threaded process initialization
155bb535300SJeff Roberson  */
156bb535300SJeff Roberson void
157bb535300SJeff Roberson _thread_init(void)
158bb535300SJeff Roberson {
159bb535300SJeff Roberson 	struct pthread	*pthread;
160bb535300SJeff Roberson 	int		fd;
161bb535300SJeff Roberson 	int             flags;
162bb535300SJeff Roberson 	int             i;
163bb535300SJeff Roberson 	size_t		len;
164bb535300SJeff Roberson 	int		mib[2];
165bb535300SJeff Roberson 	sigset_t	set;
166bb535300SJeff Roberson 
167bb535300SJeff Roberson 	struct clockinfo clockinfo;
168bb535300SJeff Roberson 	struct sigaction act;
169bb535300SJeff Roberson 
170bb535300SJeff Roberson 	/* Check if this function has already been called: */
171bb535300SJeff Roberson 	if (_thread_initial)
172bb535300SJeff Roberson 		/* Only initialise the threaded application once. */
173bb535300SJeff Roberson 		return;
174bb535300SJeff Roberson 
175bb535300SJeff Roberson 	_pthread_page_size = getpagesize();
176bb535300SJeff Roberson 	_pthread_guard_default = getpagesize();
177bb535300SJeff Roberson 
178bb535300SJeff Roberson 	pthread_attr_default.guardsize_attr = _pthread_guard_default;
179bb535300SJeff Roberson 
180bb535300SJeff Roberson 
181bb535300SJeff Roberson 	/*
182bb535300SJeff Roberson 	 * Make gcc quiescent about {,libgcc_}references not being
183bb535300SJeff Roberson 	 * referenced:
184bb535300SJeff Roberson 	 */
185bb535300SJeff Roberson 	if ((references[0] == NULL) || (libgcc_references[0] == NULL))
186bb535300SJeff Roberson 		PANIC("Failed loading mandatory references in _thread_init");
187bb535300SJeff Roberson 
188bb535300SJeff Roberson 	/*
189bb535300SJeff Roberson 	 * Check for the special case of this process running as
190bb535300SJeff Roberson 	 * or in place of init as pid = 1:
191bb535300SJeff Roberson 	 */
192bb535300SJeff Roberson 	if (getpid() == 1) {
193bb535300SJeff Roberson 		/*
194bb535300SJeff Roberson 		 * Setup a new session for this process which is
195bb535300SJeff Roberson 		 * assumed to be running as root.
196bb535300SJeff Roberson 		 */
197bb535300SJeff Roberson 		if (setsid() == -1)
198bb535300SJeff Roberson 			PANIC("Can't set session ID");
199bb535300SJeff Roberson 		if (revoke(_PATH_CONSOLE) != 0)
200bb535300SJeff Roberson 			PANIC("Can't revoke console");
201bb535300SJeff Roberson 		if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
202bb535300SJeff Roberson 			PANIC("Can't open console");
203bb535300SJeff Roberson 		if (setlogin("root") == -1)
204bb535300SJeff Roberson 			PANIC("Can't set login to root");
205bb535300SJeff Roberson 		if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1)
206bb535300SJeff Roberson 			PANIC("Can't set controlling terminal");
207bb535300SJeff Roberson 		if (__sys_dup2(fd, 0) == -1 ||
208bb535300SJeff Roberson 		    __sys_dup2(fd, 1) == -1 ||
209bb535300SJeff Roberson 		    __sys_dup2(fd, 2) == -1)
210bb535300SJeff Roberson 			PANIC("Can't dup2");
211bb535300SJeff Roberson 	}
212bb535300SJeff Roberson 
213bb535300SJeff Roberson 	/* Allocate memory for the thread structure of the initial thread: */
214bb535300SJeff Roberson 	if ((pthread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
215bb535300SJeff Roberson 		/*
216bb535300SJeff Roberson 		 * Insufficient memory to initialise this application, so
217bb535300SJeff Roberson 		 * abort:
218bb535300SJeff Roberson 		 */
219bb535300SJeff Roberson 		PANIC("Cannot allocate memory for initial thread");
220bb535300SJeff Roberson 	}
221bb535300SJeff Roberson 	_thread_initial = pthread;
222bb535300SJeff Roberson 	pthread->arch_id = _set_curthread(pthread);
223bb535300SJeff Roberson 
224bb535300SJeff Roberson 	/* Zero the initial thread structure: */
225bb535300SJeff Roberson 	memset(pthread, 0, sizeof(struct pthread));
226bb535300SJeff Roberson 	/* Get our thread id. */
227bb535300SJeff Roberson 	thr_self(&pthread->thr_id);
228bb535300SJeff Roberson 
229bb535300SJeff Roberson 	/* Give this thread default attributes: */
230bb535300SJeff Roberson 	memcpy((void *) &pthread->attr, &pthread_attr_default,
231bb535300SJeff Roberson 	    sizeof(struct pthread_attr));
232bb535300SJeff Roberson 
233bb535300SJeff Roberson 	/* Find the stack top */
234bb535300SJeff Roberson 	mib[0] = CTL_KERN;
235bb535300SJeff Roberson 	mib[1] = KERN_USRSTACK;
236bb535300SJeff Roberson 	len = sizeof (_usrstack);
237bb535300SJeff Roberson 	if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1)
238bb535300SJeff Roberson 		_usrstack = (void *)USRSTACK;
239bb535300SJeff Roberson 	/*
240bb535300SJeff Roberson 	 * Create a red zone below the main stack.  All other stacks are
241bb535300SJeff Roberson 	 * constrained to a maximum size by the paramters passed to
242bb535300SJeff Roberson 	 * mmap(), but this stack is only limited by resource limits, so
243bb535300SJeff Roberson 	 * this stack needs an explicitly mapped red zone to protect the
244bb535300SJeff Roberson 	 * thread stack that is just beyond.
245bb535300SJeff Roberson 	 */
246bb535300SJeff Roberson 	if (mmap(_usrstack - PTHREAD_STACK_INITIAL -
247bb535300SJeff Roberson 	    _pthread_guard_default, _pthread_guard_default, 0,
248bb535300SJeff Roberson 	    MAP_ANON, -1, 0) == MAP_FAILED)
249bb535300SJeff Roberson 		PANIC("Cannot allocate red zone for initial thread");
250bb535300SJeff Roberson 
251bb535300SJeff Roberson 	/* Set the main thread stack pointer. */
252bb535300SJeff Roberson 	pthread->stack = _usrstack - PTHREAD_STACK_INITIAL;
253bb535300SJeff Roberson 
254bb535300SJeff Roberson 	/* Set the stack attributes. */
255bb535300SJeff Roberson 	pthread->attr.stackaddr_attr = pthread->stack;
256bb535300SJeff Roberson 	pthread->attr.stacksize_attr = PTHREAD_STACK_INITIAL;
257bb535300SJeff Roberson 
258bb535300SJeff Roberson 	/*
259bb535300SJeff Roberson 	 * Write a magic value to the thread structure
260bb535300SJeff Roberson 	 * to help identify valid ones:
261bb535300SJeff Roberson 	 */
262bb535300SJeff Roberson 	pthread->magic = PTHREAD_MAGIC;
263bb535300SJeff Roberson 
264bb535300SJeff Roberson 	/* Set the initial cancel state */
265bb535300SJeff Roberson 	pthread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED;
266bb535300SJeff Roberson 
267bb535300SJeff Roberson 	/* Setup the context for initial thread. */
268bb535300SJeff Roberson 	getcontext(&pthread->ctx);
269bb535300SJeff Roberson 	pthread->ctx.uc_stack.ss_sp = pthread->stack;
270bb535300SJeff Roberson 	pthread->ctx.uc_stack.ss_size = PTHREAD_STACK_INITIAL;
271bb535300SJeff Roberson 
272bb535300SJeff Roberson 	/* Default the priority of the initial thread: */
273bb535300SJeff Roberson 	pthread->base_priority = PTHREAD_DEFAULT_PRIORITY;
274bb535300SJeff Roberson 	pthread->active_priority = PTHREAD_DEFAULT_PRIORITY;
275bb535300SJeff Roberson 	pthread->inherited_priority = 0;
276bb535300SJeff Roberson 
277bb535300SJeff Roberson 	/* Initialise the state of the initial thread: */
278bb535300SJeff Roberson 	pthread->state = PS_RUNNING;
279bb535300SJeff Roberson 
280bb535300SJeff Roberson 	/* Set the name of the thread: */
281bb535300SJeff Roberson 	pthread->name = strdup("_thread_initial");
282bb535300SJeff Roberson 
283bb535300SJeff Roberson 	/* Initialize joiner to NULL (no joiner): */
284bb535300SJeff Roberson 	pthread->joiner = NULL;
285bb535300SJeff Roberson 
286bb535300SJeff Roberson 	/* Initialize the owned mutex queue and count: */
287bb535300SJeff Roberson 	TAILQ_INIT(&(pthread->mutexq));
288bb535300SJeff Roberson 	pthread->priority_mutex_count = 0;
289bb535300SJeff Roberson 
290bb535300SJeff Roberson 	/* Initialise the rest of the fields: */
291bb535300SJeff Roberson 	pthread->specific = NULL;
292bb535300SJeff Roberson 	pthread->cleanup = NULL;
293bb535300SJeff Roberson 	pthread->flags = 0;
294bb535300SJeff Roberson 	pthread->error = 0;
295bb535300SJeff Roberson 	TAILQ_INIT(&_thread_list);
296bb535300SJeff Roberson 	TAILQ_INSERT_HEAD(&_thread_list, pthread, tle);
297bb535300SJeff Roberson 
298bb535300SJeff Roberson 	/* Enter a loop to get the existing signal status: */
299bb535300SJeff Roberson 	for (i = 1; i < NSIG; i++) {
300bb535300SJeff Roberson 		/* Check for signals which cannot be trapped. */
301bb535300SJeff Roberson 		if (i == SIGKILL || i == SIGSTOP)
302bb535300SJeff Roberson 			continue;
303bb535300SJeff Roberson 
304bb535300SJeff Roberson 		/* Get the signal handler details. */
305bb535300SJeff Roberson 		if (__sys_sigaction(i, NULL,
306bb535300SJeff Roberson 		    &_thread_sigact[i - 1]) != 0)
307bb535300SJeff Roberson 			PANIC("Cannot read signal handler info");
308bb535300SJeff Roberson 	}
309bb535300SJeff Roberson 	act.sa_sigaction = _thread_sig_wrapper;
310bb535300SJeff Roberson 	act.sa_flags = SA_SIGINFO;
311bb535300SJeff Roberson 	SIGFILLSET(act.sa_mask);
312bb535300SJeff Roberson 
313bb535300SJeff Roberson 	if (__sys_sigaction(SIGTHR, &act, NULL))
314bb535300SJeff Roberson 		PANIC("Cannot set SIGTHR handler.\n");
315bb535300SJeff Roberson 
316bb535300SJeff Roberson 	SIGEMPTYSET(set);
317bb535300SJeff Roberson 	SIGADDSET(set, SIGTHR);
318bb535300SJeff Roberson 	__sys_sigprocmask(SIG_BLOCK, &set, 0);
319bb535300SJeff Roberson 
320bb535300SJeff Roberson 	/* Get the kernel clockrate: */
321bb535300SJeff Roberson 	mib[0] = CTL_KERN;
322bb535300SJeff Roberson 	mib[1] = KERN_CLOCKRATE;
323bb535300SJeff Roberson 	len = sizeof (struct clockinfo);
324bb535300SJeff Roberson 	if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0)
325bb535300SJeff Roberson 		_clock_res_usec = clockinfo.tick > CLOCK_RES_USEC_MIN ?
326bb535300SJeff Roberson 		    clockinfo.tick : CLOCK_RES_USEC_MIN;
327bb535300SJeff Roberson 
328bb535300SJeff Roberson 	/* Initialise the garbage collector mutex and condition variable. */
329bb535300SJeff Roberson 	if (_pthread_mutex_init(&_gc_mutex,NULL) != 0 ||
330bb535300SJeff Roberson 	    pthread_cond_init(&_gc_cond,NULL) != 0)
331bb535300SJeff Roberson 		PANIC("Failed to initialise garbage collector mutex or condvar");
332bb535300SJeff Roberson }
333bb535300SJeff Roberson 
334bb535300SJeff Roberson struct pthread *
335bb535300SJeff Roberson _get_curthread_slow(void)
336bb535300SJeff Roberson {
337bb535300SJeff Roberson 	struct pthread *td;
338bb535300SJeff Roberson 	thr_id_t id;
339bb535300SJeff Roberson 
340bb535300SJeff Roberson 	if (_thread_initial == NULL)
341bb535300SJeff Roberson 		_thread_init();
342bb535300SJeff Roberson 
343bb535300SJeff Roberson 	thr_self(&id);
344bb535300SJeff Roberson 	TAILQ_FOREACH(td, &_thread_list, tle)
345bb535300SJeff Roberson 		if (td->thr_id == id)
346bb535300SJeff Roberson 			return (td);
347bb535300SJeff Roberson 	return (NULL);
348bb535300SJeff Roberson }
349bb535300SJeff Roberson 
350bb535300SJeff Roberson /*
351bb535300SJeff Roberson  * Special start up code for NetBSD/Alpha
352bb535300SJeff Roberson  */
353bb535300SJeff Roberson #if	defined(__NetBSD__) && defined(__alpha__)
354bb535300SJeff Roberson int
355bb535300SJeff Roberson main(int argc, char *argv[], char *env);
356bb535300SJeff Roberson 
357bb535300SJeff Roberson int
358bb535300SJeff Roberson _thread_main(int argc, char *argv[], char *env)
359bb535300SJeff Roberson {
360bb535300SJeff Roberson 	_thread_init();
361bb535300SJeff Roberson 	return (main(argc, argv, env));
362bb535300SJeff Roberson }
363bb535300SJeff Roberson #endif
364