1*c3f8e2eeSad /* $NetBSD: pthread.c,v 1.72 2007/08/07 19:04:21 ad Exp $ */ 2c62a74e6Sthorpej 3c62a74e6Sthorpej /*- 41296e850Sad * 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*c3f8e2eeSad __RCSID("$NetBSD: pthread.c,v 1.72 2007/08/07 19:04:21 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> 548bcff70bSnathanw 55c62a74e6Sthorpej #include <sched.h> 56c62a74e6Sthorpej #include "pthread.h" 57c62a74e6Sthorpej #include "pthread_int.h" 58c62a74e6Sthorpej 59c62a74e6Sthorpej #ifdef PTHREAD_MAIN_DEBUG 60c62a74e6Sthorpej #define SDPRINTF(x) DPRINTF(x) 61c62a74e6Sthorpej #else 62c62a74e6Sthorpej #define SDPRINTF(x) 63c62a74e6Sthorpej #endif 64c62a74e6Sthorpej 65ded26025Sad /* Maximum number of LWPs to unpark in one operation. */ 66ded26025Sad #define PTHREAD__UNPARK_MAX 128 67ded26025Sad 68ded26025Sad /* How many times to try acquiring spin locks on MP systems. */ 69dc39f9ecSad #define PTHREAD__NSPINS 1024 70ded26025Sad 7150fa8db4Sad static void pthread__create_tramp(void *(*)(void *), void *); 7250fa8db4Sad static void pthread__initthread(pthread_t); 73c62a74e6Sthorpej 74c62a74e6Sthorpej int pthread__started; 75c62a74e6Sthorpej 7650fa8db4Sad pthread_spin_t pthread__queue_lock = __SIMPLELOCK_UNLOCKED; 7750fa8db4Sad pthread_queue_t pthread__allqueue; 7850fa8db4Sad pthread_queue_t pthread__deadqueue; 79c62a74e6Sthorpej 80c62a74e6Sthorpej static pthread_attr_t pthread_default_attr; 81c62a74e6Sthorpej 820172694eSnathanw enum { 830172694eSnathanw DIAGASSERT_ABORT = 1<<0, 840172694eSnathanw DIAGASSERT_STDERR = 1<<1, 850172694eSnathanw DIAGASSERT_SYSLOG = 1<<2 860172694eSnathanw }; 87df277271Snathanw 880172694eSnathanw static int pthread__diagassert = DIAGASSERT_ABORT | DIAGASSERT_STDERR; 89df277271Snathanw 90ded26025Sad int pthread__concurrency, pthread__maxconcurrency, pthread__nspins; 91ded26025Sad int pthread__unpark_max = PTHREAD__UNPARK_MAX; 92*c3f8e2eeSad int pthread__osrevision; 93f2f10664Scl 94f782e995Sdrochner int _sys___sigprocmask14(int, const sigset_t *, sigset_t *); 95f782e995Sdrochner 96c62a74e6Sthorpej __strong_alias(__libc_thr_self,pthread_self) 977dc01dbfSthorpej __strong_alias(__libc_thr_create,pthread_create) 987dc01dbfSthorpej __strong_alias(__libc_thr_exit,pthread_exit) 99c62a74e6Sthorpej __strong_alias(__libc_thr_errno,pthread__errno) 1009e5c8705Snathanw __strong_alias(__libc_thr_setcancelstate,pthread_setcancelstate) 101c62a74e6Sthorpej 102c62a74e6Sthorpej /* 103c62a74e6Sthorpej * Static library kludge. Place a reference to a symbol any library 104c62a74e6Sthorpej * file which does not already have a reference here. 105c62a74e6Sthorpej */ 106c62a74e6Sthorpej extern int pthread__cancel_stub_binder; 107c62a74e6Sthorpej 108c62a74e6Sthorpej void *pthread__static_lib_binder[] = { 109c62a74e6Sthorpej &pthread__cancel_stub_binder, 110c62a74e6Sthorpej pthread_cond_init, 111c62a74e6Sthorpej pthread_mutex_init, 112c62a74e6Sthorpej pthread_rwlock_init, 113c62a74e6Sthorpej pthread_barrier_init, 114c62a74e6Sthorpej pthread_key_create, 115bd9a18b7Snathanw pthread_setspecific, 116c62a74e6Sthorpej }; 117c62a74e6Sthorpej 118c62a74e6Sthorpej /* 119c62a74e6Sthorpej * This needs to be started by the library loading code, before main() 120c62a74e6Sthorpej * gets to run, for various things that use the state of the initial thread 121c62a74e6Sthorpej * to work properly (thread-specific data is an application-visible example; 122c62a74e6Sthorpej * spinlock counts for mutexes is an internal example). 123c62a74e6Sthorpej */ 124c62a74e6Sthorpej void 125c62a74e6Sthorpej pthread_init(void) 126c62a74e6Sthorpej { 127c62a74e6Sthorpej pthread_t first; 1280172694eSnathanw char *p; 129ded26025Sad int i, mib[2], ncpu; 130f2f10664Scl size_t len; 131c62a74e6Sthorpej extern int __isthreaded; 132c62a74e6Sthorpej 133f2f10664Scl mib[0] = CTL_HW; 134f2f10664Scl mib[1] = HW_NCPU; 135f2f10664Scl 136f2f10664Scl len = sizeof(ncpu); 137792cc0e1Sad if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) 138792cc0e1Sad err(1, "sysctl(hw.ncpu"); 139f2f10664Scl 140*c3f8e2eeSad mib[0] = CTL_KERN; 141*c3f8e2eeSad mib[1] = KERN_OSREV; 142*c3f8e2eeSad 143*c3f8e2eeSad len = sizeof(pthread__osrev); 144*c3f8e2eeSad if (sysctl(mib, 2, &pthread__osrev, &len, NULL, 0) == -1) 145*c3f8e2eeSad err(1, "sysctl(hw.osrevision"); 146*c3f8e2eeSad 147c62a74e6Sthorpej /* Initialize locks first; they're needed elsewhere. */ 148f2f10664Scl pthread__lockprim_init(ncpu); 149f2f10664Scl 150ded26025Sad /* 151ded26025Sad * Get number of CPUs, and maximum number of LWPs that can be 152ded26025Sad * unparked at once. 153ded26025Sad */ 154ded26025Sad if ((pthread__concurrency = ncpu) > 1) 155ded26025Sad pthread__nspins = PTHREAD__NSPINS; 156ded26025Sad else 157ded26025Sad pthread__nspins = 1; 15850fa8db4Sad if ((p = getenv("PTHREAD_NSPINS")) != NULL) 15950fa8db4Sad pthread__nspins = atoi(p); 1603247035dSad i = (int)_lwp_unpark_all(NULL, 0, NULL); 1613247035dSad if (i == -1) 1623247035dSad err(1, "_lwp_unpark_all"); 163ded26025Sad if (i < pthread__unpark_max) 164ded26025Sad pthread__unpark_max = i; 165c62a74e6Sthorpej 166c62a74e6Sthorpej /* Basic data structure setup */ 167c62a74e6Sthorpej pthread_attr_init(&pthread_default_attr); 168c62a74e6Sthorpej PTQ_INIT(&pthread__allqueue); 169c62a74e6Sthorpej PTQ_INIT(&pthread__deadqueue); 170c62a74e6Sthorpej /* Create the thread structure corresponding to main() */ 171c62a74e6Sthorpej pthread__initmain(&first); 17250fa8db4Sad pthread__initthread(first); 1731ac6a89bSad 174c62a74e6Sthorpej first->pt_state = PT_STATE_RUNNING; 1751ac6a89bSad first->pt_lid = _lwp_self(); 176c62a74e6Sthorpej PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq); 177c62a74e6Sthorpej 178c62a74e6Sthorpej /* Start subsystems */ 179c62a74e6Sthorpej PTHREAD_MD_INIT 180c62a74e6Sthorpej #ifdef PTHREAD__DEBUG 181f2f10664Scl pthread__debug_init(ncpu); 182c62a74e6Sthorpej #endif 183c62a74e6Sthorpej 1840172694eSnathanw for (p = getenv("PTHREAD_DIAGASSERT"); p && *p; p++) { 1850172694eSnathanw switch (*p) { 1860172694eSnathanw case 'a': 1870172694eSnathanw pthread__diagassert |= DIAGASSERT_ABORT; 1880172694eSnathanw break; 1890172694eSnathanw case 'A': 1900172694eSnathanw pthread__diagassert &= ~DIAGASSERT_ABORT; 1910172694eSnathanw break; 1920172694eSnathanw case 'e': 1930172694eSnathanw pthread__diagassert |= DIAGASSERT_STDERR; 1940172694eSnathanw break; 1950172694eSnathanw case 'E': 1960172694eSnathanw pthread__diagassert &= ~DIAGASSERT_STDERR; 1970172694eSnathanw break; 1980172694eSnathanw case 'l': 1990172694eSnathanw pthread__diagassert |= DIAGASSERT_SYSLOG; 2000172694eSnathanw break; 2010172694eSnathanw case 'L': 2020172694eSnathanw pthread__diagassert &= ~DIAGASSERT_SYSLOG; 2030172694eSnathanw break; 204df277271Snathanw } 2050172694eSnathanw } 2060172694eSnathanw 207df277271Snathanw 208c62a74e6Sthorpej /* Tell libc that we're here and it should role-play accordingly. */ 209c62a74e6Sthorpej __isthreaded = 1; 210c62a74e6Sthorpej } 211c62a74e6Sthorpej 2122a4cef11Snathanw static void 2132a4cef11Snathanw pthread__child_callback(void) 2142a4cef11Snathanw { 2152a4cef11Snathanw /* 2162a4cef11Snathanw * Clean up data structures that a forked child process might 2172a4cef11Snathanw * trip over. Note that if threads have been created (causing 2182a4cef11Snathanw * this handler to be registered) the standards say that the 2192a4cef11Snathanw * child will trigger undefined behavior if it makes any 2202a4cef11Snathanw * pthread_* calls (or any other calls that aren't 2212a4cef11Snathanw * async-signal-safe), so we don't really have to clean up 2222a4cef11Snathanw * much. Anything that permits some pthread_* calls to work is 2232a4cef11Snathanw * merely being polite. 2242a4cef11Snathanw */ 2252a4cef11Snathanw pthread__started = 0; 2262a4cef11Snathanw } 227c62a74e6Sthorpej 2280e675542Schs static void 229c62a74e6Sthorpej pthread__start(void) 230c62a74e6Sthorpej { 2311ac6a89bSad pthread_t self; 232c62a74e6Sthorpej 233c62a74e6Sthorpej self = pthread__self(); /* should be the "main()" thread */ 234c62a74e6Sthorpej 235ff14fbf2Snathanw /* 236ff14fbf2Snathanw * Per-process timers are cleared by fork(); despite the 237ff14fbf2Snathanw * various restrictions on fork() and threads, it's legal to 238ff14fbf2Snathanw * fork() before creating any threads. 239ff14fbf2Snathanw */ 2402a4cef11Snathanw pthread_atfork(NULL, NULL, pthread__child_callback); 241c62a74e6Sthorpej SDPRINTF(("(pthread__start %p) Started.\n", self)); 242c62a74e6Sthorpej } 243c62a74e6Sthorpej 244c62a74e6Sthorpej 245c62a74e6Sthorpej /* General-purpose thread data structure sanitization. */ 24650fa8db4Sad /* ARGSUSED */ 24750fa8db4Sad static void 24850fa8db4Sad pthread__initthread(pthread_t t) 249c62a74e6Sthorpej { 250c62a74e6Sthorpej 251c62a74e6Sthorpej t->pt_magic = PT_MAGIC; 252*c3f8e2eeSad t->pt_state = PT_STATE_RUNNING; 253c62a74e6Sthorpej t->pt_spinlocks = 0; 254c62a74e6Sthorpej t->pt_exitval = NULL; 255c62a74e6Sthorpej t->pt_flags = 0; 256c62a74e6Sthorpej t->pt_cancel = 0; 257c62a74e6Sthorpej t->pt_errno = 0; 258*c3f8e2eeSad t->pt_name = NULL; 259*c3f8e2eeSad t->pt_willpark = 0; 260*c3f8e2eeSad t->pt_unpark = 0; 261*c3f8e2eeSad t->pt_sleeponq = 0; 262*c3f8e2eeSad t->pt_sleepobj = NULL; 263*c3f8e2eeSad t->pt_signalled = 0; 264*c3f8e2eeSad t->pt_sleepq = NULL; 2651ac6a89bSad 26650fa8db4Sad pthread_lockinit(&t->pt_lock); 267c62a74e6Sthorpej PTQ_INIT(&t->pt_cleanup_stack); 2687bf06aa7Sad PTQ_INIT(&t->pt_joiners); 269c62a74e6Sthorpej memset(&t->pt_specific, 0, sizeof(int) * PTHREAD_KEYS_MAX); 270c62a74e6Sthorpej } 271c62a74e6Sthorpej 272c62a74e6Sthorpej 273c62a74e6Sthorpej int 274c62a74e6Sthorpej pthread_create(pthread_t *thread, const pthread_attr_t *attr, 275c62a74e6Sthorpej void *(*startfunc)(void *), void *arg) 276c62a74e6Sthorpej { 277c62a74e6Sthorpej pthread_t self, newthread; 278c62a74e6Sthorpej pthread_attr_t nattr; 279b33971b9Sthorpej struct pthread_attr_private *p; 2803ca3d0b1Schristos char * volatile name; 281de213816Sad int ret, flag; 282c62a74e6Sthorpej 283c62a74e6Sthorpej PTHREADD_ADD(PTHREADD_CREATE); 284c62a74e6Sthorpej 285c62a74e6Sthorpej /* 286c62a74e6Sthorpej * It's okay to check this without a lock because there can 287c62a74e6Sthorpej * only be one thread before it becomes true. 288c62a74e6Sthorpej */ 289c62a74e6Sthorpej if (pthread__started == 0) { 290c62a74e6Sthorpej pthread__start(); 291c62a74e6Sthorpej pthread__started = 1; 292c62a74e6Sthorpej } 293c62a74e6Sthorpej 294c62a74e6Sthorpej if (attr == NULL) 295c62a74e6Sthorpej nattr = pthread_default_attr; 296e81f9f17Sdrochner else if (attr->pta_magic == PT_ATTR_MAGIC) 297c62a74e6Sthorpej nattr = *attr; 298c62a74e6Sthorpej else 299c62a74e6Sthorpej return EINVAL; 300c62a74e6Sthorpej 301b33971b9Sthorpej /* Fetch misc. attributes from the attr structure. */ 302508a50acSnathanw name = NULL; 303508a50acSnathanw if ((p = nattr.pta_private) != NULL) 304508a50acSnathanw if (p->ptap_name[0] != '\0') 305b33971b9Sthorpej if ((name = strdup(p->ptap_name)) == NULL) 306b33971b9Sthorpej return ENOMEM; 307c62a74e6Sthorpej 308c62a74e6Sthorpej self = pthread__self(); 309a014cf23Sad newthread = NULL; 310c62a74e6Sthorpej 311a014cf23Sad if (!PTQ_EMPTY(&pthread__deadqueue)) { 31250fa8db4Sad pthread_spinlock(self, &pthread__queue_lock); 313c62a74e6Sthorpej newthread = PTQ_FIRST(&pthread__deadqueue); 3144cdc2ed8Syamt if (newthread != NULL) { 31550fa8db4Sad PTQ_REMOVE(&pthread__deadqueue, newthread, pt_allq); 31650fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 317a014cf23Sad if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0) { 318a014cf23Sad /* Still running? */ 31950fa8db4Sad if (_lwp_kill(newthread->pt_lid, 0) == 0 || 32050fa8db4Sad errno != ESRCH) { 321a014cf23Sad pthread_spinlock(self, 322a014cf23Sad &pthread__queue_lock); 32350fa8db4Sad PTQ_INSERT_TAIL(&pthread__deadqueue, 32450fa8db4Sad newthread, pt_allq); 325a014cf23Sad pthread_spinunlock(self, 326a014cf23Sad &pthread__queue_lock); 3274cdc2ed8Syamt newthread = NULL; 32850fa8db4Sad } 3294cdc2ed8Syamt } 330a014cf23Sad } else 33150fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 332a014cf23Sad } 333a014cf23Sad 3344cdc2ed8Syamt if (newthread == NULL) { 335c62a74e6Sthorpej /* Set up a stack and allocate space for a pthread_st. */ 336c62a74e6Sthorpej ret = pthread__stackalloc(&newthread); 337b7559f85Schristos if (ret != 0) { 338b7559f85Schristos if (name) 339b7559f85Schristos free(name); 340c62a74e6Sthorpej return ret; 341c62a74e6Sthorpej } 342b7559f85Schristos } 343c62a74e6Sthorpej 344c62a74e6Sthorpej /* 2. Set up state. */ 34550fa8db4Sad pthread__initthread(newthread); 346c62a74e6Sthorpej newthread->pt_flags = nattr.pta_flags; 347c62a74e6Sthorpej 348b33971b9Sthorpej /* 3. Set up misc. attributes. */ 349b33971b9Sthorpej newthread->pt_name = name; 350b33971b9Sthorpej 351c62a74e6Sthorpej /* 352b33971b9Sthorpej * 4. Set up context. 353c62a74e6Sthorpej * 354c62a74e6Sthorpej * The pt_uc pointer points to a location safely below the 355c62a74e6Sthorpej * stack start; this is arranged by pthread__stackalloc(). 356c62a74e6Sthorpej */ 357c62a74e6Sthorpej _INITCONTEXT_U(newthread->pt_uc); 358877f8985Snathanw #ifdef PTHREAD_MACHINE_HAS_ID_REGISTER 359877f8985Snathanw pthread__uc_id(newthread->pt_uc) = newthread; 360877f8985Snathanw #endif 361c62a74e6Sthorpej newthread->pt_uc->uc_stack = newthread->pt_stack; 362c62a74e6Sthorpej newthread->pt_uc->uc_link = NULL; 363c62a74e6Sthorpej makecontext(newthread->pt_uc, pthread__create_tramp, 2, 364c62a74e6Sthorpej startfunc, arg); 365c62a74e6Sthorpej 366efb1fc06Sad /* 5. Add to list of all threads. */ 36750fa8db4Sad pthread_spinlock(self, &pthread__queue_lock); 368efb1fc06Sad PTQ_INSERT_HEAD(&pthread__allqueue, newthread, pt_allq); 36950fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 370efb1fc06Sad 371efb1fc06Sad /* 5a. Create the new LWP. */ 3727630e387Sad newthread->pt_sleeponq = 0; 373ded26025Sad flag = 0; 374ded26025Sad if ((newthread->pt_flags & PT_FLAG_SUSPENDED) != 0) 375ded26025Sad flag |= LWP_SUSPENDED; 376ded26025Sad if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0) 377ded26025Sad flag |= LWP_DETACHED; 3781ac6a89bSad ret = _lwp_create(newthread->pt_uc, (u_long)flag, &newthread->pt_lid); 3791ac6a89bSad if (ret != 0) { 3801ac6a89bSad SDPRINTF(("(pthread_create %p) _lwp_create: %s\n", 3811ac6a89bSad strerror(errno))); 3821ac6a89bSad free(name); 38350fa8db4Sad pthread_spinlock(self, &pthread__queue_lock); 384efb1fc06Sad PTQ_REMOVE(&pthread__allqueue, newthread, pt_allq); 385efb1fc06Sad PTQ_INSERT_HEAD(&pthread__deadqueue, newthread, pt_allq); 38650fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 3871ac6a89bSad return ret; 3881ac6a89bSad } 3891ac6a89bSad 39050fa8db4Sad /* XXX must die */ 39150fa8db4Sad newthread->pt_num = newthread->pt_lid; 39250fa8db4Sad 3931ac6a89bSad SDPRINTF(("(pthread_create %p) new thread %p (name %p, lid %d).\n", 3941ac6a89bSad self, newthread, newthread->pt_name, 3951ac6a89bSad (int)newthread->pt_lid)); 396c62a74e6Sthorpej 397c62a74e6Sthorpej *thread = newthread; 398c62a74e6Sthorpej 399c62a74e6Sthorpej return 0; 400c62a74e6Sthorpej } 401c62a74e6Sthorpej 402c62a74e6Sthorpej 403c62a74e6Sthorpej static void 404c62a74e6Sthorpej pthread__create_tramp(void *(*start)(void *), void *arg) 405c62a74e6Sthorpej { 406c62a74e6Sthorpej void *retval; 407c62a74e6Sthorpej 40850fa8db4Sad /* 40950fa8db4Sad * Throw away some stack in a feeble attempt to reduce cache 41050fa8db4Sad * thrash. May help for SMT processors. XXX We should not 41150fa8db4Sad * be allocating stacks on fixed 2MB boundaries. Needs a 41250fa8db4Sad * thread register or decent thread local storage. 41350fa8db4Sad */ 41450fa8db4Sad (void)alloca(((unsigned)pthread__self()->pt_lid & 7) << 8); 41550fa8db4Sad 41694a458ceSchs retval = (*start)(arg); 417c62a74e6Sthorpej 418c62a74e6Sthorpej pthread_exit(retval); 419c62a74e6Sthorpej 420143f5a27Schristos /*NOTREACHED*/ 421143f5a27Schristos pthread__abort(); 422c62a74e6Sthorpej } 423c62a74e6Sthorpej 42438b1c6f4Schristos int 42538b1c6f4Schristos pthread_suspend_np(pthread_t thread) 42638b1c6f4Schristos { 427ba70e96aSchs pthread_t self; 428ba70e96aSchs 429ba70e96aSchs self = pthread__self(); 43038b1c6f4Schristos if (self == thread) { 43138b1c6f4Schristos return EDEADLK; 43238b1c6f4Schristos } 433ba70e96aSchs #ifdef ERRORCHECK 434ba70e96aSchs if (pthread__find(self, thread) != 0) 435ba70e96aSchs return ESRCH; 436ba70e96aSchs #endif 4371ac6a89bSad SDPRINTF(("(pthread_suspend_np %p) Suspend thread %p.\n", 4381ac6a89bSad self, thread)); 4391ac6a89bSad return _lwp_suspend(thread->pt_lid); 44038b1c6f4Schristos } 44138b1c6f4Schristos 44238b1c6f4Schristos int 44338b1c6f4Schristos pthread_resume_np(pthread_t thread) 44438b1c6f4Schristos { 445ba70e96aSchs pthread_t self; 44638b1c6f4Schristos 447ba70e96aSchs self = pthread__self(); 448ba70e96aSchs #ifdef ERRORCHECK 449ba70e96aSchs if (pthread__find(self, thread) != 0) 450ba70e96aSchs return ESRCH; 451ba70e96aSchs #endif 4521ac6a89bSad SDPRINTF(("(pthread_resume_np %p) Resume thread %p.\n", 4531ac6a89bSad self, thread)); 4541ac6a89bSad return _lwp_continue(thread->pt_lid); 45538b1c6f4Schristos } 45638b1c6f4Schristos 457c62a74e6Sthorpej void 458c62a74e6Sthorpej pthread_exit(void *retval) 459c62a74e6Sthorpej { 46096b5a26dSnathanw pthread_t self; 461c62a74e6Sthorpej struct pt_clean_t *cleanup; 462b33971b9Sthorpej char *name; 463c62a74e6Sthorpej 464c62a74e6Sthorpej self = pthread__self(); 465ba70e96aSchs SDPRINTF(("(pthread_exit %p) status %p, flags %x, cancel %d\n", 466ba70e96aSchs self, retval, self->pt_flags, self->pt_cancel)); 467c62a74e6Sthorpej 468c62a74e6Sthorpej /* Disable cancellability. */ 46950fa8db4Sad pthread_spinlock(self, &self->pt_lock); 470c62a74e6Sthorpej self->pt_flags |= PT_FLAG_CS_DISABLED; 47166fcc1ceSnathanw self->pt_cancel = 0; 47250fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 473c62a74e6Sthorpej 474c62a74e6Sthorpej /* Call any cancellation cleanup handlers */ 475c62a74e6Sthorpej while (!PTQ_EMPTY(&self->pt_cleanup_stack)) { 476c62a74e6Sthorpej cleanup = PTQ_FIRST(&self->pt_cleanup_stack); 477c62a74e6Sthorpej PTQ_REMOVE(&self->pt_cleanup_stack, cleanup, ptc_next); 478c62a74e6Sthorpej (*cleanup->ptc_cleanup)(cleanup->ptc_arg); 479c62a74e6Sthorpej } 480c62a74e6Sthorpej 481c62a74e6Sthorpej /* Perform cleanup of thread-specific data */ 482c62a74e6Sthorpej pthread__destroy_tsd(self); 483c62a74e6Sthorpej 484c62a74e6Sthorpej self->pt_exitval = retval; 485c62a74e6Sthorpej 48650fa8db4Sad pthread_spinlock(self, &self->pt_lock); 4876b2b9c62Syamt if (self->pt_flags & PT_FLAG_DETACHED) { 4886b2b9c62Syamt self->pt_state = PT_STATE_DEAD; 489b33971b9Sthorpej name = self->pt_name; 490b33971b9Sthorpej self->pt_name = NULL; 49150fa8db4Sad pthread_spinlock(self, &pthread__queue_lock); 49250fa8db4Sad PTQ_REMOVE(&pthread__allqueue, self, pt_allq); 49350fa8db4Sad PTQ_INSERT_TAIL(&pthread__deadqueue, self, pt_allq); 49450fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 49550fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 496b33971b9Sthorpej if (name != NULL) 497b33971b9Sthorpej free(name); 4981ac6a89bSad _lwp_exit(); 499c62a74e6Sthorpej } else { 5006b2b9c62Syamt self->pt_state = PT_STATE_ZOMBIE; 50150fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 502b33971b9Sthorpej /* Note: name will be freed by the joiner. */ 5031ac6a89bSad _lwp_exit(); 504c62a74e6Sthorpej } 505c62a74e6Sthorpej 506143f5a27Schristos /*NOTREACHED*/ 507143f5a27Schristos pthread__abort(); 508c62a74e6Sthorpej exit(1); 509c62a74e6Sthorpej } 510c62a74e6Sthorpej 511c62a74e6Sthorpej 512c62a74e6Sthorpej int 513c62a74e6Sthorpej pthread_join(pthread_t thread, void **valptr) 514c62a74e6Sthorpej { 515c62a74e6Sthorpej pthread_t self; 516b33971b9Sthorpej char *name; 5171ac6a89bSad int num, retval; 518c62a74e6Sthorpej 519c62a74e6Sthorpej self = pthread__self(); 520c62a74e6Sthorpej SDPRINTF(("(pthread_join %p) Joining %p.\n", self, thread)); 521c62a74e6Sthorpej 522c62a74e6Sthorpej if (pthread__find(self, thread) != 0) 523c62a74e6Sthorpej return ESRCH; 524c62a74e6Sthorpej 525c62a74e6Sthorpej if (thread->pt_magic != PT_MAGIC) 526c62a74e6Sthorpej return EINVAL; 527c62a74e6Sthorpej 528c62a74e6Sthorpej if (thread == self) 529c62a74e6Sthorpej return EDEADLK; 530c62a74e6Sthorpej 5311ac6a89bSad retval = 0; 5321ac6a89bSad name = NULL; 5331ac6a89bSad again: 53450fa8db4Sad pthread_spinlock(self, &thread->pt_lock); 5351ac6a89bSad switch (thread->pt_state) { 5361ac6a89bSad case PT_STATE_RUNNING: 53750fa8db4Sad pthread_spinunlock(self, &thread->pt_lock); 538ded26025Sad 539ded26025Sad /* 540ded26025Sad * IEEE Std 1003.1, 2004 Edition: 541ded26025Sad * 542ded26025Sad * "The pthread_join() function shall not 543ded26025Sad * return an error code of [EINTR]." 544ded26025Sad */ 545ded26025Sad if (_lwp_wait(thread->pt_lid, &num) != 0 && errno != EINTR) 546ded26025Sad return errno; 5471ac6a89bSad goto again; 5481ac6a89bSad case PT_STATE_ZOMBIE: 5491ac6a89bSad if (valptr != NULL) 550ded26025Sad *valptr = thread->pt_exitval; 5511ac6a89bSad if (retval == 0) { 5521ac6a89bSad name = thread->pt_name; 5531ac6a89bSad thread->pt_name = NULL; 5541ac6a89bSad } 5551ac6a89bSad thread->pt_state = PT_STATE_DEAD; 55650fa8db4Sad pthread_spinlock(self, &pthread__queue_lock); 55750fa8db4Sad PTQ_REMOVE(&pthread__allqueue, thread, pt_allq); 55850fa8db4Sad PTQ_INSERT_HEAD(&pthread__deadqueue, thread, pt_allq); 55950fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 56050fa8db4Sad pthread_spinunlock(self, &thread->pt_lock); 56150fa8db4Sad SDPRINTF(("(pthread_join %p) Joined %p.\n", self, thread)); 56250fa8db4Sad if (name != NULL) 56350fa8db4Sad free(name); 564b8daad98Sad (void)_lwp_detach(thread->pt_lid); 56550fa8db4Sad return retval; 5661ac6a89bSad default: 56750fa8db4Sad pthread_spinunlock(self, &thread->pt_lock); 5681ac6a89bSad return EINVAL; 5691ac6a89bSad } 5701ac6a89bSad 571c62a74e6Sthorpej } 572c62a74e6Sthorpej 573c62a74e6Sthorpej 574c62a74e6Sthorpej int 575c62a74e6Sthorpej pthread_equal(pthread_t t1, pthread_t t2) 576c62a74e6Sthorpej { 577c62a74e6Sthorpej 578c62a74e6Sthorpej /* Nothing special here. */ 579c62a74e6Sthorpej return (t1 == t2); 580c62a74e6Sthorpej } 581c62a74e6Sthorpej 582c62a74e6Sthorpej 583c62a74e6Sthorpej int 584c62a74e6Sthorpej pthread_detach(pthread_t thread) 585c62a74e6Sthorpej { 58696b5a26dSnathanw pthread_t self; 587c62a74e6Sthorpej 588c62a74e6Sthorpej self = pthread__self(); 589c62a74e6Sthorpej 590c62a74e6Sthorpej if (pthread__find(self, thread) != 0) 591c62a74e6Sthorpej return ESRCH; 592c62a74e6Sthorpej 593c62a74e6Sthorpej if (thread->pt_magic != PT_MAGIC) 594c62a74e6Sthorpej return EINVAL; 595c62a74e6Sthorpej 59650fa8db4Sad pthread_spinlock(self, &self->pt_lock); 5971296e850Sad thread->pt_flags |= PT_FLAG_DETACHED; 59850fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 599de213816Sad 6001ac6a89bSad return _lwp_detach(thread->pt_lid); 601c62a74e6Sthorpej } 602c62a74e6Sthorpej 603c62a74e6Sthorpej 604c62a74e6Sthorpej int 605b33971b9Sthorpej pthread_getname_np(pthread_t thread, char *name, size_t len) 606c62a74e6Sthorpej { 607b33971b9Sthorpej pthread_t self; 608c62a74e6Sthorpej 609b33971b9Sthorpej self = pthread__self(); 610b33971b9Sthorpej 611b33971b9Sthorpej if (pthread__find(self, thread) != 0) 612b33971b9Sthorpej return ESRCH; 613b33971b9Sthorpej 614b33971b9Sthorpej if (thread->pt_magic != PT_MAGIC) 615b33971b9Sthorpej return EINVAL; 616b33971b9Sthorpej 61750fa8db4Sad pthread_spinlock(self, &thread->pt_lock); 618b33971b9Sthorpej if (thread->pt_name == NULL) 619b33971b9Sthorpej name[0] = '\0'; 620b33971b9Sthorpej else 621b33971b9Sthorpej strlcpy(name, thread->pt_name, len); 62250fa8db4Sad pthread_spinunlock(self, &thread->pt_lock); 623c62a74e6Sthorpej 624c62a74e6Sthorpej return 0; 625c62a74e6Sthorpej } 626c62a74e6Sthorpej 627c62a74e6Sthorpej 628c62a74e6Sthorpej int 629b33971b9Sthorpej pthread_setname_np(pthread_t thread, const char *name, void *arg) 630b33971b9Sthorpej { 631ba70e96aSchs pthread_t self; 632b33971b9Sthorpej char *oldname, *cp, newname[PTHREAD_MAX_NAMELEN_NP]; 633b33971b9Sthorpej int namelen; 634b33971b9Sthorpej 635ba70e96aSchs self = pthread__self(); 636b33971b9Sthorpej if (pthread__find(self, thread) != 0) 637b33971b9Sthorpej return ESRCH; 638b33971b9Sthorpej 639b33971b9Sthorpej if (thread->pt_magic != PT_MAGIC) 640b33971b9Sthorpej return EINVAL; 641b33971b9Sthorpej 642b33971b9Sthorpej namelen = snprintf(newname, sizeof(newname), name, arg); 643b33971b9Sthorpej if (namelen >= PTHREAD_MAX_NAMELEN_NP) 644b33971b9Sthorpej return EINVAL; 645b33971b9Sthorpej 646b33971b9Sthorpej cp = strdup(newname); 647b33971b9Sthorpej if (cp == NULL) 648b33971b9Sthorpej return ENOMEM; 649b33971b9Sthorpej 65050fa8db4Sad pthread_spinlock(self, &thread->pt_lock); 651b33971b9Sthorpej oldname = thread->pt_name; 652b33971b9Sthorpej thread->pt_name = cp; 65350fa8db4Sad pthread_spinunlock(self, &thread->pt_lock); 654b33971b9Sthorpej 655b33971b9Sthorpej if (oldname != NULL) 656b33971b9Sthorpej free(oldname); 657b33971b9Sthorpej 658b33971b9Sthorpej return 0; 659b33971b9Sthorpej } 660b33971b9Sthorpej 661b33971b9Sthorpej 662b33971b9Sthorpej 663c62a74e6Sthorpej /* 664c62a74e6Sthorpej * XXX There should be a way for applications to use the efficent 665c62a74e6Sthorpej * inline version, but there are opacity/namespace issues. 666c62a74e6Sthorpej */ 667c62a74e6Sthorpej pthread_t 668c62a74e6Sthorpej pthread_self(void) 669c62a74e6Sthorpej { 670c62a74e6Sthorpej 671c62a74e6Sthorpej return pthread__self(); 672c62a74e6Sthorpej } 673c62a74e6Sthorpej 674c62a74e6Sthorpej 675c62a74e6Sthorpej int 676c62a74e6Sthorpej pthread_cancel(pthread_t thread) 677c62a74e6Sthorpej { 678c62a74e6Sthorpej pthread_t self; 679c62a74e6Sthorpej 680ba70e96aSchs self = pthread__self(); 681ba70e96aSchs if (pthread__find(self, thread) != 0) 682ba70e96aSchs return ESRCH; 68350fa8db4Sad pthread_spinlock(self, &thread->pt_lock); 6841ac6a89bSad thread->pt_flags |= PT_FLAG_CS_PENDING; 6851ac6a89bSad if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) { 6861ac6a89bSad thread->pt_cancel = 1; 68750fa8db4Sad pthread_spinunlock(self, &thread->pt_lock); 6881ac6a89bSad _lwp_wakeup(thread->pt_lid); 6891ac6a89bSad } else 69050fa8db4Sad pthread_spinunlock(self, &thread->pt_lock); 691c62a74e6Sthorpej 692c62a74e6Sthorpej return 0; 693c62a74e6Sthorpej } 694c62a74e6Sthorpej 695c62a74e6Sthorpej 696c62a74e6Sthorpej int 697c62a74e6Sthorpej pthread_setcancelstate(int state, int *oldstate) 698c62a74e6Sthorpej { 699c62a74e6Sthorpej pthread_t self; 7000878df5dSnathanw int retval; 701c62a74e6Sthorpej 702c62a74e6Sthorpej self = pthread__self(); 7030878df5dSnathanw retval = 0; 704c62a74e6Sthorpej 70550fa8db4Sad pthread_spinlock(self, &self->pt_lock); 70650fa8db4Sad 707c62a74e6Sthorpej if (oldstate != NULL) { 7080878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_DISABLED) 709c62a74e6Sthorpej *oldstate = PTHREAD_CANCEL_DISABLE; 710c62a74e6Sthorpej else 711c62a74e6Sthorpej *oldstate = PTHREAD_CANCEL_ENABLE; 712c62a74e6Sthorpej } 713c62a74e6Sthorpej 7140878df5dSnathanw if (state == PTHREAD_CANCEL_DISABLE) { 7150878df5dSnathanw self->pt_flags |= PT_FLAG_CS_DISABLED; 7160878df5dSnathanw if (self->pt_cancel) { 7170878df5dSnathanw self->pt_flags |= PT_FLAG_CS_PENDING; 7180878df5dSnathanw self->pt_cancel = 0; 7190878df5dSnathanw } 7200878df5dSnathanw } else if (state == PTHREAD_CANCEL_ENABLE) { 7210878df5dSnathanw self->pt_flags &= ~PT_FLAG_CS_DISABLED; 722c62a74e6Sthorpej /* 723c62a74e6Sthorpej * If a cancellation was requested while cancellation 724c62a74e6Sthorpej * was disabled, note that fact for future 725c62a74e6Sthorpej * cancellation tests. 726c62a74e6Sthorpej */ 7270878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_PENDING) { 728c62a74e6Sthorpej self->pt_cancel = 1; 729c62a74e6Sthorpej /* This is not a deferred cancellation point. */ 7300878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_ASYNC) { 73150fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 732c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 733c62a74e6Sthorpej } 7340878df5dSnathanw } 735c62a74e6Sthorpej } else 7360878df5dSnathanw retval = EINVAL; 737c62a74e6Sthorpej 73850fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 73950fa8db4Sad 7400878df5dSnathanw return retval; 741c62a74e6Sthorpej } 742c62a74e6Sthorpej 743c62a74e6Sthorpej 744c62a74e6Sthorpej int 745c62a74e6Sthorpej pthread_setcanceltype(int type, int *oldtype) 746c62a74e6Sthorpej { 747c62a74e6Sthorpej pthread_t self; 7480878df5dSnathanw int retval; 749c62a74e6Sthorpej 750c62a74e6Sthorpej self = pthread__self(); 7510878df5dSnathanw retval = 0; 7520878df5dSnathanw 75350fa8db4Sad pthread_spinlock(self, &self->pt_lock); 754c62a74e6Sthorpej 755c62a74e6Sthorpej if (oldtype != NULL) { 7560878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_ASYNC) 757c62a74e6Sthorpej *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS; 758c62a74e6Sthorpej else 759c62a74e6Sthorpej *oldtype = PTHREAD_CANCEL_DEFERRED; 760c62a74e6Sthorpej } 761c62a74e6Sthorpej 762c62a74e6Sthorpej if (type == PTHREAD_CANCEL_ASYNCHRONOUS) { 7630878df5dSnathanw self->pt_flags |= PT_FLAG_CS_ASYNC; 7640878df5dSnathanw if (self->pt_cancel) { 76550fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 766c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 7670878df5dSnathanw } 768c62a74e6Sthorpej } else if (type == PTHREAD_CANCEL_DEFERRED) 7690878df5dSnathanw self->pt_flags &= ~PT_FLAG_CS_ASYNC; 770c62a74e6Sthorpej else 7710878df5dSnathanw retval = EINVAL; 772c62a74e6Sthorpej 77350fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 77450fa8db4Sad 7750878df5dSnathanw return retval; 776c62a74e6Sthorpej } 777c62a74e6Sthorpej 778c62a74e6Sthorpej 779c62a74e6Sthorpej void 780c62a74e6Sthorpej pthread_testcancel() 781c62a74e6Sthorpej { 782c62a74e6Sthorpej pthread_t self; 783c62a74e6Sthorpej 784c62a74e6Sthorpej self = pthread__self(); 785c62a74e6Sthorpej if (self->pt_cancel) 786c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 787c62a74e6Sthorpej } 788c62a74e6Sthorpej 789c62a74e6Sthorpej 790c62a74e6Sthorpej /* 791c62a74e6Sthorpej * POSIX requires that certain functions return an error rather than 792c62a74e6Sthorpej * invoking undefined behavior even when handed completely bogus 793c62a74e6Sthorpej * pthread_t values, e.g. stack garbage or (pthread_t)666. This 794c62a74e6Sthorpej * utility routine searches the list of threads for the pthread_t 795c62a74e6Sthorpej * value without dereferencing it. 796c62a74e6Sthorpej */ 797c62a74e6Sthorpej int 798c62a74e6Sthorpej pthread__find(pthread_t self, pthread_t id) 799c62a74e6Sthorpej { 800c62a74e6Sthorpej pthread_t target; 801c62a74e6Sthorpej 80250fa8db4Sad pthread_spinlock(self, &pthread__queue_lock); 803c62a74e6Sthorpej PTQ_FOREACH(target, &pthread__allqueue, pt_allq) 804c62a74e6Sthorpej if (target == id) 805c62a74e6Sthorpej break; 80650fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 807c62a74e6Sthorpej 808c62a74e6Sthorpej if (target == NULL) 809c62a74e6Sthorpej return ESRCH; 810c62a74e6Sthorpej 811c62a74e6Sthorpej return 0; 812c62a74e6Sthorpej } 813c62a74e6Sthorpej 814c62a74e6Sthorpej 815c62a74e6Sthorpej void 816c62a74e6Sthorpej pthread__testcancel(pthread_t self) 817c62a74e6Sthorpej { 818c62a74e6Sthorpej 819c62a74e6Sthorpej if (self->pt_cancel) 820c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 821c62a74e6Sthorpej } 822c62a74e6Sthorpej 823c62a74e6Sthorpej 824c62a74e6Sthorpej void 825c62a74e6Sthorpej pthread__cleanup_push(void (*cleanup)(void *), void *arg, void *store) 826c62a74e6Sthorpej { 827c62a74e6Sthorpej pthread_t self; 828c62a74e6Sthorpej struct pt_clean_t *entry; 829c62a74e6Sthorpej 830c62a74e6Sthorpej self = pthread__self(); 831c62a74e6Sthorpej entry = store; 832c62a74e6Sthorpej entry->ptc_cleanup = cleanup; 833c62a74e6Sthorpej entry->ptc_arg = arg; 834c62a74e6Sthorpej PTQ_INSERT_HEAD(&self->pt_cleanup_stack, entry, ptc_next); 835c62a74e6Sthorpej } 836c62a74e6Sthorpej 837c62a74e6Sthorpej 838c62a74e6Sthorpej void 839c62a74e6Sthorpej pthread__cleanup_pop(int ex, void *store) 840c62a74e6Sthorpej { 841c62a74e6Sthorpej pthread_t self; 842c62a74e6Sthorpej struct pt_clean_t *entry; 843c62a74e6Sthorpej 844c62a74e6Sthorpej self = pthread__self(); 845c62a74e6Sthorpej entry = store; 846c62a74e6Sthorpej 847c62a74e6Sthorpej PTQ_REMOVE(&self->pt_cleanup_stack, entry, ptc_next); 848c62a74e6Sthorpej if (ex) 849c62a74e6Sthorpej (*entry->ptc_cleanup)(entry->ptc_arg); 850c62a74e6Sthorpej } 851c62a74e6Sthorpej 852c62a74e6Sthorpej 853c62a74e6Sthorpej int * 854c62a74e6Sthorpej pthread__errno(void) 855c62a74e6Sthorpej { 856c62a74e6Sthorpej pthread_t self; 857c62a74e6Sthorpej 858c62a74e6Sthorpej self = pthread__self(); 859c62a74e6Sthorpej 860c62a74e6Sthorpej return &(self->pt_errno); 861c62a74e6Sthorpej } 8628bcff70bSnathanw 8630c967901Snathanw ssize_t _sys_write(int, const void *, size_t); 8640c967901Snathanw 8658bcff70bSnathanw void 8660e6c93b9Sdrochner pthread__assertfunc(const char *file, int line, const char *function, 8670e6c93b9Sdrochner const char *expr) 8688bcff70bSnathanw { 8698bcff70bSnathanw char buf[1024]; 8708bcff70bSnathanw int len; 8718bcff70bSnathanw 87275a94788Smycroft SDPRINTF(("(af)\n")); 87375a94788Smycroft 8748bcff70bSnathanw /* 8758bcff70bSnathanw * snprintf should not acquire any locks, or we could 8768bcff70bSnathanw * end up deadlocked if the assert caller held locks. 8778bcff70bSnathanw */ 8788bcff70bSnathanw len = snprintf(buf, 1024, 8798bcff70bSnathanw "assertion \"%s\" failed: file \"%s\", line %d%s%s%s\n", 8808bcff70bSnathanw expr, file, line, 8818bcff70bSnathanw function ? ", function \"" : "", 8828bcff70bSnathanw function ? function : "", 8838bcff70bSnathanw function ? "\"" : ""); 8848bcff70bSnathanw 8850c967901Snathanw _sys_write(STDERR_FILENO, buf, (size_t)len); 8868bcff70bSnathanw (void)kill(getpid(), SIGABRT); 8878bcff70bSnathanw 8888bcff70bSnathanw _exit(1); 8898bcff70bSnathanw } 890df277271Snathanw 891df277271Snathanw 892df277271Snathanw void 8930e6c93b9Sdrochner pthread__errorfunc(const char *file, int line, const char *function, 8940e6c93b9Sdrochner const char *msg) 895df277271Snathanw { 896df277271Snathanw char buf[1024]; 8970172694eSnathanw size_t len; 898df277271Snathanw 8990172694eSnathanw if (pthread__diagassert == 0) 900df277271Snathanw return; 901df277271Snathanw 902df277271Snathanw /* 903df277271Snathanw * snprintf should not acquire any locks, or we could 904df277271Snathanw * end up deadlocked if the assert caller held locks. 905df277271Snathanw */ 906df277271Snathanw len = snprintf(buf, 1024, 9070172694eSnathanw "%s: Error detected by libpthread: %s.\n" 9080172694eSnathanw "Detected by file \"%s\", line %d%s%s%s.\n" 9090172694eSnathanw "See pthread(3) for information.\n", 9100172694eSnathanw getprogname(), msg, file, line, 911df277271Snathanw function ? ", function \"" : "", 912df277271Snathanw function ? function : "", 9130172694eSnathanw function ? "\"" : ""); 914df277271Snathanw 9150172694eSnathanw if (pthread__diagassert & DIAGASSERT_STDERR) 9160c967901Snathanw _sys_write(STDERR_FILENO, buf, len); 9170172694eSnathanw 9180172694eSnathanw if (pthread__diagassert & DIAGASSERT_SYSLOG) 9190172694eSnathanw syslog(LOG_DEBUG | LOG_USER, "%s", buf); 9200172694eSnathanw 9210172694eSnathanw if (pthread__diagassert & DIAGASSERT_ABORT) { 922df277271Snathanw (void)kill(getpid(), SIGABRT); 923df277271Snathanw _exit(1); 924df277271Snathanw } 925df277271Snathanw } 9261ac6a89bSad 927fe9718acSad /* 928ded26025Sad * Thread park/unpark operations. The kernel operations are 929ded26025Sad * modelled after a brief description from "Multithreading in 930ded26025Sad * the Solaris Operating Environment": 931fe9718acSad * 932fe9718acSad * http://www.sun.com/software/whitepapers/solaris9/multithread.pdf 933fe9718acSad */ 934fe9718acSad 9351ac6a89bSad #define OOPS(msg) \ 936858097f9Schristos pthread__errorfunc(__FILE__, __LINE__, __func__, msg) 9371ac6a89bSad 9381ac6a89bSad int 9391ac6a89bSad pthread__park(pthread_t self, pthread_spin_t *lock, 94050fa8db4Sad pthread_queue_t *queue, const struct timespec *abstime, 94150fa8db4Sad int cancelpt, const void *hint) 9421ac6a89bSad { 943*c3f8e2eeSad int rv, error; 9441ac6a89bSad 945792cc0e1Sad SDPRINTF(("(pthread__park %p) queue %p enter\n", self, queue)); 9461ac6a89bSad 947*c3f8e2eeSad /* Clear the willpark flag, since we're about to block. */ 948*c3f8e2eeSad self->pt_willpark = 0; 949*c3f8e2eeSad 950*c3f8e2eeSad /* 951*c3f8e2eeSad * Kernels before 4.99.27 can't park and unpark in one step, 952*c3f8e2eeSad * so take care of it now if on an old kernel. 953*c3f8e2eeSad * 954*c3f8e2eeSad * XXX Remove this check before NetBSD 5.0 is released. 955*c3f8e2eeSad * It's for compatibility with recent -current only. 956*c3f8e2eeSad */ 957*c3f8e2eeSad if (__predict_false(pthread__osrev < 499002700) && 958*c3f8e2eeSad self->pt_unpark != 0) { 959*c3f8e2eeSad _lwp_unpark(self->pt_unpark, self->pt_unparkhint); 960*c3f8e2eeSad self->pt_unpark = 0; 961*c3f8e2eeSad } 962*c3f8e2eeSad 963ded26025Sad /* 964ded26025Sad * Wait until we are awoken by a pending unpark operation, 965ded26025Sad * a signal, an unpark posted after we have gone asleep, 966ded26025Sad * or an expired timeout. 96750fa8db4Sad * 96850fa8db4Sad * It is fine to test the value of both pt_sleepobj and 96950fa8db4Sad * pt_sleeponq without holding any locks, because: 97050fa8db4Sad * 97150fa8db4Sad * o Only the blocking thread (this thread) ever sets them 97250fa8db4Sad * to a non-NULL value. 97350fa8db4Sad * 97450fa8db4Sad * o Other threads may set them NULL, but if they do so they 97550fa8db4Sad * must also make this thread return from _lwp_park. 97650fa8db4Sad * 97750fa8db4Sad * o _lwp_park, _lwp_unpark and _lwp_unpark_all are system 97850fa8db4Sad * calls and all make use of spinlocks in the kernel. So 97950fa8db4Sad * these system calls act as full memory barriers, and will 98050fa8db4Sad * ensure that the calling CPU's store buffers are drained. 98150fa8db4Sad * In combination with the spinlock release before unpark, 98250fa8db4Sad * this means that modification of pt_sleepobj/onq by another 98350fa8db4Sad * thread will become globally visible before that thread 98450fa8db4Sad * schedules an unpark operation on this thread. 985*c3f8e2eeSad * 986*c3f8e2eeSad * Note: the test in the while() statement dodges the park op if 987*c3f8e2eeSad * we have already been awoken, unless there is another thread to 988*c3f8e2eeSad * awaken. This saves a syscall - if we were already awakened, 989*c3f8e2eeSad * the next call to _lwp_park() would need to return early in order 990*c3f8e2eeSad * to eat the previous wakeup. 991ded26025Sad */ 992ded26025Sad rv = 0; 993*c3f8e2eeSad while ((self->pt_sleepobj != NULL || self->pt_unpark != 0) && rv == 0) { 994*c3f8e2eeSad /* 995*c3f8e2eeSad * If we deferred unparking a thread, arrange to 996*c3f8e2eeSad * have _lwp_park() restart it before blocking. 997*c3f8e2eeSad */ 998*c3f8e2eeSad error = _lwp_park(abstime, self->pt_unpark, hint, 999*c3f8e2eeSad self->pt_unparkhint); 1000*c3f8e2eeSad self->pt_unpark = 0; 1001*c3f8e2eeSad if (error != 0) { 1002ded26025Sad switch (rv = errno) { 10031ac6a89bSad case EINTR: 10041ac6a89bSad case EALREADY: 1005ded26025Sad rv = 0; 1006ded26025Sad break; 1007ded26025Sad case ETIMEDOUT: 10081ac6a89bSad break; 10091ac6a89bSad default: 10101ac6a89bSad OOPS("_lwp_park failed"); 10111ac6a89bSad SDPRINTF(("(pthread__park %p) syscall rv=%d\n", 10121ac6a89bSad self, rv)); 10131ac6a89bSad break; 10141ac6a89bSad } 1015ded26025Sad } 10160c61b6a6Sad /* Check for cancellation. */ 10170c61b6a6Sad if (cancelpt && self->pt_cancel) { 10180c61b6a6Sad /* 10190c61b6a6Sad * Ensure visibility of the correct value. 10200c61b6a6Sad * _lwp_park/_lwp_wakeup also provide a 10210c61b6a6Sad * barrier. 10220c61b6a6Sad */ 102350fa8db4Sad pthread_spinlock(self, &self->pt_lock); 10240c61b6a6Sad if (self->pt_cancel) 10250c61b6a6Sad rv = EINTR; 102650fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 10270c61b6a6Sad } 102850fa8db4Sad } 10291ac6a89bSad 1030ded26025Sad /* 1031ded26025Sad * If we have been awoken early but are still on the queue, 103250fa8db4Sad * then remove ourself. Again, it's safe to do the test 103350fa8db4Sad * without holding any locks. 1034ded26025Sad */ 1035792cc0e1Sad if (self->pt_sleeponq) { 103650fa8db4Sad pthread_spinlock(self, lock); 103750fa8db4Sad if (self->pt_sleeponq) { 10381ac6a89bSad PTQ_REMOVE(queue, self, pt_sleep); 10391ac6a89bSad self->pt_sleepobj = NULL; 1040ded26025Sad self->pt_sleeponq = 0; 1041792cc0e1Sad } 104250fa8db4Sad pthread_spinunlock(self, lock); 104350fa8db4Sad } 10441ac6a89bSad 1045792cc0e1Sad SDPRINTF(("(pthread__park %p) queue %p exit\n", self, queue)); 10461ac6a89bSad 10471ac6a89bSad return rv; 10481ac6a89bSad } 10491ac6a89bSad 10501ac6a89bSad void 1051792cc0e1Sad pthread__unpark(pthread_t self, pthread_spin_t *lock, 105250fa8db4Sad pthread_queue_t *queue, pthread_t target) 10531ac6a89bSad { 10541ac6a89bSad int rv; 10551ac6a89bSad 10560c61b6a6Sad if (target == NULL) { 10570c61b6a6Sad pthread_spinunlock(self, lock); 10580c61b6a6Sad return; 10590c61b6a6Sad } 10600c61b6a6Sad 1061792cc0e1Sad SDPRINTF(("(pthread__unpark %p) queue %p target %p\n", 1062792cc0e1Sad self, queue, target)); 10631ac6a89bSad 1064ded26025Sad /* 1065ded26025Sad * Easy: the thread has already been removed from 1066ded26025Sad * the queue, so just awaken it. 1067ded26025Sad */ 10681ac6a89bSad target->pt_sleepobj = NULL; 1069ded26025Sad target->pt_sleeponq = 0; 107050fa8db4Sad 107150fa8db4Sad /* 107250fa8db4Sad * Releasing the spinlock serves as a store barrier, 107350fa8db4Sad * which ensures that all our modifications are visible 107450fa8db4Sad * to the thread in pthread__park() before the unpark 107550fa8db4Sad * operation is set in motion. 107650fa8db4Sad */ 10771ac6a89bSad pthread_spinunlock(self, lock); 10781ac6a89bSad 1079*c3f8e2eeSad /* 1080*c3f8e2eeSad * If the calling thread is about to block, defer 1081*c3f8e2eeSad * unparking the target until _lwp_park() is called. 1082*c3f8e2eeSad */ 1083*c3f8e2eeSad if (self->pt_willpark && self->pt_unpark == 0) { 1084*c3f8e2eeSad self->pt_unpark = target->pt_lid; 1085*c3f8e2eeSad self->pt_unparkhint = queue; 1086*c3f8e2eeSad } else { 1087*c3f8e2eeSad rv = _lwp_unpark(target->pt_lid, queue); 10881ac6a89bSad if (rv != 0 && errno != EALREADY && errno != EINTR) { 10891ac6a89bSad SDPRINTF(("(pthread__unpark %p) syscall rv=%d\n", 10901ac6a89bSad self, rv)); 10911ac6a89bSad OOPS("_lwp_unpark failed"); 10921ac6a89bSad } 10931ac6a89bSad } 1094*c3f8e2eeSad } 10951ac6a89bSad 10961ac6a89bSad void 1097792cc0e1Sad pthread__unpark_all(pthread_t self, pthread_spin_t *lock, 109850fa8db4Sad pthread_queue_t *queue) 10991ac6a89bSad { 1100ded26025Sad lwpid_t waiters[PTHREAD__UNPARK_MAX]; 110167513ce0Sad ssize_t n, rv; 1102ded26025Sad pthread_t thread, next; 1103ded26025Sad 1104ded26025Sad if (PTQ_EMPTY(queue)) { 1105ded26025Sad pthread_spinunlock(self, lock); 1106ded26025Sad return; 1107ded26025Sad } 1108ded26025Sad 1109ded26025Sad /* 1110ded26025Sad * First, clear all sleepobj pointers, since we can release the 1111ded26025Sad * spin lock before awkening everybody, and must synchronise with 1112ded26025Sad * pthread__park(). 1113ded26025Sad */ 1114ded26025Sad PTQ_FOREACH(thread, queue, pt_sleep) { 1115ded26025Sad thread->pt_sleepobj = NULL; 1116792cc0e1Sad if (thread == PTQ_NEXT(thread, pt_sleep)) 1117792cc0e1Sad OOPS("unpark: thread linked to self"); 1118ded26025Sad } 11191ac6a89bSad 11201ac6a89bSad for (;;) { 1121ded26025Sad thread = PTQ_FIRST(queue); 1122ded26025Sad for (n = 0; n < pthread__unpark_max && thread != NULL; 1123ded26025Sad thread = next) { 1124ded26025Sad /* 1125ded26025Sad * If the sleepobj pointer is non-NULL, it 1126ded26025Sad * means one of two things: 1127ded26025Sad * 1128ded26025Sad * o The thread has awoken early, spun 1129ded26025Sad * through application code and is 1130ded26025Sad * once more asleep on this object. 1131ded26025Sad * 1132ded26025Sad * o This is a new thread that has blocked 1133ded26025Sad * on the object after we have released 1134ded26025Sad * the interlock in this loop. 1135ded26025Sad * 1136ded26025Sad * In both cases we shouldn't remove the 1137ded26025Sad * thread from the queue. 1138ded26025Sad */ 1139ded26025Sad next = PTQ_NEXT(thread, pt_sleep); 1140ded26025Sad if (thread->pt_sleepobj != NULL) 1141ded26025Sad continue; 1142ded26025Sad thread->pt_sleeponq = 0; 1143ded26025Sad waiters[n++] = thread->pt_lid; 11441ac6a89bSad PTQ_REMOVE(queue, thread, pt_sleep); 1145792cc0e1Sad SDPRINTF(("(pthread__unpark_all %p) queue %p " 1146792cc0e1Sad "unpark %p\n", self, queue, thread)); 11471ac6a89bSad } 1148ded26025Sad 114950fa8db4Sad /* 115050fa8db4Sad * Releasing the spinlock serves as a store barrier, 115150fa8db4Sad * which ensures that all our modifications are visible 115250fa8db4Sad * to the thread in pthread__park() before the unpark 115350fa8db4Sad * operation is set in motion. 115450fa8db4Sad */ 11551ac6a89bSad pthread_spinunlock(self, lock); 1156ded26025Sad switch (n) { 11571ac6a89bSad case 0: 11581ac6a89bSad return; 11591ac6a89bSad case 1: 1160*c3f8e2eeSad /* 1161*c3f8e2eeSad * If the calling thread is about to block, 1162*c3f8e2eeSad * defer unparking the target until _lwp_park() 1163*c3f8e2eeSad * is called. 1164*c3f8e2eeSad */ 1165*c3f8e2eeSad if (self->pt_willpark && self->pt_unpark == 0) { 1166*c3f8e2eeSad self->pt_unpark = waiters[0]; 1167*c3f8e2eeSad self->pt_unparkhint = queue; 1168*c3f8e2eeSad return; 1169*c3f8e2eeSad } 1170792cc0e1Sad rv = (ssize_t)_lwp_unpark(waiters[0], queue); 11711ac6a89bSad if (rv != 0 && errno != EALREADY && errno != EINTR) { 11721ac6a89bSad OOPS("_lwp_unpark failed"); 11731ac6a89bSad SDPRINTF(("(pthread__unpark_all %p) " 11741ac6a89bSad "syscall rv=%d\n", self, rv)); 11751ac6a89bSad } 11761ac6a89bSad return; 11771ac6a89bSad default: 117850fa8db4Sad rv = _lwp_unpark_all(waiters, (size_t)n, queue); 11791ac6a89bSad if (rv != 0 && errno != EINTR) { 11801ac6a89bSad OOPS("_lwp_unpark_all failed"); 11811ac6a89bSad SDPRINTF(("(pthread__unpark_all %p) " 11821ac6a89bSad "syscall rv=%d\n", self, rv)); 11831ac6a89bSad } 11841ac6a89bSad break; 11851ac6a89bSad } 11861ac6a89bSad pthread_spinlock(self, lock); 11871ac6a89bSad } 11881ac6a89bSad } 11891ac6a89bSad 11901ac6a89bSad #undef OOPS 1191