thr_init.c revision 123859
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 123859 2003-12-26 08:16:17Z 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 } else { 184 memset(&td->join_status, 0, sizeof(struct join_status)); 185 } 186 td->joiner = NULL; 187 td->error = 0; 188 td->flags = 0; 189} 190 191/* 192 * Initialize the active and dead threads list. Any threads in the active 193 * list will be removed and the thread td * will be marked as the 194 * initial thread and inserted in the list as the only thread. Any threads 195 * in the dead threads list will also be removed. 196 */ 197void 198init_tdlist(struct pthread *td, int reinit) 199{ 200 struct pthread *tdTemp, *tdTemp2; 201 202 _thread_initial = td; 203 td->name = strdup("_thread_initial"); 204 205 /* 206 * If this is not the first initialization, remove any entries 207 * that may be in the list and deallocate their memory. Also 208 * destroy any global pthread primitives (they will be recreated). 209 */ 210 if (reinit) { 211 TAILQ_FOREACH_SAFE(tdTemp, &_thread_list, tle, tdTemp2) { 212 if (tdTemp != NULL) { 213 TAILQ_REMOVE(&_thread_list, tdTemp, tle); 214 free(tdTemp); 215 } 216 } 217 TAILQ_FOREACH_SAFE(tdTemp, &_dead_list, dle, tdTemp2) { 218 if (tdTemp != NULL) { 219 TAILQ_REMOVE(&_dead_list, tdTemp, dle); 220 free(tdTemp); 221 } 222 } 223 _pthread_mutex_destroy(&dead_list_lock); 224 _pthread_cond_destroy(&_gc_cond); 225 } else { 226 TAILQ_INIT(&_thread_list); 227 TAILQ_INIT(&_dead_list); 228 } 229 230 /* Insert this thread as the first thread in the active list */ 231 TAILQ_INSERT_HEAD(&_thread_list, td, tle); 232 233 /* 234 * Initialize the active thread list lock and the 235 * dead threads list lock & associated condition variable. 236 */ 237 memset(&thread_list_lock, 0, sizeof(spinlock_t)); 238 if (_pthread_mutex_init(&dead_list_lock,NULL) != 0 || 239 _pthread_cond_init(&_gc_cond,NULL) != 0) 240 PANIC("Failed to initialize garbage collector primitives"); 241} 242 243/* 244 * Threaded process initialization 245 */ 246void 247_thread_init(void) 248{ 249 struct pthread *pthread; 250 int fd; 251 int i; 252 size_t len; 253 int mib[2]; 254 sigset_t set; 255 int osreldate; 256 int error; 257 258 struct clockinfo clockinfo; 259 struct sigaction act; 260 261 /* Check if this function has already been called: */ 262 if (_thread_initial) 263 /* Only initialise the threaded application once. */ 264 return; 265 266 _pthread_page_size = getpagesize(); 267 _pthread_guard_default = getpagesize(); 268 269 pthread_attr_default.guardsize_attr = _pthread_guard_default; 270 271 272 /* 273 * Make gcc quiescent about {,libgcc_}references not being 274 * referenced: 275 */ 276 if ((references[0] == NULL) || (libgcc_references[0] == NULL)) 277 PANIC("Failed loading mandatory references in _thread_init"); 278 279 /* 280 * Check for the special case of this process running as 281 * or in place of init as pid = 1: 282 */ 283 if (getpid() == 1) { 284 /* 285 * Setup a new session for this process which is 286 * assumed to be running as root. 287 */ 288 if (setsid() == -1) 289 PANIC("Can't set session ID"); 290 if (revoke(_PATH_CONSOLE) != 0) 291 PANIC("Can't revoke console"); 292 if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0) 293 PANIC("Can't open console"); 294 if (setlogin("root") == -1) 295 PANIC("Can't set login to root"); 296 if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1) 297 PANIC("Can't set controlling terminal"); 298 if (__sys_dup2(fd, 0) == -1 || 299 __sys_dup2(fd, 1) == -1 || 300 __sys_dup2(fd, 2) == -1) 301 PANIC("Can't dup2"); 302 } 303 304 /* Allocate memory for the thread structure of the initial thread: */ 305 if ((pthread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { 306 /* 307 * Insufficient memory to initialise this application, so 308 * abort: 309 */ 310 PANIC("Cannot allocate memory for initial thread"); 311 } 312 313 init_tdlist(pthread, 0); 314 init_td_common(pthread, &pthread_attr_default, 0); 315 pthread->arch_id = _set_curthread(NULL, pthread, &error); 316 317 /* Get our thread id. */ 318 thr_self(&pthread->thr_id); 319 320 /* Find the stack top */ 321 mib[0] = CTL_KERN; 322 mib[1] = KERN_USRSTACK; 323 len = sizeof (_usrstack); 324 if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1) 325 _usrstack = (void *)USRSTACK; 326 /* 327 * Create a red zone below the main stack. All other stacks are 328 * constrained to a maximum size by the paramters passed to 329 * mmap(), but this stack is only limited by resource limits, so 330 * this stack needs an explicitly mapped red zone to protect the 331 * thread stack that is just beyond. 332 */ 333 if (mmap(_usrstack - PTHREAD_STACK_INITIAL - 334 _pthread_guard_default, _pthread_guard_default, 0, 335 MAP_ANON, -1, 0) == MAP_FAILED) 336 PANIC("Cannot allocate red zone for initial thread"); 337 338 /* Set the main thread stack pointer. */ 339 pthread->stack = _usrstack - PTHREAD_STACK_INITIAL; 340 341 /* Set the stack attributes. */ 342 pthread->attr.stackaddr_attr = pthread->stack; 343 pthread->attr.stacksize_attr = PTHREAD_STACK_INITIAL; 344 345 /* Setup the context for initial thread. */ 346 getcontext(&pthread->ctx); 347 pthread->ctx.uc_stack.ss_sp = pthread->stack; 348 pthread->ctx.uc_stack.ss_size = PTHREAD_STACK_INITIAL; 349 350 /* Default the priority of the initial thread: */ 351 pthread->base_priority = PTHREAD_DEFAULT_PRIORITY; 352 pthread->active_priority = PTHREAD_DEFAULT_PRIORITY; 353 pthread->inherited_priority = 0; 354 355 /* Initialise the state of the initial thread: */ 356 pthread->state = PS_RUNNING; 357 358 /* Enter a loop to get the existing signal status: */ 359 for (i = 1; i < NSIG; i++) { 360 /* Check for signals which cannot be trapped. */ 361 if (i == SIGKILL || i == SIGSTOP) 362 continue; 363 364 /* Get the signal handler details. */ 365 if (__sys_sigaction(i, NULL, 366 &_thread_sigact[i - 1]) != 0) 367 PANIC("Cannot read signal handler info"); 368 } 369 act.sa_sigaction = _thread_sig_wrapper; 370 act.sa_flags = SA_SIGINFO; 371 SIGFILLSET(act.sa_mask); 372 373 if (__sys_sigaction(SIGTHR, &act, NULL)) 374 PANIC("Cannot set SIGTHR handler.\n"); 375 376 SIGEMPTYSET(set); 377 SIGADDSET(set, SIGTHR); 378 __sys_sigprocmask(SIG_BLOCK, &set, 0); 379 380 /* 381 * Precompute the signal set used by _thread_suspend to wait 382 * for SIGTHR. 383 */ 384 mib[0] = CTL_KERN; 385 mib[1] = KERN_OSRELDATE; 386 len = sizeof(osreldate); 387 if (sysctl(mib, 2, &osreldate, &len, NULL, 0) == 0 && 388 SIGTIMEDWAIT_SET_IS_INVERTED(osreldate)) { 389 /* Kernel bug requires an inverted signal set. */ 390 SIGFILLSET(_thread_suspend_sigset); 391 SIGDELSET(_thread_suspend_sigset, SIGTHR); 392 } else { 393 SIGEMPTYSET(_thread_suspend_sigset); 394 SIGADDSET(_thread_suspend_sigset, SIGTHR); 395 } 396#ifdef _PTHREADS_INVARIANTS 397 SIGADDSET(_thread_suspend_sigset, SIGALRM); 398#endif 399 400 /* Get the kernel clockrate: */ 401 mib[0] = CTL_KERN; 402 mib[1] = KERN_CLOCKRATE; 403 len = sizeof (struct clockinfo); 404 if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0) 405 _clock_res_usec = clockinfo.tick > CLOCK_RES_USEC_MIN ? 406 clockinfo.tick : CLOCK_RES_USEC_MIN; 407} 408 409/* 410 * Special start up code for NetBSD/Alpha 411 */ 412#if defined(__NetBSD__) && defined(__alpha__) 413int 414main(int argc, char *argv[], char *env); 415 416int 417_thread_main(int argc, char *argv[], char *env) 418{ 419 _thread_init(); 420 return (main(argc, argv, env)); 421} 422#endif 423