1112918Sjeff/* 2144518Sdavidxu * Copyright (c) 2003 Daniel M. Eischen <deischen@gdeb.com> 3153496Sdavidxu * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 4112918Sjeff * All rights reserved. 5112918Sjeff * 6112918Sjeff * Redistribution and use in source and binary forms, with or without 7112918Sjeff * modification, are permitted provided that the following conditions 8112918Sjeff * are met: 9112918Sjeff * 1. Redistributions of source code must retain the above copyright 10153496Sdavidxu * notice unmodified, this list of conditions, and the following 11153496Sdavidxu * disclaimer. 12112918Sjeff * 2. Redistributions in binary form must reproduce the above copyright 13112918Sjeff * notice, this list of conditions and the following disclaimer in the 14112918Sjeff * documentation and/or other materials provided with the distribution. 15112918Sjeff * 16153496Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17153496Sdavidxu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18153496Sdavidxu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19153496Sdavidxu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20153496Sdavidxu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21153496Sdavidxu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22153496Sdavidxu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23153496Sdavidxu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24153496Sdavidxu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25153496Sdavidxu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26112918Sjeff * 27112918Sjeff * $FreeBSD$ 28112918Sjeff */ 29144518Sdavidxu 30157457Sdavidxu#include "namespace.h" 31149691Sstefanf#include <sys/types.h> 32176860Sdavidxu#include <sys/rtprio.h> 33149691Sstefanf#include <sys/signalvar.h> 34112918Sjeff#include <errno.h> 35217191Skib#include <link.h> 36112918Sjeff#include <stdlib.h> 37112918Sjeff#include <string.h> 38112918Sjeff#include <stddef.h> 39112918Sjeff#include <pthread.h> 40176781Sdavidxu#include <pthread_np.h> 41157457Sdavidxu#include "un-namespace.h" 42144518Sdavidxu 43112918Sjeff#include "thr_private.h" 44112918Sjeff 45144518Sdavidxustatic int create_stack(struct pthread_attr *pattr); 46144518Sdavidxustatic void thread_start(struct pthread *curthread); 47112918Sjeff 48112918Sjeff__weak_reference(_pthread_create, pthread_create); 49112918Sjeff 50112918Sjeffint 51112918Sjeff_pthread_create(pthread_t * thread, const pthread_attr_t * attr, 52112918Sjeff void *(*start_routine) (void *), void *arg) 53112918Sjeff{ 54144518Sdavidxu struct pthread *curthread, *new_thread; 55145436Sdavidxu struct thr_param param; 56162499Sdavidxu struct sched_param sched_param; 57176860Sdavidxu struct rtprio rtp; 58154055Sdavidxu int ret = 0, locked, create_suspended; 59154055Sdavidxu sigset_t set, oset; 60178446Sdelphij cpuset_t *cpusetp = NULL; 61176817Sdavidxu int cpusetsize = 0; 62217191Skib int old_stack_prot; 63112918Sjeff 64144518Sdavidxu _thr_check_init(); 65144518Sdavidxu 66112918Sjeff /* 67144518Sdavidxu * Tell libc and others now they need lock to protect their data. 68112918Sjeff */ 69144518Sdavidxu if (_thr_isthreaded() == 0 && _thr_setthreaded(1)) 70144518Sdavidxu return (EAGAIN); 71112918Sjeff 72144518Sdavidxu curthread = _get_curthread(); 73144518Sdavidxu if ((new_thread = _thr_alloc(curthread)) == NULL) 74112918Sjeff return (EAGAIN); 75112918Sjeff 76145436Sdavidxu memset(¶m, 0, sizeof(param)); 77145436Sdavidxu 78144518Sdavidxu if (attr == NULL || *attr == NULL) 79144518Sdavidxu /* Use the default thread attributes: */ 80144518Sdavidxu new_thread->attr = _pthread_attr_default; 81176781Sdavidxu else { 82144518Sdavidxu new_thread->attr = *(*attr); 83178446Sdelphij cpusetp = new_thread->attr.cpuset; 84176817Sdavidxu cpusetsize = new_thread->attr.cpusetsize; 85176781Sdavidxu new_thread->attr.cpuset = NULL; 86176781Sdavidxu new_thread->attr.cpusetsize = 0; 87176781Sdavidxu } 88144518Sdavidxu if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) { 89144518Sdavidxu /* inherit scheduling contention scope */ 90144518Sdavidxu if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) 91144518Sdavidxu new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM; 92144518Sdavidxu else 93144518Sdavidxu new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM; 94160331Sdavidxu 95160331Sdavidxu new_thread->attr.prio = curthread->attr.prio; 96160331Sdavidxu new_thread->attr.sched_policy = curthread->attr.sched_policy; 97112918Sjeff } 98112918Sjeff 99144921Sdavidxu new_thread->tid = TID_TERMINATED; 100144921Sdavidxu 101217191Skib old_stack_prot = _rtld_get_stack_prot(); 102144518Sdavidxu if (create_stack(&new_thread->attr) != 0) { 103144518Sdavidxu /* Insufficient memory to create a stack: */ 104144518Sdavidxu _thr_free(curthread, new_thread); 105144518Sdavidxu return (EAGAIN); 106144518Sdavidxu } 107144518Sdavidxu /* 108144518Sdavidxu * Write a magic value to the thread structure 109144518Sdavidxu * to help identify valid ones: 110144518Sdavidxu */ 111144518Sdavidxu new_thread->magic = THR_MAGIC; 112112918Sjeff new_thread->start_routine = start_routine; 113112918Sjeff new_thread->arg = arg; 114164583Sdavidxu new_thread->cancel_enable = 1; 115164583Sdavidxu new_thread->cancel_async = 0; 116144518Sdavidxu /* Initialize the mutex queue: */ 117144518Sdavidxu TAILQ_INIT(&new_thread->mutexq); 118161681Sdavidxu TAILQ_INIT(&new_thread->pp_mutexq); 119115306Smtm 120144518Sdavidxu /* Initialise hooks in the thread structure: */ 121154055Sdavidxu if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) { 122151199Sdavidxu new_thread->flags = THR_FLAGS_NEED_SUSPEND; 123154055Sdavidxu create_suspended = 1; 124154055Sdavidxu } else { 125154055Sdavidxu create_suspended = 0; 126154055Sdavidxu } 127154055Sdavidxu 128144518Sdavidxu new_thread->state = PS_RUNNING; 129145436Sdavidxu 130154055Sdavidxu if (new_thread->attr.flags & PTHREAD_CREATE_DETACHED) 131212536Sdavidxu new_thread->flags |= THR_FLAGS_DETACHED; 132154055Sdavidxu 133144518Sdavidxu /* Add the new thread. */ 134154055Sdavidxu new_thread->refcount = 1; 135144518Sdavidxu _thr_link(curthread, new_thread); 136217191Skib 137217191Skib /* 138217191Skib * Handle the race between __pthread_map_stacks_exec and 139217191Skib * thread linkage. 140217191Skib */ 141217191Skib if (old_stack_prot != _rtld_get_stack_prot()) 142217191Skib _thr_stack_fix_protection(new_thread); 143217191Skib 144144518Sdavidxu /* Return thread pointer eariler so that new thread can use it. */ 145144518Sdavidxu (*thread) = new_thread; 146178446Sdelphij if (SHOULD_REPORT_EVENT(curthread, TD_CREATE) || cpusetp != NULL) { 147144921Sdavidxu THR_THREAD_LOCK(curthread, new_thread); 148144921Sdavidxu locked = 1; 149144921Sdavidxu } else 150144921Sdavidxu locked = 0; 151145436Sdavidxu param.start_func = (void (*)(void *)) thread_start; 152145436Sdavidxu param.arg = new_thread; 153145436Sdavidxu param.stack_base = new_thread->attr.stackaddr_attr; 154145436Sdavidxu param.stack_size = new_thread->attr.stacksize_attr; 155145436Sdavidxu param.tls_base = (char *)new_thread->tcb; 156145436Sdavidxu param.tls_size = sizeof(struct tcb); 157145436Sdavidxu param.child_tid = &new_thread->tid; 158145436Sdavidxu param.parent_tid = &new_thread->tid; 159145436Sdavidxu param.flags = 0; 160145436Sdavidxu if (new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) 161145436Sdavidxu param.flags |= THR_SYSTEM_SCOPE; 162176860Sdavidxu if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) 163176860Sdavidxu param.rtp = NULL; 164176860Sdavidxu else { 165177378Sdavidxu sched_param.sched_priority = new_thread->attr.prio; 166177378Sdavidxu _schedparam_to_rtp(new_thread->attr.sched_policy, 167177378Sdavidxu &sched_param, &rtp); 168177378Sdavidxu param.rtp = &rtp; 169176860Sdavidxu } 170154055Sdavidxu 171144518Sdavidxu /* Schedule the new thread. */ 172154055Sdavidxu if (create_suspended) { 173154055Sdavidxu SIGFILLSET(set); 174154055Sdavidxu SIGDELSET(set, SIGTRAP); 175154055Sdavidxu __sys_sigprocmask(SIG_SETMASK, &set, &oset); 176154055Sdavidxu new_thread->sigmask = oset; 177177231Sdavidxu SIGDELSET(new_thread->sigmask, SIGCANCEL); 178154055Sdavidxu } 179154055Sdavidxu 180145436Sdavidxu ret = thr_new(¶m, sizeof(param)); 181154055Sdavidxu 182160287Sdavidxu if (ret != 0) { 183160287Sdavidxu ret = errno; 184160287Sdavidxu /* 185160287Sdavidxu * Translate EPROCLIM into well-known POSIX code EAGAIN. 186160287Sdavidxu */ 187160287Sdavidxu if (ret == EPROCLIM) 188160287Sdavidxu ret = EAGAIN; 189160287Sdavidxu } 190160287Sdavidxu 191177231Sdavidxu if (create_suspended) 192154055Sdavidxu __sys_sigprocmask(SIG_SETMASK, &oset, NULL); 193154055Sdavidxu 194112918Sjeff if (ret != 0) { 195154055Sdavidxu if (!locked) 196154055Sdavidxu THR_THREAD_LOCK(curthread, new_thread); 197154055Sdavidxu new_thread->state = PS_DEAD; 198154055Sdavidxu new_thread->tid = TID_TERMINATED; 199212536Sdavidxu new_thread->flags |= THR_FLAGS_DETACHED; 200212536Sdavidxu new_thread->refcount--; 201154055Sdavidxu if (new_thread->flags & THR_FLAGS_NEED_SUSPEND) { 202154055Sdavidxu new_thread->cycle++; 203178647Sdavidxu _thr_umtx_wake(&new_thread->cycle, INT_MAX, 0); 204154055Sdavidxu } 205212536Sdavidxu _thr_try_gc(curthread, new_thread); /* thread lock released */ 206212536Sdavidxu atomic_add_int(&_thread_active_threads, -1); 207144921Sdavidxu } else if (locked) { 208178446Sdelphij if (cpusetp != NULL) { 209176817Sdavidxu if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, 210178446Sdelphij TID(new_thread), cpusetsize, cpusetp)) { 211176817Sdavidxu ret = errno; 212176817Sdavidxu /* kill the new thread */ 213176817Sdavidxu new_thread->force_exit = 1; 214212536Sdavidxu new_thread->flags |= THR_FLAGS_DETACHED; 215212536Sdavidxu _thr_try_gc(curthread, new_thread); 216212536Sdavidxu /* thread lock released */ 217176817Sdavidxu goto out; 218176817Sdavidxu } 219176817Sdavidxu } 220176817Sdavidxu 221144921Sdavidxu _thr_report_creation(curthread, new_thread); 222144921Sdavidxu THR_THREAD_UNLOCK(curthread, new_thread); 223212536Sdavidxu } 224176817Sdavidxuout: 225176817Sdavidxu if (ret) 226176817Sdavidxu (*thread) = 0; 227144518Sdavidxu return (ret); 228144518Sdavidxu} 229112918Sjeff 230144518Sdavidxustatic int 231144518Sdavidxucreate_stack(struct pthread_attr *pattr) 232144518Sdavidxu{ 233144518Sdavidxu int ret; 234112918Sjeff 235144518Sdavidxu /* Check if a stack was specified in the thread attributes: */ 236144518Sdavidxu if ((pattr->stackaddr_attr) != NULL) { 237144518Sdavidxu pattr->guardsize_attr = 0; 238144518Sdavidxu pattr->flags |= THR_STACK_USER; 239144518Sdavidxu ret = 0; 240144518Sdavidxu } 241144518Sdavidxu else 242144518Sdavidxu ret = _thr_stack_alloc(pattr); 243144518Sdavidxu return (ret); 244112918Sjeff} 245112918Sjeff 246144518Sdavidxustatic void 247154055Sdavidxuthread_start(struct pthread *curthread) 248112918Sjeff{ 249177337Sdavidxu sigset_t set; 250177337Sdavidxu 251177337Sdavidxu if (curthread->attr.suspend == THR_CREATE_SUSPENDED) 252177337Sdavidxu set = curthread->sigmask; 253177337Sdavidxu 254176817Sdavidxu /* 255176817Sdavidxu * This is used as a serialization point to allow parent 256176817Sdavidxu * to report 'new thread' event to debugger or tweak new thread's 257176817Sdavidxu * attributes before the new thread does real-world work. 258176817Sdavidxu */ 259176817Sdavidxu THR_LOCK(curthread); 260176817Sdavidxu THR_UNLOCK(curthread); 261176817Sdavidxu 262176817Sdavidxu if (curthread->force_exit) 263176817Sdavidxu _pthread_exit(PTHREAD_CANCELED); 264176817Sdavidxu 265154055Sdavidxu if (curthread->attr.suspend == THR_CREATE_SUSPENDED) { 266177337Sdavidxu#if 0 267177337Sdavidxu /* Done in THR_UNLOCK() */ 268154055Sdavidxu _thr_ast(curthread); 269177337Sdavidxu#endif 270154055Sdavidxu 271154055Sdavidxu /* 272154055Sdavidxu * Parent thread have stored signal mask for us, 273154055Sdavidxu * we should restore it now. 274154055Sdavidxu */ 275177337Sdavidxu __sys_sigprocmask(SIG_SETMASK, &set, NULL); 276144518Sdavidxu } 277134051Sdavidxu 278212630Sdavidxu#ifdef _PTHREAD_FORCED_UNWIND 279212630Sdavidxu curthread->unwind_stackend = (char *)curthread->attr.stackaddr_attr + 280212630Sdavidxu curthread->attr.stacksize_attr; 281212630Sdavidxu#endif 282212630Sdavidxu 283144518Sdavidxu /* Run the current thread's start routine with argument: */ 284157457Sdavidxu _pthread_exit(curthread->start_routine(curthread->arg)); 285144518Sdavidxu 286112918Sjeff /* This point should never be reached. */ 287112918Sjeff PANIC("Thread has resumed after exit"); 288112918Sjeff} 289