thr_create.c revision 113870
1128355Sru/* 2128355Sru * Copyright (c) 2003 Daniel M. Eischen <deischen@gdeb.com> 3128355Sru * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 4128355Sru * All rights reserved. 5128355Sru * 6128355Sru * Redistribution and use in source and binary forms, with or without 7128355Sru * modification, are permitted provided that the following conditions 8128355Sru * are met: 9128355Sru * 1. Redistributions of source code must retain the above copyright 10128355Sru * notice, this list of conditions and the following disclaimer. 11128355Sru * 2. Redistributions in binary form must reproduce the above copyright 12128355Sru * notice, this list of conditions and the following disclaimer in the 13128355Sru * documentation and/or other materials provided with the distribution. 14128355Sru * 3. All advertising materials mentioning features or use of this software 15128355Sru * must display the following acknowledgement: 16128355Sru * This product includes software developed by John Birrell. 17128355Sru * 4. Neither the name of the author nor the names of any co-contributors 18128355Sru * may be used to endorse or promote products derived from this software 19128355Sru * without specific prior written permission. 20128355Sru * 21128355Sru * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 22128355Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23128355Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24128355Sru * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25128355Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26128355Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27207680Szec * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28128355Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29128355Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30128355Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31128355Sru * SUCH DAMAGE. 32128355Sru * 33128355Sru * $FreeBSD: head/lib/libkse/thread/thr_create.c 113870 2003-04-22 20:28:33Z deischen $ 34128355Sru */ 35128355Sru#include <errno.h> 36128355Sru#include <stdlib.h> 37128355Sru#include <string.h> 38128355Sru#include <fcntl.h> 39128355Sru#include <unistd.h> 40128355Sru#include <stddef.h> 41128355Sru#include <sys/time.h> 42128355Sru#include <machine/reg.h> 43128355Sru#include <pthread.h> 44128355Sru#include "thr_private.h" 45128355Sru#include "libc_private.h" 46128355Sru 47128355Srustatic u_int64_t next_uniqueid = 1; 48207680Szec 49207680Szec#define OFF(f) offsetof(struct pthread, f) 50207680Szecint _thread_next_offset = OFF(tle.tqe_next); 51242997Sjoelint _thread_uniqueid_offset = OFF(uniqueid); 52207680Szecint _thread_state_offset = OFF(state); 53207680Szecint _thread_name_offset = OFF(name); 54128355Sruint _thread_ctx_offset = OFF(tmbx.tm_context); 55128355Sru#undef OFF 56128355Sru 57207680Szecint _thread_PS_RUNNING_value = PS_RUNNING; 58207680Szecint _thread_PS_DEAD_value = PS_DEAD; 59207680Szec 60207680Szecstatic void free_thread(struct pthread *curthread, struct pthread *thread); 61207680Szecstatic int create_stack(struct pthread_attr *pattr); 62128355Srustatic void thread_start(struct pthread *curthread, 63128355Sru void *(*start_routine) (void *), void *arg); 64128355Sru 65128355Sru__weak_reference(_pthread_create, pthread_create); 66128355Sru 67128355Sru/* 68128355Sru * Some notes on new thread creation and first time initializion 69128355Sru * to enable multi-threading. 70128355Sru * 71128355Sru * There are basically two things that need to be done. 72128355Sru * 73128355Sru * 1) The internal library variables must be initialized. 74128355Sru * 2) Upcalls need to be enabled to allow multiple threads 75128355Sru * to be run. 76 * 77 * The first may be done as a result of other pthread functions 78 * being called. When _thr_initial is null, _libpthread_init is 79 * called to initialize the internal variables; this also creates 80 * or sets the initial thread. It'd be nice to automatically 81 * have _libpthread_init called on program execution so we don't 82 * have to have checks throughout the library. 83 * 84 * The second part is only triggered by the creation of the first 85 * thread (other than the initial/main thread). If the thread 86 * being created is a scope system thread, then a new KSE/KSEG 87 * pair needs to be allocated. Also, if upcalls haven't been 88 * enabled on the initial thread's KSE, they must be now that 89 * there is more than one thread; this could be delayed until 90 * the initial KSEG has more than one thread. 91 */ 92int 93_pthread_create(pthread_t * thread, const pthread_attr_t * attr, 94 void *(*start_routine) (void *), void *arg) 95{ 96 struct kse *curkse; 97 struct pthread *curthread, *new_thread; 98 struct kse *kse = NULL; 99 struct kse_group *kseg = NULL; 100 kse_critical_t crit; 101 int i; 102 int ret = 0; 103 104 if (_thr_initial == NULL) 105 _libpthread_init(NULL); 106 107 /* 108 * Turn on threaded mode, if failed, it is unnecessary to 109 * do further work. 110 */ 111 if (_kse_isthreaded() == 0 && _kse_setthreaded(1)) { 112 return (EAGAIN); 113 } 114 curthread = _get_curthread(); 115 116 /* 117 * Allocate memory for the thread structure. 118 * Some functions use malloc, so don't put it 119 * in a critical region. 120 */ 121 if ((new_thread = _thr_alloc(curthread)) == NULL) { 122 /* Insufficient memory to create a thread: */ 123 ret = EAGAIN; 124 } else { 125 /* Initialize the thread structure: */ 126 memset(new_thread, 0, sizeof(struct pthread)); 127 128 /* Check if default thread attributes are required: */ 129 if (attr == NULL || *attr == NULL) 130 /* Use the default thread attributes: */ 131 new_thread->attr = _pthread_attr_default; 132 else 133 new_thread->attr = *(*attr); 134 135 if (create_stack(&new_thread->attr) != 0) { 136 /* Insufficient memory to create a stack: */ 137 ret = EAGAIN; 138 _thr_free(curthread, new_thread); 139 } 140 else if (((new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) && 141 (((kse = _kse_alloc(curthread)) == NULL) 142 || ((kseg = _kseg_alloc(curthread)) == NULL))) { 143 /* Insufficient memory to create a new KSE/KSEG: */ 144 ret = EAGAIN; 145 if (kse != NULL) 146 _kse_free(curthread, kse); 147 if ((new_thread->attr.flags & THR_STACK_USER) == 0) { 148 crit = _kse_critical_enter(); 149 curkse = _get_curkse(); 150 KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock); 151 /* Stack routines don't use malloc/free. */ 152 _thr_stack_free(&new_thread->attr); 153 KSE_LOCK_RELEASE(curkse, &_thread_list_lock); 154 _kse_critical_leave(crit); 155 } 156 _thr_free(curthread, new_thread); 157 } 158 else { 159 if (kseg != NULL) { 160 /* Add the KSE to the KSEG's list of KSEs. */ 161 TAILQ_INSERT_HEAD(&kseg->kg_kseq, kse, k_qe); 162 kse->k_kseg = kseg; 163 kse->k_schedq = &kseg->kg_schedq; 164 } 165 /* 166 * Write a magic value to the thread structure 167 * to help identify valid ones: 168 */ 169 new_thread->magic = THR_MAGIC; 170 171 new_thread->slice_usec = -1; 172 new_thread->start_routine = start_routine; 173 new_thread->arg = arg; 174 new_thread->cancelflags = PTHREAD_CANCEL_ENABLE | 175 PTHREAD_CANCEL_DEFERRED; 176 177 /* Initialize the thread for signals: */ 178 new_thread->sigmask = curthread->sigmask; 179 180 /* No thread is wanting to join to this one: */ 181 new_thread->joiner = NULL; 182 183 /* Initialize the signal frame: */ 184 new_thread->curframe = NULL; 185 186 /* 187 * Initialize the machine context. 188 * Enter a critical region to get consistent context. 189 */ 190 crit = _kse_critical_enter(); 191 THR_GETCONTEXT(&new_thread->tmbx.tm_context); 192 _kse_critical_leave(crit); 193 new_thread->tmbx.tm_udata = new_thread; 194 new_thread->tmbx.tm_context.uc_sigmask = 195 new_thread->sigmask; 196 new_thread->tmbx.tm_context.uc_stack.ss_size = 197 new_thread->attr.stacksize_attr; 198 new_thread->tmbx.tm_context.uc_stack.ss_sp = 199 new_thread->attr.stackaddr_attr; 200 makecontext(&new_thread->tmbx.tm_context, 201 (void (*)(void))thread_start, 4, new_thread, 202 start_routine, arg); 203 /* 204 * Check if this thread is to inherit the scheduling 205 * attributes from its parent: 206 */ 207 if ((new_thread->attr.flags & PTHREAD_INHERIT_SCHED) != 0) { 208 /* 209 * Copy the scheduling attributes. 210 * Lock the scheduling lock to get consistent 211 * scheduling parameters. 212 */ 213 THR_SCHED_LOCK(curthread, curthread); 214 new_thread->base_priority = 215 curthread->base_priority & 216 ~THR_SIGNAL_PRIORITY; 217 new_thread->attr.prio = 218 curthread->base_priority & 219 ~THR_SIGNAL_PRIORITY; 220 new_thread->attr.sched_policy = 221 curthread->attr.sched_policy; 222 THR_SCHED_UNLOCK(curthread, curthread); 223 } else { 224 /* 225 * Use just the thread priority, leaving the 226 * other scheduling attributes as their 227 * default values: 228 */ 229 new_thread->base_priority = 230 new_thread->attr.prio; 231 } 232 new_thread->active_priority = new_thread->base_priority; 233 new_thread->inherited_priority = 0; 234 235 /* Initialize the mutex queue: */ 236 TAILQ_INIT(&new_thread->mutexq); 237 238 /* 239 * Initialize thread locking. 240 * Lock initializing needs malloc, so don't 241 * enter critical region before doing this! 242 */ 243 if (_lock_init(&new_thread->lock, LCK_ADAPTIVE, 244 _thr_lock_wait, _thr_lock_wakeup) != 0) 245 PANIC("Cannot initialize thread lock"); 246 for (i = 0; i < MAX_THR_LOCKLEVEL; i++) { 247 _lockuser_init(&new_thread->lockusers[i], 248 (void *)new_thread); 249 _LCK_SET_PRIVATE2(&new_thread->lockusers[i], 250 (void *)new_thread); 251 } 252 253 /* Initialise hooks in the thread structure: */ 254 new_thread->specific = NULL; 255 new_thread->cleanup = NULL; 256 new_thread->flags = 0; 257 new_thread->continuation = NULL; 258 259 if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) 260 new_thread->state = PS_SUSPENDED; 261 else 262 new_thread->state = PS_RUNNING; 263 264 /* 265 * System scope threads have their own kse and 266 * kseg. Process scope threads are all hung 267 * off the main process kseg. 268 */ 269 if ((new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0) { 270 new_thread->kseg = _kse_initial->k_kseg; 271 new_thread->kse = _kse_initial; 272 } 273 else { 274 kse->k_curthread = NULL; 275#ifdef NOT_YET 276 kse->k_kseg->kg_flags |= KGF_SINGLE_THREAD; 277#endif 278 new_thread->kse = kse; 279 new_thread->kseg = kse->k_kseg; 280 kse->k_mbx.km_udata = kse; 281 kse->k_mbx.km_curthread = NULL; 282 } 283 284 crit = _kse_critical_enter(); 285 KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock); 286 /* 287 * Initialise the unique id which GDB uses to 288 * track threads. 289 */ 290 new_thread->uniqueid = next_uniqueid++; 291 /* Add the thread to the linked list of all threads: */ 292 THR_LIST_ADD(new_thread); 293 KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock); 294 295 /* 296 * Schedule the new thread starting a new KSEG/KSE 297 * pair if necessary. 298 */ 299 ret = _thr_schedule_add(curthread, new_thread); 300 _kse_critical_leave(crit); 301 if (ret != 0) 302 free_thread(curthread, new_thread); 303 304 /* Return a pointer to the thread structure: */ 305 (*thread) = new_thread; 306 } 307 } 308 309 /* Return the status: */ 310 return (ret); 311} 312 313static void 314free_thread(struct pthread *curthread, struct pthread *thread) 315{ 316 if ((thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) { 317 /* Free the KSE and KSEG. */ 318 _kseg_free(thread->kseg); 319 _kse_free(curthread, thread->kse); 320 } 321 _thr_free(curthread, thread); 322} 323 324static int 325create_stack(struct pthread_attr *pattr) 326{ 327 int ret; 328 329 /* Check if a stack was specified in the thread attributes: */ 330 if ((pattr->stackaddr_attr) != NULL) { 331 pattr->guardsize_attr = 0; 332 pattr->flags = THR_STACK_USER; 333 ret = 0; 334 } 335 else 336 ret = _thr_stack_alloc(pattr); 337 return (ret); 338} 339 340 341static void 342thread_start(struct pthread *curthread, void *(*start_routine) (void *), 343 void *arg) 344{ 345 /* Run the current thread's start routine with argument: */ 346 pthread_exit(start_routine(arg)); 347 348 /* This point should never be reached. */ 349 PANIC("Thread has resumed after exit"); 350} 351