thr_create.c revision 48569
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 * $Id: uthread_create.c,v 1.13 1999/06/20 08:28:14 jb Exp $ 33 */ 34#include <errno.h> 35#include <stdlib.h> 36#include <string.h> 37#include <fcntl.h> 38#include <unistd.h> 39#include <sys/time.h> 40#ifdef _PTHREAD_GSTACK 41#include <sys/types.h> 42#include <sys/mman.h> 43#endif 44#ifdef _THREAD_SAFE 45#include <machine/reg.h> 46#include <pthread.h> 47#include "pthread_private.h" 48#include "libc_private.h" 49 50int 51pthread_create(pthread_t * thread, const pthread_attr_t * attr, 52 void *(*start_routine) (void *), void *arg) 53{ 54 int f_gc = 0; 55 int i; 56 int ret = 0; 57 int status; 58 pthread_t gc_thread; 59 pthread_t new_thread; 60 pthread_attr_t pattr; 61 void *stack; 62 63 /* 64 * Locking functions in libc are required when there are 65 * threads other than the initial thread. 66 */ 67 __isthreaded = 1; 68 69 /* Allocate memory for the thread structure: */ 70 if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { 71 /* Insufficient memory to create a thread: */ 72 ret = EAGAIN; 73 } else { 74 /* Check if default thread attributes are required: */ 75 if (attr == NULL || *attr == NULL) { 76 /* Use the default thread attributes: */ 77 pattr = &pthread_attr_default; 78 } else { 79 pattr = *attr; 80 } 81 /* Check if a stack was specified in the thread attributes: */ 82 if ((stack = pattr->stackaddr_attr) != NULL) { 83 } 84#ifdef _PTHREAD_GSTACK 85 /* Allocate memory for a default-size stack: */ 86 else if (pattr->stacksize_attr == PTHREAD_STACK_DEFAULT) { 87 struct stack * spare_stack; 88 89 /* Allocate or re-use a default-size stack. */ 90 91 /* Use the garbage collector mutex for synchronization 92 * of the spare stack list. 93 * 94 * XXX This may not be ideal. */ 95 if (pthread_mutex_lock(&_gc_mutex) != 0) 96 PANIC("Cannot lock gc mutex"); 97 98 if (NULL != (spare_stack = SLIST_FIRST(&_stackq))) { 99 /* Use the spare stack. */ 100 SLIST_REMOVE_HEAD(&_stackq, qe); 101 stack = sizeof(struct stack) + (void *) spare_stack - PTHREAD_STACK_DEFAULT; 102 } else { 103 /* Allocate a new stack. */ 104 stack = _next_stack + PTHREAD_STACK_GUARD; 105 /* Even if stack allocation fails, we don't want to try to use this location again, so unconditionally 106 * decrement _next_stack. Under normal operating conditions, the most likely reason for an mmap() 107 * error is a stack overflow of the adjacent thread stack. */ 108 _next_stack -= (PTHREAD_STACK_DEFAULT + PTHREAD_STACK_GUARD); 109 110 /* Red zone: */ 111 if (MAP_FAILED == mmap(_next_stack, PTHREAD_STACK_GUARD, 0, MAP_ANON, -1, 0)) { 112 ret = EAGAIN; 113 free(new_thread); 114 } 115 /* Stack: */ 116 else if (MAP_FAILED == mmap(stack, PTHREAD_STACK_DEFAULT, PROT_READ | PROT_WRITE, MAP_STACK, -1, 0)) { 117 ret = EAGAIN; 118 munmap(_next_stack, PTHREAD_STACK_GUARD); 119 free(new_thread); 120 } 121 } 122 123 /* Unlock the garbage collector mutex. */ 124 if (pthread_mutex_unlock(&_gc_mutex) != 0) 125 PANIC("Cannot unlock gc mutex"); 126 } 127 /* The user wants a stack of a particular size. Lets hope they really know what they want, and simply malloc the 128 * stack. */ 129 else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) { 130 /* Insufficient memory to create a thread: */ 131 ret = EAGAIN; 132 free(new_thread); 133 } 134#else 135 /* Allocate memory for the stack: */ 136 else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) { 137 /* Insufficient memory to create a thread: */ 138 ret = EAGAIN; 139 free(new_thread); 140 } 141#endif 142 /* Check for errors: */ 143 if (ret != 0) { 144 } else { 145 /* Initialise the thread structure: */ 146 memset(new_thread, 0, sizeof(struct pthread)); 147 new_thread->slice_usec = -1; 148 new_thread->sig_saved = 0; 149 new_thread->stack = stack; 150 new_thread->start_routine = start_routine; 151 new_thread->arg = arg; 152 153 /* 154 * Write a magic value to the thread structure 155 * to help identify valid ones: 156 */ 157 new_thread->magic = PTHREAD_MAGIC; 158 159 /* Initialise the thread for signals: */ 160 new_thread->sigmask = _thread_run->sigmask; 161 162 /* Initialise the jump buffer: */ 163 setjmp(new_thread->saved_jmp_buf); 164 165 /* 166 * Set up new stack frame so that it looks like it 167 * returned from a longjmp() to the beginning of 168 * _thread_start(). 169 */ 170#if defined(__FreeBSD__) 171#if defined(__alpha__) 172 new_thread->saved_jmp_buf[0]._jb[2] = (long) _thread_start; 173 new_thread->saved_jmp_buf[0]._jb[4 + R_RA] = 0; 174 new_thread->saved_jmp_buf[0]._jb[4 + R_T12] = (long) _thread_start; 175#else 176 new_thread->saved_jmp_buf[0]._jb[0] = (long) _thread_start; 177#endif 178#elif defined(__NetBSD__) 179#if defined(__alpha__) 180 new_thread->saved_jmp_buf[2] = (long) _thread_start; 181 new_thread->saved_jmp_buf[4 + R_RA] = 0; 182 new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start; 183#else 184 new_thread->saved_jmp_buf[0] = (long) _thread_start; 185#endif 186#else 187#error "Don't recognize this operating system!" 188#endif 189 190 /* The stack starts high and builds down: */ 191#if defined(__FreeBSD__) 192#if defined(__alpha__) 193 new_thread->saved_jmp_buf[0]._jb[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 194#else 195 new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + pattr->stacksize_attr - sizeof(double)); 196#endif 197#elif defined(__NetBSD__) 198#if defined(__alpha__) 199 new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 200#else 201 new_thread->saved_jmp_buf[2] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 202#endif 203#else 204#error "Don't recognize this operating system!" 205#endif 206 207 /* Copy the thread attributes: */ 208 memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); 209 210 /* 211 * Check if this thread is to inherit the scheduling 212 * attributes from its parent: 213 */ 214 if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) { 215 /* Copy the scheduling attributes: */ 216 new_thread->base_priority = _thread_run->base_priority; 217 new_thread->attr.prio = _thread_run->base_priority; 218 new_thread->attr.sched_policy = _thread_run->attr.sched_policy; 219 } else { 220 /* 221 * Use just the thread priority, leaving the 222 * other scheduling attributes as their 223 * default values: 224 */ 225 new_thread->base_priority = new_thread->attr.prio; 226 } 227 new_thread->active_priority = new_thread->base_priority; 228 new_thread->inherited_priority = 0; 229 230 /* Initialise the join queue for the new thread: */ 231 TAILQ_INIT(&(new_thread->join_queue)); 232 233 /* Initialize the mutex queue: */ 234 TAILQ_INIT(&new_thread->mutexq); 235 236 /* Initialise hooks in the thread structure: */ 237 new_thread->specific_data = NULL; 238 new_thread->cleanup = NULL; 239 new_thread->flags = 0; 240 new_thread->poll_data.nfds = 0; 241 new_thread->poll_data.fds = NULL; 242 243 /* 244 * Defer signals to protect the scheduling queues 245 * from access by the signal handler: 246 */ 247 _thread_kern_sig_defer(); 248 249 /* 250 * Check if the garbage collector thread 251 * needs to be started. 252 */ 253 f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial); 254 255 /* Add the thread to the linked list of all threads: */ 256 TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle); 257 258 if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) { 259 new_thread->state = PS_SUSPENDED; 260 PTHREAD_WAITQ_INSERT(new_thread); 261 } 262 else { 263 new_thread->state = PS_RUNNING; 264 PTHREAD_PRIOQ_INSERT_TAIL(new_thread); 265 } 266 267 /* 268 * Undefer and handle pending signals, yielding 269 * if necessary. 270 */ 271 _thread_kern_sig_undefer(); 272 273 /* Return a pointer to the thread structure: */ 274 (*thread) = new_thread; 275 276 /* Schedule the new user thread: */ 277 _thread_kern_sched(NULL); 278 279 /* 280 * Start a garbage collector thread 281 * if necessary. 282 */ 283 if (f_gc && pthread_create(&gc_thread,NULL, 284 _thread_gc,NULL) != 0) 285 PANIC("Can't create gc thread"); 286 } 287 } 288 289 /* Return the status: */ 290 return (ret); 291} 292 293void 294_thread_start(void) 295{ 296 /* We just left the scheduler via longjmp: */ 297 _thread_kern_in_sched = 0; 298 299 /* Run the current thread's start routine with argument: */ 300 pthread_exit(_thread_run->start_routine(_thread_run->arg)); 301 302 /* This point should never be reached. */ 303 PANIC("Thread has resumed after exit"); 304} 305#endif 306