1bb535300SJeff Roberson /* 2a091d823SDavid Xu * Copyright (c) 2003 Daniel M. Eischen <deischen@gdeb.com> 3df2cf821SDavid Xu * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 4bb535300SJeff Roberson * All rights reserved. 5bb535300SJeff Roberson * 6bb535300SJeff Roberson * Redistribution and use in source and binary forms, with or without 7bb535300SJeff Roberson * modification, are permitted provided that the following conditions 8bb535300SJeff Roberson * are met: 9bb535300SJeff Roberson * 1. Redistributions of source code must retain the above copyright 10df2cf821SDavid Xu * notice unmodified, this list of conditions, and the following 11df2cf821SDavid Xu * disclaimer. 12bb535300SJeff Roberson * 2. Redistributions in binary form must reproduce the above copyright 13bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer in the 14bb535300SJeff Roberson * documentation and/or other materials provided with the distribution. 15bb535300SJeff Roberson * 16df2cf821SDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17df2cf821SDavid Xu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18df2cf821SDavid Xu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19df2cf821SDavid Xu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20df2cf821SDavid Xu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21df2cf821SDavid Xu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22df2cf821SDavid Xu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23df2cf821SDavid Xu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24df2cf821SDavid Xu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25df2cf821SDavid Xu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26bb535300SJeff Roberson * 27bb535300SJeff Roberson * $FreeBSD$ 28bb535300SJeff Roberson */ 29a091d823SDavid Xu 3037a6356bSDavid Xu #include "namespace.h" 317e4cbc3aSStefan Farfeleder #include <sys/types.h> 3270e79fbbSDavid Xu #include <sys/rtprio.h> 337e4cbc3aSStefan Farfeleder #include <sys/signalvar.h> 34bb535300SJeff Roberson #include <errno.h> 35da2fcff7SKonstantin Belousov #include <link.h> 36bb535300SJeff Roberson #include <stdlib.h> 37bb535300SJeff Roberson #include <string.h> 38bb535300SJeff Roberson #include <stddef.h> 39bb535300SJeff Roberson #include <pthread.h> 40a759db94SDavid Xu #include <pthread_np.h> 4137a6356bSDavid Xu #include "un-namespace.h" 42a091d823SDavid Xu 438495e8b1SKonstantin Belousov #include "libc_private.h" 44bb535300SJeff Roberson #include "thr_private.h" 45bb535300SJeff Roberson 46a091d823SDavid Xu static int create_stack(struct pthread_attr *pattr); 47a091d823SDavid Xu static void thread_start(struct pthread *curthread); 48bb535300SJeff Roberson 49bb535300SJeff Roberson __weak_reference(_pthread_create, pthread_create); 50bb535300SJeff Roberson 51bb535300SJeff Roberson int 52bb535300SJeff Roberson _pthread_create(pthread_t * thread, const pthread_attr_t * attr, 53bb535300SJeff Roberson void *(*start_routine) (void *), void *arg) 54bb535300SJeff Roberson { 55a091d823SDavid Xu struct pthread *curthread, *new_thread; 5680c9676eSDavid Xu struct thr_param param; 57e6747c7cSDavid Xu struct sched_param sched_param; 5870e79fbbSDavid Xu struct rtprio rtp; 59bc414752SDavid Xu sigset_t set, oset; 601bdbd705SKonstantin Belousov cpuset_t *cpusetp; 611bdbd705SKonstantin Belousov int i, cpusetsize, create_suspended, locked, old_stack_prot, ret; 62a091d823SDavid Xu 631bdbd705SKonstantin Belousov cpusetp = NULL; 641bdbd705SKonstantin Belousov ret = cpusetsize = 0; 65a091d823SDavid Xu _thr_check_init(); 66bb535300SJeff Roberson 67bb535300SJeff Roberson /* 68a091d823SDavid Xu * Tell libc and others now they need lock to protect their data. 69bb535300SJeff Roberson */ 708495e8b1SKonstantin Belousov if (_thr_isthreaded() == 0) { 718495e8b1SKonstantin Belousov _malloc_first_thread(); 728495e8b1SKonstantin Belousov if (_thr_setthreaded(1)) 73bb535300SJeff Roberson return (EAGAIN); 748495e8b1SKonstantin Belousov } 75bb535300SJeff Roberson 76a091d823SDavid Xu curthread = _get_curthread(); 77a091d823SDavid Xu if ((new_thread = _thr_alloc(curthread)) == NULL) 78a091d823SDavid Xu return (EAGAIN); 79a091d823SDavid Xu 8080c9676eSDavid Xu memset(¶m, 0, sizeof(param)); 8180c9676eSDavid Xu 82bb535300SJeff Roberson if (attr == NULL || *attr == NULL) 83a091d823SDavid Xu /* Use the default thread attributes: */ 84a091d823SDavid Xu new_thread->attr = _pthread_attr_default; 85a759db94SDavid Xu else { 86a091d823SDavid Xu new_thread->attr = *(*attr); 87d0aa4fd3SXin LI cpusetp = new_thread->attr.cpuset; 8854dff16bSDavid Xu cpusetsize = new_thread->attr.cpusetsize; 89a759db94SDavid Xu new_thread->attr.cpuset = NULL; 90a759db94SDavid Xu new_thread->attr.cpusetsize = 0; 91a759db94SDavid Xu } 92a091d823SDavid Xu if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) { 93a091d823SDavid Xu /* inherit scheduling contention scope */ 94a091d823SDavid Xu if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) 95a091d823SDavid Xu new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM; 96a091d823SDavid Xu else 97a091d823SDavid Xu new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM; 98e2dc286cSDavid Xu 99e2dc286cSDavid Xu new_thread->attr.prio = curthread->attr.prio; 100e2dc286cSDavid Xu new_thread->attr.sched_policy = curthread->attr.sched_policy; 101a091d823SDavid Xu } 102bb535300SJeff Roberson 103d245d9e1SDavid Xu new_thread->tid = TID_TERMINATED; 104d245d9e1SDavid Xu 105da2fcff7SKonstantin Belousov old_stack_prot = _rtld_get_stack_prot(); 106a091d823SDavid Xu if (create_stack(&new_thread->attr) != 0) { 107a091d823SDavid Xu /* Insufficient memory to create a stack: */ 108a091d823SDavid Xu _thr_free(curthread, new_thread); 109bb535300SJeff Roberson return (EAGAIN); 110bb535300SJeff Roberson } 111a091d823SDavid Xu /* 112a091d823SDavid Xu * Write a magic value to the thread structure 113a091d823SDavid Xu * to help identify valid ones: 114a091d823SDavid Xu */ 115a091d823SDavid Xu new_thread->magic = THR_MAGIC; 116bb535300SJeff Roberson new_thread->start_routine = start_routine; 117bb535300SJeff Roberson new_thread->arg = arg; 118f08e1bf6SDavid Xu new_thread->cancel_enable = 1; 119f08e1bf6SDavid Xu new_thread->cancel_async = 0; 120a091d823SDavid Xu /* Initialize the mutex queue: */ 1211bdbd705SKonstantin Belousov for (i = 0; i < TMQ_NITEMS; i++) 1221bdbd705SKonstantin Belousov TAILQ_INIT(&new_thread->mq[i]); 1234393f2c4SMike Makonnen 124a091d823SDavid Xu /* Initialise hooks in the thread structure: */ 125bc414752SDavid Xu if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) { 12688676cbcSDavid Xu new_thread->flags = THR_FLAGS_NEED_SUSPEND; 127bc414752SDavid Xu create_suspended = 1; 128bc414752SDavid Xu } else { 129bc414752SDavid Xu create_suspended = 0; 130bc414752SDavid Xu } 131bc414752SDavid Xu 132a091d823SDavid Xu new_thread->state = PS_RUNNING; 13380c9676eSDavid Xu 134bc414752SDavid Xu if (new_thread->attr.flags & PTHREAD_CREATE_DETACHED) 135a9b764e2SDavid Xu new_thread->flags |= THR_FLAGS_DETACHED; 136bc414752SDavid Xu 137a091d823SDavid Xu /* Add the new thread. */ 138bc414752SDavid Xu new_thread->refcount = 1; 139a091d823SDavid Xu _thr_link(curthread, new_thread); 140da2fcff7SKonstantin Belousov 141da2fcff7SKonstantin Belousov /* 142da2fcff7SKonstantin Belousov * Handle the race between __pthread_map_stacks_exec and 143da2fcff7SKonstantin Belousov * thread linkage. 144da2fcff7SKonstantin Belousov */ 145da2fcff7SKonstantin Belousov if (old_stack_prot != _rtld_get_stack_prot()) 146da2fcff7SKonstantin Belousov _thr_stack_fix_protection(new_thread); 147da2fcff7SKonstantin Belousov 148a091d823SDavid Xu /* Return thread pointer eariler so that new thread can use it. */ 149bb535300SJeff Roberson (*thread) = new_thread; 150d0aa4fd3SXin LI if (SHOULD_REPORT_EVENT(curthread, TD_CREATE) || cpusetp != NULL) { 151d245d9e1SDavid Xu THR_THREAD_LOCK(curthread, new_thread); 152d245d9e1SDavid Xu locked = 1; 153d245d9e1SDavid Xu } else 154d245d9e1SDavid Xu locked = 0; 15580c9676eSDavid Xu param.start_func = (void (*)(void *)) thread_start; 15680c9676eSDavid Xu param.arg = new_thread; 15780c9676eSDavid Xu param.stack_base = new_thread->attr.stackaddr_attr; 15880c9676eSDavid Xu param.stack_size = new_thread->attr.stacksize_attr; 15980c9676eSDavid Xu param.tls_base = (char *)new_thread->tcb; 16080c9676eSDavid Xu param.tls_size = sizeof(struct tcb); 16180c9676eSDavid Xu param.child_tid = &new_thread->tid; 16280c9676eSDavid Xu param.parent_tid = &new_thread->tid; 16380c9676eSDavid Xu param.flags = 0; 16480c9676eSDavid Xu if (new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) 16580c9676eSDavid Xu param.flags |= THR_SYSTEM_SCOPE; 16670e79fbbSDavid Xu if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) 167e6747c7cSDavid Xu param.rtp = NULL; 16870e79fbbSDavid Xu else { 16970e79fbbSDavid Xu sched_param.sched_priority = new_thread->attr.prio; 17070e79fbbSDavid Xu _schedparam_to_rtp(new_thread->attr.sched_policy, 17170e79fbbSDavid Xu &sched_param, &rtp); 17270e79fbbSDavid Xu param.rtp = &rtp; 17370e79fbbSDavid Xu } 174bc414752SDavid Xu 175a091d823SDavid Xu /* Schedule the new thread. */ 176bc414752SDavid Xu if (create_suspended) { 177bc414752SDavid Xu SIGFILLSET(set); 178bc414752SDavid Xu SIGDELSET(set, SIGTRAP); 179bc414752SDavid Xu __sys_sigprocmask(SIG_SETMASK, &set, &oset); 180bc414752SDavid Xu new_thread->sigmask = oset; 181a9a11568SDavid Xu SIGDELSET(new_thread->sigmask, SIGCANCEL); 182bc414752SDavid Xu } 183bc414752SDavid Xu 18480c9676eSDavid Xu ret = thr_new(¶m, sizeof(param)); 185bc414752SDavid Xu 1867b4f8f03SDavid Xu if (ret != 0) { 1877b4f8f03SDavid Xu ret = errno; 1887b4f8f03SDavid Xu /* 1897b4f8f03SDavid Xu * Translate EPROCLIM into well-known POSIX code EAGAIN. 1907b4f8f03SDavid Xu */ 1917b4f8f03SDavid Xu if (ret == EPROCLIM) 1927b4f8f03SDavid Xu ret = EAGAIN; 1937b4f8f03SDavid Xu } 1947b4f8f03SDavid Xu 195a9a11568SDavid Xu if (create_suspended) 196bc414752SDavid Xu __sys_sigprocmask(SIG_SETMASK, &oset, NULL); 197bc414752SDavid Xu 198a091d823SDavid Xu if (ret != 0) { 199bc414752SDavid Xu if (!locked) 200bc414752SDavid Xu THR_THREAD_LOCK(curthread, new_thread); 201bc414752SDavid Xu new_thread->state = PS_DEAD; 202bc414752SDavid Xu new_thread->tid = TID_TERMINATED; 203a9b764e2SDavid Xu new_thread->flags |= THR_FLAGS_DETACHED; 204a9b764e2SDavid Xu new_thread->refcount--; 205bc414752SDavid Xu if (new_thread->flags & THR_FLAGS_NEED_SUSPEND) { 206bc414752SDavid Xu new_thread->cycle++; 2078d6a11a0SDavid Xu _thr_umtx_wake(&new_thread->cycle, INT_MAX, 0); 208bc414752SDavid Xu } 209a9b764e2SDavid Xu _thr_try_gc(curthread, new_thread); /* thread lock released */ 210a9b764e2SDavid Xu atomic_add_int(&_thread_active_threads, -1); 211d245d9e1SDavid Xu } else if (locked) { 212d0aa4fd3SXin LI if (cpusetp != NULL) { 21354dff16bSDavid Xu if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, 214d0aa4fd3SXin LI TID(new_thread), cpusetsize, cpusetp)) { 21554dff16bSDavid Xu ret = errno; 21654dff16bSDavid Xu /* kill the new thread */ 21754dff16bSDavid Xu new_thread->force_exit = 1; 218a9b764e2SDavid Xu new_thread->flags |= THR_FLAGS_DETACHED; 219a9b764e2SDavid Xu _thr_try_gc(curthread, new_thread); 220a9b764e2SDavid Xu /* thread lock released */ 22154dff16bSDavid Xu goto out; 22254dff16bSDavid Xu } 22354dff16bSDavid Xu } 22454dff16bSDavid Xu 225d245d9e1SDavid Xu _thr_report_creation(curthread, new_thread); 226d245d9e1SDavid Xu THR_THREAD_UNLOCK(curthread, new_thread); 227a9b764e2SDavid Xu } 22854dff16bSDavid Xu out: 22954dff16bSDavid Xu if (ret) 23054dff16bSDavid Xu (*thread) = 0; 231a091d823SDavid Xu return (ret); 232bb535300SJeff Roberson } 233bb535300SJeff Roberson 234a091d823SDavid Xu static int 235a091d823SDavid Xu create_stack(struct pthread_attr *pattr) 236bb535300SJeff Roberson { 2379027ac47SDavid Xu int ret; 2389027ac47SDavid Xu 239a091d823SDavid Xu /* Check if a stack was specified in the thread attributes: */ 240a091d823SDavid Xu if ((pattr->stackaddr_attr) != NULL) { 241a091d823SDavid Xu pattr->guardsize_attr = 0; 242a091d823SDavid Xu pattr->flags |= THR_STACK_USER; 243a091d823SDavid Xu ret = 0; 244a091d823SDavid Xu } 245a091d823SDavid Xu else 246a091d823SDavid Xu ret = _thr_stack_alloc(pattr); 247a091d823SDavid Xu return (ret); 248a091d823SDavid Xu } 2499027ac47SDavid Xu 250a091d823SDavid Xu static void 251a091d823SDavid Xu thread_start(struct pthread *curthread) 252a091d823SDavid Xu { 2532ea1f90aSDavid Xu sigset_t set; 2542ea1f90aSDavid Xu 2552ea1f90aSDavid Xu if (curthread->attr.suspend == THR_CREATE_SUSPENDED) 2562ea1f90aSDavid Xu set = curthread->sigmask; 2572ea1f90aSDavid Xu 25854dff16bSDavid Xu /* 25954dff16bSDavid Xu * This is used as a serialization point to allow parent 26054dff16bSDavid Xu * to report 'new thread' event to debugger or tweak new thread's 26154dff16bSDavid Xu * attributes before the new thread does real-world work. 26254dff16bSDavid Xu */ 26354dff16bSDavid Xu THR_LOCK(curthread); 26454dff16bSDavid Xu THR_UNLOCK(curthread); 26554dff16bSDavid Xu 26654dff16bSDavid Xu if (curthread->force_exit) 26754dff16bSDavid Xu _pthread_exit(PTHREAD_CANCELED); 26854dff16bSDavid Xu 269bc414752SDavid Xu if (curthread->attr.suspend == THR_CREATE_SUSPENDED) { 2702ea1f90aSDavid Xu #if 0 2712ea1f90aSDavid Xu /* Done in THR_UNLOCK() */ 272bc414752SDavid Xu _thr_ast(curthread); 2732ea1f90aSDavid Xu #endif 274bc414752SDavid Xu 275bc414752SDavid Xu /* 276bc414752SDavid Xu * Parent thread have stored signal mask for us, 277bc414752SDavid Xu * we should restore it now. 278bc414752SDavid Xu */ 2792ea1f90aSDavid Xu __sys_sigprocmask(SIG_SETMASK, &set, NULL); 280bc414752SDavid Xu } 281bc414752SDavid Xu 2823832fd24SDavid Xu #ifdef _PTHREAD_FORCED_UNWIND 2833832fd24SDavid Xu curthread->unwind_stackend = (char *)curthread->attr.stackaddr_attr + 2843832fd24SDavid Xu curthread->attr.stacksize_attr; 2853832fd24SDavid Xu #endif 2863832fd24SDavid Xu 287a091d823SDavid Xu /* Run the current thread's start routine with argument: */ 28837a6356bSDavid Xu _pthread_exit(curthread->start_routine(curthread->arg)); 289a091d823SDavid Xu 290bb535300SJeff Roberson /* This point should never be reached. */ 291bb535300SJeff Roberson PANIC("Thread has resumed after exit"); 292bb535300SJeff Roberson } 293