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