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