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