thr_init.c revision 39807
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 REGENTS 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 */ 33 34/* Allocate space for global thread variables here: */ 35#define GLOBAL_PTHREAD_PRIVATE 36 37#include <errno.h> 38#include <stdlib.h> 39#include <string.h> 40#include <fcntl.h> 41#include <paths.h> 42#include <unistd.h> 43#include <sys/time.h> 44#include <sys/ttycom.h> 45#ifdef _THREAD_SAFE 46#include <machine/reg.h> 47#include <pthread.h> 48#include "pthread_private.h" 49 50#ifdef GCC_2_8_MADE_THREAD_AWARE 51typedef void *** (*dynamic_handler_allocator)(); 52extern void __set_dynamic_handler_allocator(dynamic_handler_allocator); 53 54static pthread_key_t except_head_key; 55 56typedef struct { 57 void **__dynamic_handler_chain; 58 void *top_elt[2]; 59} except_struct; 60 61static void ***dynamic_allocator_handler_fn() 62{ 63 except_struct *dh = (except_struct *)pthread_getspecific(except_head_key); 64 65 if(dh == NULL) { 66 dh = (except_struct *)malloc( sizeof(except_struct) ); 67 memset(dh, '\0', sizeof(except_struct)); 68 dh->__dynamic_handler_chain= dh->top_elt; 69 pthread_setspecific(except_head_key, (void *)dh); 70 } 71 return &dh->__dynamic_handler_chain; 72} 73#endif /* GCC_2_8_MADE_THREAD_AWARE */ 74 75/* 76 * Threaded process initialization 77 */ 78void 79_thread_init(void) 80{ 81 int fd; 82 int flags; 83 int i; 84 struct sigaction act; 85 86 /* Check if this function has already been called: */ 87 if (_thread_initial) 88 /* Only initialise the threaded application once. */ 89 return; 90 91 /* 92 * Check for the special case of this process running as 93 * or in place of init as pid = 1: 94 */ 95 if (getpid() == 1) { 96 /* 97 * Setup a new session for this process which is 98 * assumed to be running as root. 99 */ 100 if (setsid() == -1) 101 PANIC("Can't set session ID"); 102 if (revoke(_PATH_CONSOLE) != 0) 103 PANIC("Can't revoke console"); 104 if ((fd = _thread_sys_open(_PATH_CONSOLE, O_RDWR)) < 0) 105 PANIC("Can't open console"); 106 if (setlogin("root") == -1) 107 PANIC("Can't set login to root"); 108 if (_thread_sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1) 109 PANIC("Can't set controlling terminal"); 110 if (_thread_sys_dup2(fd,0) == -1 || 111 _thread_sys_dup2(fd,1) == -1 || 112 _thread_sys_dup2(fd,2) == -1) 113 PANIC("Can't dup2"); 114 } 115 116 /* Get the standard I/O flags before messing with them : */ 117 for (i = 0; i < 3; i++) 118 if ((_pthread_stdio_flags[i] = 119 _thread_sys_fcntl(i,F_GETFL, NULL)) == -1) 120 PANIC("Cannot get stdio flags"); 121 122 /* 123 * Create a pipe that is written to by the signal handler to prevent 124 * signals being missed in calls to _select: 125 */ 126 if (_thread_sys_pipe(_thread_kern_pipe) != 0) { 127 /* Cannot create pipe, so abort: */ 128 PANIC("Cannot create kernel pipe"); 129 } 130 /* Get the flags for the read pipe: */ 131 else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) { 132 /* Abort this application: */ 133 PANIC("Cannot get kernel read pipe flags"); 134 } 135 /* Make the read pipe non-blocking: */ 136 else if (_thread_sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) { 137 /* Abort this application: */ 138 PANIC("Cannot make kernel read pipe non-blocking"); 139 } 140 /* Get the flags for the write pipe: */ 141 else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) { 142 /* Abort this application: */ 143 PANIC("Cannot get kernel write pipe flags"); 144 } 145 /* Make the write pipe non-blocking: */ 146 else if (_thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) { 147 /* Abort this application: */ 148 PANIC("Cannot get kernel write pipe flags"); 149 } 150 /* Allocate memory for the thread structure of the initial thread: */ 151 else if ((_thread_initial = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { 152 /* 153 * Insufficient memory to initialise this application, so 154 * abort: 155 */ 156 PANIC("Cannot allocate memory for initial thread"); 157 } else { 158 /* Zero the global kernel thread structure: */ 159 memset(&_thread_kern_thread, 0, sizeof(struct pthread)); 160 memset(_thread_initial, 0, sizeof(struct pthread)); 161 162 /* Default the priority of the initial thread: */ 163 _thread_initial->pthread_priority = PTHREAD_DEFAULT_PRIORITY; 164 165 /* Initialise the state of the initial thread: */ 166 _thread_initial->state = PS_RUNNING; 167 168 /* Initialise the queue: */ 169 _thread_queue_init(&(_thread_initial->join_queue)); 170 171 /* Initialise the rest of the fields: */ 172 _thread_initial->specific_data = NULL; 173 _thread_initial->cleanup = NULL; 174 _thread_initial->queue = NULL; 175 _thread_initial->qnxt = NULL; 176 _thread_initial->nxt = NULL; 177 _thread_initial->flags = 0; 178 _thread_initial->error = 0; 179 _thread_link_list = _thread_initial; 180 _thread_run = _thread_initial; 181 182 /* Initialise the global signal action structure: */ 183 sigfillset(&act.sa_mask); 184 act.sa_handler = (void (*) ()) _thread_sig_handler; 185 act.sa_flags = 0; 186 187 /* Enter a loop to get the existing signal status: */ 188 for (i = 1; i < NSIG; i++) { 189 /* Check for signals which cannot be trapped: */ 190 if (i == SIGKILL || i == SIGSTOP) { 191 } 192 193 /* Get the signal handler details: */ 194 else if (_thread_sys_sigaction(i, NULL, 195 &_thread_sigact[i - 1]) != 0) { 196 /* 197 * Abort this process if signal 198 * initialisation fails: 199 */ 200 PANIC("Cannot read signal handler info"); 201 } 202 } 203 204 /* 205 * Install the signal handler for the most important 206 * signals that the user-thread kernel needs. Actually 207 * SIGINFO isn't really needed, but it is nice to have. 208 */ 209 if (_thread_sys_sigaction(SIGVTALRM, &act, NULL) != 0 || 210 _thread_sys_sigaction(SIGINFO , &act, NULL) != 0 || 211 _thread_sys_sigaction(SIGCHLD , &act, NULL) != 0) { 212 /* 213 * Abort this process if signal initialisation fails: 214 */ 215 PANIC("Cannot initialise signal handler"); 216 } 217 218 /* Get the table size: */ 219 if ((_thread_dtablesize = getdtablesize()) < 0) { 220 /* 221 * Cannot get the system defined table size, so abort 222 * this process. 223 */ 224 PANIC("Cannot get dtablesize"); 225 } 226 /* Allocate memory for the file descriptor table: */ 227 if ((_thread_fd_table = (struct fd_table_entry **) malloc(sizeof(struct fd_table_entry *) * _thread_dtablesize)) == NULL) { 228 /* 229 * Cannot allocate memory for the file descriptor 230 * table, so abort this process. 231 */ 232 PANIC("Cannot allocate memory for file descriptor table"); 233 } else { 234 /* 235 * Enter a loop to initialise the file descriptor 236 * table: 237 */ 238 for (i = 0; i < _thread_dtablesize; i++) { 239 /* Initialise the file descriptor table: */ 240 _thread_fd_table[i] = NULL; 241 } 242 } 243 } 244 245#ifdef GCC_2_8_MADE_THREAD_AWARE 246 /* Create the thread-specific data for the exception linked list. */ 247 if(pthread_key_create(&except_head_key, NULL) != 0) 248 PANIC("Failed to create thread specific execption head"); 249 250 /* Setup the gcc exception handler per thread. */ 251 __set_dynamic_handler_allocator( dynamic_allocator_handler_fn ); 252#endif /* GCC_2_8_MADE_THREAD_AWARE */ 253 254 /* Initialise the garbage collector mutex and condition variable. */ 255 if (pthread_mutex_init(&_gc_mutex,NULL) != 0 || 256 pthread_cond_init(&_gc_cond,NULL) != 0) 257 PANIC("Failed to initialise garbage collector mutex or condvar"); 258 259 return; 260} 261 262/* 263 * Special start up code for NetBSD/Alpha 264 */ 265#if defined(__NetBSD__) && defined(__alpha__) 266int 267main(int argc, char *argv[], char *env); 268 269int 270_thread_main(int argc, char *argv[], char *env) 271{ 272 _thread_init(); 273 return (main(argc, argv, env)); 274} 275#endif 276#else 277/* 278 * A stub for non-threaded programs. 279 */ 280void 281_thread_init(void) 282{ 283} 284#endif 285