thr_create.c revision 71581
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 71581 2001-01-24 13:03:38Z 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 <sys/param.h> 42#include <sys/mman.h> 43#include <machine/reg.h> 44#include <pthread.h> 45#include "pthread_private.h" 46#include "libc_private.h" 47 48static u_int64_t next_uniqueid = 1; 49 50#define OFF(f) offsetof(struct pthread, f) 51int _thread_next_offset = OFF(tle.tqe_next); 52int _thread_uniqueid_offset = OFF(uniqueid); 53int _thread_state_offset = OFF(state); 54int _thread_name_offset = OFF(name); 55int _thread_ctxtype_offset = OFF(ctxtype); 56int _thread_ctx_offset = OFF(ctx); 57#undef OFF 58 59int _thread_PS_RUNNING_value = PS_RUNNING; 60int _thread_PS_DEAD_value = PS_DEAD; 61int _thread_CTX_JB_NOSIG_value = CTX_JB_NOSIG; 62int _thread_CTX_JB_value = CTX_JB; 63int _thread_CTX_SJB_value = CTX_SJB; 64int _thread_CTX_UC_value = CTX_UC; 65 66#pragma weak pthread_create=_pthread_create 67 68int 69_pthread_create(pthread_t * thread, const pthread_attr_t * attr, 70 void *(*start_routine) (void *), void *arg) 71{ 72 struct pthread *curthread = _get_curthread(); 73 struct itimerval itimer; 74 int f_gc = 0; 75 int ret = 0; 76 pthread_t gc_thread; 77 pthread_t new_thread; 78 pthread_attr_t pattr; 79 void *stack; 80 81 /* 82 * Locking functions in libc are required when there are 83 * threads other than the initial thread. 84 */ 85 __isthreaded = 1; 86 87 /* Allocate memory for the thread structure: */ 88 if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { 89 /* Insufficient memory to create a thread: */ 90 ret = EAGAIN; 91 } else { 92 /* Check if default thread attributes are required: */ 93 if (attr == NULL || *attr == NULL) { 94 /* Use the default thread attributes: */ 95 pattr = &pthread_attr_default; 96 } else { 97 pattr = *attr; 98 } 99 /* Check if a stack was specified in the thread attributes: */ 100 if ((stack = pattr->stackaddr_attr) != NULL) { 101 } 102 /* Allocate memory for a default-size stack: */ 103 else if (pattr->stacksize_attr == PTHREAD_STACK_DEFAULT) { 104 struct stack *spare_stack; 105 106 /* Allocate or re-use a default-size stack. */ 107 108 /* 109 * Use the garbage collector mutex for synchronization 110 * of the spare stack list. 111 */ 112 if (pthread_mutex_lock(&_gc_mutex) != 0) 113 PANIC("Cannot lock gc mutex"); 114 115 if ((spare_stack = SLIST_FIRST(&_stackq)) != NULL) { 116 /* Use the spare stack. */ 117 SLIST_REMOVE_HEAD(&_stackq, qe); 118 119 /* Unlock the garbage collector mutex. */ 120 if (pthread_mutex_unlock(&_gc_mutex) != 0) 121 PANIC("Cannot unlock gc mutex"); 122 123 stack = sizeof(struct stack) 124 + (void *) spare_stack 125 - PTHREAD_STACK_DEFAULT; 126 } else { 127 /* Allocate a new stack. */ 128 stack = _next_stack + PTHREAD_STACK_GUARD; 129 130 /* 131 * Even if stack allocation fails, we don't want 132 * to try to use this location again, so 133 * unconditionally decrement _next_stack. Under 134 * normal operating conditions, the most likely 135 * reason for an mmap() error is a stack 136 * overflow of the adjacent thread stack. 137 */ 138 _next_stack -= (PTHREAD_STACK_DEFAULT 139 + PTHREAD_STACK_GUARD); 140 141 /* Unlock the garbage collector mutex. */ 142 if (pthread_mutex_unlock(&_gc_mutex) != 0) 143 PANIC("Cannot unlock gc mutex"); 144 145 /* Stack: */ 146 if (mmap(stack, PTHREAD_STACK_DEFAULT, 147 PROT_READ | PROT_WRITE, MAP_STACK, 148 -1, 0) == MAP_FAILED) { 149 ret = EAGAIN; 150 free(new_thread); 151 } 152 } 153 } 154 /* 155 * The user wants a stack of a particular size. Lets hope they 156 * really know what they want, and simply malloc the stack. 157 */ 158 else if ((stack = (void *) malloc(pattr->stacksize_attr)) 159 == NULL) { 160 /* Insufficient memory to create a thread: */ 161 ret = EAGAIN; 162 free(new_thread); 163 } 164 165 /* Check for errors: */ 166 if (ret != 0) { 167 } else { 168 /* Initialise the thread structure: */ 169 memset(new_thread, 0, sizeof(struct pthread)); 170 new_thread->slice_usec = -1; 171 new_thread->stack = stack; 172 new_thread->start_routine = start_routine; 173 new_thread->arg = arg; 174 175 new_thread->cancelflags = PTHREAD_CANCEL_ENABLE | 176 PTHREAD_CANCEL_DEFERRED; 177 178 /* 179 * Write a magic value to the thread structure 180 * to help identify valid ones: 181 */ 182 new_thread->magic = PTHREAD_MAGIC; 183 184 /* Initialise the thread for signals: */ 185 new_thread->sigmask = curthread->sigmask; 186 new_thread->sigmask_seqno = 0; 187 188 /* Initialize the signal frame: */ 189 new_thread->curframe = NULL; 190 191 /* Initialise the jump buffer: */ 192 _setjmp(new_thread->ctx.jb); 193 194 /* 195 * Set up new stack frame so that it looks like it 196 * returned from a longjmp() to the beginning of 197 * _thread_start(). 198 */ 199 SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start); 200 201 /* The stack starts high and builds down: */ 202 SET_STACK_JB(new_thread->ctx.jb, 203 (long)new_thread->stack + pattr->stacksize_attr 204 - sizeof(double)); 205 206 /* Initialize the rest of the frame: */ 207 new_thread->ctxtype = CTX_JB_NOSIG; 208 209 /* Copy the thread attributes: */ 210 memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); 211 212 /* 213 * Check if this thread is to inherit the scheduling 214 * attributes from its parent: 215 */ 216 if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) { 217 /* Copy the scheduling attributes: */ 218 new_thread->base_priority = 219 curthread->base_priority & 220 ~PTHREAD_SIGNAL_PRIORITY; 221 new_thread->attr.prio = 222 curthread->base_priority & 223 ~PTHREAD_SIGNAL_PRIORITY; 224 new_thread->attr.sched_policy = 225 curthread->attr.sched_policy; 226 } else { 227 /* 228 * Use just the thread priority, leaving the 229 * other scheduling attributes as their 230 * default values: 231 */ 232 new_thread->base_priority = 233 new_thread->attr.prio; 234 } 235 new_thread->active_priority = new_thread->base_priority; 236 new_thread->inherited_priority = 0; 237 238 /* Initialise the join queue for the new thread: */ 239 TAILQ_INIT(&(new_thread->join_queue)); 240 241 /* Initialize the mutex queue: */ 242 TAILQ_INIT(&new_thread->mutexq); 243 244 /* Initialise hooks in the thread structure: */ 245 new_thread->specific_data = NULL; 246 new_thread->cleanup = NULL; 247 new_thread->flags = 0; 248 new_thread->poll_data.nfds = 0; 249 new_thread->poll_data.fds = NULL; 250 new_thread->continuation = NULL; 251 252 /* 253 * Defer signals to protect the scheduling queues 254 * from access by the signal handler: 255 */ 256 _thread_kern_sig_defer(); 257 258 /* 259 * Initialise the unique id which GDB uses to 260 * track threads. 261 */ 262 new_thread->uniqueid = next_uniqueid++; 263 264 /* 265 * Check if the garbage collector thread 266 * needs to be started. 267 */ 268 f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial); 269 270 /* Add the thread to the linked list of all threads: */ 271 TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle); 272 273 if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) 274 new_thread->state = PS_SUSPENDED; 275 else { 276 new_thread->state = PS_RUNNING; 277 PTHREAD_PRIOQ_INSERT_TAIL(new_thread); 278 } 279 280 /* 281 * Undefer and handle pending signals, yielding 282 * if necessary. 283 */ 284 _thread_kern_sig_undefer(); 285 286 /* Return a pointer to the thread structure: */ 287 (*thread) = new_thread; 288 289 if (f_gc != 0) { 290 /* Install the scheduling timer: */ 291 itimer.it_interval.tv_sec = 0; 292 itimer.it_interval.tv_usec = _clock_res_usec; 293 itimer.it_value = itimer.it_interval; 294 if (setitimer(_ITIMER_SCHED_TIMER, &itimer, 295 NULL) != 0) 296 PANIC("Cannot set interval timer"); 297 } 298 299 /* Schedule the new user thread: */ 300 _thread_kern_sched(NULL); 301 302 /* 303 * Start a garbage collector thread 304 * if necessary. 305 */ 306 if (f_gc && pthread_create(&gc_thread,NULL, 307 _thread_gc,NULL) != 0) 308 PANIC("Can't create gc thread"); 309 310 } 311 } 312 313 /* Return the status: */ 314 return (ret); 315} 316 317void 318_thread_start(void) 319{ 320 struct pthread *curthread = _get_curthread(); 321 322 /* We just left the scheduler via longjmp: */ 323 _thread_kern_in_sched = 0; 324 325 /* Run the current thread's start routine with argument: */ 326 pthread_exit(curthread->start_routine(curthread->arg)); 327 328 /* This point should never be reached. */ 329 PANIC("Thread has resumed after exit"); 330} 331