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