thr_create.c revision 55193
11556Srgrimes/* 21556Srgrimes * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 31556Srgrimes * All rights reserved. 41556Srgrimes * 51556Srgrimes * Redistribution and use in source and binary forms, with or without 61556Srgrimes * modification, are permitted provided that the following conditions 71556Srgrimes * are met: 81556Srgrimes * 1. Redistributions of source code must retain the above copyright 91556Srgrimes * notice, this list of conditions and the following disclaimer. 101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111556Srgrimes * notice, this list of conditions and the following disclaimer in the 121556Srgrimes * documentation and/or other materials provided with the distribution. 131556Srgrimes * 3. All advertising materials mentioning features or use of this software 141556Srgrimes * must display the following acknowledgement: 151556Srgrimes * This product includes software developed by John Birrell. 161556Srgrimes * 4. Neither the name of the author nor the names of any co-contributors 171556Srgrimes * may be used to endorse or promote products derived from this software 181556Srgrimes * without specific prior written permission. 191556Srgrimes * 201556Srgrimes * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301556Srgrimes * SUCH DAMAGE. 311556Srgrimes * 321556Srgrimes * $FreeBSD: head/lib/libkse/thread/thr_create.c 55193 1999-12-28 18:12:07Z deischen $ 331556Srgrimes */ 341556Srgrimes#include <errno.h> 351556Srgrimes#include <stdlib.h> 361556Srgrimes#include <string.h> 371556Srgrimes#include <fcntl.h> 381556Srgrimes#include <unistd.h> 3935773Scharnier#include <stddef.h> 4036007Scharnier#include <sys/time.h> 4135773Scharnier#include <sys/param.h> 4235773Scharnier#include <sys/mman.h> 4350471Speter#ifdef _THREAD_SAFE 441556Srgrimes#include <machine/reg.h> 451556Srgrimes#include <pthread.h> 461556Srgrimes#include "pthread_private.h" 471556Srgrimes#include "libc_private.h" 481556Srgrimes 491556Srgrimesstatic u_int64_t next_uniqueid = 1; 501556Srgrimes 511556Srgrimes#define OFF(f) offsetof(struct pthread, f) 521556Srgrimesint _thread_next_offset = OFF(tle.tqe_next); 531556Srgrimesint _thread_uniqueid_offset = OFF(uniqueid); 541556Srgrimesint _thread_state_offset = OFF(state); 551556Srgrimesint _thread_name_offset = OFF(name); 561556Srgrimesint _thread_sig_saved_offset = OFF(sig_saved); 571556Srgrimesint _thread_saved_sigcontext_offset = OFF(saved_sigcontext); 581556Srgrimesint _thread_saved_jmp_buf_offset = OFF(saved_jmp_buf); 591556Srgrimes#undef OFF 601556Srgrimes 611556Srgrimesint _thread_PS_RUNNING_value = PS_RUNNING; 621556Srgrimesint _thread_PS_DEAD_value = PS_DEAD; 631556Srgrimes 641556Srgrimesint 651556Srgrimespthread_create(pthread_t * thread, const pthread_attr_t * attr, 661556Srgrimes void *(*start_routine) (void *), void *arg) 671556Srgrimes{ 681556Srgrimes int f_gc = 0; 691556Srgrimes int ret = 0; 7051137Sgreen pthread_t gc_thread; 7151208Sgreen pthread_t new_thread; 721556Srgrimes pthread_attr_t pattr; 7351208Sgreen void *stack; 7454245Sgreen 751556Srgrimes /* 761556Srgrimes * Locking functions in libc are required when there are 771556Srgrimes * threads other than the initial thread. 781556Srgrimes */ 791556Srgrimes __isthreaded = 1; 801556Srgrimes 811556Srgrimes /* Allocate memory for the thread structure: */ 821556Srgrimes if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { 831556Srgrimes /* Insufficient memory to create a thread: */ 841556Srgrimes ret = EAGAIN; 8557523Sgreen } else { 861556Srgrimes /* Check if default thread attributes are required: */ 871556Srgrimes if (attr == NULL || *attr == NULL) { 8857523Sgreen /* Use the default thread attributes: */ 891556Srgrimes pattr = &pthread_attr_default; 901556Srgrimes } else { 911556Srgrimes pattr = *attr; 921556Srgrimes } 931556Srgrimes /* Check if a stack was specified in the thread attributes: */ 941556Srgrimes if ((stack = pattr->stackaddr_attr) != NULL) { 951556Srgrimes } 961556Srgrimes /* Allocate memory for a default-size stack: */ 971556Srgrimes else if (pattr->stacksize_attr == PTHREAD_STACK_DEFAULT) { 981556Srgrimes struct stack *spare_stack; 991556Srgrimes 1001556Srgrimes /* Allocate or re-use a default-size stack. */ 1011556Srgrimes 1021556Srgrimes /* 1031556Srgrimes * Use the garbage collector mutex for synchronization 1041556Srgrimes * of the spare stack list. 1051556Srgrimes */ 1061556Srgrimes if (pthread_mutex_lock(&_gc_mutex) != 0) 10719720Sphk PANIC("Cannot lock gc mutex"); 10830230Seivind 10948051Sgreen if ((spare_stack = SLIST_FIRST(&_stackq)) != NULL) { 1101556Srgrimes /* Use the spare stack. */ 1111556Srgrimes SLIST_REMOVE_HEAD(&_stackq, qe); 1121556Srgrimes 1131556Srgrimes /* Unlock the garbage collector mutex. */ 1141556Srgrimes if (pthread_mutex_unlock(&_gc_mutex) != 0) 1151556Srgrimes PANIC("Cannot unlock gc mutex"); 11648051Sgreen 11748051Sgreen stack = sizeof(struct stack) 11848051Sgreen + (void *) spare_stack 1191556Srgrimes - PTHREAD_STACK_DEFAULT; 1201556Srgrimes } else { 12148051Sgreen /* Allocate a new stack. */ 12248051Sgreen stack = _next_stack + PTHREAD_STACK_GUARD; 1231556Srgrimes 1241556Srgrimes /* 1251556Srgrimes * Even if stack allocation fails, we don't want 1261556Srgrimes * to try to use this location again, so 1271556Srgrimes * unconditionally decrement _next_stack. Under 1281556Srgrimes * normal operating conditions, the most likely 1291556Srgrimes * reason for an mmap() error is a stack 1301556Srgrimes * overflow of the adjacent thread stack. 1311556Srgrimes */ 1321556Srgrimes _next_stack -= (PTHREAD_STACK_DEFAULT 1331556Srgrimes + PTHREAD_STACK_GUARD); 1341556Srgrimes 1351556Srgrimes /* Unlock the garbage collector mutex. */ 1361556Srgrimes if (pthread_mutex_unlock(&_gc_mutex) != 0) 1371556Srgrimes PANIC("Cannot unlock gc mutex"); 1381556Srgrimes 1391556Srgrimes /* Red zone: */ 1401556Srgrimes if (mmap(stack - PTHREAD_STACK_GUARD, 1411556Srgrimes PTHREAD_STACK_GUARD, 0, MAP_ANON, 1421556Srgrimes -1, 0) == MAP_FAILED) { 1431556Srgrimes ret = EAGAIN; 1441556Srgrimes free(new_thread); 1451556Srgrimes } 1461556Srgrimes /* Stack: */ 14751249Sgreen else if (mmap(stack, PTHREAD_STACK_DEFAULT, 1481556Srgrimes PROT_READ | PROT_WRITE, MAP_STACK, 1491556Srgrimes -1, 0) == MAP_FAILED) { 1501556Srgrimes ret = EAGAIN; 1511556Srgrimes munmap(stack - PTHREAD_STACK_GUARD, 1521556Srgrimes PTHREAD_STACK_GUARD); 1531556Srgrimes free(new_thread); 15451249Sgreen } 1551556Srgrimes } 1561556Srgrimes } 1571556Srgrimes /* 1581556Srgrimes * The user wants a stack of a particular size. Lets hope they 1591556Srgrimes * really know what they want, and simply malloc the stack. 1601556Srgrimes */ 1611556Srgrimes else if ((stack = (void *) malloc(pattr->stacksize_attr)) 1621556Srgrimes == NULL) { 1631556Srgrimes /* Insufficient memory to create a thread: */ 1641556Srgrimes ret = EAGAIN; 1651556Srgrimes free(new_thread); 16651249Sgreen } 16751208Sgreen 16851208Sgreen /* Check for errors: */ 16951208Sgreen if (ret != 0) { 17051208Sgreen } else { 17151208Sgreen /* Initialise the thread structure: */ 1721556Srgrimes memset(new_thread, 0, sizeof(struct pthread)); 1731556Srgrimes new_thread->slice_usec = -1; 1741556Srgrimes new_thread->sig_saved = 0; 1751556Srgrimes new_thread->stack = stack; 1761556Srgrimes new_thread->start_routine = start_routine; 1771556Srgrimes new_thread->arg = arg; 1781556Srgrimes 17954278Sgreen new_thread->cancelflags = PTHREAD_CANCEL_ENABLE | 18054278Sgreen PTHREAD_CANCEL_DEFERRED; 1811556Srgrimes 1821556Srgrimes /* 1831556Srgrimes * Write a magic value to the thread structure 1841556Srgrimes * to help identify valid ones: 1851556Srgrimes */ 1861556Srgrimes new_thread->magic = PTHREAD_MAGIC; 18751208Sgreen 1881556Srgrimes /* Initialise the thread for signals: */ 18951208Sgreen new_thread->sigmask = _thread_run->sigmask; 19051208Sgreen 19151208Sgreen /* Initialise the jump buffer: */ 19251208Sgreen setjmp(new_thread->saved_jmp_buf); 1931556Srgrimes 1941556Srgrimes /* 1951556Srgrimes * Set up new stack frame so that it looks like it 1961556Srgrimes * returned from a longjmp() to the beginning of 1971556Srgrimes * _thread_start(). 1981556Srgrimes */ 19951208Sgreen#if defined(__FreeBSD__) 2001556Srgrimes#if defined(__alpha__) 20151208Sgreen new_thread->saved_jmp_buf[0]._jb[2] = (long) _thread_start; 20251208Sgreen new_thread->saved_jmp_buf[0]._jb[4 + R_RA] = 0; 20351208Sgreen new_thread->saved_jmp_buf[0]._jb[4 + R_T12] = (long) _thread_start; 20451208Sgreen#else 2051556Srgrimes new_thread->saved_jmp_buf[0]._jb[0] = (long) _thread_start; 2061556Srgrimes#endif 2071556Srgrimes#elif defined(__NetBSD__) 2081556Srgrimes#if defined(__alpha__) 2091556Srgrimes new_thread->saved_jmp_buf[2] = (long) _thread_start; 2101556Srgrimes new_thread->saved_jmp_buf[4 + R_RA] = 0; 2111556Srgrimes new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start; 21251137Sgreen#else 21351326Sgreen new_thread->saved_jmp_buf[0] = (long) _thread_start; 21451326Sgreen#endif 21551335Sgreen#else 21651335Sgreen#error "Don't recognize this operating system!" 2171556Srgrimes#endif 2181556Srgrimes 2191556Srgrimes /* The stack starts high and builds down: */ 2201556Srgrimes#if defined(__FreeBSD__) 2211556Srgrimes#if defined(__alpha__) 2221556Srgrimes new_thread->saved_jmp_buf[0]._jb[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 2231556Srgrimes#else 22451137Sgreen new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + pattr->stacksize_attr - sizeof(double)); 22551249Sgreen#endif 22651249Sgreen#elif defined(__NetBSD__) 2271556Srgrimes#if defined(__alpha__) 2281556Srgrimes new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 2291556Srgrimes#else 2301556Srgrimes new_thread->saved_jmp_buf[2] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); 2311556Srgrimes#endif 2321556Srgrimes#else 23351208Sgreen#error "Don't recognize this operating system!" 2341556Srgrimes#endif 23548051Sgreen 23651208Sgreen /* Copy the thread attributes: */ 23751208Sgreen memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); 23851249Sgreen 23951249Sgreen /* 24048051Sgreen * Check if this thread is to inherit the scheduling 2411556Srgrimes * attributes from its parent: 2421556Srgrimes */ 2431556Srgrimes if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) { 2441556Srgrimes /* Copy the scheduling attributes: */ 2451556Srgrimes new_thread->base_priority 2461556Srgrimes = _thread_run->base_priority; 2471556Srgrimes new_thread->attr.prio 2481556Srgrimes = _thread_run->base_priority; 2491556Srgrimes new_thread->attr.sched_policy 2501556Srgrimes = _thread_run->attr.sched_policy; 2511556Srgrimes } else { 2521556Srgrimes /* 2531556Srgrimes * Use just the thread priority, leaving the 2541556Srgrimes * other scheduling attributes as their 25551208Sgreen * default values: 2561556Srgrimes */ 25748051Sgreen new_thread->base_priority 25851208Sgreen = new_thread->attr.prio; 25951208Sgreen } 26051208Sgreen new_thread->active_priority = new_thread->base_priority; 26151208Sgreen new_thread->inherited_priority = 0; 26248051Sgreen 2631556Srgrimes /* Initialise the join queue for the new thread: */ 2641556Srgrimes TAILQ_INIT(&(new_thread->join_queue)); 2651556Srgrimes 2661556Srgrimes /* Initialize the mutex queue: */ 2671556Srgrimes TAILQ_INIT(&new_thread->mutexq); 2681556Srgrimes 2691556Srgrimes /* Initialise hooks in the thread structure: */ 2701556Srgrimes new_thread->specific_data = NULL; 2711556Srgrimes new_thread->cleanup = NULL; 2721556Srgrimes new_thread->flags = 0; 2731556Srgrimes new_thread->poll_data.nfds = 0; 2741556Srgrimes new_thread->poll_data.fds = NULL; 2751556Srgrimes 2761556Srgrimes /* 2771556Srgrimes * Defer signals to protect the scheduling queues 27851208Sgreen * from access by the signal handler: 2791556Srgrimes */ 2801556Srgrimes _thread_kern_sig_defer(); 2811556Srgrimes 2821556Srgrimes /* 2831556Srgrimes * Initialise the unique id which GDB uses to 2841556Srgrimes * track threads. 2851556Srgrimes */ 28651208Sgreen new_thread->uniqueid = next_uniqueid++; 2871556Srgrimes 2881556Srgrimes /* 28951208Sgreen * Check if the garbage collector thread 29054245Sgreen * needs to be started. 2911556Srgrimes */ 29251208Sgreen f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial); 2931556Srgrimes 2941556Srgrimes /* Add the thread to the linked list of all threads: */ 2951556Srgrimes TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle); 2961556Srgrimes 2971556Srgrimes if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) { 2981556Srgrimes new_thread->state = PS_SUSPENDED; 2991556Srgrimes PTHREAD_WAITQ_INSERT(new_thread); 3001556Srgrimes } else { 3011556Srgrimes new_thread->state = PS_RUNNING; 3021556Srgrimes PTHREAD_PRIOQ_INSERT_TAIL(new_thread); 3031556Srgrimes } 30431120Sjoerg 30530312Sjoerg /* 3061556Srgrimes * Undefer and handle pending signals, yielding 3071556Srgrimes * if necessary. 3081556Srgrimes */ 3091556Srgrimes _thread_kern_sig_undefer(); 3101556Srgrimes 3111556Srgrimes /* Return a pointer to the thread structure: */ 3121556Srgrimes (*thread) = new_thread; 3131556Srgrimes 3141556Srgrimes /* Schedule the new user thread: */ 3151556Srgrimes _thread_kern_sched(NULL); 3161556Srgrimes 3171556Srgrimes /* 3181556Srgrimes * Start a garbage collector thread 3191556Srgrimes * if necessary. 32051208Sgreen */ 32151208Sgreen if (f_gc && pthread_create(&gc_thread,NULL, 32251208Sgreen _thread_gc,NULL) != 0) 3231556Srgrimes PANIC("Can't create gc thread"); 3241556Srgrimes } 3251556Srgrimes } 3261556Srgrimes 3271556Srgrimes /* Return the status: */ 3281556Srgrimes return (ret); 3291556Srgrimes} 3301556Srgrimes 3311556Srgrimesvoid 3321556Srgrimes_thread_start(void) 3331556Srgrimes{ 3341556Srgrimes /* We just left the scheduler via longjmp: */ 3351556Srgrimes _thread_kern_in_sched = 0; 3361556Srgrimes 33754278Sgreen /* Run the current thread's start routine with argument: */ 33854278Sgreen pthread_exit(_thread_run->start_routine(_thread_run->arg)); 3391556Srgrimes 3401556Srgrimes /* This point should never be reached. */ 3411556Srgrimes PANIC("Thread has resumed after exit"); 34248051Sgreen} 3431556Srgrimes#endif 34448051Sgreen