thr_create.c revision 48046
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$ 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 _THREAD_SAFE 41#include <machine/reg.h> 42#include <pthread.h> 43#include "pthread_private.h" 44#include "libc_private.h" 45 46int 47pthread_create(pthread_t * thread, const pthread_attr_t * attr, 48 void *(*start_routine) (void *), void *arg) 49{ 50 int f_gc = 0; 51 int i; 52 int ret = 0; 53 int status; 54 pthread_t gc_thread; 55 pthread_t new_thread; 56 pthread_attr_t pattr; 57 void *stack; 58 59 /* 60 * Locking functions in libc are required when there are 61 * threads other than the initial thread. 62 */ 63 __isthreaded = 1; 64 65 /* Allocate memory for the thread structure: */ 66 if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { 67 /* Insufficient memory to create a thread: */ 68 ret = EAGAIN; 69 } else { 70 /* Check if default thread attributes are required: */ 71 if (attr == NULL || *attr == NULL) { 72 /* Use the default thread attributes: */ 73 pattr = &pthread_attr_default; 74 } else { 75 pattr = *attr; 76 } 77 /* Check if a stack was specified in the thread attributes: */ 78 if ((stack = pattr->stackaddr_attr) != NULL) { 79 } 80 /* Allocate memory for the stack: */ 81 else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) { 82 /* Insufficient memory to create a thread: */ 83 ret = EAGAIN; 84 free(new_thread); 85 } 86 /* Check for errors: */ 87 if (ret != 0) { 88 } else { 89 /* Initialise the thread structure: */ 90 memset(new_thread, 0, sizeof(struct pthread)); 91 new_thread->slice_usec = -1; 92 new_thread->sig_saved = 0; 93 new_thread->stack = stack; 94 new_thread->start_routine = start_routine; 95 new_thread->arg = arg; 96 97 /* 98 * Write a magic value to the thread structure 99 * to help identify valid ones: 100 */ 101 new_thread->magic = PTHREAD_MAGIC; 102 103 /* Initialise the thread for signals: */ 104 new_thread->sigmask = _thread_run->sigmask; 105 106 /* Initialise the jump buffer: */ 107 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(). 113 */ 114#if defined(__FreeBSD__) 115#if defined(__alpha__) 116 new_thread->saved_jmp_buf[0]._jb[2] = (long) _thread_start; 117 new_thread->saved_jmp_buf[0]._jb[4 + R_RA] = 0; 118 new_thread->saved_jmp_buf[0]._jb[4 + R_T12] = (long) _thread_start; 119#else 120 new_thread->saved_jmp_buf[0]._jb[0] = (long) _thread_start; 121#endif 122#elif defined(__NetBSD__) 123#if defined(__alpha__) 124 new_thread->saved_jmp_buf[2] = (long) _thread_start; 125 new_thread->saved_jmp_buf[4 + R_RA] = 0; 126 new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start; 127#else 128 new_thread->saved_jmp_buf[0] = (long) _thread_start; 129#endif 130#else 131#error "Don't recognize this operating system!" 132#endif 133 134 /* The stack starts high and builds down: */ 135#if defined(__FreeBSD__) 136#if defined(__alpha__) 137 new_thread->saved_jmp_buf[0]._jb[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 138#else 139 new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + pattr->stacksize_attr - sizeof(double)); 140#endif 141#elif defined(__NetBSD__) 142#if defined(__alpha__) 143 new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 144#else 145 new_thread->saved_jmp_buf[2] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 146#endif 147#else 148#error "Don't recognize this operating system!" 149#endif 150 151 /* Copy the thread attributes: */ 152 memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); 153 154 /* 155 * Check if this thread is to inherit the scheduling 156 * attributes from its parent: 157 */ 158 if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) { 159 /* Copy the scheduling attributes: */ 160 new_thread->base_priority = _thread_run->base_priority; 161 new_thread->attr.prio = _thread_run->base_priority; 162 new_thread->attr.sched_policy = _thread_run->attr.sched_policy; 163 } else { 164 /* 165 * Use just the thread priority, leaving the 166 * other scheduling attributes as their 167 * default values: 168 */ 169 new_thread->base_priority = new_thread->attr.prio; 170 } 171 new_thread->active_priority = new_thread->base_priority; 172 new_thread->inherited_priority = 0; 173 174 /* Initialise the join queue for the new thread: */ 175 TAILQ_INIT(&(new_thread->join_queue)); 176 177 /* Initialize the mutex queue: */ 178 TAILQ_INIT(&new_thread->mutexq); 179 180 /* Initialise hooks in the thread structure: */ 181 new_thread->specific_data = NULL; 182 new_thread->cleanup = NULL; 183 new_thread->flags = 0; 184 new_thread->poll_data.nfds = 0; 185 new_thread->poll_data.fds = NULL; 186 187 /* 188 * Defer signals to protect the scheduling queues 189 * from access by the signal handler: 190 */ 191 _thread_kern_sig_defer(); 192 193 /* 194 * Check if the garbage collector thread 195 * needs to be started. 196 */ 197 f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial); 198 199 /* Add the thread to the linked list of all threads: */ 200 TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle); 201 202 if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) { 203 new_thread->state = PS_SUSPENDED; 204 PTHREAD_WAITQ_INSERT(new_thread); 205 } 206 else { 207 new_thread->state = PS_RUNNING; 208 PTHREAD_PRIOQ_INSERT_TAIL(new_thread); 209 } 210 211 /* 212 * Undefer and handle pending signals, yielding 213 * if necessary. 214 */ 215 _thread_kern_sig_undefer(); 216 217 /* Return a pointer to the thread structure: */ 218 (*thread) = new_thread; 219 220 /* Schedule the new user thread: */ 221 _thread_kern_sched(NULL); 222 223 /* 224 * Start a garbage collector thread 225 * if necessary. 226 */ 227 if (f_gc && pthread_create(&gc_thread,NULL, 228 _thread_gc,NULL) != 0) 229 PANIC("Can't create gc thread"); 230 } 231 } 232 233 /* Return the status: */ 234 return (ret); 235} 236 237void 238_thread_start(void) 239{ 240 /* We just left the scheduler via longjmp: */ 241 _thread_kern_in_sched = 0; 242 243 /* Run the current thread's start routine with argument: */ 244 pthread_exit(_thread_run->start_routine(_thread_run->arg)); 245 246 /* This point should never be reached. */ 247 PANIC("Thread has resumed after exit"); 248} 249#endif 250