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