thr_create.c revision 40127
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 */ 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 46pthread_create(pthread_t * thread, const pthread_attr_t * attr, 47 void *(*start_routine) (void *), void *arg) 48{ 49 int f_gc = 0; 50 int i; 51 int ret = 0; 52 int status; 53 pthread_t gc_thread; 54 pthread_t new_thread; 55 pthread_attr_t pattr; 56 void *stack; 57 58 /* 59 * Locking functions in libc are required when there are 60 * threads other than the initial thread. 61 */ 62 __isthreaded = 1; 63 64 /* Allocate memory for the thread structure: */ 65 if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { 66 /* Insufficient memory to create a thread: */ 67 ret = EAGAIN; 68 } else { 69 /* Check if default thread attributes are required: */ 70 if (attr == NULL || *attr == NULL) { 71 /* Use the default thread attributes: */ 72 pattr = &pthread_attr_default; 73 } else { 74 pattr = *attr; 75 } 76 /* Check if a stack was specified in the thread attributes: */ 77 if ((stack = pattr->stackaddr_attr) != NULL) { 78 } 79 /* Allocate memory for the stack: */ 80 else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) { 81 /* Insufficient memory to create a thread: */ 82 ret = EAGAIN; 83 free(new_thread); 84 } 85 /* Check for errors: */ 86 if (ret != 0) { 87 } else { 88 /* Initialise the thread structure: */ 89 memset(new_thread, 0, sizeof(struct pthread)); 90 new_thread->slice_usec = -1; 91 new_thread->sig_saved = 0; 92 new_thread->stack = stack; 93 new_thread->start_routine = start_routine; 94 new_thread->arg = arg; 95 96 /* 97 * Write a magic value to the thread structure 98 * to help identify valid ones: 99 */ 100 new_thread->magic = PTHREAD_MAGIC; 101 102 if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) { 103 PTHREAD_NEW_STATE(new_thread,PS_SUSPENDED); 104 } else { 105 PTHREAD_NEW_STATE(new_thread,PS_RUNNING); 106 } 107 108 /* Initialise the thread for signals: */ 109 new_thread->sigmask = _thread_run->sigmask; 110 111 /* Initialise the jump buffer: */ 112 setjmp(new_thread->saved_jmp_buf); 113 114 /* 115 * Set up new stack frame so that it looks like it 116 * returned from a longjmp() to the beginning of 117 * _thread_start(). 118 */ 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 139 /* The stack starts high and builds down: */ 140#if defined(__FreeBSD__) 141#if defined(__alpha__) 142 new_thread->saved_jmp_buf[0]._jb[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 143#else 144 new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + pattr->stacksize_attr - sizeof(double)); 145#endif 146#elif defined(__NetBSD__) 147#if defined(__alpha__) 148 new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 149#else 150 new_thread->saved_jmp_buf[2] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 151#endif 152#else 153#error "Don't recognize this operating system!" 154#endif 155 156 /* Copy the thread attributes: */ 157 memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); 158 159 /* 160 * Check if this thread is to inherit the scheduling 161 * attributes from its parent: 162 */ 163 if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) { 164 /* Copy the scheduling attributes: */ 165 new_thread->pthread_priority = _thread_run->pthread_priority; 166 new_thread->attr.prio = _thread_run->pthread_priority; 167 new_thread->attr.schedparam_policy = _thread_run->attr.schedparam_policy; 168 } else { 169 /* 170 * Use just the thread priority, leaving the 171 * other scheduling attributes as their 172 * default values: 173 */ 174 new_thread->pthread_priority = new_thread->attr.prio; 175 } 176 177 /* Initialise the join queue for the new thread: */ 178 _thread_queue_init(&(new_thread->join_queue)); 179 180 /* Initialise hooks in the thread structure: */ 181 new_thread->specific_data = NULL; 182 new_thread->cleanup = NULL; 183 new_thread->queue = NULL; 184 new_thread->qnxt = NULL; 185 new_thread->flags = 0; 186 187 /* Lock the thread list: */ 188 _lock_thread_list(); 189 190 /* 191 * Check if the garbage collector thread 192 * needs to be started. 193 */ 194 f_gc = (_thread_link_list == _thread_initial); 195 196 /* Add the thread to the linked list of all threads: */ 197 new_thread->nxt = _thread_link_list; 198 _thread_link_list = new_thread; 199 200 /* Unlock the thread list: */ 201 _unlock_thread_list(); 202 203 /* Return a pointer to the thread structure: */ 204 (*thread) = new_thread; 205 206 /* Schedule the new user thread: */ 207 _thread_kern_sched(NULL); 208 209 /* 210 * Start a garbage collector thread 211 * if necessary. 212 */ 213 if (f_gc && pthread_create(&gc_thread,NULL, 214 _thread_gc,NULL) != 0) 215 PANIC("Can't create gc thread"); 216 } 217 } 218 219 /* Return the status: */ 220 return (ret); 221} 222 223void 224_thread_start(void) 225{ 226 /* We just left the scheduler via longjmp: */ 227 _thread_kern_in_sched = 0; 228 229 /* Run the current thread's start routine with argument: */ 230 pthread_exit(_thread_run->start_routine(_thread_run->arg)); 231 232 /* This point should never be reached. */ 233 PANIC("Thread has resumed after exit"); 234} 235#endif 236