1 /*	$OpenBSD: uthread_init.c,v 1.32 2004/06/07 21:11:23 marc Exp $	*/
2 /*
3  * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by John Birrell.
17  * 4. Neither the name of the author nor the names of any co-contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: uthread_init.c,v 1.18 1999/08/28 00:03:36 peter Exp $
34  */
35 
36 /* Allocate space for global thread variables here: */
37 #define GLOBAL_PTHREAD_PRIVATE
38 
39 #include <sys/types.h>
40 #include <sys/param.h>
41 
42 #include <sys/ioctl.h>
43 #include <sys/mman.h>
44 #include <sys/mount.h>
45 #include <sys/socket.h>
46 #include <sys/stat.h>
47 #include <sys/sysctl.h>
48 #include <sys/time.h>
49 #include <sys/ttycom.h>
50 #include <sys/user.h>
51 #include <sys/wait.h>
52 
53 #include <dlfcn.h>
54 #include <dirent.h>
55 #include <errno.h>
56 #include <fcntl.h>
57 #include <paths.h>
58 #include <poll.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <unistd.h>
62 
63 #ifdef _THREAD_SAFE
64 #include <machine/reg.h>
65 #include <pthread.h>
66 #include "pthread_private.h"
67 
68 /* Global thread variables. */
69 _stack_list_t	_stackq;
70 
71 extern int _thread_autoinit_dummy_decl;
72 
73 /*
74  * All weak references used within libc that are redefined in libpthread
75  * MUST be in this table.   This is necessary to force the proper version to
76  * be used when linking -static.
77  */
78 static void *references[] = {
79 	&_exit,
80 	&accept,
81 	&bind,
82 	&close,
83 	&closefrom,
84 	&connect,
85 	&dup,
86 	&dup2,
87 	&execve,
88 	&fchflags,
89 	&fchmod,
90 	&fchown,
91 	&fcntl,
92 	&flock,
93 	&fork,
94 	&fpathconf,
95 	&fstat,
96 	&fstatfs,
97 	&fsync,
98 	&getdirentries,
99 	&getpeername,
100 	&getsockname,
101 	&getsockopt,
102 	&ioctl,
103 	&kevent,
104 	&kqueue,
105 	&listen,
106 	&msync,
107 	&nanosleep,
108 	&open,
109 	&pipe,
110 	&poll,
111 	&read,
112 	&readv,
113 	&recvfrom,
114 	&recvmsg,
115 	&select,
116 	&sendmsg,
117 	&sendto,
118 	&setsockopt,
119 	&shutdown,
120 	&sigaction,
121 	&sigaltstack,
122 	&sigpending,
123 	&sigprocmask,
124 	&sigsuspend,
125 	&socket,
126 	&socketpair,
127 	&vfork,
128 	&wait4,
129 	&write,
130 	&writev,
131 	/* libc thread-safe helper functions */
132 	&_thread_fd_lock,
133 	&_thread_fd_unlock,
134 	&_thread_malloc_init,
135 	&_thread_malloc_lock,
136 	&_thread_malloc_unlock,
137 	&_thread_tag_lock,
138 	&_thread_tag_unlock,
139 	&_thread_tag_storage,
140 	&flockfile,
141 	&ftrylockfile,
142 	&funlockfile
143 };
144 
145 /*
146  * Threaded process initialization
147  */
148 void
_thread_init(void)149 _thread_init(void)
150 {
151 	int		fd;
152 	int             flags;
153 	int		res;
154 	int             i;
155 	size_t		len;
156 	int		mib[2];
157 	struct clockinfo clockinfo;
158 	struct sigaction act;
159 
160 	/* Check if this function has already been called: */
161 	if (_thread_initial)
162 		/* Only initialise the threaded application once. */
163 		return;
164 
165 	if (references[0] == NULL)
166 		PANIC("Failed loading mandatory references in _thread_init");
167 
168 	/*
169 	 * Check for the special case of this process running as
170 	 * or in place of init as pid = 1:
171 	 */
172 	if (getpid() == 1) {
173 		/*
174 		 * Setup a new session for this process which is
175 		 * assumed to be running as root.
176 		 */
177 		if (setsid() == -1)
178 			PANIC("Can't set session ID");
179 		if (revoke(_PATH_CONSOLE) != 0)
180 			PANIC("Can't revoke console");
181 		if ((fd = _thread_sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
182 			PANIC("Can't open console");
183 		if (setlogin("root") == -1)
184 			PANIC("Can't set login to root");
185 		if (_thread_sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1)
186 			PANIC("Can't set controlling terminal");
187 		if (_thread_sys_dup2(fd,0) == -1 ||
188 		    _thread_sys_dup2(fd,1) == -1 ||
189 		    _thread_sys_dup2(fd,2) == -1)
190 			PANIC("Can't dup2");
191 	}
192 
193 	/*
194 	 * Create a pipe that is written to by the signal handler to prevent
195 	 * signals being missed in calls to _select:
196 	 */
197 	if (_thread_sys_pipe(_thread_kern_pipe) != 0)
198 		PANIC("Cannot create kernel pipe");
199 
200 	flags = _thread_sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL);
201 	if (flags == -1)
202 		PANIC("Cannot get kernel read pipe flags");
203 
204 	res = _thread_sys_fcntl(_thread_kern_pipe[0], F_SETFL,
205 			       flags | O_NONBLOCK);
206 	if (res == -1)
207 		PANIC("Cannot make kernel read pipe non-blocking");
208 
209 	flags = _thread_sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL);
210 	if (flags == -1)
211 		PANIC("Cannot get kernel write pipe flags");
212 
213 	res = _thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL,
214 				flags | O_NONBLOCK);
215 	if (res == -1)
216 		PANIC("Cannot make kernel write pipe non-blocking");
217 
218 	res = _pq_alloc(&_readyq, PTHREAD_MIN_PRIORITY, PTHREAD_LAST_PRIORITY);
219 	if (res != 0)
220 		PANIC("Cannot allocate priority ready queue.");
221 
222 	_thread_initial = (pthread_t) malloc(sizeof(struct pthread));
223 	if (_thread_initial == NULL)
224 		PANIC("Cannot allocate memory for initial thread");
225 
226 
227 	/* Zero the global kernel thread structure: */
228 	memset(&_thread_kern_thread, 0, sizeof(struct pthread));
229 	_thread_kern_thread.flags = PTHREAD_FLAGS_PRIVATE;
230 	memset(_thread_initial, 0, sizeof(struct pthread));
231 
232 	/* Initialize the waiting and work queues: */
233 	TAILQ_INIT(&_waitingq);
234 	TAILQ_INIT(&_workq);
235 
236 	/* Initialize the scheduling switch hook routine: */
237 	_sched_switch_hook = NULL;
238 
239 	/* Initialize the thread stack cache: */
240 	SLIST_INIT(&_stackq);
241 
242 	/*
243 	 * Write a magic value to the thread structure
244 	 * to help identify valid ones:
245 	 */
246 	_thread_initial->magic = PTHREAD_MAGIC;
247 
248 	/* Set the initial cancel state */
249 	_thread_initial->cancelflags = PTHREAD_CANCEL_ENABLE |
250 		PTHREAD_CANCEL_DEFERRED;
251 
252 	/* Default the priority of the initial thread: */
253 	_thread_initial->base_priority = PTHREAD_DEFAULT_PRIORITY;
254 	_thread_initial->active_priority = PTHREAD_DEFAULT_PRIORITY;
255 	_thread_initial->inherited_priority = 0;
256 
257 	/* Initialise the state of the initial thread: */
258 	_thread_initial->state = PS_RUNNING;
259 
260 	/* Initialize joiner to NULL (no joiner): */
261 	_thread_initial->joiner = NULL;
262 
263 	/* Initialize the owned mutex queue and count: */
264 	TAILQ_INIT(&(_thread_initial->mutexq));
265 	_thread_initial->priority_mutex_count = 0;
266 
267 	/* Initialize the global scheduling time: */
268 	_sched_ticks = 0;
269 	gettimeofday((struct timeval *) &_sched_tod, NULL);
270 
271 	/* Initialize last active: */
272 	_thread_initial->last_active = (long) _sched_ticks;
273 
274 	/* Give it a useful name */
275 	pthread_set_name_np(_thread_initial, (char *)"main");
276 
277 	/* Initialise the rest of the fields: */
278 	_thread_initial->poll_data.nfds = 0;
279 	_thread_initial->poll_data.fds = NULL;
280 	_thread_initial->sig_defer_count = 0;
281 	_thread_initial->slice_usec = -1;
282 	_thread_initial->sig_saved = 0;
283 	_thread_initial->yield_on_sig_undefer = 0;
284 	_thread_initial->specific_data = NULL;
285 	_thread_initial->cleanup = NULL;
286 	_thread_initial->flags = 0;
287 	_thread_initial->error = 0;
288 	_SPINLOCK_INIT(&_thread_initial->lock);
289 	TAILQ_INIT(&_thread_list);
290 	TAILQ_INSERT_HEAD(&_thread_list, _thread_initial, tle);
291 	_set_curthread(_thread_initial);
292 
293 	/* Initialise the global signal action structure: */
294 	sigfillset(&act.sa_mask);
295 	act.sa_handler = (void (*) (int)) _thread_sig_handler;
296 	act.sa_flags = SA_SIGINFO;
297 
298 	/* Clear pending signals for the process: */
299 	sigemptyset(&_process_sigpending);
300 
301 	/* Initialize signal handling: */
302 	_thread_sig_init();
303 
304 	/* Enter a loop to get the existing signal status: */
305 	for (i = 1; i < NSIG; i++) {
306 		/* Check for signals which cannot be trapped: */
307 		if (i == SIGKILL || i == SIGSTOP)
308 			continue;
309 
310 		/* Get the signal handler details: */
311 		if (_thread_sys_sigaction(i, NULL, &_thread_sigact[i - 1]) != 0)
312 			PANIC("Cannot read signal handler info");
313 
314 		/* Initialize the SIG_DFL dummy handler count. */
315 		_thread_dfl_count[i] = 0;
316 	}
317 
318 	/*
319 	 * Install the signal handler for the most important
320 	 * signals that the user-thread kernel needs. Actually
321 	 * SIGINFO isn't really needed, but it is nice to have.
322 	 */
323 	if (_thread_sys_sigaction(_SCHED_SIGNAL, &act, NULL) != 0 ||
324 	    _thread_sys_sigaction(SIGINFO,       &act, NULL) != 0 ||
325 	    _thread_sys_sigaction(SIGCHLD,       &act, NULL) != 0)
326 		PANIC("Cannot initialize signal handler");
327 
328 	_thread_sigact[_SCHED_SIGNAL - 1].sa_flags = SA_SIGINFO;
329 	_thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO;
330 	_thread_sigact[SIGCHLD - 1].sa_flags = SA_SIGINFO;
331 
332 	/* Get the process signal mask: */
333 	_thread_sys_sigprocmask(SIG_SETMASK, NULL, &_process_sigmask);
334 
335 	/* Get the kernel clockrate: */
336 	mib[0] = CTL_KERN;
337 	mib[1] = KERN_CLOCKRATE;
338 	len = sizeof (struct clockinfo);
339 	if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0)
340 		_clock_res_usec = clockinfo.tick > CLOCK_RES_USEC_MIN ?
341 			clockinfo.tick : CLOCK_RES_USEC_MIN;
342 
343 	/* Get the table size: */
344 	if ((_thread_dtablesize = getdtablesize()) < 0)
345 		PANIC("Cannot get dtablesize");
346 
347 	/* Allocate memory for the file descriptor table: */
348 	_thread_fd_table = calloc(_thread_dtablesize,
349 				  sizeof(struct fd_table_entry *));
350 	if (_thread_fd_table == NULL) {
351 		_thread_dtablesize = 0;
352 		PANIC("Cannot allocate memory for file descriptor table");
353 	}
354 
355 	/* Allocate memory for the pollfd table: */
356 	_thread_pfd_table = calloc(_thread_dtablesize, sizeof(struct pollfd));
357 	if (_thread_pfd_table == NULL)
358 		PANIC("Cannot allocate memory for pollfd table");
359 
360 	/* initialize the fd table */
361 	_thread_fd_init();
362 
363 	/* Initialise the garbage collector mutex and condition variable. */
364 	if (pthread_mutex_init(&_gc_mutex,NULL) != 0 ||
365 	    pthread_cond_init(&_gc_cond,NULL) != 0)
366 		PANIC("Failed to initialise garbage collector mutex or cond");
367 
368 #if defined(__ELF__)
369 	/* Register with dlctl for thread safe dlopen */
370 	dlctl(NULL, DL_SETTHREADLCK, _thread_kern_lock);
371 #endif
372 	_thread_autoinit_dummy_decl = 0;
373 }
374 #endif
375