thr_create.c revision 113658
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 113658 2003-04-18 05:04:16Z 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 <machine/reg.h> 42#include <pthread.h> 43#include "thr_private.h" 44#include "libc_private.h" 45 46static u_int64_t next_uniqueid = 1; 47 48#define OFF(f) offsetof(struct pthread, f) 49int _thread_next_offset = OFF(tle.tqe_next); 50int _thread_uniqueid_offset = OFF(uniqueid); 51int _thread_state_offset = OFF(state); 52int _thread_name_offset = OFF(name); 53int _thread_ctx_offset = OFF(tmbx.tm_context); 54#undef OFF 55 56int _thread_PS_RUNNING_value = PS_RUNNING; 57int _thread_PS_DEAD_value = PS_DEAD; 58 59static int create_stack(struct pthread_attr *pattr); 60static void thread_start(struct pthread *curthread, 61 void *(*start_routine) (void *), void *arg); 62 63__weak_reference(_pthread_create, pthread_create); 64 65/* 66 * Some notes on new thread creation and first time initializion 67 * to enable multi-threading. 68 * 69 * There are basically two things that need to be done. 70 * 71 * 1) The internal library variables must be initialized. 72 * 2) Upcalls need to be enabled to allow multiple threads 73 * to be run. 74 * 75 * The first may be done as a result of other pthread functions 76 * being called. When _thr_initial is null, _libpthread_init is 77 * called to initialize the internal variables; this also creates 78 * or sets the initial thread. It'd be nice to automatically 79 * have _libpthread_init called on program execution so we don't 80 * have to have checks throughout the library. 81 * 82 * The second part is only triggered by the creation of the first 83 * thread (other than the initial/main thread). If the thread 84 * being created is a scope system thread, then a new KSE/KSEG 85 * pair needs to be allocated. Also, if upcalls haven't been 86 * enabled on the initial thread's KSE, they must be now that 87 * there is more than one thread; this could be delayed until 88 * the initial KSEG has more than one thread. 89 */ 90int 91_pthread_create(pthread_t * thread, const pthread_attr_t * attr, 92 void *(*start_routine) (void *), void *arg) 93{ 94 struct kse *curkse; 95 struct pthread *curthread, *new_thread; 96 struct kse *kse = NULL; 97 struct kse_group *kseg = NULL; 98 kse_critical_t crit; 99 int i; 100 int ret = 0; 101 102 if (_thr_initial == NULL) 103 _libpthread_init(NULL); 104 105 crit = _kse_critical_enter(); 106 curthread = _get_curthread(); 107 curkse = curthread->kse; 108 109 /* Allocate memory for the thread structure: */ 110 if ((new_thread = _thr_alloc(curkse)) == NULL) { 111 /* Insufficient memory to create a thread: */ 112 ret = EAGAIN; 113 } else { 114 /* Initialize the thread structure: */ 115 memset(new_thread, 0, sizeof(struct pthread)); 116 117 /* Check if default thread attributes are required: */ 118 if (attr == NULL || *attr == NULL) 119 /* Use the default thread attributes: */ 120 new_thread->attr = _pthread_attr_default; 121 else 122 new_thread->attr = *(*attr); 123 124 if (create_stack(&new_thread->attr) != 0) { 125 /* Insufficient memory to create a stack: */ 126 ret = EAGAIN; 127 _thr_free(curkse, new_thread); 128 } 129 else if (((new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) && 130 (((kse = _kse_alloc(curkse)) == NULL) 131 || ((kseg = _kseg_alloc(curkse)) == NULL))) { 132 /* Insufficient memory to create a new KSE/KSEG: */ 133 ret = EAGAIN; 134 if (kse != NULL) 135 _kse_free(curkse, kse); 136 if ((new_thread->attr.flags & THR_STACK_USER) == 0) { 137 KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock); 138 _thr_stack_free(&new_thread->attr); 139 KSE_LOCK_RELEASE(curkse, &_thread_list_lock); 140 } 141 _thr_free(curkse, new_thread); 142 } 143 else { 144 if (kseg != NULL) { 145 /* Add the KSE to the KSEG's list of KSEs. */ 146 TAILQ_INSERT_HEAD(&kseg->kg_kseq, kse, k_qe); 147 kse->k_kseg = kseg; 148 kse->k_schedq = &kseg->kg_schedq; 149 } 150 /* 151 * Write a magic value to the thread structure 152 * to help identify valid ones: 153 */ 154 new_thread->magic = THR_MAGIC; 155 156 new_thread->slice_usec = -1; 157 new_thread->start_routine = start_routine; 158 new_thread->arg = arg; 159 new_thread->cancelflags = PTHREAD_CANCEL_ENABLE | 160 PTHREAD_CANCEL_DEFERRED; 161 162 /* Initialize the thread for signals: */ 163 new_thread->sigmask = curthread->sigmask; 164 165 /* No thread is wanting to join to this one: */ 166 new_thread->joiner = NULL; 167 168 /* Initialize the signal frame: */ 169 new_thread->curframe = NULL; 170 171 /* Initialize the machine context: */ 172 THR_GETCONTEXT(&new_thread->tmbx.tm_context); 173 new_thread->tmbx.tm_udata = new_thread; 174 new_thread->tmbx.tm_context.uc_sigmask = 175 new_thread->sigmask; 176 new_thread->tmbx.tm_context.uc_stack.ss_size = 177 new_thread->attr.stacksize_attr; 178 new_thread->tmbx.tm_context.uc_stack.ss_sp = 179 new_thread->attr.stackaddr_attr; 180 181 makecontext(&new_thread->tmbx.tm_context, 182 (void (*)(void))thread_start, 4, new_thread, 183 start_routine, arg); 184 185 /* 186 * Check if this thread is to inherit the scheduling 187 * attributes from its parent: 188 */ 189 if ((new_thread->attr.flags & PTHREAD_INHERIT_SCHED) != 0) { 190 /* Copy the scheduling attributes: */ 191 new_thread->base_priority = 192 curthread->base_priority & 193 ~THR_SIGNAL_PRIORITY; 194 new_thread->attr.prio = 195 curthread->base_priority & 196 ~THR_SIGNAL_PRIORITY; 197 new_thread->attr.sched_policy = 198 curthread->attr.sched_policy; 199 } else { 200 /* 201 * Use just the thread priority, leaving the 202 * other scheduling attributes as their 203 * default values: 204 */ 205 new_thread->base_priority = 206 new_thread->attr.prio; 207 } 208 new_thread->active_priority = new_thread->base_priority; 209 new_thread->inherited_priority = 0; 210 211 /* Initialize the mutex queue: */ 212 TAILQ_INIT(&new_thread->mutexq); 213 214 /* Initialize thread locking. */ 215 if (_lock_init(&new_thread->lock, LCK_ADAPTIVE, 216 _thr_lock_wait, _thr_lock_wakeup) != 0) 217 PANIC("Cannot initialize thread lock"); 218 for (i = 0; i < MAX_THR_LOCKLEVEL; i++) { 219 _lockuser_init(&new_thread->lockusers[i], 220 (void *)new_thread); 221 _LCK_SET_PRIVATE2(&new_thread->lockusers[i], 222 (void *)new_thread); 223 } 224 225 /* Initialise hooks in the thread structure: */ 226 new_thread->specific = NULL; 227 new_thread->cleanup = NULL; 228 new_thread->flags = 0; 229 new_thread->continuation = NULL; 230 231 if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) 232 new_thread->state = PS_SUSPENDED; 233 else 234 new_thread->state = PS_RUNNING; 235 236 /* 237 * System scope threads have their own kse and 238 * kseg. Process scope threads are all hung 239 * off the main process kseg. 240 */ 241 if ((new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0) { 242 new_thread->kseg = _kse_initial->k_kseg; 243 new_thread->kse = _kse_initial; 244 } 245 else { 246 kse->k_curthread = NULL; 247 kse->k_kseg->kg_flags |= KGF_SINGLE_THREAD; 248 new_thread->kse = kse; 249 new_thread->kseg = kse->k_kseg; 250 kse->k_mbx.km_udata = kse; 251 kse->k_mbx.km_curthread = NULL; 252 } 253 KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock); 254 255 /* 256 * Initialise the unique id which GDB uses to 257 * track threads. 258 */ 259 new_thread->uniqueid = next_uniqueid++; 260 261 /* Add the thread to the linked list of all threads: */ 262 THR_LIST_ADD(new_thread); 263 264 KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock); 265 266 /* 267 * Schedule the new thread starting a new KSEG/KSE 268 * pair if necessary. 269 */ 270 _thr_schedule_add(curthread, new_thread); 271 272 /* Return a pointer to the thread structure: */ 273 (*thread) = new_thread; 274 } 275 } 276 _kse_critical_leave(crit); 277 278 if ((ret == 0) && (_kse_isthreaded() == 0)) 279 _kse_setthreaded(1); 280 281 /* Return the status: */ 282 return (ret); 283} 284 285static int 286create_stack(struct pthread_attr *pattr) 287{ 288 int ret; 289 290 /* Check if a stack was specified in the thread attributes: */ 291 if ((pattr->stackaddr_attr) != NULL) { 292 pattr->guardsize_attr = 0; 293 pattr->flags = THR_STACK_USER; 294 ret = 0; 295 } 296 else 297 ret = _thr_stack_alloc(pattr); 298 return (ret); 299} 300 301 302static void 303thread_start(struct pthread *curthread, void *(*start_routine) (void *), 304 void *arg) 305{ 306 /* Run the current thread's start routine with argument: */ 307 pthread_exit(start_routine(arg)); 308 309 /* This point should never be reached. */ 310 PANIC("Thread has resumed after exit"); 311} 312