thr_create.c revision 35022
1/* 2 * Copyright (c) 1995 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#include <errno.h> 34#include <stdlib.h> 35#include <string.h> 36#include <fcntl.h> 37#include <unistd.h> 38#include <sys/time.h> 39#ifdef _THREAD_SAFE 40#include <machine/reg.h> 41#include <pthread.h> 42#include "pthread_private.h" 43 44int 45_thread_create(pthread_t * thread, const pthread_attr_t * attr, 46 void *(*start_routine) (void *), void *arg, pthread_t parent) 47{ 48 int i; 49 int ret = 0; 50 int status; 51 pthread_t new_thread; 52 pthread_attr_t pattr; 53 void *stack; 54 55 /* Block signals: */ 56 _thread_kern_sig_block(&status); 57 58 /* Allocate memory for the thread structure: */ 59 if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { 60 /* Insufficient memory to create a thread: */ 61 ret = EAGAIN; 62 } else { 63 /* Check if default thread attributes are required: */ 64 if (attr == NULL || *attr == NULL) { 65 /* Use the default thread attributes: */ 66 pattr = &pthread_attr_default; 67 } else { 68 pattr = *attr; 69 } 70 /* Check if a stack was specified in the thread attributes: */ 71 if ((stack = pattr->stackaddr_attr) != NULL) { 72 } 73 /* Allocate memory for the stack: */ 74 else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) { 75 /* Insufficient memory to create a thread: */ 76 ret = EAGAIN; 77 free(new_thread); 78 } 79 /* Check for errors: */ 80 if (ret != 0) { 81 } else { 82 /* Initialise the thread structure: */ 83 memset(new_thread, 0, sizeof(struct pthread)); 84 new_thread->slice_usec = -1; 85 new_thread->sig_saved = 0; 86 new_thread->stack = stack; 87 new_thread->start_routine = start_routine; 88 new_thread->arg = arg; 89 90 /* 91 * Write a magic value to the thread structure 92 * to help identify valid ones: 93 */ 94 new_thread->magic = PTHREAD_MAGIC; 95 96 if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) { 97 PTHREAD_NEW_STATE(new_thread,PS_SUSPENDED); 98 } else { 99 PTHREAD_NEW_STATE(new_thread,PS_RUNNING); 100 } 101 102 /* Initialise the thread for signals: */ 103 new_thread->sigmask = _thread_run->sigmask; 104 105 /* 106 * Enter a loop to initialise the signal handler 107 * array: 108 */ 109 for (i = 1; i < NSIG; i++) { 110 /* Default the signal handler: */ 111 sigfillset(&new_thread->act[i - 1].sa_mask); 112 new_thread->act[i - 1].sa_handler = _thread_run->act[i - 1].sa_handler; 113 new_thread->act[i - 1].sa_flags = _thread_run->act[i - 1].sa_flags; 114 } 115 116 /* Initialise the jump buffer: */ 117 _thread_sys_setjmp(new_thread->saved_jmp_buf); 118 119 /* 120 * Set up new stack frame so that it looks like it 121 * returned from a longjmp() to the beginning of 122 * _thread_start(). Check if this is a user thread: 123 */ 124 if (parent == NULL) { 125 /* Use the user start function: */ 126#if defined(__FreeBSD__) 127#if defined(__alpha__) 128 new_thread->saved_jmp_buf[0]._jb[2] = (long) _thread_start; 129 new_thread->saved_jmp_buf[0]._jb[4 + R_RA] = 0; 130 new_thread->saved_jmp_buf[0]._jb[4 + R_T12] = (long) _thread_start; 131#else 132 new_thread->saved_jmp_buf[0]._jb[0] = (long) _thread_start; 133#endif 134#elif defined(__NetBSD__) 135#if defined(__alpha__) 136 new_thread->saved_jmp_buf[2] = (long) _thread_start; 137 new_thread->saved_jmp_buf[4 + R_RA] = 0; 138 new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start; 139#else 140 new_thread->saved_jmp_buf[0] = (long) _thread_start; 141#endif 142#else 143#error "Don't recognize this operating system!" 144#endif 145 } else { 146 /* 147 * Use the (funny) signal handler start 148 * function: 149 */ 150#if defined(__FreeBSD__) 151#if defined(__alpha__) 152 new_thread->saved_jmp_buf[0]._jb[2] = (long) _thread_start_sig_handler; 153 new_thread->saved_jmp_buf[0]._jb[4 + R_RA] = 0; 154 new_thread->saved_jmp_buf[0]._jb[4 + R_T12] = (long) _thread_start_sig_handler; 155#else 156 new_thread->saved_jmp_buf[0]._jb[0] = (int) _thread_start_sig_handler; 157#endif 158#elif defined(__NetBSD__) 159#if defined(__alpha__) 160 new_thread->saved_jmp_buf[2] = (long) _thread_start_sig_handler; 161 new_thread->saved_jmp_buf[4 + R_RA] = 0; 162 new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start_sig_handler; 163#else 164 new_thread->saved_jmp_buf[0] = (long) _thread_start_sig_handler; 165#endif 166#else 167#error "Don't recognize this operating system!" 168#endif 169 } 170 171 /* The stack starts high and builds down: */ 172#if defined(__FreeBSD__) 173#if defined(__alpha__) 174 new_thread->saved_jmp_buf[0]._jb[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 175#else 176 new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + pattr->stacksize_attr - sizeof(double)); 177#endif 178#elif defined(__NetBSD__) 179#if defined(__alpha__) 180 new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 181#else 182 new_thread->saved_jmp_buf[2] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 183#endif 184#else 185#error "Don't recognize this operating system!" 186#endif 187 188 /* Copy the thread attributes: */ 189 memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); 190 191 /* 192 * Check if this thread is to inherit the scheduling 193 * attributes from its parent: 194 */ 195 if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) { 196 /* Copy the scheduling attributes: */ 197 new_thread->pthread_priority = _thread_run->pthread_priority; 198 new_thread->attr.prio = _thread_run->pthread_priority; 199 new_thread->attr.schedparam_policy = _thread_run->attr.schedparam_policy; 200 } else { 201 /* 202 * Use just the thread priority, leaving the 203 * other scheduling attributes as their 204 * default values: 205 */ 206 new_thread->pthread_priority = new_thread->attr.prio; 207 } 208 209 /* Initialise the join queue for the new thread: */ 210 _thread_queue_init(&(new_thread->join_queue)); 211 212 /* Initialise hooks in the thread structure: */ 213 new_thread->specific_data = NULL; 214 new_thread->cleanup = NULL; 215 new_thread->queue = NULL; 216 new_thread->qnxt = NULL; 217 new_thread->parent_thread = parent; 218 new_thread->flags = 0; 219 220 /* Add the thread to the linked list of all threads: */ 221 new_thread->nxt = _thread_link_list; 222 _thread_link_list = new_thread; 223 224 /* Return a pointer to the thread structure: */ 225 if(thread) 226 (*thread) = new_thread; 227 228 /* Check if a parent thread was specified: */ 229 if (parent != NULL) { 230 /* 231 * A parent thread was specified, so this is 232 * a signal handler thread which must now 233 * wait for the signal handler to complete: 234 */ 235 PTHREAD_NEW_STATE(parent,PS_SIGTHREAD); 236 } else { 237 /* Schedule the new user thread: */ 238 _thread_kern_sched(NULL); 239 } 240 } 241 } 242 243 /* Unblock signals: */ 244 _thread_kern_sig_unblock(status); 245 246 /* Return the status: */ 247 return (ret); 248} 249 250int 251pthread_create(pthread_t * thread, const pthread_attr_t * attr, 252 void *(*start_routine) (void *), void *arg) 253{ 254 int ret = 0; 255 256 /* 257 * Call the low level thread creation function which allows a parent 258 * thread to be specified: 259 */ 260 ret = _thread_create(thread, attr, start_routine, arg, NULL); 261 262 /* Return the status: */ 263 return (ret); 264} 265 266void 267_thread_start(void) 268{ 269 /* Run the current thread's start routine with argument: */ 270 pthread_exit(_thread_run->start_routine(_thread_run->arg)); 271 272 /* This point should never be reached. */ 273 PANIC("Thread has resumed after exit"); 274} 275 276void 277_thread_start_sig_handler(void) 278{ 279 int sig; 280 long arg; 281 void (*sig_routine) (int); 282 283 /* 284 * Cast the argument from 'void *' to a variable that is NO SMALLER 285 * than a pointer (otherwise gcc under NetBSD/Alpha will complain): 286 */ 287 arg = (long) _thread_run->arg; 288 289 /* Cast the argument as a signal number: */ 290 sig = (int) arg; 291 292 /* Cast a pointer to the signal handler function: */ 293 sig_routine = (void (*) (int)) _thread_run->start_routine; 294 295 /* Call the signal handler function: */ 296 (*sig_routine) (sig); 297 298 /* Exit the signal handler thread: */ 299 pthread_exit(&arg); 300 301 /* This point should never be reached. */ 302 PANIC("Signal handler thread has resumed after exit"); 303} 304#endif 305