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