1*f782e995Sdrochner /* $NetBSD: pthread.c,v 1.48 2006/04/24 18:39:36 drochner Exp $ */ 2c62a74e6Sthorpej 3c62a74e6Sthorpej /*- 4ec2c1698Snathanw * Copyright (c) 2001,2002,2003 The NetBSD Foundation, Inc. 5c62a74e6Sthorpej * All rights reserved. 6c62a74e6Sthorpej * 7c62a74e6Sthorpej * This code is derived from software contributed to The NetBSD Foundation 8c62a74e6Sthorpej * by Nathan J. Williams. 9c62a74e6Sthorpej * 10c62a74e6Sthorpej * Redistribution and use in source and binary forms, with or without 11c62a74e6Sthorpej * modification, are permitted provided that the following conditions 12c62a74e6Sthorpej * are met: 13c62a74e6Sthorpej * 1. Redistributions of source code must retain the above copyright 14c62a74e6Sthorpej * notice, this list of conditions and the following disclaimer. 15c62a74e6Sthorpej * 2. Redistributions in binary form must reproduce the above copyright 16c62a74e6Sthorpej * notice, this list of conditions and the following disclaimer in the 17c62a74e6Sthorpej * documentation and/or other materials provided with the distribution. 18c62a74e6Sthorpej * 3. All advertising materials mentioning features or use of this software 19c62a74e6Sthorpej * must display the following acknowledgement: 20c62a74e6Sthorpej * This product includes software developed by the NetBSD 21c62a74e6Sthorpej * Foundation, Inc. and its contributors. 22c62a74e6Sthorpej * 4. Neither the name of The NetBSD Foundation nor the names of its 23c62a74e6Sthorpej * contributors may be used to endorse or promote products derived 24c62a74e6Sthorpej * from this software without specific prior written permission. 25c62a74e6Sthorpej * 26c62a74e6Sthorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27c62a74e6Sthorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28c62a74e6Sthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29c62a74e6Sthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30c62a74e6Sthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31c62a74e6Sthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32c62a74e6Sthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33c62a74e6Sthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34c62a74e6Sthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35c62a74e6Sthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36c62a74e6Sthorpej * POSSIBILITY OF SUCH DAMAGE. 37c62a74e6Sthorpej */ 38c62a74e6Sthorpej 39f043c0fbSlukem #include <sys/cdefs.h> 40*f782e995Sdrochner __RCSID("$NetBSD: pthread.c,v 1.48 2006/04/24 18:39:36 drochner Exp $"); 41f043c0fbSlukem 42c62a74e6Sthorpej #include <err.h> 43c62a74e6Sthorpej #include <errno.h> 44c62a74e6Sthorpej #include <lwp.h> 45c62a74e6Sthorpej #include <signal.h> 468bcff70bSnathanw #include <stdio.h> 47c62a74e6Sthorpej #include <stdlib.h> 48c62a74e6Sthorpej #include <string.h> 490172694eSnathanw #include <syslog.h> 50c62a74e6Sthorpej #include <ucontext.h> 518bcff70bSnathanw #include <unistd.h> 52f2f10664Scl #include <sys/param.h> 53f2f10664Scl #include <sys/sysctl.h> 54cca94056Schristos #ifdef PTHREAD_MLOCK_KLUDGE 55cca94056Schristos #include <sys/mman.h> 56cca94056Schristos #endif 578bcff70bSnathanw 58c62a74e6Sthorpej #include <sched.h> 59c62a74e6Sthorpej #include "pthread.h" 60c62a74e6Sthorpej #include "pthread_int.h" 61c62a74e6Sthorpej 62c62a74e6Sthorpej #ifdef PTHREAD_MAIN_DEBUG 63c62a74e6Sthorpej #define SDPRINTF(x) DPRINTF(x) 64c62a74e6Sthorpej #else 65c62a74e6Sthorpej #define SDPRINTF(x) 66c62a74e6Sthorpej #endif 67c62a74e6Sthorpej 68c62a74e6Sthorpej static void pthread__create_tramp(void *(*start)(void *), void *arg); 696b2b9c62Syamt static void pthread__dead(pthread_t, pthread_t); 70c62a74e6Sthorpej 71c62a74e6Sthorpej int pthread__started; 72c62a74e6Sthorpej 7394a458ceSchs pthread_spin_t pthread__allqueue_lock = __SIMPLELOCK_UNLOCKED; 74c62a74e6Sthorpej struct pthread_queue_t pthread__allqueue; 75c62a74e6Sthorpej 7694a458ceSchs pthread_spin_t pthread__deadqueue_lock = __SIMPLELOCK_UNLOCKED; 77c62a74e6Sthorpej struct pthread_queue_t pthread__deadqueue; 78f2f10664Scl struct pthread_queue_t *pthread__reidlequeue; 79c62a74e6Sthorpej 80c62a74e6Sthorpej static int nthreads; 81c62a74e6Sthorpej static int nextthread; 8294a458ceSchs static pthread_spin_t nextthread_lock = __SIMPLELOCK_UNLOCKED; 83c62a74e6Sthorpej static pthread_attr_t pthread_default_attr; 84c62a74e6Sthorpej 850172694eSnathanw enum { 860172694eSnathanw DIAGASSERT_ABORT = 1<<0, 870172694eSnathanw DIAGASSERT_STDERR = 1<<1, 880172694eSnathanw DIAGASSERT_SYSLOG = 1<<2 890172694eSnathanw }; 90df277271Snathanw 910172694eSnathanw static int pthread__diagassert = DIAGASSERT_ABORT | DIAGASSERT_STDERR; 92df277271Snathanw 9394a458ceSchs pthread_spin_t pthread__runqueue_lock = __SIMPLELOCK_UNLOCKED; 94c62a74e6Sthorpej struct pthread_queue_t pthread__runqueue; 95c62a74e6Sthorpej struct pthread_queue_t pthread__idlequeue; 9638b1c6f4Schristos struct pthread_queue_t pthread__suspqueue; 97c62a74e6Sthorpej 98f2f10664Scl int pthread__concurrency, pthread__maxconcurrency; 99f2f10664Scl 100*f782e995Sdrochner int _sys___sigprocmask14(int, const sigset_t *, sigset_t *); 101*f782e995Sdrochner 102c62a74e6Sthorpej __strong_alias(__libc_thr_self,pthread_self) 1037dc01dbfSthorpej __strong_alias(__libc_thr_create,pthread_create) 1047dc01dbfSthorpej __strong_alias(__libc_thr_exit,pthread_exit) 105c62a74e6Sthorpej __strong_alias(__libc_thr_errno,pthread__errno) 1069e5c8705Snathanw __strong_alias(__libc_thr_setcancelstate,pthread_setcancelstate) 107c62a74e6Sthorpej 108c62a74e6Sthorpej /* 109c62a74e6Sthorpej * Static library kludge. Place a reference to a symbol any library 110c62a74e6Sthorpej * file which does not already have a reference here. 111c62a74e6Sthorpej */ 112c62a74e6Sthorpej extern int pthread__cancel_stub_binder; 113c62a74e6Sthorpej extern int pthread__sched_binder; 1148bcff70bSnathanw extern struct pthread_queue_t pthread__nanosleeping; 115c62a74e6Sthorpej 116c62a74e6Sthorpej void *pthread__static_lib_binder[] = { 117c62a74e6Sthorpej &pthread__cancel_stub_binder, 118c62a74e6Sthorpej pthread_cond_init, 119c62a74e6Sthorpej pthread_mutex_init, 120c62a74e6Sthorpej pthread_rwlock_init, 121c62a74e6Sthorpej pthread_barrier_init, 122c62a74e6Sthorpej pthread_key_create, 123bd9a18b7Snathanw pthread_setspecific, 124c62a74e6Sthorpej &pthread__sched_binder, 1258bcff70bSnathanw &pthread__nanosleeping 126c62a74e6Sthorpej }; 127c62a74e6Sthorpej 128c62a74e6Sthorpej /* 129c62a74e6Sthorpej * This needs to be started by the library loading code, before main() 130c62a74e6Sthorpej * gets to run, for various things that use the state of the initial thread 131c62a74e6Sthorpej * to work properly (thread-specific data is an application-visible example; 132c62a74e6Sthorpej * spinlock counts for mutexes is an internal example). 133c62a74e6Sthorpej */ 134c62a74e6Sthorpej void 135c62a74e6Sthorpej pthread_init(void) 136c62a74e6Sthorpej { 137c62a74e6Sthorpej pthread_t first; 1380172694eSnathanw char *p; 139f2f10664Scl int i, mib[2], ncpu; 140f2f10664Scl size_t len; 141c62a74e6Sthorpej extern int __isthreaded; 142cca94056Schristos #ifdef PTHREAD_MLOCK_KLUDGE 143cca94056Schristos int ret; 144cca94056Schristos #endif 145c62a74e6Sthorpej 146f2f10664Scl mib[0] = CTL_HW; 147f2f10664Scl mib[1] = HW_NCPU; 148f2f10664Scl 149f2f10664Scl len = sizeof(ncpu); 150f2f10664Scl sysctl(mib, 2, &ncpu, &len, NULL, 0); 151f2f10664Scl 152c62a74e6Sthorpej /* Initialize locks first; they're needed elsewhere. */ 153f2f10664Scl pthread__lockprim_init(ncpu); 154f2f10664Scl 155f2f10664Scl /* Find out requested/possible concurrency */ 156f2f10664Scl p = getenv("PTHREAD_CONCURRENCY"); 157b35aef8dSchristos pthread__maxconcurrency = p ? atoi(p) : 1; 1583a610280Schristos 159f2f10664Scl if (pthread__maxconcurrency < 1) 160f2f10664Scl pthread__maxconcurrency = 1; 161f2f10664Scl if (pthread__maxconcurrency > ncpu) 162f2f10664Scl pthread__maxconcurrency = ncpu; 163f2f10664Scl 164f2f10664Scl /* Allocate data structures */ 165f2f10664Scl pthread__reidlequeue = (struct pthread_queue_t *)malloc 166f2f10664Scl (pthread__maxconcurrency * sizeof(struct pthread_queue_t)); 167f2f10664Scl if (pthread__reidlequeue == NULL) 168f2f10664Scl err(1, "Couldn't allocate memory for pthread__reidlequeue"); 169c62a74e6Sthorpej 170c62a74e6Sthorpej /* Basic data structure setup */ 171c62a74e6Sthorpej pthread_attr_init(&pthread_default_attr); 172c62a74e6Sthorpej PTQ_INIT(&pthread__allqueue); 173c62a74e6Sthorpej PTQ_INIT(&pthread__deadqueue); 174cca94056Schristos #ifdef PTHREAD_MLOCK_KLUDGE 175cca94056Schristos ret = mlock(&pthread__deadqueue, sizeof(pthread__deadqueue)); 176cca94056Schristos pthread__assert(ret == 0); 177cca94056Schristos #endif 178c62a74e6Sthorpej PTQ_INIT(&pthread__runqueue); 179c62a74e6Sthorpej PTQ_INIT(&pthread__idlequeue); 180f2f10664Scl for (i = 0; i < pthread__maxconcurrency; i++) 181f2f10664Scl PTQ_INIT(&pthread__reidlequeue[i]); 18268a63a40Snathanw nthreads = 1; 183c62a74e6Sthorpej 184c62a74e6Sthorpej /* Create the thread structure corresponding to main() */ 185c62a74e6Sthorpej pthread__initmain(&first); 186c62a74e6Sthorpej pthread__initthread(first, first); 187c62a74e6Sthorpej first->pt_state = PT_STATE_RUNNING; 188*f782e995Sdrochner _sys___sigprocmask14(0, NULL, &first->pt_sigmask); 189c62a74e6Sthorpej PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq); 190c62a74e6Sthorpej 191c62a74e6Sthorpej /* Start subsystems */ 192c62a74e6Sthorpej pthread__signal_init(); 193c62a74e6Sthorpej PTHREAD_MD_INIT 194c62a74e6Sthorpej #ifdef PTHREAD__DEBUG 195f2f10664Scl pthread__debug_init(ncpu); 196c62a74e6Sthorpej #endif 197c62a74e6Sthorpej 1980172694eSnathanw for (p = getenv("PTHREAD_DIAGASSERT"); p && *p; p++) { 1990172694eSnathanw switch (*p) { 2000172694eSnathanw case 'a': 2010172694eSnathanw pthread__diagassert |= DIAGASSERT_ABORT; 2020172694eSnathanw break; 2030172694eSnathanw case 'A': 2040172694eSnathanw pthread__diagassert &= ~DIAGASSERT_ABORT; 2050172694eSnathanw break; 2060172694eSnathanw case 'e': 2070172694eSnathanw pthread__diagassert |= DIAGASSERT_STDERR; 2080172694eSnathanw break; 2090172694eSnathanw case 'E': 2100172694eSnathanw pthread__diagassert &= ~DIAGASSERT_STDERR; 2110172694eSnathanw break; 2120172694eSnathanw case 'l': 2130172694eSnathanw pthread__diagassert |= DIAGASSERT_SYSLOG; 2140172694eSnathanw break; 2150172694eSnathanw case 'L': 2160172694eSnathanw pthread__diagassert &= ~DIAGASSERT_SYSLOG; 2170172694eSnathanw break; 218df277271Snathanw } 2190172694eSnathanw } 2200172694eSnathanw 221df277271Snathanw 222c62a74e6Sthorpej /* Tell libc that we're here and it should role-play accordingly. */ 223c62a74e6Sthorpej __isthreaded = 1; 224c62a74e6Sthorpej } 225c62a74e6Sthorpej 2262a4cef11Snathanw static void 2272a4cef11Snathanw pthread__child_callback(void) 2282a4cef11Snathanw { 2292a4cef11Snathanw /* 2302a4cef11Snathanw * Clean up data structures that a forked child process might 2312a4cef11Snathanw * trip over. Note that if threads have been created (causing 2322a4cef11Snathanw * this handler to be registered) the standards say that the 2332a4cef11Snathanw * child will trigger undefined behavior if it makes any 2342a4cef11Snathanw * pthread_* calls (or any other calls that aren't 2352a4cef11Snathanw * async-signal-safe), so we don't really have to clean up 2362a4cef11Snathanw * much. Anything that permits some pthread_* calls to work is 2372a4cef11Snathanw * merely being polite. 2382a4cef11Snathanw */ 2392a4cef11Snathanw pthread__started = 0; 2402a4cef11Snathanw } 241c62a74e6Sthorpej 2420e675542Schs static void 243c62a74e6Sthorpej pthread__start(void) 244c62a74e6Sthorpej { 245c62a74e6Sthorpej pthread_t self, idle; 246c62a74e6Sthorpej int i, ret; 247c62a74e6Sthorpej 248c62a74e6Sthorpej self = pthread__self(); /* should be the "main()" thread */ 249c62a74e6Sthorpej 250ff14fbf2Snathanw /* 251ff14fbf2Snathanw * Per-process timers are cleared by fork(); despite the 252ff14fbf2Snathanw * various restrictions on fork() and threads, it's legal to 253ff14fbf2Snathanw * fork() before creating any threads. 254ff14fbf2Snathanw */ 255ff14fbf2Snathanw pthread__alarm_init(); 256ff14fbf2Snathanw 257916de878Snathanw pthread__signal_start(); 258916de878Snathanw 2592a4cef11Snathanw pthread_atfork(NULL, NULL, pthread__child_callback); 260c62a74e6Sthorpej 261f2f10664Scl /* 262f2f10664Scl * Create idle threads 263f2f10664Scl * XXX need to create more idle threads if concurrency > 3 264f2f10664Scl */ 265c62a74e6Sthorpej for (i = 0; i < NIDLETHREADS; i++) { 266c62a74e6Sthorpej ret = pthread__stackalloc(&idle); 267c62a74e6Sthorpej if (ret != 0) 268c62a74e6Sthorpej err(1, "Couldn't allocate stack for idle thread!"); 269c62a74e6Sthorpej pthread__initthread(self, idle); 270c62a74e6Sthorpej sigfillset(&idle->pt_sigmask); 271c62a74e6Sthorpej idle->pt_type = PT_THREAD_IDLE; 272c62a74e6Sthorpej PTQ_INSERT_HEAD(&pthread__allqueue, idle, pt_allq); 273c62a74e6Sthorpej pthread__sched_idle(self, idle); 274c62a74e6Sthorpej } 275c62a74e6Sthorpej 276c62a74e6Sthorpej /* Start up the SA subsystem */ 277c62a74e6Sthorpej pthread__sa_start(); 278c62a74e6Sthorpej SDPRINTF(("(pthread__start %p) Started.\n", self)); 279c62a74e6Sthorpej } 280c62a74e6Sthorpej 281c62a74e6Sthorpej 282c62a74e6Sthorpej /* General-purpose thread data structure sanitization. */ 283c62a74e6Sthorpej void 284c62a74e6Sthorpej pthread__initthread(pthread_t self, pthread_t t) 285c62a74e6Sthorpej { 286c62a74e6Sthorpej int id; 287c62a74e6Sthorpej 288c62a74e6Sthorpej pthread_spinlock(self, &nextthread_lock); 289c62a74e6Sthorpej id = nextthread; 290c62a74e6Sthorpej nextthread++; 291c62a74e6Sthorpej pthread_spinunlock(self, &nextthread_lock); 292c62a74e6Sthorpej t->pt_num = id; 293c62a74e6Sthorpej 294c62a74e6Sthorpej t->pt_magic = PT_MAGIC; 295c62a74e6Sthorpej t->pt_type = PT_THREAD_NORMAL; 296c62a74e6Sthorpej t->pt_state = PT_STATE_RUNNABLE; 297c62a74e6Sthorpej pthread_lockinit(&t->pt_statelock); 2980878df5dSnathanw pthread_lockinit(&t->pt_flaglock); 299c62a74e6Sthorpej t->pt_spinlocks = 0; 300c62a74e6Sthorpej t->pt_next = NULL; 301c62a74e6Sthorpej t->pt_exitval = NULL; 302c62a74e6Sthorpej t->pt_flags = 0; 303c62a74e6Sthorpej t->pt_cancel = 0; 304c62a74e6Sthorpej t->pt_errno = 0; 305c62a74e6Sthorpej t->pt_parent = NULL; 306c62a74e6Sthorpej t->pt_heldlock = NULL; 307c62a74e6Sthorpej t->pt_switchto = NULL; 308487eb7e1Snathanw t->pt_trapuc = NULL; 309c62a74e6Sthorpej sigemptyset(&t->pt_siglist); 310c62a74e6Sthorpej sigemptyset(&t->pt_sigmask); 311c62a74e6Sthorpej pthread_lockinit(&t->pt_siglock); 312c62a74e6Sthorpej PTQ_INIT(&t->pt_joiners); 313c62a74e6Sthorpej pthread_lockinit(&t->pt_join_lock); 314c62a74e6Sthorpej PTQ_INIT(&t->pt_cleanup_stack); 315c62a74e6Sthorpej memset(&t->pt_specific, 0, sizeof(int) * PTHREAD_KEYS_MAX); 316b33971b9Sthorpej t->pt_name = NULL; 317c62a74e6Sthorpej #ifdef PTHREAD__DEBUG 318c62a74e6Sthorpej t->blocks = 0; 319c62a74e6Sthorpej t->preempts = 0; 320c62a74e6Sthorpej t->rescheds = 0; 321c62a74e6Sthorpej #endif 322c62a74e6Sthorpej } 323c62a74e6Sthorpej 324c62a74e6Sthorpej 325c62a74e6Sthorpej int 326c62a74e6Sthorpej pthread_create(pthread_t *thread, const pthread_attr_t *attr, 327c62a74e6Sthorpej void *(*startfunc)(void *), void *arg) 328c62a74e6Sthorpej { 329c62a74e6Sthorpej pthread_t self, newthread; 330c62a74e6Sthorpej pthread_attr_t nattr; 331b33971b9Sthorpej struct pthread_attr_private *p; 332b33971b9Sthorpej char *name; 333c62a74e6Sthorpej int ret; 334c62a74e6Sthorpej 335c62a74e6Sthorpej PTHREADD_ADD(PTHREADD_CREATE); 336c62a74e6Sthorpej 337c62a74e6Sthorpej /* 338c62a74e6Sthorpej * It's okay to check this without a lock because there can 339c62a74e6Sthorpej * only be one thread before it becomes true. 340c62a74e6Sthorpej */ 341c62a74e6Sthorpej if (pthread__started == 0) { 342c62a74e6Sthorpej pthread__start(); 343c62a74e6Sthorpej pthread__started = 1; 344c62a74e6Sthorpej } 345c62a74e6Sthorpej 346c62a74e6Sthorpej if (attr == NULL) 347c62a74e6Sthorpej nattr = pthread_default_attr; 348e81f9f17Sdrochner else if (attr->pta_magic == PT_ATTR_MAGIC) 349c62a74e6Sthorpej nattr = *attr; 350c62a74e6Sthorpej else 351c62a74e6Sthorpej return EINVAL; 352c62a74e6Sthorpej 353b33971b9Sthorpej /* Fetch misc. attributes from the attr structure. */ 354508a50acSnathanw name = NULL; 355508a50acSnathanw if ((p = nattr.pta_private) != NULL) 356508a50acSnathanw if (p->ptap_name[0] != '\0') 357b33971b9Sthorpej if ((name = strdup(p->ptap_name)) == NULL) 358b33971b9Sthorpej return ENOMEM; 359c62a74e6Sthorpej 360c62a74e6Sthorpej self = pthread__self(); 361c62a74e6Sthorpej 362c62a74e6Sthorpej pthread_spinlock(self, &pthread__deadqueue_lock); 363c62a74e6Sthorpej if (!PTQ_EMPTY(&pthread__deadqueue)) { 364c62a74e6Sthorpej newthread = PTQ_FIRST(&pthread__deadqueue); 365c62a74e6Sthorpej PTQ_REMOVE(&pthread__deadqueue, newthread, pt_allq); 366c62a74e6Sthorpej pthread_spinunlock(self, &pthread__deadqueue_lock); 367c62a74e6Sthorpej } else { 368c62a74e6Sthorpej pthread_spinunlock(self, &pthread__deadqueue_lock); 369c62a74e6Sthorpej /* Set up a stack and allocate space for a pthread_st. */ 370c62a74e6Sthorpej ret = pthread__stackalloc(&newthread); 371b7559f85Schristos if (ret != 0) { 372b7559f85Schristos if (name) 373b7559f85Schristos free(name); 374c62a74e6Sthorpej return ret; 375c62a74e6Sthorpej } 376b7559f85Schristos } 377c62a74e6Sthorpej 378c62a74e6Sthorpej /* 2. Set up state. */ 379c62a74e6Sthorpej pthread__initthread(self, newthread); 380c62a74e6Sthorpej newthread->pt_flags = nattr.pta_flags; 381c62a74e6Sthorpej newthread->pt_sigmask = self->pt_sigmask; 382c62a74e6Sthorpej 383b33971b9Sthorpej /* 3. Set up misc. attributes. */ 384b33971b9Sthorpej newthread->pt_name = name; 385b33971b9Sthorpej 386c62a74e6Sthorpej /* 387b33971b9Sthorpej * 4. Set up context. 388c62a74e6Sthorpej * 389c62a74e6Sthorpej * The pt_uc pointer points to a location safely below the 390c62a74e6Sthorpej * stack start; this is arranged by pthread__stackalloc(). 391c62a74e6Sthorpej */ 392c62a74e6Sthorpej _INITCONTEXT_U(newthread->pt_uc); 393877f8985Snathanw #ifdef PTHREAD_MACHINE_HAS_ID_REGISTER 394877f8985Snathanw pthread__uc_id(newthread->pt_uc) = newthread; 395877f8985Snathanw #endif 396c62a74e6Sthorpej newthread->pt_uc->uc_stack = newthread->pt_stack; 397c62a74e6Sthorpej newthread->pt_uc->uc_link = NULL; 398c62a74e6Sthorpej makecontext(newthread->pt_uc, pthread__create_tramp, 2, 399c62a74e6Sthorpej startfunc, arg); 400c62a74e6Sthorpej 401b33971b9Sthorpej /* 5. Add to list of all threads. */ 402c62a74e6Sthorpej pthread_spinlock(self, &pthread__allqueue_lock); 403c62a74e6Sthorpej PTQ_INSERT_HEAD(&pthread__allqueue, newthread, pt_allq); 404c62a74e6Sthorpej nthreads++; 405c62a74e6Sthorpej pthread_spinunlock(self, &pthread__allqueue_lock); 406c62a74e6Sthorpej 407ba70e96aSchs SDPRINTF(("(pthread_create %p) new thread %p (name pointer %p).\n", 408ba70e96aSchs self, newthread, newthread->pt_name)); 40938b1c6f4Schristos /* 6. Put on appropriate queue. */ 41038b1c6f4Schristos if (newthread->pt_flags & PT_FLAG_SUSPENDED) { 41138b1c6f4Schristos pthread_spinlock(self, &newthread->pt_statelock); 41238b1c6f4Schristos pthread__suspend(self, newthread); 41338b1c6f4Schristos pthread_spinunlock(self, &newthread->pt_statelock); 41438b1c6f4Schristos } else 415c62a74e6Sthorpej pthread__sched(self, newthread); 416c62a74e6Sthorpej 417c62a74e6Sthorpej *thread = newthread; 418c62a74e6Sthorpej 419c62a74e6Sthorpej return 0; 420c62a74e6Sthorpej } 421c62a74e6Sthorpej 422c62a74e6Sthorpej 423c62a74e6Sthorpej static void 424c62a74e6Sthorpej pthread__create_tramp(void *(*start)(void *), void *arg) 425c62a74e6Sthorpej { 426c62a74e6Sthorpej void *retval; 427c62a74e6Sthorpej 42894a458ceSchs retval = (*start)(arg); 429c62a74e6Sthorpej 430c62a74e6Sthorpej pthread_exit(retval); 431c62a74e6Sthorpej 432143f5a27Schristos /*NOTREACHED*/ 433143f5a27Schristos pthread__abort(); 434c62a74e6Sthorpej } 435c62a74e6Sthorpej 43638b1c6f4Schristos int 43738b1c6f4Schristos pthread_suspend_np(pthread_t thread) 43838b1c6f4Schristos { 439ba70e96aSchs pthread_t self; 440ba70e96aSchs 441ba70e96aSchs self = pthread__self(); 44238b1c6f4Schristos if (self == thread) { 44338b1c6f4Schristos return EDEADLK; 44438b1c6f4Schristos } 445ba70e96aSchs #ifdef ERRORCHECK 446ba70e96aSchs if (pthread__find(self, thread) != 0) 447ba70e96aSchs return ESRCH; 448ba70e96aSchs #endif 44938b1c6f4Schristos SDPRINTF(("(pthread_suspend_np %p) Suspend thread %p (state %d).\n", 45038b1c6f4Schristos self, thread, thread->pt_state)); 45138b1c6f4Schristos pthread_spinlock(self, &thread->pt_statelock); 45282b6b2dbScl if (thread->pt_blockgen != thread->pt_unblockgen) { 45382b6b2dbScl /* XXX flaglock? */ 45482b6b2dbScl thread->pt_flags |= PT_FLAG_SUSPENDED; 45582b6b2dbScl pthread_spinunlock(self, &thread->pt_statelock); 45682b6b2dbScl return 0; 45782b6b2dbScl } 45838b1c6f4Schristos switch (thread->pt_state) { 45938b1c6f4Schristos case PT_STATE_RUNNING: 46038b1c6f4Schristos pthread__abort(); /* XXX */ 46138b1c6f4Schristos break; 46238b1c6f4Schristos case PT_STATE_SUSPENDED: 46338b1c6f4Schristos pthread_spinunlock(self, &thread->pt_statelock); 46438b1c6f4Schristos return 0; 46538b1c6f4Schristos case PT_STATE_RUNNABLE: 46638b1c6f4Schristos pthread_spinlock(self, &pthread__runqueue_lock); 46738b1c6f4Schristos PTQ_REMOVE(&pthread__runqueue, thread, pt_runq); 46838b1c6f4Schristos pthread_spinunlock(self, &pthread__runqueue_lock); 46938b1c6f4Schristos break; 47038b1c6f4Schristos case PT_STATE_BLOCKED_QUEUE: 47138b1c6f4Schristos pthread_spinlock(self, thread->pt_sleeplock); 47238b1c6f4Schristos PTQ_REMOVE(thread->pt_sleepq, thread, pt_sleep); 47338b1c6f4Schristos pthread_spinunlock(self, thread->pt_sleeplock); 47438b1c6f4Schristos break; 475ba70e96aSchs case PT_STATE_ZOMBIE: 476ba70e96aSchs goto out; 47738b1c6f4Schristos default: 47838b1c6f4Schristos break; /* XXX */ 47938b1c6f4Schristos } 48038b1c6f4Schristos pthread__suspend(self, thread); 481ba70e96aSchs 482ba70e96aSchs out: 48338b1c6f4Schristos pthread_spinunlock(self, &thread->pt_statelock); 48438b1c6f4Schristos return 0; 48538b1c6f4Schristos } 48638b1c6f4Schristos 48738b1c6f4Schristos int 48838b1c6f4Schristos pthread_resume_np(pthread_t thread) 48938b1c6f4Schristos { 490ba70e96aSchs pthread_t self; 49138b1c6f4Schristos 492ba70e96aSchs self = pthread__self(); 493ba70e96aSchs #ifdef ERRORCHECK 494ba70e96aSchs if (pthread__find(self, thread) != 0) 495ba70e96aSchs return ESRCH; 496ba70e96aSchs #endif 49738b1c6f4Schristos SDPRINTF(("(pthread_resume_np %p) Resume thread %p (state %d).\n", 49838b1c6f4Schristos self, thread, thread->pt_state)); 49938b1c6f4Schristos pthread_spinlock(self, &thread->pt_statelock); 50038b1c6f4Schristos /* XXX flaglock? */ 50138b1c6f4Schristos thread->pt_flags &= ~PT_FLAG_SUSPENDED; 50238b1c6f4Schristos if (thread->pt_state == PT_STATE_SUSPENDED) { 50338b1c6f4Schristos pthread_spinlock(self, &pthread__runqueue_lock); 50438b1c6f4Schristos PTQ_REMOVE(&pthread__suspqueue, thread, pt_runq); 50538b1c6f4Schristos pthread_spinunlock(self, &pthread__runqueue_lock); 50638b1c6f4Schristos pthread__sched(self, thread); 50738b1c6f4Schristos } 50838b1c6f4Schristos pthread_spinunlock(self, &thread->pt_statelock); 50938b1c6f4Schristos return 0; 51038b1c6f4Schristos } 51138b1c6f4Schristos 512c62a74e6Sthorpej 513c62a74e6Sthorpej /* 514c62a74e6Sthorpej * Other threads will switch to the idle thread so that they 515c62a74e6Sthorpej * can dispose of any awkward locks or recycle upcall state. 516c62a74e6Sthorpej */ 517c62a74e6Sthorpej void 518c62a74e6Sthorpej pthread__idle(void) 519c62a74e6Sthorpej { 520c62a74e6Sthorpej pthread_t self; 521c62a74e6Sthorpej 522c62a74e6Sthorpej PTHREADD_ADD(PTHREADD_IDLE); 523c62a74e6Sthorpej self = pthread__self(); 524c62a74e6Sthorpej SDPRINTF(("(pthread__idle %p).\n", self)); 525c62a74e6Sthorpej 526c62a74e6Sthorpej /* 527c62a74e6Sthorpej * The drill here is that we want to yield the processor, 528c62a74e6Sthorpej * but for the thread itself to be recovered, we need to be on 529c62a74e6Sthorpej * a list somewhere for the thread system to know about us. 530c62a74e6Sthorpej */ 531c62a74e6Sthorpej pthread_spinlock(self, &pthread__deadqueue_lock); 532f2f10664Scl PTQ_INSERT_TAIL(&pthread__reidlequeue[self->pt_vpid], self, pt_runq); 533f2f10664Scl pthread__concurrency--; 534f2f10664Scl SDPRINTF(("(yield %p concurrency) now %d\n", self, 535f2f10664Scl pthread__concurrency)); 5360878df5dSnathanw /* Don't need a flag lock; nothing else has a handle on this thread */ 537c62a74e6Sthorpej self->pt_flags |= PT_FLAG_IDLED; 538c62a74e6Sthorpej pthread_spinunlock(self, &pthread__deadqueue_lock); 539c62a74e6Sthorpej 540c62a74e6Sthorpej /* 541c62a74e6Sthorpej * If we get to run this, then no preemption has happened 542c62a74e6Sthorpej * (because the upcall handler will not continue an idle thread with 543c62a74e6Sthorpej * PT_FLAG_IDLED set), and so we can yield the processor safely. 544c62a74e6Sthorpej */ 545c62a74e6Sthorpej SDPRINTF(("(pthread__idle %p) yielding.\n", self)); 546c62a74e6Sthorpej sa_yield(); 547c62a74e6Sthorpej 548c62a74e6Sthorpej /* NOTREACHED */ 549c62a74e6Sthorpej self->pt_spinlocks++; /* XXX make sure we get to finish the assert! */ 550c62a74e6Sthorpej SDPRINTF(("(pthread__idle %p) Returned! Error.\n", self)); 551143f5a27Schristos pthread__abort(); 552c62a74e6Sthorpej } 553c62a74e6Sthorpej 554c62a74e6Sthorpej 555c62a74e6Sthorpej void 556c62a74e6Sthorpej pthread_exit(void *retval) 557c62a74e6Sthorpej { 55896b5a26dSnathanw pthread_t self; 559c62a74e6Sthorpej struct pt_clean_t *cleanup; 560b33971b9Sthorpej char *name; 5616b2b9c62Syamt int nt; 562c62a74e6Sthorpej 563c62a74e6Sthorpej self = pthread__self(); 564ba70e96aSchs SDPRINTF(("(pthread_exit %p) status %p, flags %x, cancel %d\n", 565ba70e96aSchs self, retval, self->pt_flags, self->pt_cancel)); 566c62a74e6Sthorpej 567c62a74e6Sthorpej /* Disable cancellability. */ 5680878df5dSnathanw pthread_spinlock(self, &self->pt_flaglock); 569c62a74e6Sthorpej self->pt_flags |= PT_FLAG_CS_DISABLED; 57066fcc1ceSnathanw self->pt_cancel = 0; 5710878df5dSnathanw pthread_spinunlock(self, &self->pt_flaglock); 572c62a74e6Sthorpej 573c62a74e6Sthorpej /* Call any cancellation cleanup handlers */ 574c62a74e6Sthorpej while (!PTQ_EMPTY(&self->pt_cleanup_stack)) { 575c62a74e6Sthorpej cleanup = PTQ_FIRST(&self->pt_cleanup_stack); 576c62a74e6Sthorpej PTQ_REMOVE(&self->pt_cleanup_stack, cleanup, ptc_next); 577c62a74e6Sthorpej (*cleanup->ptc_cleanup)(cleanup->ptc_arg); 578c62a74e6Sthorpej } 579c62a74e6Sthorpej 580c62a74e6Sthorpej /* Perform cleanup of thread-specific data */ 581c62a74e6Sthorpej pthread__destroy_tsd(self); 582c62a74e6Sthorpej 583c62a74e6Sthorpej self->pt_exitval = retval; 584c62a74e6Sthorpej 5856b2b9c62Syamt /* 5866b2b9c62Syamt * it's safe to check PT_FLAG_DETACHED without pt_flaglock 5876b2b9c62Syamt * because it's only set by pthread_detach with pt_join_lock held. 5886b2b9c62Syamt */ 5896b2b9c62Syamt pthread_spinlock(self, &self->pt_join_lock); 5906b2b9c62Syamt if (self->pt_flags & PT_FLAG_DETACHED) { 5916b2b9c62Syamt self->pt_state = PT_STATE_DEAD; 5926b2b9c62Syamt pthread_spinunlock(self, &self->pt_join_lock); 593b33971b9Sthorpej name = self->pt_name; 594b33971b9Sthorpej self->pt_name = NULL; 595c62a74e6Sthorpej 596b33971b9Sthorpej if (name != NULL) 597b33971b9Sthorpej free(name); 598b33971b9Sthorpej 599c62a74e6Sthorpej pthread_spinlock(self, &pthread__allqueue_lock); 600c62a74e6Sthorpej PTQ_REMOVE(&pthread__allqueue, self, pt_allq); 601c62a74e6Sthorpej nthreads--; 602c62a74e6Sthorpej nt = nthreads; 603c62a74e6Sthorpej pthread_spinunlock(self, &pthread__allqueue_lock); 604c62a74e6Sthorpej 605c62a74e6Sthorpej if (nt == 0) { 606c62a74e6Sthorpej /* Whoah, we're the last one. Time to go. */ 607c62a74e6Sthorpej exit(0); 608c62a74e6Sthorpej } 609c62a74e6Sthorpej 610c62a74e6Sthorpej /* Yeah, yeah, doing work while we're dead is tacky. */ 611c62a74e6Sthorpej pthread_spinlock(self, &pthread__deadqueue_lock); 612c62a74e6Sthorpej PTQ_INSERT_HEAD(&pthread__deadqueue, self, pt_allq); 613c62a74e6Sthorpej pthread__block(self, &pthread__deadqueue_lock); 614ba70e96aSchs SDPRINTF(("(pthread_exit %p) walking dead\n", self)); 615c62a74e6Sthorpej } else { 6166b2b9c62Syamt self->pt_state = PT_STATE_ZOMBIE; 617b33971b9Sthorpej /* Note: name will be freed by the joiner. */ 618c62a74e6Sthorpej pthread_spinlock(self, &pthread__allqueue_lock); 619c62a74e6Sthorpej nthreads--; 620c62a74e6Sthorpej nt = nthreads; 621c62a74e6Sthorpej pthread_spinunlock(self, &pthread__allqueue_lock); 622c62a74e6Sthorpej if (nt == 0) { 623c62a74e6Sthorpej /* Whoah, we're the last one. Time to go. */ 624c62a74e6Sthorpej exit(0); 625c62a74e6Sthorpej } 62696b5a26dSnathanw /* 62796b5a26dSnathanw * Wake up all the potential joiners. Only one can win. 628c62a74e6Sthorpej * (Can you say "Thundering Herd"? I knew you could.) 629c62a74e6Sthorpej */ 63096b5a26dSnathanw pthread__sched_sleepers(self, &self->pt_joiners); 631c62a74e6Sthorpej pthread__block(self, &self->pt_join_lock); 632ba70e96aSchs SDPRINTF(("(pthread_exit %p) walking zombie\n", self)); 633c62a74e6Sthorpej } 634c62a74e6Sthorpej 635143f5a27Schristos /*NOTREACHED*/ 636143f5a27Schristos pthread__abort(); 637c62a74e6Sthorpej exit(1); 638c62a74e6Sthorpej } 639c62a74e6Sthorpej 640c62a74e6Sthorpej 641c62a74e6Sthorpej int 642c62a74e6Sthorpej pthread_join(pthread_t thread, void **valptr) 643c62a74e6Sthorpej { 644c62a74e6Sthorpej pthread_t self; 645b33971b9Sthorpej char *name; 646564fe117Snathanw int num; 647c62a74e6Sthorpej 648c62a74e6Sthorpej self = pthread__self(); 649c62a74e6Sthorpej SDPRINTF(("(pthread_join %p) Joining %p.\n", self, thread)); 650c62a74e6Sthorpej 651c62a74e6Sthorpej if (pthread__find(self, thread) != 0) 652c62a74e6Sthorpej return ESRCH; 653c62a74e6Sthorpej 654c62a74e6Sthorpej if (thread->pt_magic != PT_MAGIC) 655c62a74e6Sthorpej return EINVAL; 656c62a74e6Sthorpej 657c62a74e6Sthorpej if (thread == self) 658c62a74e6Sthorpej return EDEADLK; 659c62a74e6Sthorpej 6600878df5dSnathanw pthread_spinlock(self, &thread->pt_flaglock); 661c62a74e6Sthorpej 662c62a74e6Sthorpej if (thread->pt_flags & PT_FLAG_DETACHED) { 6630878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 664c62a74e6Sthorpej return EINVAL; 665c62a74e6Sthorpej } 666c62a74e6Sthorpej 667564fe117Snathanw num = thread->pt_num; 6680878df5dSnathanw pthread_spinlock(self, &thread->pt_join_lock); 669564fe117Snathanw while (thread->pt_state != PT_STATE_ZOMBIE) { 670564fe117Snathanw if ((thread->pt_state == PT_STATE_DEAD) || 671564fe117Snathanw (thread->pt_flags & PT_FLAG_DETACHED) || 672564fe117Snathanw (thread->pt_num != num)) { 673564fe117Snathanw /* 674564fe117Snathanw * Another thread beat us to the join, or called 675564fe117Snathanw * pthread_detach(). If num didn't match, the 676564fe117Snathanw * thread died and was recycled before we got 677564fe117Snathanw * another chance to run. 678564fe117Snathanw */ 679564fe117Snathanw pthread_spinunlock(self, &thread->pt_join_lock); 6800878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 681564fe117Snathanw return ESRCH; 682564fe117Snathanw } 683c62a74e6Sthorpej /* 684c62a74e6Sthorpej * "I'm not dead yet!" 685c62a74e6Sthorpej * "You will be soon enough." 686c62a74e6Sthorpej */ 6870878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 688c62a74e6Sthorpej pthread_spinlock(self, &self->pt_statelock); 689c62a74e6Sthorpej if (self->pt_cancel) { 690c62a74e6Sthorpej pthread_spinunlock(self, &self->pt_statelock); 691c62a74e6Sthorpej pthread_spinunlock(self, &thread->pt_join_lock); 692c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 693c62a74e6Sthorpej } 694c62a74e6Sthorpej self->pt_state = PT_STATE_BLOCKED_QUEUE; 695c62a74e6Sthorpej self->pt_sleepobj = thread; 696c62a74e6Sthorpej self->pt_sleepq = &thread->pt_joiners; 697c62a74e6Sthorpej self->pt_sleeplock = &thread->pt_join_lock; 698c62a74e6Sthorpej pthread_spinunlock(self, &self->pt_statelock); 699c62a74e6Sthorpej 700c62a74e6Sthorpej PTQ_INSERT_TAIL(&thread->pt_joiners, self, pt_sleep); 701c62a74e6Sthorpej pthread__block(self, &thread->pt_join_lock); 7020878df5dSnathanw pthread_spinlock(self, &thread->pt_flaglock); 703c62a74e6Sthorpej pthread_spinlock(self, &thread->pt_join_lock); 704c62a74e6Sthorpej } 705c62a74e6Sthorpej 706c62a74e6Sthorpej /* All ours. */ 707c62a74e6Sthorpej thread->pt_state = PT_STATE_DEAD; 708b33971b9Sthorpej name = thread->pt_name; 709b33971b9Sthorpej thread->pt_name = NULL; 710c62a74e6Sthorpej pthread_spinunlock(self, &thread->pt_join_lock); 7110878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 712c62a74e6Sthorpej 713c62a74e6Sthorpej if (valptr != NULL) 714c62a74e6Sthorpej *valptr = thread->pt_exitval; 715c62a74e6Sthorpej 716c62a74e6Sthorpej SDPRINTF(("(pthread_join %p) Joined %p.\n", self, thread)); 717c62a74e6Sthorpej 7186b2b9c62Syamt pthread__dead(self, thread); 719c62a74e6Sthorpej 720b33971b9Sthorpej if (name != NULL) 721b33971b9Sthorpej free(name); 722b33971b9Sthorpej 723c62a74e6Sthorpej return 0; 724c62a74e6Sthorpej } 725c62a74e6Sthorpej 726c62a74e6Sthorpej 727c62a74e6Sthorpej int 728c62a74e6Sthorpej pthread_equal(pthread_t t1, pthread_t t2) 729c62a74e6Sthorpej { 730c62a74e6Sthorpej 731c62a74e6Sthorpej /* Nothing special here. */ 732c62a74e6Sthorpej return (t1 == t2); 733c62a74e6Sthorpej } 734c62a74e6Sthorpej 735c62a74e6Sthorpej 736c62a74e6Sthorpej int 737c62a74e6Sthorpej pthread_detach(pthread_t thread) 738c62a74e6Sthorpej { 73996b5a26dSnathanw pthread_t self; 7406b2b9c62Syamt int doreclaim = 0; 7416b2b9c62Syamt char *name = NULL; 742c62a74e6Sthorpej 743c62a74e6Sthorpej self = pthread__self(); 744c62a74e6Sthorpej 745c62a74e6Sthorpej if (pthread__find(self, thread) != 0) 746c62a74e6Sthorpej return ESRCH; 747c62a74e6Sthorpej 748c62a74e6Sthorpej if (thread->pt_magic != PT_MAGIC) 749c62a74e6Sthorpej return EINVAL; 750c62a74e6Sthorpej 7510878df5dSnathanw pthread_spinlock(self, &thread->pt_flaglock); 752c62a74e6Sthorpej pthread_spinlock(self, &thread->pt_join_lock); 753c62a74e6Sthorpej 754c62a74e6Sthorpej if (thread->pt_flags & PT_FLAG_DETACHED) { 755c62a74e6Sthorpej pthread_spinunlock(self, &thread->pt_join_lock); 7560878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 757c62a74e6Sthorpej return EINVAL; 758c62a74e6Sthorpej } 759c62a74e6Sthorpej 760c62a74e6Sthorpej thread->pt_flags |= PT_FLAG_DETACHED; 761c62a74e6Sthorpej 762c62a74e6Sthorpej /* Any joiners have to be punted now. */ 76396b5a26dSnathanw pthread__sched_sleepers(self, &thread->pt_joiners); 764c62a74e6Sthorpej 7656b2b9c62Syamt if (thread->pt_state == PT_STATE_ZOMBIE) { 7666b2b9c62Syamt thread->pt_state = PT_STATE_DEAD; 7676b2b9c62Syamt name = thread->pt_name; 7686b2b9c62Syamt thread->pt_name = NULL; 7696b2b9c62Syamt doreclaim = 1; 7706b2b9c62Syamt } 7716b2b9c62Syamt 772c62a74e6Sthorpej pthread_spinunlock(self, &thread->pt_join_lock); 7730878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 774c62a74e6Sthorpej 7756b2b9c62Syamt if (doreclaim) { 7766b2b9c62Syamt pthread__dead(self, thread); 7776b2b9c62Syamt if (name != NULL) 7786b2b9c62Syamt free(name); 7796b2b9c62Syamt } 7806b2b9c62Syamt 781c62a74e6Sthorpej return 0; 782c62a74e6Sthorpej } 783c62a74e6Sthorpej 784c62a74e6Sthorpej 7856b2b9c62Syamt static void 7866b2b9c62Syamt pthread__dead(pthread_t self, pthread_t thread) 7876b2b9c62Syamt { 7886b2b9c62Syamt 7896b2b9c62Syamt SDPRINTF(("(pthread__dead %p) Reclaimed %p.\n", self, thread)); 7906b2b9c62Syamt pthread__assert(thread != self); 7916b2b9c62Syamt pthread__assert(thread->pt_state == PT_STATE_DEAD); 7926b2b9c62Syamt pthread__assert(thread->pt_name == NULL); 7936b2b9c62Syamt 7946b2b9c62Syamt /* Cleanup time. Move the dead thread from allqueue to the deadqueue */ 7956b2b9c62Syamt pthread_spinlock(self, &pthread__allqueue_lock); 7966b2b9c62Syamt PTQ_REMOVE(&pthread__allqueue, thread, pt_allq); 7976b2b9c62Syamt pthread_spinunlock(self, &pthread__allqueue_lock); 7986b2b9c62Syamt 7996b2b9c62Syamt pthread_spinlock(self, &pthread__deadqueue_lock); 8006b2b9c62Syamt PTQ_INSERT_HEAD(&pthread__deadqueue, thread, pt_allq); 8016b2b9c62Syamt pthread_spinunlock(self, &pthread__deadqueue_lock); 8026b2b9c62Syamt } 8036b2b9c62Syamt 8046b2b9c62Syamt 805c62a74e6Sthorpej int 806b33971b9Sthorpej pthread_getname_np(pthread_t thread, char *name, size_t len) 807c62a74e6Sthorpej { 808b33971b9Sthorpej pthread_t self; 809c62a74e6Sthorpej 810b33971b9Sthorpej self = pthread__self(); 811b33971b9Sthorpej 812b33971b9Sthorpej if (pthread__find(self, thread) != 0) 813b33971b9Sthorpej return ESRCH; 814b33971b9Sthorpej 815b33971b9Sthorpej if (thread->pt_magic != PT_MAGIC) 816b33971b9Sthorpej return EINVAL; 817b33971b9Sthorpej 818b33971b9Sthorpej pthread_spinlock(self, &thread->pt_join_lock); 819b33971b9Sthorpej if (thread->pt_name == NULL) 820b33971b9Sthorpej name[0] = '\0'; 821b33971b9Sthorpej else 822b33971b9Sthorpej strlcpy(name, thread->pt_name, len); 823b33971b9Sthorpej pthread_spinunlock(self, &thread->pt_join_lock); 824c62a74e6Sthorpej 825c62a74e6Sthorpej return 0; 826c62a74e6Sthorpej } 827c62a74e6Sthorpej 828c62a74e6Sthorpej 829c62a74e6Sthorpej int 830b33971b9Sthorpej pthread_setname_np(pthread_t thread, const char *name, void *arg) 831b33971b9Sthorpej { 832ba70e96aSchs pthread_t self; 833b33971b9Sthorpej char *oldname, *cp, newname[PTHREAD_MAX_NAMELEN_NP]; 834b33971b9Sthorpej int namelen; 835b33971b9Sthorpej 836ba70e96aSchs self = pthread__self(); 837b33971b9Sthorpej if (pthread__find(self, thread) != 0) 838b33971b9Sthorpej return ESRCH; 839b33971b9Sthorpej 840b33971b9Sthorpej if (thread->pt_magic != PT_MAGIC) 841b33971b9Sthorpej return EINVAL; 842b33971b9Sthorpej 843b33971b9Sthorpej namelen = snprintf(newname, sizeof(newname), name, arg); 844b33971b9Sthorpej if (namelen >= PTHREAD_MAX_NAMELEN_NP) 845b33971b9Sthorpej return EINVAL; 846b33971b9Sthorpej 847b33971b9Sthorpej cp = strdup(newname); 848b33971b9Sthorpej if (cp == NULL) 849b33971b9Sthorpej return ENOMEM; 850b33971b9Sthorpej 851b33971b9Sthorpej pthread_spinlock(self, &thread->pt_join_lock); 852b33971b9Sthorpej 853b33971b9Sthorpej if (thread->pt_state == PT_STATE_DEAD) { 854b33971b9Sthorpej pthread_spinunlock(self, &thread->pt_join_lock); 855b33971b9Sthorpej free(cp); 856b33971b9Sthorpej return EINVAL; 857b33971b9Sthorpej } 858b33971b9Sthorpej 859b33971b9Sthorpej oldname = thread->pt_name; 860b33971b9Sthorpej thread->pt_name = cp; 861b33971b9Sthorpej 862b33971b9Sthorpej pthread_spinunlock(self, &thread->pt_join_lock); 863b33971b9Sthorpej 864b33971b9Sthorpej if (oldname != NULL) 865b33971b9Sthorpej free(oldname); 866b33971b9Sthorpej 867b33971b9Sthorpej return 0; 868b33971b9Sthorpej } 869b33971b9Sthorpej 870b33971b9Sthorpej 871b33971b9Sthorpej 872c62a74e6Sthorpej /* 873c62a74e6Sthorpej * XXX There should be a way for applications to use the efficent 874c62a74e6Sthorpej * inline version, but there are opacity/namespace issues. 875c62a74e6Sthorpej */ 876c62a74e6Sthorpej pthread_t 877c62a74e6Sthorpej pthread_self(void) 878c62a74e6Sthorpej { 879c62a74e6Sthorpej 880c62a74e6Sthorpej return pthread__self(); 881c62a74e6Sthorpej } 882c62a74e6Sthorpej 883c62a74e6Sthorpej 884c62a74e6Sthorpej int 885c62a74e6Sthorpej pthread_cancel(pthread_t thread) 886c62a74e6Sthorpej { 887c62a74e6Sthorpej pthread_t self; 888c62a74e6Sthorpej 889ba70e96aSchs self = pthread__self(); 890ba70e96aSchs #ifdef ERRORCHECK 891ba70e96aSchs if (pthread__find(self, thread) != 0) 892ba70e96aSchs return ESRCH; 893ba70e96aSchs #endif 894c62a74e6Sthorpej if (!(thread->pt_state == PT_STATE_RUNNING || 895c62a74e6Sthorpej thread->pt_state == PT_STATE_RUNNABLE || 89682b6b2dbScl thread->pt_state == PT_STATE_BLOCKED_QUEUE)) 897c62a74e6Sthorpej return ESRCH; 898c62a74e6Sthorpej 8990878df5dSnathanw pthread_spinlock(self, &thread->pt_flaglock); 9000878df5dSnathanw thread->pt_flags |= PT_FLAG_CS_PENDING; 9010878df5dSnathanw if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) { 902c62a74e6Sthorpej thread->pt_cancel = 1; 9030878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 904c62a74e6Sthorpej pthread_spinlock(self, &thread->pt_statelock); 90582b6b2dbScl if (thread->pt_blockgen != thread->pt_unblockgen) { 906c62a74e6Sthorpej /* 907c62a74e6Sthorpej * It's sleeping in the kernel. If we can wake 908c62a74e6Sthorpej * it up, it will notice the cancellation when 909c62a74e6Sthorpej * it returns. If it doesn't wake up when we 910c62a74e6Sthorpej * make this call, then it's blocked 911c62a74e6Sthorpej * uninterruptably in the kernel, and there's 912c62a74e6Sthorpej * not much to be done about it. 913c62a74e6Sthorpej */ 914c62a74e6Sthorpej _lwp_wakeup(thread->pt_blockedlwp); 915c62a74e6Sthorpej } else if (thread->pt_state == PT_STATE_BLOCKED_QUEUE) { 916c62a74e6Sthorpej /* 917c62a74e6Sthorpej * We're blocked somewhere (pthread__block() 9188bcff70bSnathanw * was called). Cause it to wake up; it will 9198bcff70bSnathanw * check for the cancellation if the routine 9208bcff70bSnathanw * is a cancellation point, and loop and reblock 9218bcff70bSnathanw * otherwise. 922c62a74e6Sthorpej */ 923c62a74e6Sthorpej pthread_spinlock(self, thread->pt_sleeplock); 924c62a74e6Sthorpej PTQ_REMOVE(thread->pt_sleepq, thread, 925c62a74e6Sthorpej pt_sleep); 926c62a74e6Sthorpej pthread_spinunlock(self, thread->pt_sleeplock); 927c62a74e6Sthorpej pthread__sched(self, thread); 928c62a74e6Sthorpej } else { 929c62a74e6Sthorpej /* 930c62a74e6Sthorpej * Nothing. The target thread is running and will 931c62a74e6Sthorpej * notice at the next deferred cancellation point. 932c62a74e6Sthorpej */ 933c62a74e6Sthorpej } 934c62a74e6Sthorpej pthread_spinunlock(self, &thread->pt_statelock); 9350878df5dSnathanw } else 9360878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 937c62a74e6Sthorpej 938c62a74e6Sthorpej return 0; 939c62a74e6Sthorpej } 940c62a74e6Sthorpej 941c62a74e6Sthorpej 942c62a74e6Sthorpej int 943c62a74e6Sthorpej pthread_setcancelstate(int state, int *oldstate) 944c62a74e6Sthorpej { 945c62a74e6Sthorpej pthread_t self; 9460878df5dSnathanw int retval; 947c62a74e6Sthorpej 948c62a74e6Sthorpej self = pthread__self(); 9490878df5dSnathanw retval = 0; 950c62a74e6Sthorpej 9510878df5dSnathanw pthread_spinlock(self, &self->pt_flaglock); 952c62a74e6Sthorpej if (oldstate != NULL) { 9530878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_DISABLED) 954c62a74e6Sthorpej *oldstate = PTHREAD_CANCEL_DISABLE; 955c62a74e6Sthorpej else 956c62a74e6Sthorpej *oldstate = PTHREAD_CANCEL_ENABLE; 957c62a74e6Sthorpej } 958c62a74e6Sthorpej 9590878df5dSnathanw if (state == PTHREAD_CANCEL_DISABLE) { 9600878df5dSnathanw self->pt_flags |= PT_FLAG_CS_DISABLED; 9610878df5dSnathanw if (self->pt_cancel) { 9620878df5dSnathanw self->pt_flags |= PT_FLAG_CS_PENDING; 9630878df5dSnathanw self->pt_cancel = 0; 9640878df5dSnathanw } 9650878df5dSnathanw } else if (state == PTHREAD_CANCEL_ENABLE) { 9660878df5dSnathanw self->pt_flags &= ~PT_FLAG_CS_DISABLED; 967c62a74e6Sthorpej /* 968c62a74e6Sthorpej * If a cancellation was requested while cancellation 969c62a74e6Sthorpej * was disabled, note that fact for future 970c62a74e6Sthorpej * cancellation tests. 971c62a74e6Sthorpej */ 9720878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_PENDING) { 973c62a74e6Sthorpej self->pt_cancel = 1; 974c62a74e6Sthorpej /* This is not a deferred cancellation point. */ 9750878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_ASYNC) { 9760878df5dSnathanw pthread_spinunlock(self, &self->pt_flaglock); 977c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 978c62a74e6Sthorpej } 9790878df5dSnathanw } 980c62a74e6Sthorpej } else 9810878df5dSnathanw retval = EINVAL; 982c62a74e6Sthorpej 9830878df5dSnathanw pthread_spinunlock(self, &self->pt_flaglock); 9840878df5dSnathanw return retval; 985c62a74e6Sthorpej } 986c62a74e6Sthorpej 987c62a74e6Sthorpej 988c62a74e6Sthorpej int 989c62a74e6Sthorpej pthread_setcanceltype(int type, int *oldtype) 990c62a74e6Sthorpej { 991c62a74e6Sthorpej pthread_t self; 9920878df5dSnathanw int retval; 993c62a74e6Sthorpej 994c62a74e6Sthorpej self = pthread__self(); 9950878df5dSnathanw retval = 0; 9960878df5dSnathanw 9970878df5dSnathanw pthread_spinlock(self, &self->pt_flaglock); 998c62a74e6Sthorpej 999c62a74e6Sthorpej if (oldtype != NULL) { 10000878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_ASYNC) 1001c62a74e6Sthorpej *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS; 1002c62a74e6Sthorpej else 1003c62a74e6Sthorpej *oldtype = PTHREAD_CANCEL_DEFERRED; 1004c62a74e6Sthorpej } 1005c62a74e6Sthorpej 1006c62a74e6Sthorpej if (type == PTHREAD_CANCEL_ASYNCHRONOUS) { 10070878df5dSnathanw self->pt_flags |= PT_FLAG_CS_ASYNC; 10080878df5dSnathanw if (self->pt_cancel) { 10090878df5dSnathanw pthread_spinunlock(self, &self->pt_flaglock); 1010c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 10110878df5dSnathanw } 1012c62a74e6Sthorpej } else if (type == PTHREAD_CANCEL_DEFERRED) 10130878df5dSnathanw self->pt_flags &= ~PT_FLAG_CS_ASYNC; 1014c62a74e6Sthorpej else 10150878df5dSnathanw retval = EINVAL; 1016c62a74e6Sthorpej 10170878df5dSnathanw pthread_spinunlock(self, &self->pt_flaglock); 10180878df5dSnathanw return retval; 1019c62a74e6Sthorpej } 1020c62a74e6Sthorpej 1021c62a74e6Sthorpej 1022c62a74e6Sthorpej void 1023c62a74e6Sthorpej pthread_testcancel() 1024c62a74e6Sthorpej { 1025c62a74e6Sthorpej pthread_t self; 1026c62a74e6Sthorpej 1027c62a74e6Sthorpej self = pthread__self(); 1028c62a74e6Sthorpej if (self->pt_cancel) 1029c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 1030c62a74e6Sthorpej } 1031c62a74e6Sthorpej 1032c62a74e6Sthorpej 1033c62a74e6Sthorpej /* 1034c62a74e6Sthorpej * POSIX requires that certain functions return an error rather than 1035c62a74e6Sthorpej * invoking undefined behavior even when handed completely bogus 1036c62a74e6Sthorpej * pthread_t values, e.g. stack garbage or (pthread_t)666. This 1037c62a74e6Sthorpej * utility routine searches the list of threads for the pthread_t 1038c62a74e6Sthorpej * value without dereferencing it. 1039c62a74e6Sthorpej */ 1040c62a74e6Sthorpej int 1041c62a74e6Sthorpej pthread__find(pthread_t self, pthread_t id) 1042c62a74e6Sthorpej { 1043c62a74e6Sthorpej pthread_t target; 1044c62a74e6Sthorpej 1045c62a74e6Sthorpej pthread_spinlock(self, &pthread__allqueue_lock); 1046c62a74e6Sthorpej PTQ_FOREACH(target, &pthread__allqueue, pt_allq) 1047c62a74e6Sthorpej if (target == id) 1048c62a74e6Sthorpej break; 1049c62a74e6Sthorpej pthread_spinunlock(self, &pthread__allqueue_lock); 1050c62a74e6Sthorpej 1051c62a74e6Sthorpej if (target == NULL) 1052c62a74e6Sthorpej return ESRCH; 1053c62a74e6Sthorpej 1054c62a74e6Sthorpej return 0; 1055c62a74e6Sthorpej } 1056c62a74e6Sthorpej 1057c62a74e6Sthorpej 1058c62a74e6Sthorpej void 1059c62a74e6Sthorpej pthread__testcancel(pthread_t self) 1060c62a74e6Sthorpej { 1061c62a74e6Sthorpej 1062c62a74e6Sthorpej if (self->pt_cancel) 1063c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 1064c62a74e6Sthorpej } 1065c62a74e6Sthorpej 1066c62a74e6Sthorpej 1067c62a74e6Sthorpej void 1068c62a74e6Sthorpej pthread__cleanup_push(void (*cleanup)(void *), void *arg, void *store) 1069c62a74e6Sthorpej { 1070c62a74e6Sthorpej pthread_t self; 1071c62a74e6Sthorpej struct pt_clean_t *entry; 1072c62a74e6Sthorpej 1073c62a74e6Sthorpej self = pthread__self(); 1074c62a74e6Sthorpej entry = store; 1075c62a74e6Sthorpej entry->ptc_cleanup = cleanup; 1076c62a74e6Sthorpej entry->ptc_arg = arg; 1077c62a74e6Sthorpej PTQ_INSERT_HEAD(&self->pt_cleanup_stack, entry, ptc_next); 1078c62a74e6Sthorpej } 1079c62a74e6Sthorpej 1080c62a74e6Sthorpej 1081c62a74e6Sthorpej void 1082c62a74e6Sthorpej pthread__cleanup_pop(int ex, void *store) 1083c62a74e6Sthorpej { 1084c62a74e6Sthorpej pthread_t self; 1085c62a74e6Sthorpej struct pt_clean_t *entry; 1086c62a74e6Sthorpej 1087c62a74e6Sthorpej self = pthread__self(); 1088c62a74e6Sthorpej entry = store; 1089c62a74e6Sthorpej 1090c62a74e6Sthorpej PTQ_REMOVE(&self->pt_cleanup_stack, entry, ptc_next); 1091c62a74e6Sthorpej if (ex) 1092c62a74e6Sthorpej (*entry->ptc_cleanup)(entry->ptc_arg); 1093c62a74e6Sthorpej } 1094c62a74e6Sthorpej 1095c62a74e6Sthorpej 1096c62a74e6Sthorpej int * 1097c62a74e6Sthorpej pthread__errno(void) 1098c62a74e6Sthorpej { 1099c62a74e6Sthorpej pthread_t self; 1100c62a74e6Sthorpej 1101c62a74e6Sthorpej self = pthread__self(); 1102c62a74e6Sthorpej 1103c62a74e6Sthorpej return &(self->pt_errno); 1104c62a74e6Sthorpej } 11058bcff70bSnathanw 11060c967901Snathanw ssize_t _sys_write(int, const void *, size_t); 11070c967901Snathanw 11088bcff70bSnathanw void 11090e6c93b9Sdrochner pthread__assertfunc(const char *file, int line, const char *function, 11100e6c93b9Sdrochner const char *expr) 11118bcff70bSnathanw { 11128bcff70bSnathanw char buf[1024]; 11138bcff70bSnathanw int len; 11148bcff70bSnathanw 111575a94788Smycroft SDPRINTF(("(af)\n")); 111675a94788Smycroft 11178bcff70bSnathanw /* 11188bcff70bSnathanw * snprintf should not acquire any locks, or we could 11198bcff70bSnathanw * end up deadlocked if the assert caller held locks. 11208bcff70bSnathanw */ 11218bcff70bSnathanw len = snprintf(buf, 1024, 11228bcff70bSnathanw "assertion \"%s\" failed: file \"%s\", line %d%s%s%s\n", 11238bcff70bSnathanw expr, file, line, 11248bcff70bSnathanw function ? ", function \"" : "", 11258bcff70bSnathanw function ? function : "", 11268bcff70bSnathanw function ? "\"" : ""); 11278bcff70bSnathanw 11280c967901Snathanw _sys_write(STDERR_FILENO, buf, (size_t)len); 11298bcff70bSnathanw (void)kill(getpid(), SIGABRT); 11308bcff70bSnathanw 11318bcff70bSnathanw _exit(1); 11328bcff70bSnathanw } 1133df277271Snathanw 1134df277271Snathanw 1135df277271Snathanw void 11360e6c93b9Sdrochner pthread__errorfunc(const char *file, int line, const char *function, 11370e6c93b9Sdrochner const char *msg) 1138df277271Snathanw { 1139df277271Snathanw char buf[1024]; 11400172694eSnathanw size_t len; 1141df277271Snathanw 11420172694eSnathanw if (pthread__diagassert == 0) 1143df277271Snathanw return; 1144df277271Snathanw 1145df277271Snathanw /* 1146df277271Snathanw * snprintf should not acquire any locks, or we could 1147df277271Snathanw * end up deadlocked if the assert caller held locks. 1148df277271Snathanw */ 1149df277271Snathanw len = snprintf(buf, 1024, 11500172694eSnathanw "%s: Error detected by libpthread: %s.\n" 11510172694eSnathanw "Detected by file \"%s\", line %d%s%s%s.\n" 11520172694eSnathanw "See pthread(3) for information.\n", 11530172694eSnathanw getprogname(), msg, file, line, 1154df277271Snathanw function ? ", function \"" : "", 1155df277271Snathanw function ? function : "", 11560172694eSnathanw function ? "\"" : ""); 1157df277271Snathanw 11580172694eSnathanw if (pthread__diagassert & DIAGASSERT_STDERR) 11590c967901Snathanw _sys_write(STDERR_FILENO, buf, len); 11600172694eSnathanw 11610172694eSnathanw if (pthread__diagassert & DIAGASSERT_SYSLOG) 11620172694eSnathanw syslog(LOG_DEBUG | LOG_USER, "%s", buf); 11630172694eSnathanw 11640172694eSnathanw if (pthread__diagassert & DIAGASSERT_ABORT) { 1165df277271Snathanw (void)kill(getpid(), SIGABRT); 1166df277271Snathanw _exit(1); 1167df277271Snathanw } 1168df277271Snathanw } 1169