thr_create.c revision 92730
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 AUTHOR 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 * $FreeBSD: head/lib/libkse/thread/thr_create.c 92730 2002-03-19 22:58:56Z deischen $ 33 */ 34#include <errno.h> 35#include <stdlib.h> 36#include <string.h> 37#include <fcntl.h> 38#include <unistd.h> 39#include <stddef.h> 40#include <sys/time.h> 41#include <machine/reg.h> 42#include <pthread.h> 43#include "pthread_private.h" 44#include "libc_private.h" 45 46static u_int64_t next_uniqueid = 1; 47 48#define OFF(f) offsetof(struct pthread, f) 49int _thread_next_offset = OFF(tle.tqe_next); 50int _thread_uniqueid_offset = OFF(uniqueid); 51int _thread_state_offset = OFF(state); 52int _thread_name_offset = OFF(name); 53int _thread_ctx_offset = OFF(ctx); 54#undef OFF 55 56int _thread_PS_RUNNING_value = PS_RUNNING; 57int _thread_PS_DEAD_value = PS_DEAD; 58 59__weak_reference(_pthread_create, pthread_create); 60 61int 62_pthread_create(pthread_t * thread, const pthread_attr_t * attr, 63 void *(*start_routine) (void *), void *arg) 64{ 65 struct pthread *curthread = _get_curthread(); 66 struct itimerval itimer; 67 int f_gc = 0; 68 int ret = 0; 69 pthread_t gc_thread; 70 pthread_t new_thread; 71 pthread_attr_t pattr; 72 void *stack; 73 74 /* 75 * Locking functions in libc are required when there are 76 * threads other than the initial thread. 77 */ 78 __isthreaded = 1; 79 80 /* Allocate memory for the thread structure: */ 81 if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { 82 /* Insufficient memory to create a thread: */ 83 ret = EAGAIN; 84 } else { 85 /* Check if default thread attributes are required: */ 86 if (attr == NULL || *attr == NULL) { 87 /* Use the default thread attributes: */ 88 pattr = &pthread_attr_default; 89 } else { 90 pattr = *attr; 91 } 92 /* Check if a stack was specified in the thread attributes: */ 93 if ((stack = pattr->stackaddr_attr) != NULL) { 94 } 95 /* Allocate a stack: */ 96 else { 97 stack = _thread_stack_alloc(pattr->stacksize_attr, 98 pattr->guardsize_attr); 99 if (stack == NULL) { 100 ret = EAGAIN; 101 free(new_thread); 102 } 103 } 104 105 /* Check for errors: */ 106 if (ret != 0) { 107 } else { 108 /* Initialise the thread structure: */ 109 memset(new_thread, 0, sizeof(struct pthread)); 110 new_thread->slice_usec = -1; 111 new_thread->stack = stack; 112 new_thread->start_routine = start_routine; 113 new_thread->arg = arg; 114 115 new_thread->cancelflags = PTHREAD_CANCEL_ENABLE | 116 PTHREAD_CANCEL_DEFERRED; 117 118 /* 119 * Write a magic value to the thread structure 120 * to help identify valid ones: 121 */ 122 new_thread->magic = PTHREAD_MAGIC; 123 124 /* Initialise the thread for signals: */ 125 new_thread->sigmask = curthread->sigmask; 126 new_thread->sigmask_seqno = 0; 127 128 /* Initialize the signal frame: */ 129 new_thread->curframe = NULL; 130 131 /* Initialise the jump buffer: */ 132 _setjmp(new_thread->ctx.jb); 133 134 /* 135 * Set up new stack frame so that it looks like it 136 * returned from a longjmp() to the beginning of 137 * _thread_start(). 138 */ 139 SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start); 140 141 /* The stack starts high and builds down: */ 142 SET_STACK_JB(new_thread->ctx.jb, 143 (long)new_thread->stack + pattr->stacksize_attr 144 - sizeof(double)); 145 146 /* Copy the thread attributes: */ 147 memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); 148 149 /* 150 * Check if this thread is to inherit the scheduling 151 * attributes from its parent: 152 */ 153 if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) { 154 /* Copy the scheduling attributes: */ 155 new_thread->base_priority = 156 curthread->base_priority & 157 ~PTHREAD_SIGNAL_PRIORITY; 158 new_thread->attr.prio = 159 curthread->base_priority & 160 ~PTHREAD_SIGNAL_PRIORITY; 161 new_thread->attr.sched_policy = 162 curthread->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 = 170 new_thread->attr.prio; 171 } 172 new_thread->active_priority = new_thread->base_priority; 173 new_thread->inherited_priority = 0; 174 175 /* Initialize joiner to NULL (no joiner): */ 176 new_thread->joiner = NULL; 177 178 /* Initialize the mutex queue: */ 179 TAILQ_INIT(&new_thread->mutexq); 180 181 /* Initialise hooks in the thread structure: */ 182 new_thread->specific = NULL; 183 new_thread->cleanup = NULL; 184 new_thread->flags = 0; 185 new_thread->poll_data.nfds = 0; 186 new_thread->poll_data.fds = NULL; 187 new_thread->continuation = NULL; 188 189 /* 190 * Defer signals to protect the scheduling queues 191 * from access by the signal handler: 192 */ 193 _thread_kern_sig_defer(); 194 195 /* 196 * Initialise the unique id which GDB uses to 197 * track threads. 198 */ 199 new_thread->uniqueid = next_uniqueid++; 200 201 /* 202 * Check if the garbage collector thread 203 * needs to be started. 204 */ 205 f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial); 206 207 /* Add the thread to the linked list of all threads: */ 208 TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle); 209 210 if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) 211 new_thread->state = PS_SUSPENDED; 212 else { 213 new_thread->state = PS_RUNNING; 214 PTHREAD_PRIOQ_INSERT_TAIL(new_thread); 215 } 216 217 /* 218 * Undefer and handle pending signals, yielding 219 * if necessary. 220 */ 221 _thread_kern_sig_undefer(); 222 223 /* Return a pointer to the thread structure: */ 224 (*thread) = new_thread; 225 226 if (f_gc != 0) { 227 /* Install the scheduling timer: */ 228 itimer.it_interval.tv_sec = 0; 229 itimer.it_interval.tv_usec = _clock_res_usec; 230 itimer.it_value = itimer.it_interval; 231 if (setitimer(_ITIMER_SCHED_TIMER, &itimer, 232 NULL) != 0) 233 PANIC("Cannot set interval timer"); 234 } 235 236 /* Schedule the new user thread: */ 237 _thread_kern_sched(NULL); 238 239 /* 240 * Start a garbage collector thread 241 * if necessary. 242 */ 243 if (f_gc && pthread_create(&gc_thread,NULL, 244 _thread_gc,NULL) != 0) 245 PANIC("Can't create gc thread"); 246 247 } 248 } 249 250 /* Return the status: */ 251 return (ret); 252} 253 254void 255_thread_start(void) 256{ 257 struct pthread *curthread = _get_curthread(); 258 259 /* We just left the scheduler via longjmp: */ 260 _thread_kern_in_sched = 0; 261 262 /* Run the current thread's start routine with argument: */ 263 pthread_exit(curthread->start_routine(curthread->arg)); 264 265 /* This point should never be reached. */ 266 PANIC("Thread has resumed after exit"); 267} 268