1*1296e850Sad /* $NetBSD: pthread.c,v 1.62 2007/02/21 22:31:38 ad Exp $ */ 2c62a74e6Sthorpej 3c62a74e6Sthorpej /*- 4*1296e850Sad * Copyright (c) 2001, 2002, 2003, 2006, 2007 The NetBSD Foundation, Inc. 5c62a74e6Sthorpej * All rights reserved. 6c62a74e6Sthorpej * 7c62a74e6Sthorpej * This code is derived from software contributed to The NetBSD Foundation 81ac6a89bSad * by Nathan J. Williams and Andrew Doran. 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*1296e850Sad __RCSID("$NetBSD: pthread.c,v 1.62 2007/02/21 22:31:38 ad 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 68ded26025Sad /* Maximum number of LWPs to unpark in one operation. */ 69ded26025Sad #define PTHREAD__UNPARK_MAX 128 70ded26025Sad 71ded26025Sad /* How many times to try acquiring spin locks on MP systems. */ 72ded26025Sad #define PTHREAD__NSPINS 1000 73ded26025Sad 74c62a74e6Sthorpej static void pthread__create_tramp(void *(*start)(void *), void *arg); 756b2b9c62Syamt static void pthread__dead(pthread_t, pthread_t); 76c62a74e6Sthorpej 77c62a74e6Sthorpej int pthread__started; 78c62a74e6Sthorpej 7994a458ceSchs pthread_spin_t pthread__allqueue_lock = __SIMPLELOCK_UNLOCKED; 80c62a74e6Sthorpej struct pthread_queue_t pthread__allqueue; 81c62a74e6Sthorpej 8294a458ceSchs pthread_spin_t pthread__deadqueue_lock = __SIMPLELOCK_UNLOCKED; 83c62a74e6Sthorpej struct pthread_queue_t pthread__deadqueue; 84f2f10664Scl struct pthread_queue_t *pthread__reidlequeue; 85c62a74e6Sthorpej 86c62a74e6Sthorpej static int nthreads; 87c62a74e6Sthorpej static int nextthread; 8894a458ceSchs static pthread_spin_t nextthread_lock = __SIMPLELOCK_UNLOCKED; 89c62a74e6Sthorpej static pthread_attr_t pthread_default_attr; 90c62a74e6Sthorpej 910172694eSnathanw enum { 920172694eSnathanw DIAGASSERT_ABORT = 1<<0, 930172694eSnathanw DIAGASSERT_STDERR = 1<<1, 940172694eSnathanw DIAGASSERT_SYSLOG = 1<<2 950172694eSnathanw }; 96df277271Snathanw 970172694eSnathanw static int pthread__diagassert = DIAGASSERT_ABORT | DIAGASSERT_STDERR; 98df277271Snathanw 991ac6a89bSad #ifdef PTHREAD_SA 10094a458ceSchs pthread_spin_t pthread__runqueue_lock = __SIMPLELOCK_UNLOCKED; 101c62a74e6Sthorpej struct pthread_queue_t pthread__runqueue; 102c62a74e6Sthorpej struct pthread_queue_t pthread__idlequeue; 10338b1c6f4Schristos struct pthread_queue_t pthread__suspqueue; 104ded26025Sad #endif 105c62a74e6Sthorpej 106ded26025Sad int pthread__concurrency, pthread__maxconcurrency, pthread__nspins; 107ded26025Sad int pthread__unpark_max = PTHREAD__UNPARK_MAX; 108f2f10664Scl 109f782e995Sdrochner int _sys___sigprocmask14(int, const sigset_t *, sigset_t *); 110f782e995Sdrochner 111c62a74e6Sthorpej __strong_alias(__libc_thr_self,pthread_self) 1127dc01dbfSthorpej __strong_alias(__libc_thr_create,pthread_create) 1137dc01dbfSthorpej __strong_alias(__libc_thr_exit,pthread_exit) 114c62a74e6Sthorpej __strong_alias(__libc_thr_errno,pthread__errno) 1159e5c8705Snathanw __strong_alias(__libc_thr_setcancelstate,pthread_setcancelstate) 116c62a74e6Sthorpej 117c62a74e6Sthorpej /* 118c62a74e6Sthorpej * Static library kludge. Place a reference to a symbol any library 119c62a74e6Sthorpej * file which does not already have a reference here. 120c62a74e6Sthorpej */ 121c62a74e6Sthorpej extern int pthread__cancel_stub_binder; 1221ac6a89bSad #ifdef PTHREAD_SA 123c62a74e6Sthorpej extern int pthread__sched_binder; 1248bcff70bSnathanw extern struct pthread_queue_t pthread__nanosleeping; 1251ac6a89bSad #endif 126c62a74e6Sthorpej 127c62a74e6Sthorpej void *pthread__static_lib_binder[] = { 128c62a74e6Sthorpej &pthread__cancel_stub_binder, 129c62a74e6Sthorpej pthread_cond_init, 130c62a74e6Sthorpej pthread_mutex_init, 131c62a74e6Sthorpej pthread_rwlock_init, 132c62a74e6Sthorpej pthread_barrier_init, 133c62a74e6Sthorpej pthread_key_create, 134bd9a18b7Snathanw pthread_setspecific, 1351ac6a89bSad #ifdef PTHREAD_SA 136c62a74e6Sthorpej &pthread__sched_binder, 1378bcff70bSnathanw &pthread__nanosleeping 1381ac6a89bSad #endif 139c62a74e6Sthorpej }; 140c62a74e6Sthorpej 141c62a74e6Sthorpej /* 142c62a74e6Sthorpej * This needs to be started by the library loading code, before main() 143c62a74e6Sthorpej * gets to run, for various things that use the state of the initial thread 144c62a74e6Sthorpej * to work properly (thread-specific data is an application-visible example; 145c62a74e6Sthorpej * spinlock counts for mutexes is an internal example). 146c62a74e6Sthorpej */ 147c62a74e6Sthorpej void 148c62a74e6Sthorpej pthread_init(void) 149c62a74e6Sthorpej { 150c62a74e6Sthorpej pthread_t first; 1510172694eSnathanw char *p; 152ded26025Sad int i, mib[2], ncpu; 153f2f10664Scl size_t len; 154c62a74e6Sthorpej extern int __isthreaded; 155cca94056Schristos #ifdef PTHREAD_MLOCK_KLUDGE 156cca94056Schristos int ret; 157cca94056Schristos #endif 158c62a74e6Sthorpej 159f2f10664Scl mib[0] = CTL_HW; 160f2f10664Scl mib[1] = HW_NCPU; 161f2f10664Scl 162f2f10664Scl len = sizeof(ncpu); 163f2f10664Scl sysctl(mib, 2, &ncpu, &len, NULL, 0); 164f2f10664Scl 165c62a74e6Sthorpej /* Initialize locks first; they're needed elsewhere. */ 166f2f10664Scl pthread__lockprim_init(ncpu); 167f2f10664Scl 1681ac6a89bSad #ifdef PTHREAD_SA 169f2f10664Scl /* Find out requested/possible concurrency */ 170f2f10664Scl p = getenv("PTHREAD_CONCURRENCY"); 171b35aef8dSchristos pthread__maxconcurrency = p ? atoi(p) : 1; 1723a610280Schristos 173f2f10664Scl if (pthread__maxconcurrency < 1) 174f2f10664Scl pthread__maxconcurrency = 1; 175f2f10664Scl if (pthread__maxconcurrency > ncpu) 176f2f10664Scl pthread__maxconcurrency = ncpu; 177f2f10664Scl 178f2f10664Scl /* Allocate data structures */ 179f2f10664Scl pthread__reidlequeue = (struct pthread_queue_t *)malloc 180f2f10664Scl (pthread__maxconcurrency * sizeof(struct pthread_queue_t)); 181f2f10664Scl if (pthread__reidlequeue == NULL) 182f2f10664Scl err(1, "Couldn't allocate memory for pthread__reidlequeue"); 183ded26025Sad 184ded26025Sad pthread__nspins = PTHREAD__NSPINS; 185ded26025Sad #else 186ded26025Sad /* 187ded26025Sad * Get number of CPUs, and maximum number of LWPs that can be 188ded26025Sad * unparked at once. 189ded26025Sad */ 190ded26025Sad if ((pthread__concurrency = ncpu) > 1) 191ded26025Sad pthread__nspins = PTHREAD__NSPINS; 192ded26025Sad else 193ded26025Sad pthread__nspins = 1; 1943247035dSad i = (int)_lwp_unpark_all(NULL, 0, NULL); 1953247035dSad if (i == -1) 1963247035dSad err(1, "_lwp_unpark_all"); 197ded26025Sad if (i < pthread__unpark_max) 198ded26025Sad pthread__unpark_max = i; 1991ac6a89bSad #endif 200c62a74e6Sthorpej 201c62a74e6Sthorpej /* Basic data structure setup */ 202c62a74e6Sthorpej pthread_attr_init(&pthread_default_attr); 203c62a74e6Sthorpej PTQ_INIT(&pthread__allqueue); 204c62a74e6Sthorpej PTQ_INIT(&pthread__deadqueue); 205cca94056Schristos #ifdef PTHREAD_MLOCK_KLUDGE 206cca94056Schristos ret = mlock(&pthread__deadqueue, sizeof(pthread__deadqueue)); 207cca94056Schristos pthread__assert(ret == 0); 208cca94056Schristos #endif 2091ac6a89bSad #ifdef PTHREAD_SA 210c62a74e6Sthorpej PTQ_INIT(&pthread__runqueue); 211c62a74e6Sthorpej PTQ_INIT(&pthread__idlequeue); 212f2f10664Scl for (i = 0; i < pthread__maxconcurrency; i++) 213f2f10664Scl PTQ_INIT(&pthread__reidlequeue[i]); 2141ac6a89bSad #endif 215ded26025Sad nthreads = 1; 216c62a74e6Sthorpej /* Create the thread structure corresponding to main() */ 217c62a74e6Sthorpej pthread__initmain(&first); 218c62a74e6Sthorpej pthread__initthread(first, first); 2191ac6a89bSad 220c62a74e6Sthorpej first->pt_state = PT_STATE_RUNNING; 2211ac6a89bSad #ifdef PTHREAD_SA 222f782e995Sdrochner _sys___sigprocmask14(0, NULL, &first->pt_sigmask); 2231ac6a89bSad #else 2241ac6a89bSad first->pt_lid = _lwp_self(); 2251ac6a89bSad #endif 226c62a74e6Sthorpej PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq); 227c62a74e6Sthorpej 228c62a74e6Sthorpej /* Start subsystems */ 2291ac6a89bSad #ifdef PTHREAD_SA 230c62a74e6Sthorpej pthread__signal_init(); 2311ac6a89bSad #endif 232c62a74e6Sthorpej PTHREAD_MD_INIT 233c62a74e6Sthorpej #ifdef PTHREAD__DEBUG 234f2f10664Scl pthread__debug_init(ncpu); 235c62a74e6Sthorpej #endif 236c62a74e6Sthorpej 2370172694eSnathanw for (p = getenv("PTHREAD_DIAGASSERT"); p && *p; p++) { 2380172694eSnathanw switch (*p) { 2390172694eSnathanw case 'a': 2400172694eSnathanw pthread__diagassert |= DIAGASSERT_ABORT; 2410172694eSnathanw break; 2420172694eSnathanw case 'A': 2430172694eSnathanw pthread__diagassert &= ~DIAGASSERT_ABORT; 2440172694eSnathanw break; 2450172694eSnathanw case 'e': 2460172694eSnathanw pthread__diagassert |= DIAGASSERT_STDERR; 2470172694eSnathanw break; 2480172694eSnathanw case 'E': 2490172694eSnathanw pthread__diagassert &= ~DIAGASSERT_STDERR; 2500172694eSnathanw break; 2510172694eSnathanw case 'l': 2520172694eSnathanw pthread__diagassert |= DIAGASSERT_SYSLOG; 2530172694eSnathanw break; 2540172694eSnathanw case 'L': 2550172694eSnathanw pthread__diagassert &= ~DIAGASSERT_SYSLOG; 2560172694eSnathanw break; 257df277271Snathanw } 2580172694eSnathanw } 2590172694eSnathanw 260df277271Snathanw 261c62a74e6Sthorpej /* Tell libc that we're here and it should role-play accordingly. */ 262c62a74e6Sthorpej __isthreaded = 1; 263c62a74e6Sthorpej } 264c62a74e6Sthorpej 2652a4cef11Snathanw static void 2662a4cef11Snathanw pthread__child_callback(void) 2672a4cef11Snathanw { 2682a4cef11Snathanw /* 2692a4cef11Snathanw * Clean up data structures that a forked child process might 2702a4cef11Snathanw * trip over. Note that if threads have been created (causing 2712a4cef11Snathanw * this handler to be registered) the standards say that the 2722a4cef11Snathanw * child will trigger undefined behavior if it makes any 2732a4cef11Snathanw * pthread_* calls (or any other calls that aren't 2742a4cef11Snathanw * async-signal-safe), so we don't really have to clean up 2752a4cef11Snathanw * much. Anything that permits some pthread_* calls to work is 2762a4cef11Snathanw * merely being polite. 2772a4cef11Snathanw */ 2782a4cef11Snathanw pthread__started = 0; 2792a4cef11Snathanw } 280c62a74e6Sthorpej 2810e675542Schs static void 282c62a74e6Sthorpej pthread__start(void) 283c62a74e6Sthorpej { 2841ac6a89bSad pthread_t self; 2851ac6a89bSad #ifdef PTHREAD_SA 2861ac6a89bSad pthread_t idle; 287c62a74e6Sthorpej int i, ret; 2881ac6a89bSad #endif 289c62a74e6Sthorpej 290c62a74e6Sthorpej self = pthread__self(); /* should be the "main()" thread */ 291c62a74e6Sthorpej 292ff14fbf2Snathanw /* 293ff14fbf2Snathanw * Per-process timers are cleared by fork(); despite the 294ff14fbf2Snathanw * various restrictions on fork() and threads, it's legal to 295ff14fbf2Snathanw * fork() before creating any threads. 296ff14fbf2Snathanw */ 2971ac6a89bSad #ifdef PTHREAD_SA 298ff14fbf2Snathanw pthread__alarm_init(); 299ff14fbf2Snathanw 300916de878Snathanw pthread__signal_start(); 3011ac6a89bSad #endif 302916de878Snathanw 3032a4cef11Snathanw pthread_atfork(NULL, NULL, pthread__child_callback); 304c62a74e6Sthorpej 3051ac6a89bSad #ifdef PTHREAD_SA 306f2f10664Scl /* 307f2f10664Scl * Create idle threads 308f2f10664Scl * XXX need to create more idle threads if concurrency > 3 309f2f10664Scl */ 310c62a74e6Sthorpej for (i = 0; i < NIDLETHREADS; i++) { 311c62a74e6Sthorpej ret = pthread__stackalloc(&idle); 312c62a74e6Sthorpej if (ret != 0) 313c62a74e6Sthorpej err(1, "Couldn't allocate stack for idle thread!"); 314c62a74e6Sthorpej pthread__initthread(self, idle); 315c62a74e6Sthorpej sigfillset(&idle->pt_sigmask); 316c62a74e6Sthorpej idle->pt_type = PT_THREAD_IDLE; 317c62a74e6Sthorpej PTQ_INSERT_HEAD(&pthread__allqueue, idle, pt_allq); 318c62a74e6Sthorpej pthread__sched_idle(self, idle); 319c62a74e6Sthorpej } 320c62a74e6Sthorpej 321c62a74e6Sthorpej /* Start up the SA subsystem */ 322c62a74e6Sthorpej pthread__sa_start(); 3231ac6a89bSad #endif 3241ac6a89bSad 325c62a74e6Sthorpej SDPRINTF(("(pthread__start %p) Started.\n", self)); 326c62a74e6Sthorpej } 327c62a74e6Sthorpej 328c62a74e6Sthorpej 329c62a74e6Sthorpej /* General-purpose thread data structure sanitization. */ 330c62a74e6Sthorpej void 331c62a74e6Sthorpej pthread__initthread(pthread_t self, pthread_t t) 332c62a74e6Sthorpej { 333c62a74e6Sthorpej int id; 334c62a74e6Sthorpej 335c62a74e6Sthorpej pthread_spinlock(self, &nextthread_lock); 336c62a74e6Sthorpej id = nextthread; 337c62a74e6Sthorpej nextthread++; 338c62a74e6Sthorpej pthread_spinunlock(self, &nextthread_lock); 339c62a74e6Sthorpej t->pt_num = id; 340c62a74e6Sthorpej 341c62a74e6Sthorpej t->pt_magic = PT_MAGIC; 3420878df5dSnathanw pthread_lockinit(&t->pt_flaglock); 343c62a74e6Sthorpej t->pt_spinlocks = 0; 344c62a74e6Sthorpej t->pt_exitval = NULL; 345c62a74e6Sthorpej t->pt_flags = 0; 346c62a74e6Sthorpej t->pt_cancel = 0; 347c62a74e6Sthorpej t->pt_errno = 0; 3481ac6a89bSad 3491ac6a89bSad #ifdef PTHREAD_SA 3501ac6a89bSad t->pt_type = PT_THREAD_NORMAL; 3511ac6a89bSad t->pt_state = PT_STATE_RUNNABLE; 352c62a74e6Sthorpej t->pt_heldlock = NULL; 3531ac6a89bSad t->pt_next = NULL; 3541ac6a89bSad t->pt_parent = NULL; 355c62a74e6Sthorpej t->pt_switchto = NULL; 356487eb7e1Snathanw t->pt_trapuc = NULL; 357c62a74e6Sthorpej sigemptyset(&t->pt_siglist); 358c62a74e6Sthorpej sigemptyset(&t->pt_sigmask); 359c62a74e6Sthorpej pthread_lockinit(&t->pt_siglock); 3601ac6a89bSad #else 3611ac6a89bSad t->pt_state = PT_STATE_RUNNING; 3621ac6a89bSad #endif 3631ac6a89bSad 3641ac6a89bSad pthread_lockinit(&t->pt_statelock); 3651ac6a89bSad 366c62a74e6Sthorpej PTQ_INIT(&t->pt_joiners); 367c62a74e6Sthorpej pthread_lockinit(&t->pt_join_lock); 368c62a74e6Sthorpej PTQ_INIT(&t->pt_cleanup_stack); 369c62a74e6Sthorpej memset(&t->pt_specific, 0, sizeof(int) * PTHREAD_KEYS_MAX); 370b33971b9Sthorpej t->pt_name = NULL; 3711ac6a89bSad 3721ac6a89bSad #if defined(PTHREAD__DEBUG) && defined(PTHREAD_SA) 373c62a74e6Sthorpej t->blocks = 0; 374c62a74e6Sthorpej t->preempts = 0; 375c62a74e6Sthorpej t->rescheds = 0; 376c62a74e6Sthorpej #endif 377c62a74e6Sthorpej } 378c62a74e6Sthorpej 379c62a74e6Sthorpej 380c62a74e6Sthorpej int 381c62a74e6Sthorpej pthread_create(pthread_t *thread, const pthread_attr_t *attr, 382c62a74e6Sthorpej void *(*startfunc)(void *), void *arg) 383c62a74e6Sthorpej { 384c62a74e6Sthorpej pthread_t self, newthread; 385c62a74e6Sthorpej pthread_attr_t nattr; 386b33971b9Sthorpej struct pthread_attr_private *p; 3873ca3d0b1Schristos char * volatile name; 388c62a74e6Sthorpej int ret; 3891ac6a89bSad #ifndef PTHREAD_SA 3901ac6a89bSad int flag; 3911ac6a89bSad #endif 392c62a74e6Sthorpej 393c62a74e6Sthorpej PTHREADD_ADD(PTHREADD_CREATE); 394c62a74e6Sthorpej 395c62a74e6Sthorpej /* 396c62a74e6Sthorpej * It's okay to check this without a lock because there can 397c62a74e6Sthorpej * only be one thread before it becomes true. 398c62a74e6Sthorpej */ 399c62a74e6Sthorpej if (pthread__started == 0) { 400c62a74e6Sthorpej pthread__start(); 401c62a74e6Sthorpej pthread__started = 1; 402c62a74e6Sthorpej } 403c62a74e6Sthorpej 404c62a74e6Sthorpej if (attr == NULL) 405c62a74e6Sthorpej nattr = pthread_default_attr; 406e81f9f17Sdrochner else if (attr->pta_magic == PT_ATTR_MAGIC) 407c62a74e6Sthorpej nattr = *attr; 408c62a74e6Sthorpej else 409c62a74e6Sthorpej return EINVAL; 410c62a74e6Sthorpej 411b33971b9Sthorpej /* Fetch misc. attributes from the attr structure. */ 412508a50acSnathanw name = NULL; 413508a50acSnathanw if ((p = nattr.pta_private) != NULL) 414508a50acSnathanw if (p->ptap_name[0] != '\0') 415b33971b9Sthorpej if ((name = strdup(p->ptap_name)) == NULL) 416b33971b9Sthorpej return ENOMEM; 417c62a74e6Sthorpej 418c62a74e6Sthorpej self = pthread__self(); 419c62a74e6Sthorpej 420c62a74e6Sthorpej pthread_spinlock(self, &pthread__deadqueue_lock); 421c62a74e6Sthorpej newthread = PTQ_FIRST(&pthread__deadqueue); 4224cdc2ed8Syamt if (newthread != NULL) { 4234cdc2ed8Syamt #ifndef PTHREAD_SA 424dacd4bd9Sad if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0 && 425dacd4bd9Sad (_lwp_kill(newthread->pt_lid, 0) == 0 || errno != ESRCH)) 4264cdc2ed8Syamt newthread = NULL; 4274cdc2ed8Syamt else 4284cdc2ed8Syamt #endif 429c62a74e6Sthorpej PTQ_REMOVE(&pthread__deadqueue, newthread, pt_allq); 4304cdc2ed8Syamt } 431c62a74e6Sthorpej pthread_spinunlock(self, &pthread__deadqueue_lock); 4324cdc2ed8Syamt if (newthread == NULL) { 433c62a74e6Sthorpej /* Set up a stack and allocate space for a pthread_st. */ 434c62a74e6Sthorpej ret = pthread__stackalloc(&newthread); 435b7559f85Schristos if (ret != 0) { 436b7559f85Schristos if (name) 437b7559f85Schristos free(name); 438c62a74e6Sthorpej return ret; 439c62a74e6Sthorpej } 440b7559f85Schristos } 441c62a74e6Sthorpej 442c62a74e6Sthorpej /* 2. Set up state. */ 443c62a74e6Sthorpej pthread__initthread(self, newthread); 444c62a74e6Sthorpej newthread->pt_flags = nattr.pta_flags; 4451ac6a89bSad #ifdef PTHREAD_SA 446c62a74e6Sthorpej newthread->pt_sigmask = self->pt_sigmask; 4471ac6a89bSad #endif 448c62a74e6Sthorpej 449b33971b9Sthorpej /* 3. Set up misc. attributes. */ 450b33971b9Sthorpej newthread->pt_name = name; 451b33971b9Sthorpej 452c62a74e6Sthorpej /* 453b33971b9Sthorpej * 4. Set up context. 454c62a74e6Sthorpej * 455c62a74e6Sthorpej * The pt_uc pointer points to a location safely below the 456c62a74e6Sthorpej * stack start; this is arranged by pthread__stackalloc(). 457c62a74e6Sthorpej */ 458c62a74e6Sthorpej _INITCONTEXT_U(newthread->pt_uc); 459877f8985Snathanw #ifdef PTHREAD_MACHINE_HAS_ID_REGISTER 460877f8985Snathanw pthread__uc_id(newthread->pt_uc) = newthread; 461877f8985Snathanw #endif 462c62a74e6Sthorpej newthread->pt_uc->uc_stack = newthread->pt_stack; 463c62a74e6Sthorpej newthread->pt_uc->uc_link = NULL; 464c62a74e6Sthorpej makecontext(newthread->pt_uc, pthread__create_tramp, 2, 465c62a74e6Sthorpej startfunc, arg); 466c62a74e6Sthorpej 467efb1fc06Sad /* 5. Add to list of all threads. */ 468efb1fc06Sad pthread_spinlock(self, &pthread__allqueue_lock); 469efb1fc06Sad PTQ_INSERT_HEAD(&pthread__allqueue, newthread, pt_allq); 470efb1fc06Sad nthreads++; 471efb1fc06Sad pthread_spinunlock(self, &pthread__allqueue_lock); 472efb1fc06Sad 4731ac6a89bSad #ifndef PTHREAD_SA 474efb1fc06Sad /* 5a. Create the new LWP. */ 4757630e387Sad newthread->pt_sleeponq = 0; 476ded26025Sad flag = 0; 477ded26025Sad if ((newthread->pt_flags & PT_FLAG_SUSPENDED) != 0) 478ded26025Sad flag |= LWP_SUSPENDED; 479ded26025Sad if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0) 480ded26025Sad flag |= LWP_DETACHED; 4811ac6a89bSad ret = _lwp_create(newthread->pt_uc, (u_long)flag, &newthread->pt_lid); 4821ac6a89bSad if (ret != 0) { 4831ac6a89bSad SDPRINTF(("(pthread_create %p) _lwp_create: %s\n", 4841ac6a89bSad strerror(errno))); 4851ac6a89bSad free(name); 486efb1fc06Sad pthread_spinlock(self, &pthread__allqueue_lock); 487efb1fc06Sad PTQ_REMOVE(&pthread__allqueue, newthread, pt_allq); 488efb1fc06Sad nthreads--; 489efb1fc06Sad pthread_spinunlock(self, &pthread__allqueue_lock); 490efb1fc06Sad pthread_spinlock(self, &pthread__deadqueue_lock); 491efb1fc06Sad PTQ_INSERT_HEAD(&pthread__deadqueue, newthread, pt_allq); 492efb1fc06Sad pthread_spinunlock(self, &pthread__deadqueue_lock); 4931ac6a89bSad return ret; 4941ac6a89bSad } 4951ac6a89bSad #endif 4961ac6a89bSad 4971ac6a89bSad #ifdef PTHREAD_SA 498ba70e96aSchs SDPRINTF(("(pthread_create %p) new thread %p (name pointer %p).\n", 499ba70e96aSchs self, newthread, newthread->pt_name)); 50038b1c6f4Schristos /* 6. Put on appropriate queue. */ 50138b1c6f4Schristos if (newthread->pt_flags & PT_FLAG_SUSPENDED) { 50238b1c6f4Schristos pthread_spinlock(self, &newthread->pt_statelock); 50338b1c6f4Schristos pthread__suspend(self, newthread); 50438b1c6f4Schristos pthread_spinunlock(self, &newthread->pt_statelock); 50538b1c6f4Schristos } else 506c62a74e6Sthorpej pthread__sched(self, newthread); 5071ac6a89bSad #else 5081ac6a89bSad SDPRINTF(("(pthread_create %p) new thread %p (name %p, lid %d).\n", 5091ac6a89bSad self, newthread, newthread->pt_name, 5101ac6a89bSad (int)newthread->pt_lid)); 5111ac6a89bSad #endif 512c62a74e6Sthorpej 513c62a74e6Sthorpej *thread = newthread; 514c62a74e6Sthorpej 515c62a74e6Sthorpej return 0; 516c62a74e6Sthorpej } 517c62a74e6Sthorpej 518c62a74e6Sthorpej 519c62a74e6Sthorpej static void 520c62a74e6Sthorpej pthread__create_tramp(void *(*start)(void *), void *arg) 521c62a74e6Sthorpej { 522c62a74e6Sthorpej void *retval; 523c62a74e6Sthorpej 52494a458ceSchs retval = (*start)(arg); 525c62a74e6Sthorpej 526c62a74e6Sthorpej pthread_exit(retval); 527c62a74e6Sthorpej 528143f5a27Schristos /*NOTREACHED*/ 529143f5a27Schristos pthread__abort(); 530c62a74e6Sthorpej } 531c62a74e6Sthorpej 53238b1c6f4Schristos int 53338b1c6f4Schristos pthread_suspend_np(pthread_t thread) 53438b1c6f4Schristos { 535ba70e96aSchs pthread_t self; 536ba70e96aSchs 537ba70e96aSchs self = pthread__self(); 53838b1c6f4Schristos if (self == thread) { 53938b1c6f4Schristos return EDEADLK; 54038b1c6f4Schristos } 541ba70e96aSchs #ifdef ERRORCHECK 542ba70e96aSchs if (pthread__find(self, thread) != 0) 543ba70e96aSchs return ESRCH; 544ba70e96aSchs #endif 5451ac6a89bSad #ifdef PTHREAD_SA 54638b1c6f4Schristos SDPRINTF(("(pthread_suspend_np %p) Suspend thread %p (state %d).\n", 54738b1c6f4Schristos self, thread, thread->pt_state)); 54838b1c6f4Schristos pthread_spinlock(self, &thread->pt_statelock); 54982b6b2dbScl if (thread->pt_blockgen != thread->pt_unblockgen) { 55082b6b2dbScl /* XXX flaglock? */ 55182b6b2dbScl thread->pt_flags |= PT_FLAG_SUSPENDED; 55282b6b2dbScl pthread_spinunlock(self, &thread->pt_statelock); 55382b6b2dbScl return 0; 55482b6b2dbScl } 55538b1c6f4Schristos switch (thread->pt_state) { 55638b1c6f4Schristos case PT_STATE_RUNNING: 55738b1c6f4Schristos pthread__abort(); /* XXX */ 55838b1c6f4Schristos break; 55938b1c6f4Schristos case PT_STATE_SUSPENDED: 56038b1c6f4Schristos pthread_spinunlock(self, &thread->pt_statelock); 56138b1c6f4Schristos return 0; 56238b1c6f4Schristos case PT_STATE_RUNNABLE: 56338b1c6f4Schristos pthread_spinlock(self, &pthread__runqueue_lock); 56438b1c6f4Schristos PTQ_REMOVE(&pthread__runqueue, thread, pt_runq); 56538b1c6f4Schristos pthread_spinunlock(self, &pthread__runqueue_lock); 56638b1c6f4Schristos break; 56738b1c6f4Schristos case PT_STATE_BLOCKED_QUEUE: 56838b1c6f4Schristos pthread_spinlock(self, thread->pt_sleeplock); 56938b1c6f4Schristos PTQ_REMOVE(thread->pt_sleepq, thread, pt_sleep); 57038b1c6f4Schristos pthread_spinunlock(self, thread->pt_sleeplock); 57138b1c6f4Schristos break; 572ba70e96aSchs case PT_STATE_ZOMBIE: 573ba70e96aSchs goto out; 57438b1c6f4Schristos default: 57538b1c6f4Schristos break; /* XXX */ 57638b1c6f4Schristos } 57738b1c6f4Schristos pthread__suspend(self, thread); 578ba70e96aSchs 579ba70e96aSchs out: 58038b1c6f4Schristos pthread_spinunlock(self, &thread->pt_statelock); 58138b1c6f4Schristos return 0; 5821ac6a89bSad #else 5831ac6a89bSad SDPRINTF(("(pthread_suspend_np %p) Suspend thread %p.\n", 5841ac6a89bSad self, thread)); 5851ac6a89bSad return _lwp_suspend(thread->pt_lid); 5861ac6a89bSad #endif 58738b1c6f4Schristos } 58838b1c6f4Schristos 58938b1c6f4Schristos int 59038b1c6f4Schristos pthread_resume_np(pthread_t thread) 59138b1c6f4Schristos { 592ba70e96aSchs pthread_t self; 59338b1c6f4Schristos 594ba70e96aSchs self = pthread__self(); 595ba70e96aSchs #ifdef ERRORCHECK 596ba70e96aSchs if (pthread__find(self, thread) != 0) 597ba70e96aSchs return ESRCH; 598ba70e96aSchs #endif 5991ac6a89bSad #ifdef PTHREAD_SA 60038b1c6f4Schristos SDPRINTF(("(pthread_resume_np %p) Resume thread %p (state %d).\n", 60138b1c6f4Schristos self, thread, thread->pt_state)); 60238b1c6f4Schristos pthread_spinlock(self, &thread->pt_statelock); 60338b1c6f4Schristos /* XXX flaglock? */ 60438b1c6f4Schristos thread->pt_flags &= ~PT_FLAG_SUSPENDED; 60538b1c6f4Schristos if (thread->pt_state == PT_STATE_SUSPENDED) { 60638b1c6f4Schristos pthread_spinlock(self, &pthread__runqueue_lock); 60738b1c6f4Schristos PTQ_REMOVE(&pthread__suspqueue, thread, pt_runq); 60838b1c6f4Schristos pthread_spinunlock(self, &pthread__runqueue_lock); 60938b1c6f4Schristos pthread__sched(self, thread); 61038b1c6f4Schristos } 61138b1c6f4Schristos pthread_spinunlock(self, &thread->pt_statelock); 61238b1c6f4Schristos return 0; 6131ac6a89bSad #else 6141ac6a89bSad SDPRINTF(("(pthread_resume_np %p) Resume thread %p.\n", 6151ac6a89bSad self, thread)); 6161ac6a89bSad return _lwp_continue(thread->pt_lid); 6171ac6a89bSad #endif 61838b1c6f4Schristos } 61938b1c6f4Schristos 6201ac6a89bSad #ifdef PTHREAD_SA 621c62a74e6Sthorpej /* 622c62a74e6Sthorpej * Other threads will switch to the idle thread so that they 623c62a74e6Sthorpej * can dispose of any awkward locks or recycle upcall state. 624c62a74e6Sthorpej */ 625c62a74e6Sthorpej void 626c62a74e6Sthorpej pthread__idle(void) 627c62a74e6Sthorpej { 628c62a74e6Sthorpej pthread_t self; 629c62a74e6Sthorpej 630c62a74e6Sthorpej PTHREADD_ADD(PTHREADD_IDLE); 631c62a74e6Sthorpej self = pthread__self(); 632c62a74e6Sthorpej SDPRINTF(("(pthread__idle %p).\n", self)); 633c62a74e6Sthorpej 634c62a74e6Sthorpej /* 635c62a74e6Sthorpej * The drill here is that we want to yield the processor, 636c62a74e6Sthorpej * but for the thread itself to be recovered, we need to be on 637c62a74e6Sthorpej * a list somewhere for the thread system to know about us. 638c62a74e6Sthorpej */ 639c62a74e6Sthorpej pthread_spinlock(self, &pthread__deadqueue_lock); 640f2f10664Scl PTQ_INSERT_TAIL(&pthread__reidlequeue[self->pt_vpid], self, pt_runq); 641f2f10664Scl pthread__concurrency--; 642f2f10664Scl SDPRINTF(("(yield %p concurrency) now %d\n", self, 643f2f10664Scl pthread__concurrency)); 6440878df5dSnathanw /* Don't need a flag lock; nothing else has a handle on this thread */ 645c62a74e6Sthorpej self->pt_flags |= PT_FLAG_IDLED; 646c62a74e6Sthorpej pthread_spinunlock(self, &pthread__deadqueue_lock); 647c62a74e6Sthorpej 648c62a74e6Sthorpej /* 649c62a74e6Sthorpej * If we get to run this, then no preemption has happened 650c62a74e6Sthorpej * (because the upcall handler will not continue an idle thread with 651c62a74e6Sthorpej * PT_FLAG_IDLED set), and so we can yield the processor safely. 652c62a74e6Sthorpej */ 653c62a74e6Sthorpej SDPRINTF(("(pthread__idle %p) yielding.\n", self)); 654c62a74e6Sthorpej sa_yield(); 655c62a74e6Sthorpej 656c62a74e6Sthorpej /* NOTREACHED */ 657c62a74e6Sthorpej self->pt_spinlocks++; /* XXX make sure we get to finish the assert! */ 658c62a74e6Sthorpej SDPRINTF(("(pthread__idle %p) Returned! Error.\n", self)); 659143f5a27Schristos pthread__abort(); 660c62a74e6Sthorpej } 6611ac6a89bSad #endif 662c62a74e6Sthorpej 663c62a74e6Sthorpej 664c62a74e6Sthorpej void 665c62a74e6Sthorpej pthread_exit(void *retval) 666c62a74e6Sthorpej { 66796b5a26dSnathanw pthread_t self; 668c62a74e6Sthorpej struct pt_clean_t *cleanup; 669b33971b9Sthorpej char *name; 6706b2b9c62Syamt int nt; 671c62a74e6Sthorpej 672c62a74e6Sthorpej self = pthread__self(); 673ba70e96aSchs SDPRINTF(("(pthread_exit %p) status %p, flags %x, cancel %d\n", 674ba70e96aSchs self, retval, self->pt_flags, self->pt_cancel)); 675c62a74e6Sthorpej 676c62a74e6Sthorpej /* Disable cancellability. */ 6770878df5dSnathanw pthread_spinlock(self, &self->pt_flaglock); 678c62a74e6Sthorpej self->pt_flags |= PT_FLAG_CS_DISABLED; 67966fcc1ceSnathanw self->pt_cancel = 0; 6800878df5dSnathanw pthread_spinunlock(self, &self->pt_flaglock); 681c62a74e6Sthorpej 682c62a74e6Sthorpej /* Call any cancellation cleanup handlers */ 683c62a74e6Sthorpej while (!PTQ_EMPTY(&self->pt_cleanup_stack)) { 684c62a74e6Sthorpej cleanup = PTQ_FIRST(&self->pt_cleanup_stack); 685c62a74e6Sthorpej PTQ_REMOVE(&self->pt_cleanup_stack, cleanup, ptc_next); 686c62a74e6Sthorpej (*cleanup->ptc_cleanup)(cleanup->ptc_arg); 687c62a74e6Sthorpej } 688c62a74e6Sthorpej 689c62a74e6Sthorpej /* Perform cleanup of thread-specific data */ 690c62a74e6Sthorpej pthread__destroy_tsd(self); 691c62a74e6Sthorpej 692c62a74e6Sthorpej self->pt_exitval = retval; 693c62a74e6Sthorpej 6946b2b9c62Syamt /* 6956b2b9c62Syamt * it's safe to check PT_FLAG_DETACHED without pt_flaglock 6966b2b9c62Syamt * because it's only set by pthread_detach with pt_join_lock held. 6976b2b9c62Syamt */ 6986b2b9c62Syamt pthread_spinlock(self, &self->pt_join_lock); 6996b2b9c62Syamt if (self->pt_flags & PT_FLAG_DETACHED) { 7006b2b9c62Syamt self->pt_state = PT_STATE_DEAD; 7016b2b9c62Syamt pthread_spinunlock(self, &self->pt_join_lock); 702b33971b9Sthorpej name = self->pt_name; 703b33971b9Sthorpej self->pt_name = NULL; 704c62a74e6Sthorpej 705b33971b9Sthorpej if (name != NULL) 706b33971b9Sthorpej free(name); 707b33971b9Sthorpej 708c62a74e6Sthorpej pthread_spinlock(self, &pthread__allqueue_lock); 709c62a74e6Sthorpej PTQ_REMOVE(&pthread__allqueue, self, pt_allq); 710c62a74e6Sthorpej nthreads--; 711c62a74e6Sthorpej nt = nthreads; 712c62a74e6Sthorpej pthread_spinunlock(self, &pthread__allqueue_lock); 713c62a74e6Sthorpej 714c62a74e6Sthorpej if (nt == 0) { 715c62a74e6Sthorpej /* Whoah, we're the last one. Time to go. */ 716c62a74e6Sthorpej exit(0); 717c62a74e6Sthorpej } 718c62a74e6Sthorpej 719c62a74e6Sthorpej /* Yeah, yeah, doing work while we're dead is tacky. */ 720c62a74e6Sthorpej pthread_spinlock(self, &pthread__deadqueue_lock); 721*1296e850Sad PTQ_INSERT_TAIL(&pthread__deadqueue, self, pt_allq); 722ded26025Sad 723ded26025Sad #ifdef PTHREAD_SA 724c62a74e6Sthorpej pthread__block(self, &pthread__deadqueue_lock); 725ba70e96aSchs SDPRINTF(("(pthread_exit %p) walking dead\n", self)); 7261ac6a89bSad pthread_spinunlock(self, &pthread__allqueue_lock); 727ded26025Sad #else 728ded26025Sad pthread_spinunlock(self, &pthread__deadqueue_lock); 7291ac6a89bSad _lwp_exit(); 7301ac6a89bSad #endif 731c62a74e6Sthorpej } else { 7326b2b9c62Syamt self->pt_state = PT_STATE_ZOMBIE; 7331ac6a89bSad 734b33971b9Sthorpej /* Note: name will be freed by the joiner. */ 735c62a74e6Sthorpej pthread_spinlock(self, &pthread__allqueue_lock); 736c62a74e6Sthorpej nthreads--; 737c62a74e6Sthorpej nt = nthreads; 738c62a74e6Sthorpej pthread_spinunlock(self, &pthread__allqueue_lock); 739c62a74e6Sthorpej if (nt == 0) { 740c62a74e6Sthorpej /* Whoah, we're the last one. Time to go. */ 741c62a74e6Sthorpej exit(0); 742c62a74e6Sthorpej } 743ded26025Sad 744ded26025Sad #ifdef PTHREAD_SA 74596b5a26dSnathanw /* 74696b5a26dSnathanw * Wake up all the potential joiners. Only one can win. 747c62a74e6Sthorpej * (Can you say "Thundering Herd"? I knew you could.) 748c62a74e6Sthorpej */ 74996b5a26dSnathanw pthread__sched_sleepers(self, &self->pt_joiners); 750c62a74e6Sthorpej pthread__block(self, &self->pt_join_lock); 751ba70e96aSchs SDPRINTF(("(pthread_exit %p) walking zombie\n", self)); 7521ac6a89bSad #else 7531ac6a89bSad pthread_spinunlock(self, &self->pt_join_lock); 7541ac6a89bSad _lwp_exit(); 7551ac6a89bSad #endif 756c62a74e6Sthorpej } 757c62a74e6Sthorpej 758143f5a27Schristos /*NOTREACHED*/ 759143f5a27Schristos pthread__abort(); 760c62a74e6Sthorpej exit(1); 761c62a74e6Sthorpej } 762c62a74e6Sthorpej 763c62a74e6Sthorpej 764c62a74e6Sthorpej int 765c62a74e6Sthorpej pthread_join(pthread_t thread, void **valptr) 766c62a74e6Sthorpej { 767c62a74e6Sthorpej pthread_t self; 768b33971b9Sthorpej char *name; 7691ac6a89bSad int num, retval; 770c62a74e6Sthorpej 771c62a74e6Sthorpej self = pthread__self(); 772c62a74e6Sthorpej SDPRINTF(("(pthread_join %p) Joining %p.\n", self, thread)); 773c62a74e6Sthorpej 774c62a74e6Sthorpej if (pthread__find(self, thread) != 0) 775c62a74e6Sthorpej return ESRCH; 776c62a74e6Sthorpej 777c62a74e6Sthorpej if (thread->pt_magic != PT_MAGIC) 778c62a74e6Sthorpej return EINVAL; 779c62a74e6Sthorpej 780c62a74e6Sthorpej if (thread == self) 781c62a74e6Sthorpej return EDEADLK; 782c62a74e6Sthorpej 7831ac6a89bSad #ifdef PTHREAD_SA 7840878df5dSnathanw pthread_spinlock(self, &thread->pt_flaglock); 785c62a74e6Sthorpej 786c62a74e6Sthorpej if (thread->pt_flags & PT_FLAG_DETACHED) { 7870878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 788c62a74e6Sthorpej return EINVAL; 789c62a74e6Sthorpej } 790c62a74e6Sthorpej 791564fe117Snathanw num = thread->pt_num; 7920878df5dSnathanw pthread_spinlock(self, &thread->pt_join_lock); 793564fe117Snathanw while (thread->pt_state != PT_STATE_ZOMBIE) { 794564fe117Snathanw if ((thread->pt_state == PT_STATE_DEAD) || 795564fe117Snathanw (thread->pt_flags & PT_FLAG_DETACHED) || 796564fe117Snathanw (thread->pt_num != num)) { 797564fe117Snathanw /* 798564fe117Snathanw * Another thread beat us to the join, or called 799564fe117Snathanw * pthread_detach(). If num didn't match, the 800564fe117Snathanw * thread died and was recycled before we got 801564fe117Snathanw * another chance to run. 802564fe117Snathanw */ 803564fe117Snathanw pthread_spinunlock(self, &thread->pt_join_lock); 8040878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 805564fe117Snathanw return ESRCH; 806564fe117Snathanw } 807c62a74e6Sthorpej /* 808c62a74e6Sthorpej * "I'm not dead yet!" 809c62a74e6Sthorpej * "You will be soon enough." 810c62a74e6Sthorpej */ 8110878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 812c62a74e6Sthorpej pthread_spinlock(self, &self->pt_statelock); 813c62a74e6Sthorpej if (self->pt_cancel) { 814c62a74e6Sthorpej pthread_spinunlock(self, &self->pt_statelock); 815c62a74e6Sthorpej pthread_spinunlock(self, &thread->pt_join_lock); 816c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 817c62a74e6Sthorpej } 818c62a74e6Sthorpej self->pt_state = PT_STATE_BLOCKED_QUEUE; 819c62a74e6Sthorpej self->pt_sleepobj = thread; 820c62a74e6Sthorpej self->pt_sleepq = &thread->pt_joiners; 821c62a74e6Sthorpej self->pt_sleeplock = &thread->pt_join_lock; 822c62a74e6Sthorpej pthread_spinunlock(self, &self->pt_statelock); 823c62a74e6Sthorpej 824c62a74e6Sthorpej PTQ_INSERT_TAIL(&thread->pt_joiners, self, pt_sleep); 825c62a74e6Sthorpej pthread__block(self, &thread->pt_join_lock); 8260878df5dSnathanw pthread_spinlock(self, &thread->pt_flaglock); 827c62a74e6Sthorpej pthread_spinlock(self, &thread->pt_join_lock); 828c62a74e6Sthorpej } 829c62a74e6Sthorpej 830c62a74e6Sthorpej /* All ours. */ 831c62a74e6Sthorpej thread->pt_state = PT_STATE_DEAD; 832b33971b9Sthorpej name = thread->pt_name; 833b33971b9Sthorpej thread->pt_name = NULL; 834c62a74e6Sthorpej pthread_spinunlock(self, &thread->pt_join_lock); 8350878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 836c62a74e6Sthorpej 837c62a74e6Sthorpej if (valptr != NULL) 838c62a74e6Sthorpej *valptr = thread->pt_exitval; 839c62a74e6Sthorpej 8401ac6a89bSad retval = 0; 8411ac6a89bSad #else /* PTHREAD_SA */ 8421ac6a89bSad retval = 0; 8431ac6a89bSad name = NULL; 8441ac6a89bSad again: 8451ac6a89bSad pthread_spinlock(self, &thread->pt_join_lock); 8461ac6a89bSad switch (thread->pt_state) { 8471ac6a89bSad case PT_STATE_RUNNING: 8481ac6a89bSad pthread_spinunlock(self, &thread->pt_join_lock); 849ded26025Sad 850ded26025Sad /* 851ded26025Sad * IEEE Std 1003.1, 2004 Edition: 852ded26025Sad * 853ded26025Sad * "The pthread_join() function shall not 854ded26025Sad * return an error code of [EINTR]." 855ded26025Sad */ 856ded26025Sad if (_lwp_wait(thread->pt_lid, &num) != 0 && errno != EINTR) 857ded26025Sad return errno; 8581ac6a89bSad goto again; 8591ac6a89bSad case PT_STATE_ZOMBIE: 8601ac6a89bSad if (valptr != NULL) 861ded26025Sad *valptr = thread->pt_exitval; 8621ac6a89bSad if (retval == 0) { 8631ac6a89bSad name = thread->pt_name; 8641ac6a89bSad thread->pt_name = NULL; 8651ac6a89bSad } 8661ac6a89bSad thread->pt_state = PT_STATE_DEAD; 8671ac6a89bSad pthread_spinunlock(self, &thread->pt_join_lock); 868b8daad98Sad (void)_lwp_detach(thread->pt_lid); 8691ac6a89bSad break; 8701ac6a89bSad default: 8711ac6a89bSad pthread_spinunlock(self, &thread->pt_join_lock); 8721ac6a89bSad return EINVAL; 8731ac6a89bSad } 8741ac6a89bSad #endif /* PTHREAD_SA */ 8751ac6a89bSad 876c62a74e6Sthorpej SDPRINTF(("(pthread_join %p) Joined %p.\n", self, thread)); 877c62a74e6Sthorpej 8786b2b9c62Syamt pthread__dead(self, thread); 879c62a74e6Sthorpej 880b33971b9Sthorpej if (name != NULL) 881b33971b9Sthorpej free(name); 882b33971b9Sthorpej 8831ac6a89bSad return retval; 884c62a74e6Sthorpej } 885c62a74e6Sthorpej 886c62a74e6Sthorpej 887c62a74e6Sthorpej int 888c62a74e6Sthorpej pthread_equal(pthread_t t1, pthread_t t2) 889c62a74e6Sthorpej { 890c62a74e6Sthorpej 891c62a74e6Sthorpej /* Nothing special here. */ 892c62a74e6Sthorpej return (t1 == t2); 893c62a74e6Sthorpej } 894c62a74e6Sthorpej 895c62a74e6Sthorpej 896c62a74e6Sthorpej int 897c62a74e6Sthorpej pthread_detach(pthread_t thread) 898c62a74e6Sthorpej { 89996b5a26dSnathanw pthread_t self; 9001ac6a89bSad #ifdef PTHREAD_SA 9016b2b9c62Syamt int doreclaim = 0; 9026b2b9c62Syamt char *name = NULL; 9031ac6a89bSad #endif 904c62a74e6Sthorpej 905c62a74e6Sthorpej self = pthread__self(); 906c62a74e6Sthorpej 907c62a74e6Sthorpej if (pthread__find(self, thread) != 0) 908c62a74e6Sthorpej return ESRCH; 909c62a74e6Sthorpej 910c62a74e6Sthorpej if (thread->pt_magic != PT_MAGIC) 911c62a74e6Sthorpej return EINVAL; 912c62a74e6Sthorpej 9131ac6a89bSad #ifdef PTHREAD_SA 9140878df5dSnathanw pthread_spinlock(self, &thread->pt_flaglock); 915c62a74e6Sthorpej pthread_spinlock(self, &thread->pt_join_lock); 916c62a74e6Sthorpej 917c62a74e6Sthorpej if (thread->pt_flags & PT_FLAG_DETACHED) { 918c62a74e6Sthorpej pthread_spinunlock(self, &thread->pt_join_lock); 9190878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 920c62a74e6Sthorpej return EINVAL; 921c62a74e6Sthorpej } 922c62a74e6Sthorpej 923c62a74e6Sthorpej thread->pt_flags |= PT_FLAG_DETACHED; 924c62a74e6Sthorpej 925c62a74e6Sthorpej /* Any joiners have to be punted now. */ 92696b5a26dSnathanw pthread__sched_sleepers(self, &thread->pt_joiners); 927c62a74e6Sthorpej 9286b2b9c62Syamt if (thread->pt_state == PT_STATE_ZOMBIE) { 9296b2b9c62Syamt thread->pt_state = PT_STATE_DEAD; 9306b2b9c62Syamt name = thread->pt_name; 9316b2b9c62Syamt thread->pt_name = NULL; 9326b2b9c62Syamt doreclaim = 1; 9336b2b9c62Syamt } 9346b2b9c62Syamt 935c62a74e6Sthorpej pthread_spinunlock(self, &thread->pt_join_lock); 9360878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 937c62a74e6Sthorpej 9386b2b9c62Syamt if (doreclaim) { 9396b2b9c62Syamt pthread__dead(self, thread); 9406b2b9c62Syamt if (name != NULL) 9416b2b9c62Syamt free(name); 9426b2b9c62Syamt } 9436b2b9c62Syamt 944c62a74e6Sthorpej return 0; 9451ac6a89bSad #else 946*1296e850Sad thread->pt_flags |= PT_FLAG_DETACHED; 9471ac6a89bSad return _lwp_detach(thread->pt_lid); 9481ac6a89bSad #endif 949c62a74e6Sthorpej } 950c62a74e6Sthorpej 951c62a74e6Sthorpej 9526b2b9c62Syamt static void 9536b2b9c62Syamt pthread__dead(pthread_t self, pthread_t thread) 9546b2b9c62Syamt { 9556b2b9c62Syamt 9566b2b9c62Syamt SDPRINTF(("(pthread__dead %p) Reclaimed %p.\n", self, thread)); 957ded26025Sad #ifdef PTHREAD_SA 9586b2b9c62Syamt pthread__assert(thread != self); 959ded26025Sad #endif 9606b2b9c62Syamt pthread__assert(thread->pt_state == PT_STATE_DEAD); 9616b2b9c62Syamt pthread__assert(thread->pt_name == NULL); 9626b2b9c62Syamt 9636b2b9c62Syamt /* Cleanup time. Move the dead thread from allqueue to the deadqueue */ 9646b2b9c62Syamt pthread_spinlock(self, &pthread__allqueue_lock); 9656b2b9c62Syamt PTQ_REMOVE(&pthread__allqueue, thread, pt_allq); 9666b2b9c62Syamt pthread_spinunlock(self, &pthread__allqueue_lock); 9676b2b9c62Syamt 9686b2b9c62Syamt pthread_spinlock(self, &pthread__deadqueue_lock); 9696b2b9c62Syamt PTQ_INSERT_HEAD(&pthread__deadqueue, thread, pt_allq); 9706b2b9c62Syamt pthread_spinunlock(self, &pthread__deadqueue_lock); 9716b2b9c62Syamt } 9726b2b9c62Syamt 9736b2b9c62Syamt 974c62a74e6Sthorpej int 975b33971b9Sthorpej pthread_getname_np(pthread_t thread, char *name, size_t len) 976c62a74e6Sthorpej { 977b33971b9Sthorpej pthread_t self; 978c62a74e6Sthorpej 979b33971b9Sthorpej self = pthread__self(); 980b33971b9Sthorpej 981b33971b9Sthorpej if (pthread__find(self, thread) != 0) 982b33971b9Sthorpej return ESRCH; 983b33971b9Sthorpej 984b33971b9Sthorpej if (thread->pt_magic != PT_MAGIC) 985b33971b9Sthorpej return EINVAL; 986b33971b9Sthorpej 987b33971b9Sthorpej pthread_spinlock(self, &thread->pt_join_lock); 988b33971b9Sthorpej if (thread->pt_name == NULL) 989b33971b9Sthorpej name[0] = '\0'; 990b33971b9Sthorpej else 991b33971b9Sthorpej strlcpy(name, thread->pt_name, len); 992b33971b9Sthorpej pthread_spinunlock(self, &thread->pt_join_lock); 993c62a74e6Sthorpej 994c62a74e6Sthorpej return 0; 995c62a74e6Sthorpej } 996c62a74e6Sthorpej 997c62a74e6Sthorpej 998c62a74e6Sthorpej int 999b33971b9Sthorpej pthread_setname_np(pthread_t thread, const char *name, void *arg) 1000b33971b9Sthorpej { 1001ba70e96aSchs pthread_t self; 1002b33971b9Sthorpej char *oldname, *cp, newname[PTHREAD_MAX_NAMELEN_NP]; 1003b33971b9Sthorpej int namelen; 1004b33971b9Sthorpej 1005ba70e96aSchs self = pthread__self(); 1006b33971b9Sthorpej if (pthread__find(self, thread) != 0) 1007b33971b9Sthorpej return ESRCH; 1008b33971b9Sthorpej 1009b33971b9Sthorpej if (thread->pt_magic != PT_MAGIC) 1010b33971b9Sthorpej return EINVAL; 1011b33971b9Sthorpej 1012b33971b9Sthorpej namelen = snprintf(newname, sizeof(newname), name, arg); 1013b33971b9Sthorpej if (namelen >= PTHREAD_MAX_NAMELEN_NP) 1014b33971b9Sthorpej return EINVAL; 1015b33971b9Sthorpej 1016b33971b9Sthorpej cp = strdup(newname); 1017b33971b9Sthorpej if (cp == NULL) 1018b33971b9Sthorpej return ENOMEM; 1019b33971b9Sthorpej 1020b33971b9Sthorpej pthread_spinlock(self, &thread->pt_join_lock); 1021b33971b9Sthorpej 10221ac6a89bSad #ifdef PTHREAD_SA 1023b33971b9Sthorpej if (thread->pt_state == PT_STATE_DEAD) { 1024b33971b9Sthorpej pthread_spinunlock(self, &thread->pt_join_lock); 1025b33971b9Sthorpej free(cp); 1026b33971b9Sthorpej return EINVAL; 1027b33971b9Sthorpej } 10281ac6a89bSad #endif 1029b33971b9Sthorpej 1030b33971b9Sthorpej oldname = thread->pt_name; 1031b33971b9Sthorpej thread->pt_name = cp; 1032b33971b9Sthorpej 1033b33971b9Sthorpej pthread_spinunlock(self, &thread->pt_join_lock); 1034b33971b9Sthorpej 1035b33971b9Sthorpej if (oldname != NULL) 1036b33971b9Sthorpej free(oldname); 1037b33971b9Sthorpej 1038b33971b9Sthorpej return 0; 1039b33971b9Sthorpej } 1040b33971b9Sthorpej 1041b33971b9Sthorpej 1042b33971b9Sthorpej 1043c62a74e6Sthorpej /* 1044c62a74e6Sthorpej * XXX There should be a way for applications to use the efficent 1045c62a74e6Sthorpej * inline version, but there are opacity/namespace issues. 1046c62a74e6Sthorpej */ 1047c62a74e6Sthorpej pthread_t 1048c62a74e6Sthorpej pthread_self(void) 1049c62a74e6Sthorpej { 1050c62a74e6Sthorpej 1051c62a74e6Sthorpej return pthread__self(); 1052c62a74e6Sthorpej } 1053c62a74e6Sthorpej 1054c62a74e6Sthorpej 1055c62a74e6Sthorpej int 1056c62a74e6Sthorpej pthread_cancel(pthread_t thread) 1057c62a74e6Sthorpej { 1058c62a74e6Sthorpej pthread_t self; 1059c62a74e6Sthorpej 1060ba70e96aSchs self = pthread__self(); 1061ba70e96aSchs #ifdef ERRORCHECK 1062ba70e96aSchs if (pthread__find(self, thread) != 0) 1063ba70e96aSchs return ESRCH; 1064ba70e96aSchs #endif 10651ac6a89bSad #ifdef PTHREAD_SA 1066c62a74e6Sthorpej if (!(thread->pt_state == PT_STATE_RUNNING || 1067c62a74e6Sthorpej thread->pt_state == PT_STATE_RUNNABLE || 106882b6b2dbScl thread->pt_state == PT_STATE_BLOCKED_QUEUE)) 1069c62a74e6Sthorpej return ESRCH; 1070c62a74e6Sthorpej 10710878df5dSnathanw pthread_spinlock(self, &thread->pt_flaglock); 10720878df5dSnathanw thread->pt_flags |= PT_FLAG_CS_PENDING; 10730878df5dSnathanw if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) { 1074c62a74e6Sthorpej thread->pt_cancel = 1; 10750878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 1076c62a74e6Sthorpej pthread_spinlock(self, &thread->pt_statelock); 107782b6b2dbScl if (thread->pt_blockgen != thread->pt_unblockgen) { 1078c62a74e6Sthorpej /* 1079c62a74e6Sthorpej * It's sleeping in the kernel. If we can wake 1080c62a74e6Sthorpej * it up, it will notice the cancellation when 1081c62a74e6Sthorpej * it returns. If it doesn't wake up when we 1082c62a74e6Sthorpej * make this call, then it's blocked 1083c62a74e6Sthorpej * uninterruptably in the kernel, and there's 1084c62a74e6Sthorpej * not much to be done about it. 1085c62a74e6Sthorpej */ 1086c62a74e6Sthorpej _lwp_wakeup(thread->pt_blockedlwp); 1087c62a74e6Sthorpej } else if (thread->pt_state == PT_STATE_BLOCKED_QUEUE) { 1088c62a74e6Sthorpej /* 1089c62a74e6Sthorpej * We're blocked somewhere (pthread__block() 10908bcff70bSnathanw * was called). Cause it to wake up; it will 10918bcff70bSnathanw * check for the cancellation if the routine 10928bcff70bSnathanw * is a cancellation point, and loop and reblock 10938bcff70bSnathanw * otherwise. 1094c62a74e6Sthorpej */ 1095c62a74e6Sthorpej pthread_spinlock(self, thread->pt_sleeplock); 1096c62a74e6Sthorpej PTQ_REMOVE(thread->pt_sleepq, thread, 1097c62a74e6Sthorpej pt_sleep); 1098c62a74e6Sthorpej pthread_spinunlock(self, thread->pt_sleeplock); 1099c62a74e6Sthorpej pthread__sched(self, thread); 1100c62a74e6Sthorpej } else { 1101c62a74e6Sthorpej /* 1102c62a74e6Sthorpej * Nothing. The target thread is running and will 1103c62a74e6Sthorpej * notice at the next deferred cancellation point. 1104c62a74e6Sthorpej */ 1105c62a74e6Sthorpej } 1106c62a74e6Sthorpej pthread_spinunlock(self, &thread->pt_statelock); 11070878df5dSnathanw } else 11080878df5dSnathanw pthread_spinunlock(self, &thread->pt_flaglock); 11091ac6a89bSad #else 11101ac6a89bSad pthread_spinlock(self, &thread->pt_flaglock); 11111ac6a89bSad thread->pt_flags |= PT_FLAG_CS_PENDING; 11121ac6a89bSad if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) { 11131ac6a89bSad thread->pt_cancel = 1; 11141ac6a89bSad pthread_spinunlock(self, &thread->pt_flaglock); 11151ac6a89bSad _lwp_wakeup(thread->pt_lid); 11161ac6a89bSad } else 11171ac6a89bSad pthread_spinunlock(self, &thread->pt_flaglock); 11181ac6a89bSad #endif 1119c62a74e6Sthorpej 1120c62a74e6Sthorpej return 0; 1121c62a74e6Sthorpej } 1122c62a74e6Sthorpej 1123c62a74e6Sthorpej 1124c62a74e6Sthorpej int 1125c62a74e6Sthorpej pthread_setcancelstate(int state, int *oldstate) 1126c62a74e6Sthorpej { 1127c62a74e6Sthorpej pthread_t self; 11280878df5dSnathanw int retval; 1129c62a74e6Sthorpej 1130c62a74e6Sthorpej self = pthread__self(); 11310878df5dSnathanw retval = 0; 1132c62a74e6Sthorpej 11330878df5dSnathanw pthread_spinlock(self, &self->pt_flaglock); 1134c62a74e6Sthorpej if (oldstate != NULL) { 11350878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_DISABLED) 1136c62a74e6Sthorpej *oldstate = PTHREAD_CANCEL_DISABLE; 1137c62a74e6Sthorpej else 1138c62a74e6Sthorpej *oldstate = PTHREAD_CANCEL_ENABLE; 1139c62a74e6Sthorpej } 1140c62a74e6Sthorpej 11410878df5dSnathanw if (state == PTHREAD_CANCEL_DISABLE) { 11420878df5dSnathanw self->pt_flags |= PT_FLAG_CS_DISABLED; 11430878df5dSnathanw if (self->pt_cancel) { 11440878df5dSnathanw self->pt_flags |= PT_FLAG_CS_PENDING; 11450878df5dSnathanw self->pt_cancel = 0; 11460878df5dSnathanw } 11470878df5dSnathanw } else if (state == PTHREAD_CANCEL_ENABLE) { 11480878df5dSnathanw self->pt_flags &= ~PT_FLAG_CS_DISABLED; 1149c62a74e6Sthorpej /* 1150c62a74e6Sthorpej * If a cancellation was requested while cancellation 1151c62a74e6Sthorpej * was disabled, note that fact for future 1152c62a74e6Sthorpej * cancellation tests. 1153c62a74e6Sthorpej */ 11540878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_PENDING) { 1155c62a74e6Sthorpej self->pt_cancel = 1; 1156c62a74e6Sthorpej /* This is not a deferred cancellation point. */ 11570878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_ASYNC) { 11580878df5dSnathanw pthread_spinunlock(self, &self->pt_flaglock); 1159c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 1160c62a74e6Sthorpej } 11610878df5dSnathanw } 1162c62a74e6Sthorpej } else 11630878df5dSnathanw retval = EINVAL; 1164c62a74e6Sthorpej 11650878df5dSnathanw pthread_spinunlock(self, &self->pt_flaglock); 11660878df5dSnathanw return retval; 1167c62a74e6Sthorpej } 1168c62a74e6Sthorpej 1169c62a74e6Sthorpej 1170c62a74e6Sthorpej int 1171c62a74e6Sthorpej pthread_setcanceltype(int type, int *oldtype) 1172c62a74e6Sthorpej { 1173c62a74e6Sthorpej pthread_t self; 11740878df5dSnathanw int retval; 1175c62a74e6Sthorpej 1176c62a74e6Sthorpej self = pthread__self(); 11770878df5dSnathanw retval = 0; 11780878df5dSnathanw 11790878df5dSnathanw pthread_spinlock(self, &self->pt_flaglock); 1180c62a74e6Sthorpej 1181c62a74e6Sthorpej if (oldtype != NULL) { 11820878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_ASYNC) 1183c62a74e6Sthorpej *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS; 1184c62a74e6Sthorpej else 1185c62a74e6Sthorpej *oldtype = PTHREAD_CANCEL_DEFERRED; 1186c62a74e6Sthorpej } 1187c62a74e6Sthorpej 1188c62a74e6Sthorpej if (type == PTHREAD_CANCEL_ASYNCHRONOUS) { 11890878df5dSnathanw self->pt_flags |= PT_FLAG_CS_ASYNC; 11900878df5dSnathanw if (self->pt_cancel) { 11910878df5dSnathanw pthread_spinunlock(self, &self->pt_flaglock); 1192c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 11930878df5dSnathanw } 1194c62a74e6Sthorpej } else if (type == PTHREAD_CANCEL_DEFERRED) 11950878df5dSnathanw self->pt_flags &= ~PT_FLAG_CS_ASYNC; 1196c62a74e6Sthorpej else 11970878df5dSnathanw retval = EINVAL; 1198c62a74e6Sthorpej 11990878df5dSnathanw pthread_spinunlock(self, &self->pt_flaglock); 12000878df5dSnathanw return retval; 1201c62a74e6Sthorpej } 1202c62a74e6Sthorpej 1203c62a74e6Sthorpej 1204c62a74e6Sthorpej void 1205c62a74e6Sthorpej pthread_testcancel() 1206c62a74e6Sthorpej { 1207c62a74e6Sthorpej pthread_t self; 1208c62a74e6Sthorpej 1209c62a74e6Sthorpej self = pthread__self(); 1210c62a74e6Sthorpej if (self->pt_cancel) 1211c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 1212c62a74e6Sthorpej } 1213c62a74e6Sthorpej 1214c62a74e6Sthorpej 1215c62a74e6Sthorpej /* 1216c62a74e6Sthorpej * POSIX requires that certain functions return an error rather than 1217c62a74e6Sthorpej * invoking undefined behavior even when handed completely bogus 1218c62a74e6Sthorpej * pthread_t values, e.g. stack garbage or (pthread_t)666. This 1219c62a74e6Sthorpej * utility routine searches the list of threads for the pthread_t 1220c62a74e6Sthorpej * value without dereferencing it. 1221c62a74e6Sthorpej */ 1222c62a74e6Sthorpej int 1223c62a74e6Sthorpej pthread__find(pthread_t self, pthread_t id) 1224c62a74e6Sthorpej { 1225c62a74e6Sthorpej pthread_t target; 1226c62a74e6Sthorpej 1227c62a74e6Sthorpej pthread_spinlock(self, &pthread__allqueue_lock); 1228c62a74e6Sthorpej PTQ_FOREACH(target, &pthread__allqueue, pt_allq) 1229c62a74e6Sthorpej if (target == id) 1230c62a74e6Sthorpej break; 1231c62a74e6Sthorpej pthread_spinunlock(self, &pthread__allqueue_lock); 1232c62a74e6Sthorpej 1233c62a74e6Sthorpej if (target == NULL) 1234c62a74e6Sthorpej return ESRCH; 1235c62a74e6Sthorpej 1236c62a74e6Sthorpej return 0; 1237c62a74e6Sthorpej } 1238c62a74e6Sthorpej 1239c62a74e6Sthorpej 1240c62a74e6Sthorpej void 1241c62a74e6Sthorpej pthread__testcancel(pthread_t self) 1242c62a74e6Sthorpej { 1243c62a74e6Sthorpej 1244c62a74e6Sthorpej if (self->pt_cancel) 1245c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 1246c62a74e6Sthorpej } 1247c62a74e6Sthorpej 1248c62a74e6Sthorpej 1249c62a74e6Sthorpej void 1250c62a74e6Sthorpej pthread__cleanup_push(void (*cleanup)(void *), void *arg, void *store) 1251c62a74e6Sthorpej { 1252c62a74e6Sthorpej pthread_t self; 1253c62a74e6Sthorpej struct pt_clean_t *entry; 1254c62a74e6Sthorpej 1255c62a74e6Sthorpej self = pthread__self(); 1256c62a74e6Sthorpej entry = store; 1257c62a74e6Sthorpej entry->ptc_cleanup = cleanup; 1258c62a74e6Sthorpej entry->ptc_arg = arg; 1259c62a74e6Sthorpej PTQ_INSERT_HEAD(&self->pt_cleanup_stack, entry, ptc_next); 1260c62a74e6Sthorpej } 1261c62a74e6Sthorpej 1262c62a74e6Sthorpej 1263c62a74e6Sthorpej void 1264c62a74e6Sthorpej pthread__cleanup_pop(int ex, void *store) 1265c62a74e6Sthorpej { 1266c62a74e6Sthorpej pthread_t self; 1267c62a74e6Sthorpej struct pt_clean_t *entry; 1268c62a74e6Sthorpej 1269c62a74e6Sthorpej self = pthread__self(); 1270c62a74e6Sthorpej entry = store; 1271c62a74e6Sthorpej 1272c62a74e6Sthorpej PTQ_REMOVE(&self->pt_cleanup_stack, entry, ptc_next); 1273c62a74e6Sthorpej if (ex) 1274c62a74e6Sthorpej (*entry->ptc_cleanup)(entry->ptc_arg); 1275c62a74e6Sthorpej } 1276c62a74e6Sthorpej 1277c62a74e6Sthorpej 1278c62a74e6Sthorpej int * 1279c62a74e6Sthorpej pthread__errno(void) 1280c62a74e6Sthorpej { 1281c62a74e6Sthorpej pthread_t self; 1282c62a74e6Sthorpej 1283c62a74e6Sthorpej self = pthread__self(); 1284c62a74e6Sthorpej 1285c62a74e6Sthorpej return &(self->pt_errno); 1286c62a74e6Sthorpej } 12878bcff70bSnathanw 12880c967901Snathanw ssize_t _sys_write(int, const void *, size_t); 12890c967901Snathanw 12908bcff70bSnathanw void 12910e6c93b9Sdrochner pthread__assertfunc(const char *file, int line, const char *function, 12920e6c93b9Sdrochner const char *expr) 12938bcff70bSnathanw { 12948bcff70bSnathanw char buf[1024]; 12958bcff70bSnathanw int len; 12968bcff70bSnathanw 129775a94788Smycroft SDPRINTF(("(af)\n")); 129875a94788Smycroft 12998bcff70bSnathanw /* 13008bcff70bSnathanw * snprintf should not acquire any locks, or we could 13018bcff70bSnathanw * end up deadlocked if the assert caller held locks. 13028bcff70bSnathanw */ 13038bcff70bSnathanw len = snprintf(buf, 1024, 13048bcff70bSnathanw "assertion \"%s\" failed: file \"%s\", line %d%s%s%s\n", 13058bcff70bSnathanw expr, file, line, 13068bcff70bSnathanw function ? ", function \"" : "", 13078bcff70bSnathanw function ? function : "", 13088bcff70bSnathanw function ? "\"" : ""); 13098bcff70bSnathanw 13100c967901Snathanw _sys_write(STDERR_FILENO, buf, (size_t)len); 13118bcff70bSnathanw (void)kill(getpid(), SIGABRT); 13128bcff70bSnathanw 13138bcff70bSnathanw _exit(1); 13148bcff70bSnathanw } 1315df277271Snathanw 1316df277271Snathanw 1317df277271Snathanw void 13180e6c93b9Sdrochner pthread__errorfunc(const char *file, int line, const char *function, 13190e6c93b9Sdrochner const char *msg) 1320df277271Snathanw { 1321df277271Snathanw char buf[1024]; 13220172694eSnathanw size_t len; 1323df277271Snathanw 13240172694eSnathanw if (pthread__diagassert == 0) 1325df277271Snathanw return; 1326df277271Snathanw 1327df277271Snathanw /* 1328df277271Snathanw * snprintf should not acquire any locks, or we could 1329df277271Snathanw * end up deadlocked if the assert caller held locks. 1330df277271Snathanw */ 1331df277271Snathanw len = snprintf(buf, 1024, 13320172694eSnathanw "%s: Error detected by libpthread: %s.\n" 13330172694eSnathanw "Detected by file \"%s\", line %d%s%s%s.\n" 13340172694eSnathanw "See pthread(3) for information.\n", 13350172694eSnathanw getprogname(), msg, file, line, 1336df277271Snathanw function ? ", function \"" : "", 1337df277271Snathanw function ? function : "", 13380172694eSnathanw function ? "\"" : ""); 1339df277271Snathanw 13400172694eSnathanw if (pthread__diagassert & DIAGASSERT_STDERR) 13410c967901Snathanw _sys_write(STDERR_FILENO, buf, len); 13420172694eSnathanw 13430172694eSnathanw if (pthread__diagassert & DIAGASSERT_SYSLOG) 13440172694eSnathanw syslog(LOG_DEBUG | LOG_USER, "%s", buf); 13450172694eSnathanw 13460172694eSnathanw if (pthread__diagassert & DIAGASSERT_ABORT) { 1347df277271Snathanw (void)kill(getpid(), SIGABRT); 1348df277271Snathanw _exit(1); 1349df277271Snathanw } 1350df277271Snathanw } 13511ac6a89bSad 13521ac6a89bSad #ifndef PTHREAD_SA 13531ac6a89bSad 1354fe9718acSad /* 1355ded26025Sad * Thread park/unpark operations. The kernel operations are 1356ded26025Sad * modelled after a brief description from "Multithreading in 1357ded26025Sad * the Solaris Operating Environment": 1358fe9718acSad * 1359fe9718acSad * http://www.sun.com/software/whitepapers/solaris9/multithread.pdf 1360fe9718acSad */ 1361fe9718acSad 13621ac6a89bSad #define OOPS(msg) \ 1363858097f9Schristos pthread__errorfunc(__FILE__, __LINE__, __func__, msg) 13641ac6a89bSad 13651ac6a89bSad int 13661ac6a89bSad pthread__park(pthread_t self, pthread_spin_t *lock, 13671ac6a89bSad void *obj, struct pthread_queue_t *queue, 1368ded26025Sad const struct timespec *abstime, int tail, 1369ded26025Sad int cancelpt) 13701ac6a89bSad { 13711ac6a89bSad int rv; 13721ac6a89bSad 13731ac6a89bSad SDPRINTF(("(pthread__park %p) obj %p enter\n", self, obj)); 13741ac6a89bSad 1375ded26025Sad /* 1376ded26025Sad * Enter the object's queue. 1377ded26025Sad */ 13781ac6a89bSad if (queue != NULL) { 13791ac6a89bSad if (tail) 13801ac6a89bSad PTQ_INSERT_TAIL(queue, self, pt_sleep); 13811ac6a89bSad else 13821ac6a89bSad PTQ_INSERT_HEAD(queue, self, pt_sleep); 1383ded26025Sad self->pt_sleeponq = 1; 13841ac6a89bSad } 13851ac6a89bSad self->pt_sleepobj = obj; 13861ac6a89bSad 1387ded26025Sad /* 1388ded26025Sad * Wait until we are awoken by a pending unpark operation, 1389ded26025Sad * a signal, an unpark posted after we have gone asleep, 1390ded26025Sad * or an expired timeout. 1391ded26025Sad */ 1392ded26025Sad rv = 0; 13931ac6a89bSad do { 13941ac6a89bSad pthread_spinunlock(self, lock); 139539aa27f5Sad if (_lwp_park(abstime, NULL, obj) != 0) { 1396ded26025Sad switch (rv = errno) { 13971ac6a89bSad case EINTR: 1398ded26025Sad /* Check for cancellation. */ 1399ded26025Sad if (cancelpt && self->pt_cancel) 1400ded26025Sad break; 1401ded26025Sad /* FALLTHROUGH */ 14021ac6a89bSad case EALREADY: 1403ded26025Sad rv = 0; 1404ded26025Sad break; 1405ded26025Sad case ETIMEDOUT: 14061ac6a89bSad break; 14071ac6a89bSad default: 14081ac6a89bSad OOPS("_lwp_park failed"); 14091ac6a89bSad SDPRINTF(("(pthread__park %p) syscall rv=%d\n", 14101ac6a89bSad self, rv)); 14111ac6a89bSad break; 14121ac6a89bSad } 1413ded26025Sad } 14141ac6a89bSad pthread_spinlock(self, lock); 1415ded26025Sad } while (self->pt_sleepobj != NULL && rv == 0); 14161ac6a89bSad 1417ded26025Sad /* 1418ded26025Sad * If we have been awoken early but are still on the queue, 1419ded26025Sad * then remove ourself. 1420ded26025Sad */ 1421ded26025Sad if (queue != NULL && self->pt_sleeponq) 14221ac6a89bSad PTQ_REMOVE(queue, self, pt_sleep); 14231ac6a89bSad self->pt_sleepobj = NULL; 1424ded26025Sad self->pt_sleeponq = 0; 14251ac6a89bSad 14261ac6a89bSad SDPRINTF(("(pthread__park %p) obj %p exit\n", self, obj)); 14271ac6a89bSad 14281ac6a89bSad return rv; 14291ac6a89bSad } 14301ac6a89bSad 14311ac6a89bSad void 14321ac6a89bSad pthread__unpark(pthread_t self, pthread_spin_t *lock, void *obj, 14331ac6a89bSad pthread_t target) 14341ac6a89bSad { 14351ac6a89bSad int rv; 14361ac6a89bSad 14371ac6a89bSad if (target != NULL) { 14381ac6a89bSad SDPRINTF(("(pthread__unpark %p) obj %p target %p\n", self, obj, 14391ac6a89bSad target)); 14401ac6a89bSad 1441ded26025Sad /* 1442ded26025Sad * Easy: the thread has already been removed from 1443ded26025Sad * the queue, so just awaken it. 1444ded26025Sad */ 14451ac6a89bSad target->pt_sleepobj = NULL; 1446ded26025Sad target->pt_sleeponq = 0; 14471ac6a89bSad pthread_spinunlock(self, lock); 144839aa27f5Sad rv = _lwp_unpark(target->pt_lid, obj); 14491ac6a89bSad 14501ac6a89bSad if (rv != 0 && errno != EALREADY && errno != EINTR) { 14511ac6a89bSad SDPRINTF(("(pthread__unpark %p) syscall rv=%d\n", 14521ac6a89bSad self, rv)); 14531ac6a89bSad OOPS("_lwp_unpark failed"); 14541ac6a89bSad } 14551ac6a89bSad } else 14561ac6a89bSad pthread_spinunlock(self, lock); 14571ac6a89bSad } 14581ac6a89bSad 14591ac6a89bSad void 14601ac6a89bSad pthread__unpark_all(pthread_t self, pthread_spin_t *lock, void *obj, 14611ac6a89bSad struct pthread_queue_t *queue) 14621ac6a89bSad { 1463ded26025Sad lwpid_t waiters[PTHREAD__UNPARK_MAX]; 1464ded26025Sad int n, rv; 1465ded26025Sad pthread_t thread, next; 1466ded26025Sad 1467ded26025Sad if (PTQ_EMPTY(queue)) { 1468ded26025Sad pthread_spinunlock(self, lock); 1469ded26025Sad return; 1470ded26025Sad } 1471ded26025Sad 1472ded26025Sad /* 1473ded26025Sad * First, clear all sleepobj pointers, since we can release the 1474ded26025Sad * spin lock before awkening everybody, and must synchronise with 1475ded26025Sad * pthread__park(). 1476ded26025Sad */ 1477ded26025Sad PTQ_FOREACH(thread, queue, pt_sleep) { 1478ded26025Sad thread->pt_sleepobj = NULL; 1479ded26025Sad } 14801ac6a89bSad 14811ac6a89bSad for (;;) { 1482ded26025Sad thread = PTQ_FIRST(queue); 1483ded26025Sad for (n = 0; n < pthread__unpark_max && thread != NULL; 1484ded26025Sad thread = next) { 1485ded26025Sad /* 1486ded26025Sad * If the sleepobj pointer is non-NULL, it 1487ded26025Sad * means one of two things: 1488ded26025Sad * 1489ded26025Sad * o The thread has awoken early, spun 1490ded26025Sad * through application code and is 1491ded26025Sad * once more asleep on this object. 1492ded26025Sad * 1493ded26025Sad * o This is a new thread that has blocked 1494ded26025Sad * on the object after we have released 1495ded26025Sad * the interlock in this loop. 1496ded26025Sad * 1497ded26025Sad * In both cases we shouldn't remove the 1498ded26025Sad * thread from the queue. 1499ded26025Sad * 1500ded26025Sad * XXXLWP basic fairness issues here. 1501ded26025Sad */ 1502ded26025Sad next = PTQ_NEXT(thread, pt_sleep); 1503ded26025Sad if (thread->pt_sleepobj != NULL) 1504ded26025Sad continue; 1505ded26025Sad thread->pt_sleeponq = 0; 1506ded26025Sad waiters[n++] = thread->pt_lid; 15071ac6a89bSad PTQ_REMOVE(queue, thread, pt_sleep); 15081ac6a89bSad SDPRINTF(("(pthread__unpark_all %p) obj %p " 15091ac6a89bSad "unpark %p\n", self, obj, thread)); 15101ac6a89bSad } 1511ded26025Sad 15121ac6a89bSad pthread_spinunlock(self, lock); 1513ded26025Sad switch (n) { 15141ac6a89bSad case 0: 15151ac6a89bSad return; 15161ac6a89bSad case 1: 151739aa27f5Sad rv = _lwp_unpark(waiters[0], obj); 15181ac6a89bSad if (rv != 0 && errno != EALREADY && errno != EINTR) { 15191ac6a89bSad OOPS("_lwp_unpark failed"); 15201ac6a89bSad SDPRINTF(("(pthread__unpark_all %p) " 15211ac6a89bSad "syscall rv=%d\n", self, rv)); 15221ac6a89bSad } 15231ac6a89bSad return; 15241ac6a89bSad default: 152539aa27f5Sad rv = _lwp_unpark_all(waiters, n, obj); 15261ac6a89bSad if (rv != 0 && errno != EINTR) { 15271ac6a89bSad OOPS("_lwp_unpark_all failed"); 15281ac6a89bSad SDPRINTF(("(pthread__unpark_all %p) " 15291ac6a89bSad "syscall rv=%d\n", self, rv)); 15301ac6a89bSad } 15311ac6a89bSad break; 15321ac6a89bSad } 15331ac6a89bSad pthread_spinlock(self, lock); 15341ac6a89bSad } 15351ac6a89bSad } 15361ac6a89bSad 15371ac6a89bSad #undef OOPS 15381ac6a89bSad 15391ac6a89bSad #endif /* !PTHREAD_SA */ 1540