thr_create.c revision 68516
1104640Simp/* 252506Simp * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 352506Simp * All rights reserved. 4139749Simp * 552506Simp * Redistribution and use in source and binary forms, with or without 652506Simp * modification, are permitted provided that the following conditions 752506Simp * are met: 852506Simp * 1. Redistributions of source code must retain the above copyright 952506Simp * notice, this list of conditions and the following disclaimer. 1052506Simp * 2. Redistributions in binary form must reproduce the above copyright 1152506Simp * notice, this list of conditions and the following disclaimer in the 1252506Simp * documentation and/or other materials provided with the distribution. 1352506Simp * 3. All advertising materials mentioning features or use of this software 1452506Simp * must display the following acknowledgement: 1552506Simp * This product includes software developed by John Birrell. 1652506Simp * 4. Neither the name of the author nor the names of any co-contributors 1752506Simp * may be used to endorse or promote products derived from this software 1852506Simp * without specific prior written permission. 1952506Simp * 2052506Simp * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 2152506Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2252506Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2352506Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2452506Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2552506Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2652506Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2752506Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2852506Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2952506Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3052506Simp * SUCH DAMAGE. 3152506Simp * 3252506Simp * $FreeBSD: head/lib/libkse/thread/thr_create.c 68516 2000-11-09 05:08:26Z deischen $ 3352506Simp */ 3452506Simp#include <errno.h> 3552506Simp#include <stdlib.h> 3652506Simp#include <string.h> 3752506Simp#include <fcntl.h> 3852506Simp#include <unistd.h> 3952506Simp#include <stddef.h> 4052506Simp#include <sys/time.h> 4152506Simp#include <sys/param.h> 4252506Simp#include <sys/mman.h> 4352506Simp#ifdef _THREAD_SAFE 4452506Simp#include <machine/reg.h> 4552506Simp#include <pthread.h> 4652506Simp#include "pthread_private.h" 4752506Simp#include "libc_private.h" 48120868Simp 4952506Simpstatic u_int64_t next_uniqueid = 1; 5059193Simp 5159193Simp#define OFF(f) offsetof(struct pthread, f) 5291786Simpint _thread_next_offset = OFF(tle.tqe_next); 5391786Simpint _thread_uniqueid_offset = OFF(uniqueid); 5459193Simpint _thread_state_offset = OFF(state); 5552506Simpint _thread_name_offset = OFF(name); 56119161Simpint _thread_ctxtype_offset = OFF(ctxtype); 57119161Simpint _thread_ctx_offset = OFF(ctx); 5852506Simp#undef OFF 5952506Simp 6055720Simpint _thread_PS_RUNNING_value = PS_RUNNING; 6152506Simpint _thread_PS_DEAD_value = PS_DEAD; 6252506Simpint _thread_CTX_JB_NOSIG_value = CTX_JB_NOSIG; 63128169Simpint _thread_CTX_JB_value = CTX_JB; 6452506Simpint _thread_CTX_SJB_value = CTX_SJB; 6552506Simpint _thread_CTX_UC_value = CTX_UC; 6652506Simp 6752506Simpint 6852506Simppthread_create(pthread_t * thread, const pthread_attr_t * attr, 6952506Simp void *(*start_routine) (void *), void *arg) 7052506Simp{ 7152506Simp struct itimerval itimer; 7252506Simp int f_gc = 0; 7352506Simp int ret = 0; 74147729Simp pthread_t gc_thread; 75147729Simp pthread_t new_thread; 7652506Simp pthread_attr_t pattr; 7752506Simp void *stack; 7855720Simp 7952506Simp /* 8052506Simp * Locking functions in libc are required when there are 8152506Simp * threads other than the initial thread. 82104640Simp */ 8352506Simp __isthreaded = 1; 8452506Simp 8552506Simp /* Allocate memory for the thread structure: */ 8652506Simp if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { 8752506Simp /* Insufficient memory to create a thread: */ 8852506Simp ret = EAGAIN; 8952506Simp } else { 9052506Simp /* Check if default thread attributes are required: */ 9186272Simp if (attr == NULL || *attr == NULL) { 9286272Simp /* Use the default thread attributes: */ 9352506Simp pattr = &pthread_attr_default; 9452506Simp } else { 9552506Simp pattr = *attr; 96128169Simp } 9758997Simp /* Check if a stack was specified in the thread attributes: */ 9852506Simp if ((stack = pattr->stackaddr_attr) != NULL) { 9952506Simp } 10052506Simp /* Allocate memory for a default-size stack: */ 10152506Simp else if (pattr->stacksize_attr == PTHREAD_STACK_DEFAULT) { 10252506Simp struct stack *spare_stack; 103147711Simp 10452506Simp /* Allocate or re-use a default-size stack. */ 10555720Simp 10655720Simp /* 10752506Simp * Use the garbage collector mutex for synchronization 10852506Simp * of the spare stack list. 10952506Simp */ 110112358Simp if (pthread_mutex_lock(&_gc_mutex) != 0) 11152506Simp PANIC("Cannot lock gc mutex"); 11252506Simp 113119161Simp if ((spare_stack = SLIST_FIRST(&_stackq)) != NULL) { 114119161Simp /* Use the spare stack. */ 115119161Simp SLIST_REMOVE_HEAD(&_stackq, qe); 11652506Simp 11752506Simp /* Unlock the garbage collector mutex. */ 11852506Simp if (pthread_mutex_unlock(&_gc_mutex) != 0) 11952506Simp PANIC("Cannot unlock gc mutex"); 12052506Simp 12152506Simp stack = sizeof(struct stack) 12252506Simp + (void *) spare_stack 12352506Simp - PTHREAD_STACK_DEFAULT; 12452506Simp } else { 12552506Simp /* Allocate a new stack. */ 126128169Simp stack = _next_stack + PTHREAD_STACK_GUARD; 127128169Simp 128128169Simp /* 129128169Simp * Even if stack allocation fails, we don't want 130128169Simp * to try to use this location again, so 131128169Simp * unconditionally decrement _next_stack. Under 13255720Simp * normal operating conditions, the most likely 133128169Simp * reason for an mmap() error is a stack 134128169Simp * overflow of the adjacent thread stack. 13555720Simp */ 13655720Simp _next_stack -= (PTHREAD_STACK_DEFAULT 13752506Simp + PTHREAD_STACK_GUARD); 13852506Simp 13959193Simp /* Unlock the garbage collector mutex. */ 14059193Simp if (pthread_mutex_unlock(&_gc_mutex) != 0) 14155720Simp PANIC("Cannot unlock gc mutex"); 14255720Simp 14359389Simp /* Stack: */ 14452506Simp if (mmap(stack, PTHREAD_STACK_DEFAULT, 145119060Simp PROT_READ | PROT_WRITE, MAP_STACK, 146119060Simp -1, 0) == MAP_FAILED) { 14755720Simp ret = EAGAIN; 14852506Simp free(new_thread); 14952506Simp } 15052506Simp } 15152506Simp } 15252506Simp /* 15352506Simp * The user wants a stack of a particular size. Lets hope they 15452506Simp * really know what they want, and simply malloc the stack. 15552506Simp */ 15652506Simp else if ((stack = (void *) malloc(pattr->stacksize_attr)) 15755720Simp == NULL) { 15852506Simp /* Insufficient memory to create a thread: */ 15952506Simp ret = EAGAIN; 16052506Simp free(new_thread); 161119060Simp } 162119060Simp 163119060Simp /* Check for errors: */ 164119060Simp if (ret != 0) { 165119060Simp } else { 166119060Simp /* Initialise the thread structure: */ 167119060Simp memset(new_thread, 0, sizeof(struct pthread)); 168119060Simp new_thread->slice_usec = -1; 169119060Simp new_thread->stack = stack; 170120868Simp new_thread->start_routine = start_routine; 171119060Simp new_thread->arg = arg; 172119060Simp 173119060Simp new_thread->cancelflags = PTHREAD_CANCEL_ENABLE | 174119060Simp PTHREAD_CANCEL_DEFERRED; 17552506Simp 17652506Simp /* 17752506Simp * Write a magic value to the thread structure 178120868Simp * to help identify valid ones: 179119161Simp */ 180119161Simp new_thread->magic = PTHREAD_MAGIC; 181119161Simp 182119161Simp /* Initialise the thread for signals: */ 183119161Simp new_thread->sigmask = _thread_run->sigmask; 184119161Simp new_thread->sigmask_seqno = 0; 185119161Simp 18652506Simp /* Initialize the signal frame: */ 18752506Simp new_thread->curframe = NULL; 188120868Simp 18952506Simp /* Initialise the jump buffer: */ 19052506Simp _setjmp(new_thread->ctx.jb); 19152506Simp 192147711Simp /* 19352506Simp * Set up new stack frame so that it looks like it 19452506Simp * returned from a longjmp() to the beginning of 19552506Simp * _thread_start(). 19652506Simp */ 19752506Simp SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start); 19852506Simp 19952506Simp /* The stack starts high and builds down: */ 20052506Simp SET_STACK_JB(new_thread->ctx.jb, 20152506Simp (long)new_thread->stack + pattr->stacksize_attr 20252506Simp - sizeof(double)); 203120868Simp 204120868Simp /* Initialize the rest of the frame: */ 20552506Simp new_thread->ctxtype = CTX_JB_NOSIG; 20652506Simp 20752506Simp /* Copy the thread attributes: */ 20852506Simp memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); 20952506Simp 21052506Simp /* 21152506Simp * Check if this thread is to inherit the scheduling 21252506Simp * attributes from its parent: 21352506Simp */ 214120868Simp if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) { 21552506Simp /* Copy the scheduling attributes: */ 21652506Simp new_thread->base_priority = 21752506Simp _thread_run->base_priority & 21852506Simp ~PTHREAD_SIGNAL_PRIORITY; 21952506Simp new_thread->attr.prio = 220120868Simp _thread_run->base_priority & 22152506Simp ~PTHREAD_SIGNAL_PRIORITY; 22252506Simp new_thread->attr.sched_policy = 22352506Simp _thread_run->attr.sched_policy; 224120868Simp } else { 22552506Simp /* 22652506Simp * Use just the thread priority, leaving the 22752506Simp * other scheduling attributes as their 22852506Simp * default values: 22952506Simp */ 23052506Simp new_thread->base_priority = 23152506Simp new_thread->attr.prio; 23252506Simp } 23352506Simp new_thread->active_priority = new_thread->base_priority; 23452506Simp new_thread->inherited_priority = 0; 23590896Simp 23652506Simp /* Initialise the join queue for the new thread: */ 23752506Simp TAILQ_INIT(&(new_thread->join_queue)); 23852506Simp 23952506Simp /* Initialize the mutex queue: */ 24052506Simp TAILQ_INIT(&new_thread->mutexq); 24152506Simp 24252506Simp /* Initialise hooks in the thread structure: */ 24352506Simp new_thread->specific_data = NULL; 24452506Simp new_thread->cleanup = NULL; 24552506Simp new_thread->flags = 0; 24652506Simp new_thread->poll_data.nfds = 0; 24752506Simp new_thread->poll_data.fds = NULL; 24852506Simp new_thread->continuation = NULL; 24952506Simp 25052506Simp /* 25152506Simp * Defer signals to protect the scheduling queues 252104640Simp * from access by the signal handler: 25352506Simp */ 25452506Simp _thread_kern_sig_defer(); 25552506Simp 25652506Simp /* 25752506Simp * Initialise the unique id which GDB uses to 25852506Simp * track threads. 25952506Simp */ 26052506Simp new_thread->uniqueid = next_uniqueid++; 26152506Simp 26252506Simp /* 26352506Simp * Check if the garbage collector thread 26452506Simp * needs to be started. 26552506Simp */ 26655720Simp f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial); 26755720Simp 26852506Simp /* Add the thread to the linked list of all threads: */ 26952506Simp TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle); 27052506Simp 27152506Simp if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) 27252506Simp new_thread->state = PS_SUSPENDED; 27352506Simp else { 27452506Simp new_thread->state = PS_RUNNING; 27552506Simp PTHREAD_PRIOQ_INSERT_TAIL(new_thread); 27652506Simp } 27752506Simp 27852506Simp /* 27952506Simp * Undefer and handle pending signals, yielding 280120868Simp * if necessary. 28152506Simp */ 28252506Simp _thread_kern_sig_undefer(); 28352506Simp 28452506Simp /* Return a pointer to the thread structure: */ 28552506Simp (*thread) = new_thread; 286104640Simp 287104640Simp if (f_gc != 0) { 288104640Simp /* Install the scheduling timer: */ 289104640Simp itimer.it_interval.tv_sec = 0; 290104640Simp itimer.it_interval.tv_usec = _clock_res_usec; 29152506Simp itimer.it_value = itimer.it_interval; 29252506Simp if (setitimer(_ITIMER_SCHED_TIMER, &itimer, 29352506Simp NULL) != 0) 29452506Simp PANIC("Cannot set interval timer"); 29552506Simp } 296104640Simp 29752506Simp /* Schedule the new user thread: */ 298104640Simp _thread_kern_sched(NULL); 299104640Simp 300104640Simp /* 301104640Simp * Start a garbage collector thread 302104640Simp * if necessary. 303104640Simp */ 304104640Simp if (f_gc && pthread_create(&gc_thread,NULL, 30552506Simp _thread_gc,NULL) != 0) 306104640Simp PANIC("Can't create gc thread"); 30752506Simp 308104640Simp } 309104640Simp } 310104640Simp 311104640Simp /* Return the status: */ 312104640Simp return (ret); 313104640Simp} 314104640Simp 315104640Simpvoid 316104640Simp_thread_start(void) 317104640Simp{ 318104640Simp /* We just left the scheduler via longjmp: */ 319104640Simp _thread_kern_in_sched = 0; 320104640Simp 321104640Simp /* Run the current thread's start routine with argument: */ 322104640Simp pthread_exit(_thread_run->start_routine(_thread_run->arg)); 323104640Simp 324104640Simp /* This point should never be reached. */ 325104640Simp PANIC("Thread has resumed after exit"); 326104640Simp} 327104640Simp#endif 328104640Simp