thr_init.c revision 127556
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 127556 2004-03-29 05:45:01Z 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
69extern void _thread_init_hack(void);
70
71/*
72 * All weak references used within libc should be in this table.
73 * This will is so that static libraries will work.
74 *
75 * XXXTHR - Check this list.
76 */
77static void *references[] = {
78	&_thread_init_hack,
79	&_thread_init,
80	&_accept,
81	&_bind,
82	&_close,
83	&_connect,
84	&_dup,
85	&_dup2,
86	&_execve,
87	&_fcntl,
88	&_flock,
89	&_flockfile,
90	&_fstat,
91	&_fstatfs,
92	&_fsync,
93	&_funlockfile,
94	&_getdirentries,
95	&_getlogin,
96	&_getpeername,
97	&_getsockname,
98	&_getsockopt,
99	&_ioctl,
100	&_kevent,
101	&_listen,
102	&_nanosleep,
103	&_open,
104	&_pthread_getspecific,
105	&_pthread_key_create,
106	&_pthread_key_delete,
107	&_pthread_mutex_destroy,
108	&_pthread_mutex_init,
109	&_pthread_mutex_lock,
110	&_pthread_mutex_trylock,
111	&_pthread_mutex_unlock,
112	&_pthread_mutexattr_init,
113	&_pthread_mutexattr_destroy,
114	&_pthread_mutexattr_settype,
115	&_pthread_once,
116	&_pthread_setspecific,
117	&_read,
118	&_readv,
119	&_recvfrom,
120	&_recvmsg,
121	&_select,
122	&_sendmsg,
123	&_sendto,
124	&_setsockopt,
125	&_sigaction,
126	&_sigprocmask,
127	&_sigsuspend,
128	&_socket,
129	&_socketpair,
130	&_wait4,
131	&_write,
132	&_writev
133};
134
135/*
136 * These are needed when linking statically.  All references within
137 * libgcc (and in the future libc) to these routines are weak, but
138 * if they are not (strongly) referenced by the application or other
139 * libraries, then the actual functions will not be loaded.
140 */
141static void *libgcc_references[] = {
142	&_thread_init_hack,
143	&_thread_init,
144	&_pthread_once,
145	&_pthread_key_create,
146	&_pthread_key_delete,
147	&_pthread_getspecific,
148	&_pthread_setspecific,
149	&_pthread_mutex_init,
150	&_pthread_mutex_destroy,
151	&_pthread_mutex_lock,
152	&_pthread_mutex_trylock,
153	&_pthread_mutex_unlock
154};
155
156int _pthread_guard_default;
157int _pthread_page_size;
158
159/*
160 * Initialize the current thread.
161 */
162void
163init_td_common(struct pthread *td, struct pthread_attr *attrp, int reinit)
164{
165	/*
166	 * Some parts of a pthread are initialized only once.
167	 */
168	if (!reinit) {
169		memset(td, 0, sizeof(struct pthread));
170		td->cancelflags = PTHREAD_CANCEL_ENABLE |
171		    PTHREAD_CANCEL_DEFERRED;
172		memcpy(&td->attr, attrp, sizeof(struct pthread_attr));
173		td->magic = PTHREAD_MAGIC;
174		TAILQ_INIT(&td->mutexq);
175		td->base_priority = PTHREAD_DEFAULT_PRIORITY;
176		td->active_priority = PTHREAD_DEFAULT_PRIORITY;
177		td->inherited_priority = PTHREAD_MIN_PRIORITY;
178	} else {
179		memset(&td->join_status, 0, sizeof(struct join_status));
180	}
181	td->joiner = NULL;
182	td->error = 0;
183	td->flags = 0;
184}
185
186/*
187 * Initialize the active and dead threads list. Any threads in the active
188 * list will be removed and the thread td * will be marked as the
189 * initial thread and inserted in the list as the only thread. Any threads
190 * in the dead threads list will also be removed.
191 */
192void
193init_tdlist(struct pthread *td, int reinit)
194{
195	struct pthread *tdTemp, *tdTemp2;
196
197	_thread_initial = td;
198	td->name = strdup("_thread_initial");
199
200	/*
201	 * If this is not the first initialization, remove any entries
202	 * that may be in the list and deallocate their memory. Also
203	 * destroy any global pthread primitives (they will be recreated).
204	 */
205	if (reinit) {
206		TAILQ_FOREACH_SAFE(tdTemp, &_thread_list, tle, tdTemp2) {
207			if (tdTemp != NULL) {
208				TAILQ_REMOVE(&_thread_list, tdTemp, tle);
209				free(tdTemp);
210			}
211		}
212		TAILQ_FOREACH_SAFE(tdTemp, &_dead_list, dle, tdTemp2) {
213			if (tdTemp != NULL) {
214				TAILQ_REMOVE(&_dead_list, tdTemp, dle);
215				free(tdTemp);
216			}
217		}
218		_pthread_mutex_destroy(&dead_list_lock);
219	} else {
220		TAILQ_INIT(&_thread_list);
221		TAILQ_INIT(&_dead_list);
222	}
223
224	/* Insert this thread as the first thread in the active list */
225	TAILQ_INSERT_HEAD(&_thread_list, td, tle);
226
227	/*
228	 * Initialize the active thread list lock and the
229	 * dead threads list lock.
230	 */
231	memset(&thread_list_lock, 0, sizeof(spinlock_t));
232	if (_pthread_mutex_init(&dead_list_lock,NULL) != 0)
233		PANIC("Failed to initialize garbage collector primitives");
234}
235
236/*
237 * Threaded process initialization
238 */
239void
240_thread_init(void)
241{
242	struct pthread	*pthread;
243	int		fd;
244	int             i;
245	size_t		len;
246	int		mib[2];
247	int		error;
248
249	/* Check if this function has already been called: */
250	if (_thread_initial)
251		/* Only initialise the threaded application once. */
252		return;
253
254	_pthread_page_size = getpagesize();
255	_pthread_guard_default = getpagesize();
256
257	pthread_attr_default.guardsize_attr = _pthread_guard_default;
258
259
260	/*
261	 * Make gcc quiescent about {,libgcc_}references not being
262	 * referenced:
263	 */
264	if ((references[0] == NULL) || (libgcc_references[0] == NULL))
265		PANIC("Failed loading mandatory references in _thread_init");
266
267	/*
268	 * Check for the special case of this process running as
269	 * or in place of init as pid = 1:
270	 */
271	if (getpid() == 1) {
272		/*
273		 * Setup a new session for this process which is
274		 * assumed to be running as root.
275		 */
276		if (setsid() == -1)
277			PANIC("Can't set session ID");
278		if (revoke(_PATH_CONSOLE) != 0)
279			PANIC("Can't revoke console");
280		if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
281			PANIC("Can't open console");
282		if (setlogin("root") == -1)
283			PANIC("Can't set login to root");
284		if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1)
285			PANIC("Can't set controlling terminal");
286		if (__sys_dup2(fd, 0) == -1 ||
287		    __sys_dup2(fd, 1) == -1 ||
288		    __sys_dup2(fd, 2) == -1)
289			PANIC("Can't dup2");
290	}
291
292	/* Allocate memory for the thread structure of the initial thread: */
293	if ((pthread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
294		/*
295		 * Insufficient memory to initialise this application, so
296		 * abort:
297		 */
298		PANIC("Cannot allocate memory for initial thread");
299	}
300
301	init_tdlist(pthread, 0);
302	init_td_common(pthread, &pthread_attr_default, 0);
303	pthread->arch_id = _set_curthread(NULL, pthread, &error);
304
305	/* Get our thread id. */
306	thr_self(&pthread->thr_id);
307
308	/* Find the stack top */
309	mib[0] = CTL_KERN;
310	mib[1] = KERN_USRSTACK;
311	len = sizeof (_usrstack);
312	if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1)
313		_usrstack = (void *)USRSTACK;
314	/*
315	 * Create a red zone below the main stack.  All other stacks are
316	 * constrained to a maximum size by the paramters passed to
317	 * mmap(), but this stack is only limited by resource limits, so
318	 * this stack needs an explicitly mapped red zone to protect the
319	 * thread stack that is just beyond.
320	 */
321	if (mmap(_usrstack - PTHREAD_STACK_INITIAL -
322	    _pthread_guard_default, _pthread_guard_default, 0,
323	    MAP_ANON, -1, 0) == MAP_FAILED)
324		PANIC("Cannot allocate red zone for initial thread");
325
326	/* Set the main thread stack pointer. */
327	pthread->stack = _usrstack - PTHREAD_STACK_INITIAL;
328
329	/* Set the stack attributes. */
330	pthread->attr.stackaddr_attr = pthread->stack;
331	pthread->attr.stacksize_attr = PTHREAD_STACK_INITIAL;
332
333	/* Setup the context for initial thread. */
334	getcontext(&pthread->ctx);
335	pthread->ctx.uc_stack.ss_sp = pthread->stack;
336	pthread->ctx.uc_stack.ss_size = PTHREAD_STACK_INITIAL;
337
338	/* Initialise the state of the initial thread: */
339	pthread->state = PS_RUNNING;
340
341	/* Enter a loop to get the existing signal status: */
342	for (i = 1; i < NSIG; i++) {
343		/* Check for signals which cannot be trapped. */
344		if (i == SIGKILL || i == SIGSTOP)
345			continue;
346
347		/* Get the signal handler details. */
348		if (__sys_sigaction(i, NULL,
349		    &_thread_sigact[i - 1]) != 0)
350			PANIC("Cannot read signal handler info");
351	}
352}
353
354/*
355 * Special start up code for NetBSD/Alpha
356 */
357#if	defined(__NetBSD__) && defined(__alpha__)
358int
359main(int argc, char *argv[], char *env);
360
361int
362_thread_main(int argc, char *argv[], char *env)
363{
364	_thread_init();
365	return (main(argc, argv, env));
366}
367#endif
368