1bb535300SJeff Roberson /* 2bb535300SJeff Roberson * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 3bb535300SJeff Roberson * All rights reserved. 4bb535300SJeff Roberson * 5bb535300SJeff Roberson * Redistribution and use in source and binary forms, with or without 6bb535300SJeff Roberson * modification, are permitted provided that the following conditions 7bb535300SJeff Roberson * are met: 8bb535300SJeff Roberson * 1. Redistributions of source code must retain the above copyright 9bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer. 10bb535300SJeff Roberson * 2. Redistributions in binary form must reproduce the above copyright 11bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer in the 12bb535300SJeff Roberson * documentation and/or other materials provided with the distribution. 13bb535300SJeff Roberson * 3. All advertising materials mentioning features or use of this software 14bb535300SJeff Roberson * must display the following acknowledgement: 15bb535300SJeff Roberson * This product includes software developed by John Birrell. 16bb535300SJeff Roberson * 4. Neither the name of the author nor the names of any co-contributors 17bb535300SJeff Roberson * may be used to endorse or promote products derived from this software 18bb535300SJeff Roberson * without specific prior written permission. 19bb535300SJeff Roberson * 20bb535300SJeff Roberson * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 21bb535300SJeff Roberson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22bb535300SJeff Roberson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23bb535300SJeff Roberson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24bb535300SJeff Roberson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25bb535300SJeff Roberson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26bb535300SJeff Roberson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27bb535300SJeff Roberson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28bb535300SJeff Roberson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29bb535300SJeff Roberson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30bb535300SJeff Roberson * SUCH DAMAGE. 31bb535300SJeff Roberson * 32bb535300SJeff Roberson * $FreeBSD$ 33bb535300SJeff Roberson */ 34bb535300SJeff Roberson 35bb535300SJeff Roberson /* Allocate space for global thread variables here: */ 36bb535300SJeff Roberson #define GLOBAL_PTHREAD_PRIVATE 37bb535300SJeff Roberson 38bb535300SJeff Roberson #include "namespace.h" 39bb535300SJeff Roberson #include <sys/param.h> 40bb535300SJeff Roberson #include <sys/types.h> 41bb535300SJeff Roberson #include <machine/reg.h> 42bb535300SJeff Roberson 43bb535300SJeff Roberson #include <sys/ioctl.h> 44bb535300SJeff Roberson #include <sys/mount.h> 45bb535300SJeff Roberson #include <sys/uio.h> 46bb535300SJeff Roberson #include <sys/socket.h> 47bb535300SJeff Roberson #include <sys/event.h> 48bb535300SJeff Roberson #include <sys/stat.h> 49bb535300SJeff Roberson #include <sys/sysctl.h> 50bb535300SJeff Roberson #include <sys/time.h> 51bb535300SJeff Roberson #include <sys/ttycom.h> 52bb535300SJeff Roberson #include <sys/user.h> 53bb535300SJeff Roberson #include <sys/wait.h> 54bb535300SJeff Roberson #include <sys/mman.h> 55bb535300SJeff Roberson #include <dirent.h> 56bb535300SJeff Roberson #include <errno.h> 57bb535300SJeff Roberson #include <fcntl.h> 58bb535300SJeff Roberson #include <paths.h> 59bb535300SJeff Roberson #include <pthread.h> 60bb535300SJeff Roberson #include <signal.h> 61bb535300SJeff Roberson #include <stdio.h> 62bb535300SJeff Roberson #include <stdlib.h> 63bb535300SJeff Roberson #include <string.h> 64bb535300SJeff Roberson #include <unistd.h> 65bb535300SJeff Roberson #include "un-namespace.h" 66bb535300SJeff Roberson 67bb535300SJeff Roberson #include "thr_private.h" 68bb535300SJeff Roberson 69bb535300SJeff Roberson /* 70bb535300SJeff Roberson * All weak references used within libc should be in this table. 71bb535300SJeff Roberson * This will is so that static libraries will work. 72bb535300SJeff Roberson * 73bb535300SJeff Roberson * XXXTHR - Check this list. 74bb535300SJeff Roberson */ 75bb535300SJeff Roberson static void *references[] = { 76bb535300SJeff Roberson &_accept, 77bb535300SJeff Roberson &_bind, 78bb535300SJeff Roberson &_close, 79bb535300SJeff Roberson &_connect, 80bb535300SJeff Roberson &_dup, 81bb535300SJeff Roberson &_dup2, 82bb535300SJeff Roberson &_execve, 83bb535300SJeff Roberson &_fcntl, 84bb535300SJeff Roberson &_flock, 85bb535300SJeff Roberson &_flockfile, 86bb535300SJeff Roberson &_fstat, 87bb535300SJeff Roberson &_fstatfs, 88bb535300SJeff Roberson &_fsync, 89bb535300SJeff Roberson &_funlockfile, 90bb535300SJeff Roberson &_getdirentries, 91bb535300SJeff Roberson &_getlogin, 92bb535300SJeff Roberson &_getpeername, 93bb535300SJeff Roberson &_getsockname, 94bb535300SJeff Roberson &_getsockopt, 95bb535300SJeff Roberson &_ioctl, 96bb535300SJeff Roberson &_kevent, 97bb535300SJeff Roberson &_listen, 98bb535300SJeff Roberson &_nanosleep, 99bb535300SJeff Roberson &_open, 100bb535300SJeff Roberson &_pthread_getspecific, 101bb535300SJeff Roberson &_pthread_key_create, 102bb535300SJeff Roberson &_pthread_key_delete, 103bb535300SJeff Roberson &_pthread_mutex_destroy, 104bb535300SJeff Roberson &_pthread_mutex_init, 105bb535300SJeff Roberson &_pthread_mutex_lock, 106bb535300SJeff Roberson &_pthread_mutex_trylock, 107bb535300SJeff Roberson &_pthread_mutex_unlock, 108bb535300SJeff Roberson &_pthread_mutexattr_init, 109bb535300SJeff Roberson &_pthread_mutexattr_destroy, 110bb535300SJeff Roberson &_pthread_mutexattr_settype, 111bb535300SJeff Roberson &_pthread_once, 112bb535300SJeff Roberson &_pthread_setspecific, 113bb535300SJeff Roberson &_read, 114bb535300SJeff Roberson &_readv, 115bb535300SJeff Roberson &_recvfrom, 116bb535300SJeff Roberson &_recvmsg, 117bb535300SJeff Roberson &_select, 118bb535300SJeff Roberson &_sendmsg, 119bb535300SJeff Roberson &_sendto, 120bb535300SJeff Roberson &_setsockopt, 121bb535300SJeff Roberson &_sigaction, 122bb535300SJeff Roberson &_sigprocmask, 123bb535300SJeff Roberson &_sigsuspend, 124bb535300SJeff Roberson &_socket, 125bb535300SJeff Roberson &_socketpair, 126bb535300SJeff Roberson &_wait4, 127bb535300SJeff Roberson &_write, 128bb535300SJeff Roberson &_writev 129bb535300SJeff Roberson }; 130bb535300SJeff Roberson 131bb535300SJeff Roberson /* 132bb535300SJeff Roberson * These are needed when linking statically. All references within 133bb535300SJeff Roberson * libgcc (and in the future libc) to these routines are weak, but 134bb535300SJeff Roberson * if they are not (strongly) referenced by the application or other 135bb535300SJeff Roberson * libraries, then the actual functions will not be loaded. 136bb535300SJeff Roberson */ 137bb535300SJeff Roberson static void *libgcc_references[] = { 138bb535300SJeff Roberson &_pthread_once, 139bb535300SJeff Roberson &_pthread_key_create, 140bb535300SJeff Roberson &_pthread_key_delete, 141bb535300SJeff Roberson &_pthread_getspecific, 142bb535300SJeff Roberson &_pthread_setspecific, 143bb535300SJeff Roberson &_pthread_mutex_init, 144bb535300SJeff Roberson &_pthread_mutex_destroy, 145bb535300SJeff Roberson &_pthread_mutex_lock, 146bb535300SJeff Roberson &_pthread_mutex_trylock, 147bb535300SJeff Roberson &_pthread_mutex_unlock 148bb535300SJeff Roberson }; 149bb535300SJeff Roberson 150bb535300SJeff Roberson int _pthread_guard_default; 151bb535300SJeff Roberson int _pthread_page_size; 152bb535300SJeff Roberson 153bb535300SJeff Roberson /* 154bb535300SJeff Roberson * Threaded process initialization 155bb535300SJeff Roberson */ 156bb535300SJeff Roberson void 157bb535300SJeff Roberson _thread_init(void) 158bb535300SJeff Roberson { 159bb535300SJeff Roberson struct pthread *pthread; 160bb535300SJeff Roberson int fd; 161bb535300SJeff Roberson int flags; 162bb535300SJeff Roberson int i; 163bb535300SJeff Roberson size_t len; 164bb535300SJeff Roberson int mib[2]; 165bb535300SJeff Roberson sigset_t set; 166bb535300SJeff Roberson 167bb535300SJeff Roberson struct clockinfo clockinfo; 168bb535300SJeff Roberson struct sigaction act; 169bb535300SJeff Roberson 170bb535300SJeff Roberson /* Check if this function has already been called: */ 171bb535300SJeff Roberson if (_thread_initial) 172bb535300SJeff Roberson /* Only initialise the threaded application once. */ 173bb535300SJeff Roberson return; 174bb535300SJeff Roberson 175bb535300SJeff Roberson _pthread_page_size = getpagesize(); 176bb535300SJeff Roberson _pthread_guard_default = getpagesize(); 177bb535300SJeff Roberson 178bb535300SJeff Roberson pthread_attr_default.guardsize_attr = _pthread_guard_default; 179bb535300SJeff Roberson 180bb535300SJeff Roberson 181bb535300SJeff Roberson /* 182bb535300SJeff Roberson * Make gcc quiescent about {,libgcc_}references not being 183bb535300SJeff Roberson * referenced: 184bb535300SJeff Roberson */ 185bb535300SJeff Roberson if ((references[0] == NULL) || (libgcc_references[0] == NULL)) 186bb535300SJeff Roberson PANIC("Failed loading mandatory references in _thread_init"); 187bb535300SJeff Roberson 188bb535300SJeff Roberson /* 189bb535300SJeff Roberson * Check for the special case of this process running as 190bb535300SJeff Roberson * or in place of init as pid = 1: 191bb535300SJeff Roberson */ 192bb535300SJeff Roberson if (getpid() == 1) { 193bb535300SJeff Roberson /* 194bb535300SJeff Roberson * Setup a new session for this process which is 195bb535300SJeff Roberson * assumed to be running as root. 196bb535300SJeff Roberson */ 197bb535300SJeff Roberson if (setsid() == -1) 198bb535300SJeff Roberson PANIC("Can't set session ID"); 199bb535300SJeff Roberson if (revoke(_PATH_CONSOLE) != 0) 200bb535300SJeff Roberson PANIC("Can't revoke console"); 201bb535300SJeff Roberson if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0) 202bb535300SJeff Roberson PANIC("Can't open console"); 203bb535300SJeff Roberson if (setlogin("root") == -1) 204bb535300SJeff Roberson PANIC("Can't set login to root"); 205bb535300SJeff Roberson if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1) 206bb535300SJeff Roberson PANIC("Can't set controlling terminal"); 207bb535300SJeff Roberson if (__sys_dup2(fd, 0) == -1 || 208bb535300SJeff Roberson __sys_dup2(fd, 1) == -1 || 209bb535300SJeff Roberson __sys_dup2(fd, 2) == -1) 210bb535300SJeff Roberson PANIC("Can't dup2"); 211bb535300SJeff Roberson } 212bb535300SJeff Roberson 213bb535300SJeff Roberson /* Allocate memory for the thread structure of the initial thread: */ 214bb535300SJeff Roberson if ((pthread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { 215bb535300SJeff Roberson /* 216bb535300SJeff Roberson * Insufficient memory to initialise this application, so 217bb535300SJeff Roberson * abort: 218bb535300SJeff Roberson */ 219bb535300SJeff Roberson PANIC("Cannot allocate memory for initial thread"); 220bb535300SJeff Roberson } 221bb535300SJeff Roberson _thread_initial = pthread; 222bb535300SJeff Roberson pthread->arch_id = _set_curthread(pthread); 223bb535300SJeff Roberson 224bb535300SJeff Roberson /* Zero the initial thread structure: */ 225bb535300SJeff Roberson memset(pthread, 0, sizeof(struct pthread)); 226bb535300SJeff Roberson /* Get our thread id. */ 227bb535300SJeff Roberson thr_self(&pthread->thr_id); 228bb535300SJeff Roberson 229bb535300SJeff Roberson /* Give this thread default attributes: */ 230bb535300SJeff Roberson memcpy((void *) &pthread->attr, &pthread_attr_default, 231bb535300SJeff Roberson sizeof(struct pthread_attr)); 232bb535300SJeff Roberson 233bb535300SJeff Roberson /* Find the stack top */ 234bb535300SJeff Roberson mib[0] = CTL_KERN; 235bb535300SJeff Roberson mib[1] = KERN_USRSTACK; 236bb535300SJeff Roberson len = sizeof (_usrstack); 237bb535300SJeff Roberson if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1) 238bb535300SJeff Roberson _usrstack = (void *)USRSTACK; 239bb535300SJeff Roberson /* 240bb535300SJeff Roberson * Create a red zone below the main stack. All other stacks are 241bb535300SJeff Roberson * constrained to a maximum size by the paramters passed to 242bb535300SJeff Roberson * mmap(), but this stack is only limited by resource limits, so 243bb535300SJeff Roberson * this stack needs an explicitly mapped red zone to protect the 244bb535300SJeff Roberson * thread stack that is just beyond. 245bb535300SJeff Roberson */ 246bb535300SJeff Roberson if (mmap(_usrstack - PTHREAD_STACK_INITIAL - 247bb535300SJeff Roberson _pthread_guard_default, _pthread_guard_default, 0, 248bb535300SJeff Roberson MAP_ANON, -1, 0) == MAP_FAILED) 249bb535300SJeff Roberson PANIC("Cannot allocate red zone for initial thread"); 250bb535300SJeff Roberson 251bb535300SJeff Roberson /* Set the main thread stack pointer. */ 252bb535300SJeff Roberson pthread->stack = _usrstack - PTHREAD_STACK_INITIAL; 253bb535300SJeff Roberson 254bb535300SJeff Roberson /* Set the stack attributes. */ 255bb535300SJeff Roberson pthread->attr.stackaddr_attr = pthread->stack; 256bb535300SJeff Roberson pthread->attr.stacksize_attr = PTHREAD_STACK_INITIAL; 257bb535300SJeff Roberson 258bb535300SJeff Roberson /* 259bb535300SJeff Roberson * Write a magic value to the thread structure 260bb535300SJeff Roberson * to help identify valid ones: 261bb535300SJeff Roberson */ 262bb535300SJeff Roberson pthread->magic = PTHREAD_MAGIC; 263bb535300SJeff Roberson 264bb535300SJeff Roberson /* Set the initial cancel state */ 265bb535300SJeff Roberson pthread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED; 266bb535300SJeff Roberson 267bb535300SJeff Roberson /* Setup the context for initial thread. */ 268bb535300SJeff Roberson getcontext(&pthread->ctx); 269bb535300SJeff Roberson pthread->ctx.uc_stack.ss_sp = pthread->stack; 270bb535300SJeff Roberson pthread->ctx.uc_stack.ss_size = PTHREAD_STACK_INITIAL; 271bb535300SJeff Roberson 272bb535300SJeff Roberson /* Default the priority of the initial thread: */ 273bb535300SJeff Roberson pthread->base_priority = PTHREAD_DEFAULT_PRIORITY; 274bb535300SJeff Roberson pthread->active_priority = PTHREAD_DEFAULT_PRIORITY; 275bb535300SJeff Roberson pthread->inherited_priority = 0; 276bb535300SJeff Roberson 277bb535300SJeff Roberson /* Initialise the state of the initial thread: */ 278bb535300SJeff Roberson pthread->state = PS_RUNNING; 279bb535300SJeff Roberson 280bb535300SJeff Roberson /* Set the name of the thread: */ 281bb535300SJeff Roberson pthread->name = strdup("_thread_initial"); 282bb535300SJeff Roberson 283bb535300SJeff Roberson /* Initialize joiner to NULL (no joiner): */ 284bb535300SJeff Roberson pthread->joiner = NULL; 285bb535300SJeff Roberson 286bb535300SJeff Roberson /* Initialize the owned mutex queue and count: */ 287bb535300SJeff Roberson TAILQ_INIT(&(pthread->mutexq)); 288bb535300SJeff Roberson pthread->priority_mutex_count = 0; 289bb535300SJeff Roberson 290bb535300SJeff Roberson /* Initialise the rest of the fields: */ 291bb535300SJeff Roberson pthread->specific = NULL; 292bb535300SJeff Roberson pthread->cleanup = NULL; 293bb535300SJeff Roberson pthread->flags = 0; 294bb535300SJeff Roberson pthread->error = 0; 295bb535300SJeff Roberson TAILQ_INIT(&_thread_list); 296bb535300SJeff Roberson TAILQ_INSERT_HEAD(&_thread_list, pthread, tle); 297bb535300SJeff Roberson 298bb535300SJeff Roberson /* Enter a loop to get the existing signal status: */ 299bb535300SJeff Roberson for (i = 1; i < NSIG; i++) { 300bb535300SJeff Roberson /* Check for signals which cannot be trapped. */ 301bb535300SJeff Roberson if (i == SIGKILL || i == SIGSTOP) 302bb535300SJeff Roberson continue; 303bb535300SJeff Roberson 304bb535300SJeff Roberson /* Get the signal handler details. */ 305bb535300SJeff Roberson if (__sys_sigaction(i, NULL, 306bb535300SJeff Roberson &_thread_sigact[i - 1]) != 0) 307bb535300SJeff Roberson PANIC("Cannot read signal handler info"); 308bb535300SJeff Roberson } 309bb535300SJeff Roberson act.sa_sigaction = _thread_sig_wrapper; 310bb535300SJeff Roberson act.sa_flags = SA_SIGINFO; 311bb535300SJeff Roberson SIGFILLSET(act.sa_mask); 312bb535300SJeff Roberson 313bb535300SJeff Roberson if (__sys_sigaction(SIGTHR, &act, NULL)) 314bb535300SJeff Roberson PANIC("Cannot set SIGTHR handler.\n"); 315bb535300SJeff Roberson 316bb535300SJeff Roberson SIGEMPTYSET(set); 317bb535300SJeff Roberson SIGADDSET(set, SIGTHR); 318bb535300SJeff Roberson __sys_sigprocmask(SIG_BLOCK, &set, 0); 319bb535300SJeff Roberson 320bb535300SJeff Roberson /* Get the kernel clockrate: */ 321bb535300SJeff Roberson mib[0] = CTL_KERN; 322bb535300SJeff Roberson mib[1] = KERN_CLOCKRATE; 323bb535300SJeff Roberson len = sizeof (struct clockinfo); 324bb535300SJeff Roberson if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0) 325bb535300SJeff Roberson _clock_res_usec = clockinfo.tick > CLOCK_RES_USEC_MIN ? 326bb535300SJeff Roberson clockinfo.tick : CLOCK_RES_USEC_MIN; 327bb535300SJeff Roberson 328bb535300SJeff Roberson /* Initialise the garbage collector mutex and condition variable. */ 329bb535300SJeff Roberson if (_pthread_mutex_init(&_gc_mutex,NULL) != 0 || 330bb535300SJeff Roberson pthread_cond_init(&_gc_cond,NULL) != 0) 331bb535300SJeff Roberson PANIC("Failed to initialise garbage collector mutex or condvar"); 332bb535300SJeff Roberson } 333bb535300SJeff Roberson 334bb535300SJeff Roberson struct pthread * 335bb535300SJeff Roberson _get_curthread_slow(void) 336bb535300SJeff Roberson { 337bb535300SJeff Roberson struct pthread *td; 338bb535300SJeff Roberson thr_id_t id; 339bb535300SJeff Roberson 340bb535300SJeff Roberson if (_thread_initial == NULL) 341bb535300SJeff Roberson _thread_init(); 342bb535300SJeff Roberson 343bb535300SJeff Roberson thr_self(&id); 344bb535300SJeff Roberson TAILQ_FOREACH(td, &_thread_list, tle) 345bb535300SJeff Roberson if (td->thr_id == id) 346bb535300SJeff Roberson return (td); 347bb535300SJeff Roberson return (NULL); 348bb535300SJeff Roberson } 349bb535300SJeff Roberson 350bb535300SJeff Roberson /* 351bb535300SJeff Roberson * Special start up code for NetBSD/Alpha 352bb535300SJeff Roberson */ 353bb535300SJeff Roberson #if defined(__NetBSD__) && defined(__alpha__) 354bb535300SJeff Roberson int 355bb535300SJeff Roberson main(int argc, char *argv[], char *env); 356bb535300SJeff Roberson 357bb535300SJeff Roberson int 358bb535300SJeff Roberson _thread_main(int argc, char *argv[], char *env) 359bb535300SJeff Roberson { 360bb535300SJeff Roberson _thread_init(); 361bb535300SJeff Roberson return (main(argc, argv, env)); 362bb535300SJeff Roberson } 363bb535300SJeff Roberson #endif 364