thr_create.c revision 160321
1186545Srwatson/* 2186545Srwatson * Copyright (c) 2003 Daniel M. Eischen <deischen@gdeb.com> 3186545Srwatson * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 4186545Srwatson * All rights reserved. 5186545Srwatson * 6186545Srwatson * Redistribution and use in source and binary forms, with or without 7186545Srwatson * modification, are permitted provided that the following conditions 8186545Srwatson * are met: 9186545Srwatson * 1. Redistributions of source code must retain the above copyright 10186545Srwatson * notice unmodified, this list of conditions, and the following 11186545Srwatson * disclaimer. 12186545Srwatson * 2. Redistributions in binary form must reproduce the above copyright 13186545Srwatson * notice, this list of conditions and the following disclaimer in the 14186545Srwatson * documentation and/or other materials provided with the distribution. 15186545Srwatson * 16186545Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17186545Srwatson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18186545Srwatson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19186545Srwatson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20186545Srwatson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21186545Srwatson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22186545Srwatson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23186545Srwatson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24186545Srwatson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25186545Srwatson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26186545Srwatson * 27186545Srwatson * $FreeBSD: head/lib/libthr/thread/thr_create.c 160321 2006-07-13 06:35:43Z davidxu $ 28186545Srwatson */ 29186545Srwatson 30186545Srwatson#include "namespace.h" 31186545Srwatson#include <sys/types.h> 32186545Srwatson#include <sys/signalvar.h> 33186545Srwatson#include <errno.h> 34186545Srwatson#include <stdlib.h> 35186545Srwatson#include <string.h> 36186545Srwatson#include <stddef.h> 37186545Srwatson#include <pthread.h> 38186545Srwatson#include "un-namespace.h" 39186545Srwatson 40186545Srwatson#include "thr_private.h" 41186545Srwatson 42186545Srwatsonstatic int create_stack(struct pthread_attr *pattr); 43186545Srwatsonstatic void thread_start(struct pthread *curthread); 44186545Srwatson 45186545Srwatson__weak_reference(_pthread_create, pthread_create); 46186545Srwatson 47186545Srwatsonint 48186545Srwatson_pthread_create(pthread_t * thread, const pthread_attr_t * attr, 49186545Srwatson void *(*start_routine) (void *), void *arg) 50186545Srwatson{ 51186545Srwatson struct pthread *curthread, *new_thread; 52186545Srwatson struct thr_param param; 53186545Srwatson struct thr_sched_param sched_param; 54186545Srwatson int ret = 0, locked, create_suspended; 55186545Srwatson sigset_t set, oset; 56186545Srwatson 57186545Srwatson _thr_check_init(); 58186545Srwatson 59186545Srwatson /* 60186545Srwatson * Tell libc and others now they need lock to protect their data. 61186545Srwatson */ 62186545Srwatson if (_thr_isthreaded() == 0 && _thr_setthreaded(1)) 63186545Srwatson return (EAGAIN); 64186545Srwatson 65186545Srwatson curthread = _get_curthread(); 66186545Srwatson if ((new_thread = _thr_alloc(curthread)) == NULL) 67186545Srwatson return (EAGAIN); 68186545Srwatson 69186545Srwatson memset(¶m, 0, sizeof(param)); 70186545Srwatson 71186545Srwatson if (attr == NULL || *attr == NULL) 72186545Srwatson /* Use the default thread attributes: */ 73186545Srwatson new_thread->attr = _pthread_attr_default; 74186545Srwatson else 75186545Srwatson new_thread->attr = *(*attr); 76186545Srwatson if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) { 77186545Srwatson /* inherit scheduling contention scope */ 78186545Srwatson if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) 79186545Srwatson new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM; 80186545Srwatson else 81186545Srwatson new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM; 82186545Srwatson /* 83186545Srwatson * scheduling policy and scheduling parameters will be 84186545Srwatson * inherited in following code. 85186545Srwatson */ 86186545Srwatson } 87186545Srwatson 88186545Srwatson if (_thr_scope_system > 0) 89186545Srwatson new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM; 90186545Srwatson else if (_thr_scope_system < 0) 91186545Srwatson new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM; 92186545Srwatson 93186545Srwatson new_thread->tid = TID_TERMINATED; 94186545Srwatson 95186545Srwatson if (create_stack(&new_thread->attr) != 0) { 96186545Srwatson /* Insufficient memory to create a stack: */ 97186545Srwatson _thr_free(curthread, new_thread); 98186545Srwatson return (EAGAIN); 99186545Srwatson } 100186545Srwatson /* 101186545Srwatson * Write a magic value to the thread structure 102186545Srwatson * to help identify valid ones: 103186545Srwatson */ 104186545Srwatson new_thread->magic = THR_MAGIC; 105186545Srwatson new_thread->start_routine = start_routine; 106186545Srwatson new_thread->arg = arg; 107186545Srwatson new_thread->cancelflags = PTHREAD_CANCEL_ENABLE | 108186545Srwatson PTHREAD_CANCEL_DEFERRED; 109186545Srwatson /* Initialize the mutex queue: */ 110186545Srwatson TAILQ_INIT(&new_thread->mutexq); 111186545Srwatson 112186545Srwatson /* Initialise hooks in the thread structure: */ 113186545Srwatson if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) { 114186545Srwatson new_thread->flags = THR_FLAGS_NEED_SUSPEND; 115186545Srwatson create_suspended = 1; 116186545Srwatson } else { 117186545Srwatson create_suspended = 0; 118186545Srwatson } 119186545Srwatson 120186545Srwatson new_thread->state = PS_RUNNING; 121186545Srwatson 122186545Srwatson if (new_thread->attr.flags & PTHREAD_CREATE_DETACHED) 123186545Srwatson new_thread->tlflags |= TLFLAGS_DETACHED; 124186545Srwatson 125186545Srwatson /* Add the new thread. */ 126186545Srwatson new_thread->refcount = 1; 127186545Srwatson _thr_link(curthread, new_thread); 128186545Srwatson /* Return thread pointer eariler so that new thread can use it. */ 129186545Srwatson (*thread) = new_thread; 130186545Srwatson if (SHOULD_REPORT_EVENT(curthread, TD_CREATE)) { 131186545Srwatson THR_THREAD_LOCK(curthread, new_thread); 132186545Srwatson locked = 1; 133186545Srwatson } else 134186545Srwatson locked = 0; 135186545Srwatson param.start_func = (void (*)(void *)) thread_start; 136186545Srwatson param.arg = new_thread; 137186545Srwatson param.stack_base = new_thread->attr.stackaddr_attr; 138186545Srwatson param.stack_size = new_thread->attr.stacksize_attr; 139186545Srwatson param.tls_base = (char *)new_thread->tcb; 140186545Srwatson param.tls_size = sizeof(struct tcb); 141186545Srwatson param.child_tid = &new_thread->tid; 142186545Srwatson param.parent_tid = &new_thread->tid; 143186545Srwatson param.flags = 0; 144186545Srwatson if (new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) 145186545Srwatson param.flags |= THR_SYSTEM_SCOPE; 146186545Srwatson if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) 147186545Srwatson param.sched_param = NULL; 148186545Srwatson else { 149186545Srwatson param.sched_param = &sched_param; 150186545Srwatson param.sched_param_size = sizeof(sched_param); 151186545Srwatson sched_param.policy = new_thread->attr.sched_policy; 152186545Srwatson sched_param.param.sched_priority = new_thread->attr.prio; 153186545Srwatson } 154186545Srwatson 155186545Srwatson /* Schedule the new thread. */ 156186545Srwatson if (create_suspended) { 157186545Srwatson SIGFILLSET(set); 158186545Srwatson SIGDELSET(set, SIGTRAP); 159186545Srwatson __sys_sigprocmask(SIG_SETMASK, &set, &oset); 160186545Srwatson new_thread->sigmask = oset; 161186545Srwatson } 162186545Srwatson 163186545Srwatson ret = thr_new(¶m, sizeof(param)); 164186545Srwatson 165186545Srwatson if (ret != 0) { 166186545Srwatson ret = errno; 167186545Srwatson /* 168186545Srwatson * Translate EPROCLIM into well-known POSIX code EAGAIN. 169186545Srwatson */ 170186545Srwatson if (ret == EPROCLIM) 171186545Srwatson ret = EAGAIN; 172186545Srwatson } 173186545Srwatson 174186545Srwatson if (create_suspended) 175186545Srwatson __sys_sigprocmask(SIG_SETMASK, &oset, NULL); 176186545Srwatson 177186545Srwatson if (ret != 0) { 178186545Srwatson if (!locked) 179186545Srwatson THR_THREAD_LOCK(curthread, new_thread); 180186545Srwatson new_thread->state = PS_DEAD; 181186545Srwatson new_thread->tid = TID_TERMINATED; 182186545Srwatson if (new_thread->flags & THR_FLAGS_NEED_SUSPEND) { 183186545Srwatson new_thread->cycle++; 184186545Srwatson _thr_umtx_wake(&new_thread->cycle, INT_MAX); 185186545Srwatson } 186186545Srwatson THR_THREAD_UNLOCK(curthread, new_thread); 187186545Srwatson THREAD_LIST_LOCK(curthread); 188186545Srwatson _thread_active_threads--; 189186545Srwatson new_thread->tlflags |= TLFLAGS_DETACHED; 190186545Srwatson _thr_ref_delete_unlocked(curthread, new_thread); 191186545Srwatson THREAD_LIST_UNLOCK(curthread); 192186545Srwatson (*thread) = 0; 193186545Srwatson } else if (locked) { 194186545Srwatson _thr_report_creation(curthread, new_thread); 195186545Srwatson THR_THREAD_UNLOCK(curthread, new_thread); 196186545Srwatson } 197186545Srwatson return (ret); 198186545Srwatson} 199186545Srwatson 200186545Srwatsonstatic int 201186545Srwatsoncreate_stack(struct pthread_attr *pattr) 202186545Srwatson{ 203186545Srwatson int ret; 204186545Srwatson 205186545Srwatson /* Check if a stack was specified in the thread attributes: */ 206186545Srwatson if ((pattr->stackaddr_attr) != NULL) { 207186545Srwatson pattr->guardsize_attr = 0; 208186545Srwatson pattr->flags |= THR_STACK_USER; 209186545Srwatson ret = 0; 210186545Srwatson } 211186545Srwatson else 212186545Srwatson ret = _thr_stack_alloc(pattr); 213186545Srwatson return (ret); 214186545Srwatson} 215186545Srwatson 216186545Srwatsonstatic void 217186545Srwatsonthread_start(struct pthread *curthread) 218186545Srwatson{ 219186545Srwatson if (curthread->attr.suspend == THR_CREATE_SUSPENDED) { 220186545Srwatson sigset_t set = curthread->sigmask; 221186545Srwatson 222186545Srwatson _thr_ast(curthread); 223186545Srwatson 224186545Srwatson /* 225186545Srwatson * Parent thread have stored signal mask for us, 226186545Srwatson * we should restore it now. 227186545Srwatson */ 228186545Srwatson sigprocmask(SIG_SETMASK, &set, NULL); 229186545Srwatson } 230186545Srwatson 231186545Srwatson /* 232186545Srwatson * This is used as a serialization point to allow parent 233186545Srwatson * to report 'new thread' event to debugger before the thread 234186545Srwatson * does real work. 235186545Srwatson */ 236186545Srwatson THR_LOCK(curthread); 237186545Srwatson THR_UNLOCK(curthread); 238186545Srwatson 239186545Srwatson /* Run the current thread's start routine with argument: */ 240186545Srwatson _pthread_exit(curthread->start_routine(curthread->arg)); 241186545Srwatson 242186545Srwatson /* This point should never be reached. */ 243186545Srwatson PANIC("Thread has resumed after exit"); 244186545Srwatson} 245186545Srwatson