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