1*50fa8db4Sad /* $NetBSD: pthread.c,v 1.69 2007/08/04 13:37:48 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*50fa8db4Sad __RCSID("$NetBSD: pthread.c,v 1.69 2007/08/04 13:37:48 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 71*50fa8db4Sad static void pthread__create_tramp(void *(*)(void *), void *); 72*50fa8db4Sad static void pthread__initthread(pthread_t); 73c62a74e6Sthorpej 74c62a74e6Sthorpej int pthread__started; 75c62a74e6Sthorpej 76*50fa8db4Sad pthread_spin_t pthread__queue_lock = __SIMPLELOCK_UNLOCKED; 77*50fa8db4Sad pthread_queue_t pthread__allqueue; 78*50fa8db4Sad 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; 92f2f10664Scl 93f782e995Sdrochner int _sys___sigprocmask14(int, const sigset_t *, sigset_t *); 94f782e995Sdrochner 95c62a74e6Sthorpej __strong_alias(__libc_thr_self,pthread_self) 967dc01dbfSthorpej __strong_alias(__libc_thr_create,pthread_create) 977dc01dbfSthorpej __strong_alias(__libc_thr_exit,pthread_exit) 98c62a74e6Sthorpej __strong_alias(__libc_thr_errno,pthread__errno) 999e5c8705Snathanw __strong_alias(__libc_thr_setcancelstate,pthread_setcancelstate) 100c62a74e6Sthorpej 101c62a74e6Sthorpej /* 102c62a74e6Sthorpej * Static library kludge. Place a reference to a symbol any library 103c62a74e6Sthorpej * file which does not already have a reference here. 104c62a74e6Sthorpej */ 105c62a74e6Sthorpej extern int pthread__cancel_stub_binder; 106c62a74e6Sthorpej 107c62a74e6Sthorpej void *pthread__static_lib_binder[] = { 108c62a74e6Sthorpej &pthread__cancel_stub_binder, 109c62a74e6Sthorpej pthread_cond_init, 110c62a74e6Sthorpej pthread_mutex_init, 111c62a74e6Sthorpej pthread_rwlock_init, 112c62a74e6Sthorpej pthread_barrier_init, 113c62a74e6Sthorpej pthread_key_create, 114bd9a18b7Snathanw pthread_setspecific, 115c62a74e6Sthorpej }; 116c62a74e6Sthorpej 117c62a74e6Sthorpej /* 118c62a74e6Sthorpej * This needs to be started by the library loading code, before main() 119c62a74e6Sthorpej * gets to run, for various things that use the state of the initial thread 120c62a74e6Sthorpej * to work properly (thread-specific data is an application-visible example; 121c62a74e6Sthorpej * spinlock counts for mutexes is an internal example). 122c62a74e6Sthorpej */ 123c62a74e6Sthorpej void 124c62a74e6Sthorpej pthread_init(void) 125c62a74e6Sthorpej { 126c62a74e6Sthorpej pthread_t first; 1270172694eSnathanw char *p; 128ded26025Sad int i, mib[2], ncpu; 129f2f10664Scl size_t len; 130c62a74e6Sthorpej extern int __isthreaded; 131c62a74e6Sthorpej 132f2f10664Scl mib[0] = CTL_HW; 133f2f10664Scl mib[1] = HW_NCPU; 134f2f10664Scl 135f2f10664Scl len = sizeof(ncpu); 136792cc0e1Sad if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) 137792cc0e1Sad err(1, "sysctl(hw.ncpu"); 138f2f10664Scl 139c62a74e6Sthorpej /* Initialize locks first; they're needed elsewhere. */ 140f2f10664Scl pthread__lockprim_init(ncpu); 141f2f10664Scl 142ded26025Sad /* 143ded26025Sad * Get number of CPUs, and maximum number of LWPs that can be 144ded26025Sad * unparked at once. 145ded26025Sad */ 146ded26025Sad if ((pthread__concurrency = ncpu) > 1) 147ded26025Sad pthread__nspins = PTHREAD__NSPINS; 148ded26025Sad else 149ded26025Sad pthread__nspins = 1; 150*50fa8db4Sad if ((p = getenv("PTHREAD_NSPINS")) != NULL) 151*50fa8db4Sad pthread__nspins = atoi(p); 1523247035dSad i = (int)_lwp_unpark_all(NULL, 0, NULL); 1533247035dSad if (i == -1) 1543247035dSad err(1, "_lwp_unpark_all"); 155ded26025Sad if (i < pthread__unpark_max) 156ded26025Sad pthread__unpark_max = i; 157c62a74e6Sthorpej 158c62a74e6Sthorpej /* Basic data structure setup */ 159c62a74e6Sthorpej pthread_attr_init(&pthread_default_attr); 160c62a74e6Sthorpej PTQ_INIT(&pthread__allqueue); 161c62a74e6Sthorpej PTQ_INIT(&pthread__deadqueue); 162c62a74e6Sthorpej /* Create the thread structure corresponding to main() */ 163c62a74e6Sthorpej pthread__initmain(&first); 164*50fa8db4Sad pthread__initthread(first); 1651ac6a89bSad 166c62a74e6Sthorpej first->pt_state = PT_STATE_RUNNING; 1671ac6a89bSad first->pt_lid = _lwp_self(); 168c62a74e6Sthorpej PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq); 169c62a74e6Sthorpej 170c62a74e6Sthorpej /* Start subsystems */ 171c62a74e6Sthorpej PTHREAD_MD_INIT 172c62a74e6Sthorpej #ifdef PTHREAD__DEBUG 173f2f10664Scl pthread__debug_init(ncpu); 174c62a74e6Sthorpej #endif 175c62a74e6Sthorpej 1760172694eSnathanw for (p = getenv("PTHREAD_DIAGASSERT"); p && *p; p++) { 1770172694eSnathanw switch (*p) { 1780172694eSnathanw case 'a': 1790172694eSnathanw pthread__diagassert |= DIAGASSERT_ABORT; 1800172694eSnathanw break; 1810172694eSnathanw case 'A': 1820172694eSnathanw pthread__diagassert &= ~DIAGASSERT_ABORT; 1830172694eSnathanw break; 1840172694eSnathanw case 'e': 1850172694eSnathanw pthread__diagassert |= DIAGASSERT_STDERR; 1860172694eSnathanw break; 1870172694eSnathanw case 'E': 1880172694eSnathanw pthread__diagassert &= ~DIAGASSERT_STDERR; 1890172694eSnathanw break; 1900172694eSnathanw case 'l': 1910172694eSnathanw pthread__diagassert |= DIAGASSERT_SYSLOG; 1920172694eSnathanw break; 1930172694eSnathanw case 'L': 1940172694eSnathanw pthread__diagassert &= ~DIAGASSERT_SYSLOG; 1950172694eSnathanw break; 196df277271Snathanw } 1970172694eSnathanw } 1980172694eSnathanw 199df277271Snathanw 200c62a74e6Sthorpej /* Tell libc that we're here and it should role-play accordingly. */ 201c62a74e6Sthorpej __isthreaded = 1; 202c62a74e6Sthorpej } 203c62a74e6Sthorpej 2042a4cef11Snathanw static void 2052a4cef11Snathanw pthread__child_callback(void) 2062a4cef11Snathanw { 2072a4cef11Snathanw /* 2082a4cef11Snathanw * Clean up data structures that a forked child process might 2092a4cef11Snathanw * trip over. Note that if threads have been created (causing 2102a4cef11Snathanw * this handler to be registered) the standards say that the 2112a4cef11Snathanw * child will trigger undefined behavior if it makes any 2122a4cef11Snathanw * pthread_* calls (or any other calls that aren't 2132a4cef11Snathanw * async-signal-safe), so we don't really have to clean up 2142a4cef11Snathanw * much. Anything that permits some pthread_* calls to work is 2152a4cef11Snathanw * merely being polite. 2162a4cef11Snathanw */ 2172a4cef11Snathanw pthread__started = 0; 2182a4cef11Snathanw } 219c62a74e6Sthorpej 2200e675542Schs static void 221c62a74e6Sthorpej pthread__start(void) 222c62a74e6Sthorpej { 2231ac6a89bSad pthread_t self; 224c62a74e6Sthorpej 225c62a74e6Sthorpej self = pthread__self(); /* should be the "main()" thread */ 226c62a74e6Sthorpej 227ff14fbf2Snathanw /* 228ff14fbf2Snathanw * Per-process timers are cleared by fork(); despite the 229ff14fbf2Snathanw * various restrictions on fork() and threads, it's legal to 230ff14fbf2Snathanw * fork() before creating any threads. 231ff14fbf2Snathanw */ 2322a4cef11Snathanw pthread_atfork(NULL, NULL, pthread__child_callback); 233c62a74e6Sthorpej SDPRINTF(("(pthread__start %p) Started.\n", self)); 234c62a74e6Sthorpej } 235c62a74e6Sthorpej 236c62a74e6Sthorpej 237c62a74e6Sthorpej /* General-purpose thread data structure sanitization. */ 238*50fa8db4Sad /* ARGSUSED */ 239*50fa8db4Sad static void 240*50fa8db4Sad pthread__initthread(pthread_t t) 241c62a74e6Sthorpej { 242c62a74e6Sthorpej 243c62a74e6Sthorpej t->pt_magic = PT_MAGIC; 244c62a74e6Sthorpej t->pt_spinlocks = 0; 245c62a74e6Sthorpej t->pt_exitval = NULL; 246c62a74e6Sthorpej t->pt_flags = 0; 247c62a74e6Sthorpej t->pt_cancel = 0; 248c62a74e6Sthorpej t->pt_errno = 0; 2491ac6a89bSad t->pt_state = PT_STATE_RUNNING; 2501ac6a89bSad 251*50fa8db4Sad pthread_lockinit(&t->pt_lock); 252c62a74e6Sthorpej PTQ_INIT(&t->pt_cleanup_stack); 253c62a74e6Sthorpej memset(&t->pt_specific, 0, sizeof(int) * PTHREAD_KEYS_MAX); 254b33971b9Sthorpej t->pt_name = NULL; 255c62a74e6Sthorpej } 256c62a74e6Sthorpej 257c62a74e6Sthorpej 258c62a74e6Sthorpej int 259c62a74e6Sthorpej pthread_create(pthread_t *thread, const pthread_attr_t *attr, 260c62a74e6Sthorpej void *(*startfunc)(void *), void *arg) 261c62a74e6Sthorpej { 262c62a74e6Sthorpej pthread_t self, newthread; 263c62a74e6Sthorpej pthread_attr_t nattr; 264b33971b9Sthorpej struct pthread_attr_private *p; 2653ca3d0b1Schristos char * volatile name; 266de213816Sad int ret, flag; 267c62a74e6Sthorpej 268c62a74e6Sthorpej PTHREADD_ADD(PTHREADD_CREATE); 269c62a74e6Sthorpej 270c62a74e6Sthorpej /* 271c62a74e6Sthorpej * It's okay to check this without a lock because there can 272c62a74e6Sthorpej * only be one thread before it becomes true. 273c62a74e6Sthorpej */ 274c62a74e6Sthorpej if (pthread__started == 0) { 275c62a74e6Sthorpej pthread__start(); 276c62a74e6Sthorpej pthread__started = 1; 277c62a74e6Sthorpej } 278c62a74e6Sthorpej 279c62a74e6Sthorpej if (attr == NULL) 280c62a74e6Sthorpej nattr = pthread_default_attr; 281e81f9f17Sdrochner else if (attr->pta_magic == PT_ATTR_MAGIC) 282c62a74e6Sthorpej nattr = *attr; 283c62a74e6Sthorpej else 284c62a74e6Sthorpej return EINVAL; 285c62a74e6Sthorpej 286b33971b9Sthorpej /* Fetch misc. attributes from the attr structure. */ 287508a50acSnathanw name = NULL; 288508a50acSnathanw if ((p = nattr.pta_private) != NULL) 289508a50acSnathanw if (p->ptap_name[0] != '\0') 290b33971b9Sthorpej if ((name = strdup(p->ptap_name)) == NULL) 291b33971b9Sthorpej return ENOMEM; 292c62a74e6Sthorpej 293c62a74e6Sthorpej self = pthread__self(); 294c62a74e6Sthorpej 295*50fa8db4Sad pthread_spinlock(self, &pthread__queue_lock); 296c62a74e6Sthorpej newthread = PTQ_FIRST(&pthread__deadqueue); 2974cdc2ed8Syamt if (newthread != NULL) { 298*50fa8db4Sad if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0) { 299*50fa8db4Sad PTQ_REMOVE(&pthread__deadqueue, newthread, pt_allq); 300*50fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 301*50fa8db4Sad if (_lwp_kill(newthread->pt_lid, 0) == 0 || 302*50fa8db4Sad errno != ESRCH) { 303*50fa8db4Sad pthread_spinlock(self, &pthread__queue_lock); 304*50fa8db4Sad PTQ_INSERT_TAIL(&pthread__deadqueue, 305*50fa8db4Sad newthread, pt_allq); 306*50fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 3074cdc2ed8Syamt newthread = NULL; 308*50fa8db4Sad } 309*50fa8db4Sad } else 310c62a74e6Sthorpej PTQ_REMOVE(&pthread__deadqueue, newthread, pt_allq); 3114cdc2ed8Syamt } 312*50fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 3134cdc2ed8Syamt if (newthread == NULL) { 314c62a74e6Sthorpej /* Set up a stack and allocate space for a pthread_st. */ 315c62a74e6Sthorpej ret = pthread__stackalloc(&newthread); 316b7559f85Schristos if (ret != 0) { 317b7559f85Schristos if (name) 318b7559f85Schristos free(name); 319c62a74e6Sthorpej return ret; 320c62a74e6Sthorpej } 321b7559f85Schristos } 322c62a74e6Sthorpej 323c62a74e6Sthorpej /* 2. Set up state. */ 324*50fa8db4Sad pthread__initthread(newthread); 325c62a74e6Sthorpej newthread->pt_flags = nattr.pta_flags; 326c62a74e6Sthorpej 327b33971b9Sthorpej /* 3. Set up misc. attributes. */ 328b33971b9Sthorpej newthread->pt_name = name; 329b33971b9Sthorpej 330c62a74e6Sthorpej /* 331b33971b9Sthorpej * 4. Set up context. 332c62a74e6Sthorpej * 333c62a74e6Sthorpej * The pt_uc pointer points to a location safely below the 334c62a74e6Sthorpej * stack start; this is arranged by pthread__stackalloc(). 335c62a74e6Sthorpej */ 336c62a74e6Sthorpej _INITCONTEXT_U(newthread->pt_uc); 337877f8985Snathanw #ifdef PTHREAD_MACHINE_HAS_ID_REGISTER 338877f8985Snathanw pthread__uc_id(newthread->pt_uc) = newthread; 339877f8985Snathanw #endif 340c62a74e6Sthorpej newthread->pt_uc->uc_stack = newthread->pt_stack; 341c62a74e6Sthorpej newthread->pt_uc->uc_link = NULL; 342c62a74e6Sthorpej makecontext(newthread->pt_uc, pthread__create_tramp, 2, 343c62a74e6Sthorpej startfunc, arg); 344c62a74e6Sthorpej 345efb1fc06Sad /* 5. Add to list of all threads. */ 346*50fa8db4Sad pthread_spinlock(self, &pthread__queue_lock); 347efb1fc06Sad PTQ_INSERT_HEAD(&pthread__allqueue, newthread, pt_allq); 348*50fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 349efb1fc06Sad 350efb1fc06Sad /* 5a. Create the new LWP. */ 3517630e387Sad newthread->pt_sleeponq = 0; 352ded26025Sad flag = 0; 353ded26025Sad if ((newthread->pt_flags & PT_FLAG_SUSPENDED) != 0) 354ded26025Sad flag |= LWP_SUSPENDED; 355ded26025Sad if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0) 356ded26025Sad flag |= LWP_DETACHED; 3571ac6a89bSad ret = _lwp_create(newthread->pt_uc, (u_long)flag, &newthread->pt_lid); 3581ac6a89bSad if (ret != 0) { 3591ac6a89bSad SDPRINTF(("(pthread_create %p) _lwp_create: %s\n", 3601ac6a89bSad strerror(errno))); 3611ac6a89bSad free(name); 362*50fa8db4Sad pthread_spinlock(self, &pthread__queue_lock); 363efb1fc06Sad PTQ_REMOVE(&pthread__allqueue, newthread, pt_allq); 364efb1fc06Sad PTQ_INSERT_HEAD(&pthread__deadqueue, newthread, pt_allq); 365*50fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 3661ac6a89bSad return ret; 3671ac6a89bSad } 3681ac6a89bSad 369*50fa8db4Sad /* XXX must die */ 370*50fa8db4Sad newthread->pt_num = newthread->pt_lid; 371*50fa8db4Sad 3721ac6a89bSad SDPRINTF(("(pthread_create %p) new thread %p (name %p, lid %d).\n", 3731ac6a89bSad self, newthread, newthread->pt_name, 3741ac6a89bSad (int)newthread->pt_lid)); 375c62a74e6Sthorpej 376c62a74e6Sthorpej *thread = newthread; 377c62a74e6Sthorpej 378c62a74e6Sthorpej return 0; 379c62a74e6Sthorpej } 380c62a74e6Sthorpej 381c62a74e6Sthorpej 382c62a74e6Sthorpej static void 383c62a74e6Sthorpej pthread__create_tramp(void *(*start)(void *), void *arg) 384c62a74e6Sthorpej { 385c62a74e6Sthorpej void *retval; 386c62a74e6Sthorpej 387*50fa8db4Sad /* 388*50fa8db4Sad * Throw away some stack in a feeble attempt to reduce cache 389*50fa8db4Sad * thrash. May help for SMT processors. XXX We should not 390*50fa8db4Sad * be allocating stacks on fixed 2MB boundaries. Needs a 391*50fa8db4Sad * thread register or decent thread local storage. 392*50fa8db4Sad */ 393*50fa8db4Sad (void)alloca(((unsigned)pthread__self()->pt_lid & 7) << 8); 394*50fa8db4Sad 39594a458ceSchs retval = (*start)(arg); 396c62a74e6Sthorpej 397c62a74e6Sthorpej pthread_exit(retval); 398c62a74e6Sthorpej 399143f5a27Schristos /*NOTREACHED*/ 400143f5a27Schristos pthread__abort(); 401c62a74e6Sthorpej } 402c62a74e6Sthorpej 40338b1c6f4Schristos int 40438b1c6f4Schristos pthread_suspend_np(pthread_t thread) 40538b1c6f4Schristos { 406ba70e96aSchs pthread_t self; 407ba70e96aSchs 408ba70e96aSchs self = pthread__self(); 40938b1c6f4Schristos if (self == thread) { 41038b1c6f4Schristos return EDEADLK; 41138b1c6f4Schristos } 412ba70e96aSchs #ifdef ERRORCHECK 413ba70e96aSchs if (pthread__find(self, thread) != 0) 414ba70e96aSchs return ESRCH; 415ba70e96aSchs #endif 4161ac6a89bSad SDPRINTF(("(pthread_suspend_np %p) Suspend thread %p.\n", 4171ac6a89bSad self, thread)); 4181ac6a89bSad return _lwp_suspend(thread->pt_lid); 41938b1c6f4Schristos } 42038b1c6f4Schristos 42138b1c6f4Schristos int 42238b1c6f4Schristos pthread_resume_np(pthread_t thread) 42338b1c6f4Schristos { 424ba70e96aSchs pthread_t self; 42538b1c6f4Schristos 426ba70e96aSchs self = pthread__self(); 427ba70e96aSchs #ifdef ERRORCHECK 428ba70e96aSchs if (pthread__find(self, thread) != 0) 429ba70e96aSchs return ESRCH; 430ba70e96aSchs #endif 4311ac6a89bSad SDPRINTF(("(pthread_resume_np %p) Resume thread %p.\n", 4321ac6a89bSad self, thread)); 4331ac6a89bSad return _lwp_continue(thread->pt_lid); 43438b1c6f4Schristos } 43538b1c6f4Schristos 436c62a74e6Sthorpej void 437c62a74e6Sthorpej pthread_exit(void *retval) 438c62a74e6Sthorpej { 43996b5a26dSnathanw pthread_t self; 440c62a74e6Sthorpej struct pt_clean_t *cleanup; 441b33971b9Sthorpej char *name; 442c62a74e6Sthorpej 443c62a74e6Sthorpej self = pthread__self(); 444ba70e96aSchs SDPRINTF(("(pthread_exit %p) status %p, flags %x, cancel %d\n", 445ba70e96aSchs self, retval, self->pt_flags, self->pt_cancel)); 446c62a74e6Sthorpej 447c62a74e6Sthorpej /* Disable cancellability. */ 448*50fa8db4Sad pthread_spinlock(self, &self->pt_lock); 449c62a74e6Sthorpej self->pt_flags |= PT_FLAG_CS_DISABLED; 45066fcc1ceSnathanw self->pt_cancel = 0; 451*50fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 452c62a74e6Sthorpej 453c62a74e6Sthorpej /* Call any cancellation cleanup handlers */ 454c62a74e6Sthorpej while (!PTQ_EMPTY(&self->pt_cleanup_stack)) { 455c62a74e6Sthorpej cleanup = PTQ_FIRST(&self->pt_cleanup_stack); 456c62a74e6Sthorpej PTQ_REMOVE(&self->pt_cleanup_stack, cleanup, ptc_next); 457c62a74e6Sthorpej (*cleanup->ptc_cleanup)(cleanup->ptc_arg); 458c62a74e6Sthorpej } 459c62a74e6Sthorpej 460c62a74e6Sthorpej /* Perform cleanup of thread-specific data */ 461c62a74e6Sthorpej pthread__destroy_tsd(self); 462c62a74e6Sthorpej 463c62a74e6Sthorpej self->pt_exitval = retval; 464c62a74e6Sthorpej 465*50fa8db4Sad pthread_spinlock(self, &self->pt_lock); 4666b2b9c62Syamt if (self->pt_flags & PT_FLAG_DETACHED) { 4676b2b9c62Syamt self->pt_state = PT_STATE_DEAD; 468b33971b9Sthorpej name = self->pt_name; 469b33971b9Sthorpej self->pt_name = NULL; 470*50fa8db4Sad pthread_spinlock(self, &pthread__queue_lock); 471*50fa8db4Sad PTQ_REMOVE(&pthread__allqueue, self, pt_allq); 472*50fa8db4Sad PTQ_INSERT_TAIL(&pthread__deadqueue, self, pt_allq); 473*50fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 474*50fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 475b33971b9Sthorpej if (name != NULL) 476b33971b9Sthorpej free(name); 4771ac6a89bSad _lwp_exit(); 478c62a74e6Sthorpej } else { 4796b2b9c62Syamt self->pt_state = PT_STATE_ZOMBIE; 480*50fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 481b33971b9Sthorpej /* Note: name will be freed by the joiner. */ 4821ac6a89bSad _lwp_exit(); 483c62a74e6Sthorpej } 484c62a74e6Sthorpej 485143f5a27Schristos /*NOTREACHED*/ 486143f5a27Schristos pthread__abort(); 487c62a74e6Sthorpej exit(1); 488c62a74e6Sthorpej } 489c62a74e6Sthorpej 490c62a74e6Sthorpej 491c62a74e6Sthorpej int 492c62a74e6Sthorpej pthread_join(pthread_t thread, void **valptr) 493c62a74e6Sthorpej { 494c62a74e6Sthorpej pthread_t self; 495b33971b9Sthorpej char *name; 4961ac6a89bSad int num, retval; 497c62a74e6Sthorpej 498c62a74e6Sthorpej self = pthread__self(); 499c62a74e6Sthorpej SDPRINTF(("(pthread_join %p) Joining %p.\n", self, thread)); 500c62a74e6Sthorpej 501c62a74e6Sthorpej if (pthread__find(self, thread) != 0) 502c62a74e6Sthorpej return ESRCH; 503c62a74e6Sthorpej 504c62a74e6Sthorpej if (thread->pt_magic != PT_MAGIC) 505c62a74e6Sthorpej return EINVAL; 506c62a74e6Sthorpej 507c62a74e6Sthorpej if (thread == self) 508c62a74e6Sthorpej return EDEADLK; 509c62a74e6Sthorpej 5101ac6a89bSad retval = 0; 5111ac6a89bSad name = NULL; 5121ac6a89bSad again: 513*50fa8db4Sad pthread_spinlock(self, &thread->pt_lock); 5141ac6a89bSad switch (thread->pt_state) { 5151ac6a89bSad case PT_STATE_RUNNING: 516*50fa8db4Sad pthread_spinunlock(self, &thread->pt_lock); 517ded26025Sad 518ded26025Sad /* 519ded26025Sad * IEEE Std 1003.1, 2004 Edition: 520ded26025Sad * 521ded26025Sad * "The pthread_join() function shall not 522ded26025Sad * return an error code of [EINTR]." 523ded26025Sad */ 524ded26025Sad if (_lwp_wait(thread->pt_lid, &num) != 0 && errno != EINTR) 525ded26025Sad return errno; 5261ac6a89bSad goto again; 5271ac6a89bSad case PT_STATE_ZOMBIE: 5281ac6a89bSad if (valptr != NULL) 529ded26025Sad *valptr = thread->pt_exitval; 5301ac6a89bSad if (retval == 0) { 5311ac6a89bSad name = thread->pt_name; 5321ac6a89bSad thread->pt_name = NULL; 5331ac6a89bSad } 5341ac6a89bSad thread->pt_state = PT_STATE_DEAD; 535*50fa8db4Sad pthread_spinlock(self, &pthread__queue_lock); 536*50fa8db4Sad PTQ_REMOVE(&pthread__allqueue, thread, pt_allq); 537*50fa8db4Sad PTQ_INSERT_HEAD(&pthread__deadqueue, thread, pt_allq); 538*50fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 539*50fa8db4Sad pthread_spinunlock(self, &thread->pt_lock); 540*50fa8db4Sad SDPRINTF(("(pthread_join %p) Joined %p.\n", self, thread)); 541*50fa8db4Sad if (name != NULL) 542*50fa8db4Sad free(name); 543b8daad98Sad (void)_lwp_detach(thread->pt_lid); 544*50fa8db4Sad return retval; 5451ac6a89bSad default: 546*50fa8db4Sad pthread_spinunlock(self, &thread->pt_lock); 5471ac6a89bSad return EINVAL; 5481ac6a89bSad } 5491ac6a89bSad 550c62a74e6Sthorpej } 551c62a74e6Sthorpej 552c62a74e6Sthorpej 553c62a74e6Sthorpej int 554c62a74e6Sthorpej pthread_equal(pthread_t t1, pthread_t t2) 555c62a74e6Sthorpej { 556c62a74e6Sthorpej 557c62a74e6Sthorpej /* Nothing special here. */ 558c62a74e6Sthorpej return (t1 == t2); 559c62a74e6Sthorpej } 560c62a74e6Sthorpej 561c62a74e6Sthorpej 562c62a74e6Sthorpej int 563c62a74e6Sthorpej pthread_detach(pthread_t thread) 564c62a74e6Sthorpej { 56596b5a26dSnathanw pthread_t self; 566c62a74e6Sthorpej 567c62a74e6Sthorpej self = pthread__self(); 568c62a74e6Sthorpej 569c62a74e6Sthorpej if (pthread__find(self, thread) != 0) 570c62a74e6Sthorpej return ESRCH; 571c62a74e6Sthorpej 572c62a74e6Sthorpej if (thread->pt_magic != PT_MAGIC) 573c62a74e6Sthorpej return EINVAL; 574c62a74e6Sthorpej 575*50fa8db4Sad pthread_spinlock(self, &self->pt_lock); 5761296e850Sad thread->pt_flags |= PT_FLAG_DETACHED; 577*50fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 578de213816Sad 5791ac6a89bSad return _lwp_detach(thread->pt_lid); 580c62a74e6Sthorpej } 581c62a74e6Sthorpej 582c62a74e6Sthorpej 583c62a74e6Sthorpej int 584b33971b9Sthorpej pthread_getname_np(pthread_t thread, char *name, size_t len) 585c62a74e6Sthorpej { 586b33971b9Sthorpej pthread_t self; 587c62a74e6Sthorpej 588b33971b9Sthorpej self = pthread__self(); 589b33971b9Sthorpej 590b33971b9Sthorpej if (pthread__find(self, thread) != 0) 591b33971b9Sthorpej return ESRCH; 592b33971b9Sthorpej 593b33971b9Sthorpej if (thread->pt_magic != PT_MAGIC) 594b33971b9Sthorpej return EINVAL; 595b33971b9Sthorpej 596*50fa8db4Sad pthread_spinlock(self, &thread->pt_lock); 597b33971b9Sthorpej if (thread->pt_name == NULL) 598b33971b9Sthorpej name[0] = '\0'; 599b33971b9Sthorpej else 600b33971b9Sthorpej strlcpy(name, thread->pt_name, len); 601*50fa8db4Sad pthread_spinunlock(self, &thread->pt_lock); 602c62a74e6Sthorpej 603c62a74e6Sthorpej return 0; 604c62a74e6Sthorpej } 605c62a74e6Sthorpej 606c62a74e6Sthorpej 607c62a74e6Sthorpej int 608b33971b9Sthorpej pthread_setname_np(pthread_t thread, const char *name, void *arg) 609b33971b9Sthorpej { 610ba70e96aSchs pthread_t self; 611b33971b9Sthorpej char *oldname, *cp, newname[PTHREAD_MAX_NAMELEN_NP]; 612b33971b9Sthorpej int namelen; 613b33971b9Sthorpej 614ba70e96aSchs self = pthread__self(); 615b33971b9Sthorpej if (pthread__find(self, thread) != 0) 616b33971b9Sthorpej return ESRCH; 617b33971b9Sthorpej 618b33971b9Sthorpej if (thread->pt_magic != PT_MAGIC) 619b33971b9Sthorpej return EINVAL; 620b33971b9Sthorpej 621b33971b9Sthorpej namelen = snprintf(newname, sizeof(newname), name, arg); 622b33971b9Sthorpej if (namelen >= PTHREAD_MAX_NAMELEN_NP) 623b33971b9Sthorpej return EINVAL; 624b33971b9Sthorpej 625b33971b9Sthorpej cp = strdup(newname); 626b33971b9Sthorpej if (cp == NULL) 627b33971b9Sthorpej return ENOMEM; 628b33971b9Sthorpej 629*50fa8db4Sad pthread_spinlock(self, &thread->pt_lock); 630b33971b9Sthorpej oldname = thread->pt_name; 631b33971b9Sthorpej thread->pt_name = cp; 632*50fa8db4Sad pthread_spinunlock(self, &thread->pt_lock); 633b33971b9Sthorpej 634b33971b9Sthorpej if (oldname != NULL) 635b33971b9Sthorpej free(oldname); 636b33971b9Sthorpej 637b33971b9Sthorpej return 0; 638b33971b9Sthorpej } 639b33971b9Sthorpej 640b33971b9Sthorpej 641b33971b9Sthorpej 642c62a74e6Sthorpej /* 643c62a74e6Sthorpej * XXX There should be a way for applications to use the efficent 644c62a74e6Sthorpej * inline version, but there are opacity/namespace issues. 645c62a74e6Sthorpej */ 646c62a74e6Sthorpej pthread_t 647c62a74e6Sthorpej pthread_self(void) 648c62a74e6Sthorpej { 649c62a74e6Sthorpej 650c62a74e6Sthorpej return pthread__self(); 651c62a74e6Sthorpej } 652c62a74e6Sthorpej 653c62a74e6Sthorpej 654c62a74e6Sthorpej int 655c62a74e6Sthorpej pthread_cancel(pthread_t thread) 656c62a74e6Sthorpej { 657c62a74e6Sthorpej pthread_t self; 658c62a74e6Sthorpej 659ba70e96aSchs self = pthread__self(); 660ba70e96aSchs if (pthread__find(self, thread) != 0) 661ba70e96aSchs return ESRCH; 662*50fa8db4Sad pthread_spinlock(self, &thread->pt_lock); 6631ac6a89bSad thread->pt_flags |= PT_FLAG_CS_PENDING; 6641ac6a89bSad if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) { 6651ac6a89bSad thread->pt_cancel = 1; 666*50fa8db4Sad pthread_spinunlock(self, &thread->pt_lock); 6671ac6a89bSad _lwp_wakeup(thread->pt_lid); 6681ac6a89bSad } else 669*50fa8db4Sad pthread_spinunlock(self, &thread->pt_lock); 670c62a74e6Sthorpej 671c62a74e6Sthorpej return 0; 672c62a74e6Sthorpej } 673c62a74e6Sthorpej 674c62a74e6Sthorpej 675c62a74e6Sthorpej int 676c62a74e6Sthorpej pthread_setcancelstate(int state, int *oldstate) 677c62a74e6Sthorpej { 678c62a74e6Sthorpej pthread_t self; 6790878df5dSnathanw int retval; 680c62a74e6Sthorpej 681c62a74e6Sthorpej self = pthread__self(); 6820878df5dSnathanw retval = 0; 683c62a74e6Sthorpej 684*50fa8db4Sad pthread_spinlock(self, &self->pt_lock); 685*50fa8db4Sad 686c62a74e6Sthorpej if (oldstate != NULL) { 6870878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_DISABLED) 688c62a74e6Sthorpej *oldstate = PTHREAD_CANCEL_DISABLE; 689c62a74e6Sthorpej else 690c62a74e6Sthorpej *oldstate = PTHREAD_CANCEL_ENABLE; 691c62a74e6Sthorpej } 692c62a74e6Sthorpej 6930878df5dSnathanw if (state == PTHREAD_CANCEL_DISABLE) { 6940878df5dSnathanw self->pt_flags |= PT_FLAG_CS_DISABLED; 6950878df5dSnathanw if (self->pt_cancel) { 6960878df5dSnathanw self->pt_flags |= PT_FLAG_CS_PENDING; 6970878df5dSnathanw self->pt_cancel = 0; 6980878df5dSnathanw } 6990878df5dSnathanw } else if (state == PTHREAD_CANCEL_ENABLE) { 7000878df5dSnathanw self->pt_flags &= ~PT_FLAG_CS_DISABLED; 701c62a74e6Sthorpej /* 702c62a74e6Sthorpej * If a cancellation was requested while cancellation 703c62a74e6Sthorpej * was disabled, note that fact for future 704c62a74e6Sthorpej * cancellation tests. 705c62a74e6Sthorpej */ 7060878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_PENDING) { 707c62a74e6Sthorpej self->pt_cancel = 1; 708c62a74e6Sthorpej /* This is not a deferred cancellation point. */ 7090878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_ASYNC) { 710*50fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 711c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 712c62a74e6Sthorpej } 7130878df5dSnathanw } 714c62a74e6Sthorpej } else 7150878df5dSnathanw retval = EINVAL; 716c62a74e6Sthorpej 717*50fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 718*50fa8db4Sad 7190878df5dSnathanw return retval; 720c62a74e6Sthorpej } 721c62a74e6Sthorpej 722c62a74e6Sthorpej 723c62a74e6Sthorpej int 724c62a74e6Sthorpej pthread_setcanceltype(int type, int *oldtype) 725c62a74e6Sthorpej { 726c62a74e6Sthorpej pthread_t self; 7270878df5dSnathanw int retval; 728c62a74e6Sthorpej 729c62a74e6Sthorpej self = pthread__self(); 7300878df5dSnathanw retval = 0; 7310878df5dSnathanw 732*50fa8db4Sad pthread_spinlock(self, &self->pt_lock); 733c62a74e6Sthorpej 734c62a74e6Sthorpej if (oldtype != NULL) { 7350878df5dSnathanw if (self->pt_flags & PT_FLAG_CS_ASYNC) 736c62a74e6Sthorpej *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS; 737c62a74e6Sthorpej else 738c62a74e6Sthorpej *oldtype = PTHREAD_CANCEL_DEFERRED; 739c62a74e6Sthorpej } 740c62a74e6Sthorpej 741c62a74e6Sthorpej if (type == PTHREAD_CANCEL_ASYNCHRONOUS) { 7420878df5dSnathanw self->pt_flags |= PT_FLAG_CS_ASYNC; 7430878df5dSnathanw if (self->pt_cancel) { 744*50fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 745c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 7460878df5dSnathanw } 747c62a74e6Sthorpej } else if (type == PTHREAD_CANCEL_DEFERRED) 7480878df5dSnathanw self->pt_flags &= ~PT_FLAG_CS_ASYNC; 749c62a74e6Sthorpej else 7500878df5dSnathanw retval = EINVAL; 751c62a74e6Sthorpej 752*50fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 753*50fa8db4Sad 7540878df5dSnathanw return retval; 755c62a74e6Sthorpej } 756c62a74e6Sthorpej 757c62a74e6Sthorpej 758c62a74e6Sthorpej void 759c62a74e6Sthorpej pthread_testcancel() 760c62a74e6Sthorpej { 761c62a74e6Sthorpej pthread_t self; 762c62a74e6Sthorpej 763c62a74e6Sthorpej self = pthread__self(); 764c62a74e6Sthorpej if (self->pt_cancel) 765c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 766c62a74e6Sthorpej } 767c62a74e6Sthorpej 768c62a74e6Sthorpej 769c62a74e6Sthorpej /* 770c62a74e6Sthorpej * POSIX requires that certain functions return an error rather than 771c62a74e6Sthorpej * invoking undefined behavior even when handed completely bogus 772c62a74e6Sthorpej * pthread_t values, e.g. stack garbage or (pthread_t)666. This 773c62a74e6Sthorpej * utility routine searches the list of threads for the pthread_t 774c62a74e6Sthorpej * value without dereferencing it. 775c62a74e6Sthorpej */ 776c62a74e6Sthorpej int 777c62a74e6Sthorpej pthread__find(pthread_t self, pthread_t id) 778c62a74e6Sthorpej { 779c62a74e6Sthorpej pthread_t target; 780c62a74e6Sthorpej 781*50fa8db4Sad pthread_spinlock(self, &pthread__queue_lock); 782c62a74e6Sthorpej PTQ_FOREACH(target, &pthread__allqueue, pt_allq) 783c62a74e6Sthorpej if (target == id) 784c62a74e6Sthorpej break; 785*50fa8db4Sad pthread_spinunlock(self, &pthread__queue_lock); 786c62a74e6Sthorpej 787c62a74e6Sthorpej if (target == NULL) 788c62a74e6Sthorpej return ESRCH; 789c62a74e6Sthorpej 790c62a74e6Sthorpej return 0; 791c62a74e6Sthorpej } 792c62a74e6Sthorpej 793c62a74e6Sthorpej 794c62a74e6Sthorpej void 795c62a74e6Sthorpej pthread__testcancel(pthread_t self) 796c62a74e6Sthorpej { 797c62a74e6Sthorpej 798c62a74e6Sthorpej if (self->pt_cancel) 799c62a74e6Sthorpej pthread_exit(PTHREAD_CANCELED); 800c62a74e6Sthorpej } 801c62a74e6Sthorpej 802c62a74e6Sthorpej 803c62a74e6Sthorpej void 804c62a74e6Sthorpej pthread__cleanup_push(void (*cleanup)(void *), void *arg, void *store) 805c62a74e6Sthorpej { 806c62a74e6Sthorpej pthread_t self; 807c62a74e6Sthorpej struct pt_clean_t *entry; 808c62a74e6Sthorpej 809c62a74e6Sthorpej self = pthread__self(); 810c62a74e6Sthorpej entry = store; 811c62a74e6Sthorpej entry->ptc_cleanup = cleanup; 812c62a74e6Sthorpej entry->ptc_arg = arg; 813c62a74e6Sthorpej PTQ_INSERT_HEAD(&self->pt_cleanup_stack, entry, ptc_next); 814c62a74e6Sthorpej } 815c62a74e6Sthorpej 816c62a74e6Sthorpej 817c62a74e6Sthorpej void 818c62a74e6Sthorpej pthread__cleanup_pop(int ex, void *store) 819c62a74e6Sthorpej { 820c62a74e6Sthorpej pthread_t self; 821c62a74e6Sthorpej struct pt_clean_t *entry; 822c62a74e6Sthorpej 823c62a74e6Sthorpej self = pthread__self(); 824c62a74e6Sthorpej entry = store; 825c62a74e6Sthorpej 826c62a74e6Sthorpej PTQ_REMOVE(&self->pt_cleanup_stack, entry, ptc_next); 827c62a74e6Sthorpej if (ex) 828c62a74e6Sthorpej (*entry->ptc_cleanup)(entry->ptc_arg); 829c62a74e6Sthorpej } 830c62a74e6Sthorpej 831c62a74e6Sthorpej 832c62a74e6Sthorpej int * 833c62a74e6Sthorpej pthread__errno(void) 834c62a74e6Sthorpej { 835c62a74e6Sthorpej pthread_t self; 836c62a74e6Sthorpej 837c62a74e6Sthorpej self = pthread__self(); 838c62a74e6Sthorpej 839c62a74e6Sthorpej return &(self->pt_errno); 840c62a74e6Sthorpej } 8418bcff70bSnathanw 8420c967901Snathanw ssize_t _sys_write(int, const void *, size_t); 8430c967901Snathanw 8448bcff70bSnathanw void 8450e6c93b9Sdrochner pthread__assertfunc(const char *file, int line, const char *function, 8460e6c93b9Sdrochner const char *expr) 8478bcff70bSnathanw { 8488bcff70bSnathanw char buf[1024]; 8498bcff70bSnathanw int len; 8508bcff70bSnathanw 85175a94788Smycroft SDPRINTF(("(af)\n")); 85275a94788Smycroft 8538bcff70bSnathanw /* 8548bcff70bSnathanw * snprintf should not acquire any locks, or we could 8558bcff70bSnathanw * end up deadlocked if the assert caller held locks. 8568bcff70bSnathanw */ 8578bcff70bSnathanw len = snprintf(buf, 1024, 8588bcff70bSnathanw "assertion \"%s\" failed: file \"%s\", line %d%s%s%s\n", 8598bcff70bSnathanw expr, file, line, 8608bcff70bSnathanw function ? ", function \"" : "", 8618bcff70bSnathanw function ? function : "", 8628bcff70bSnathanw function ? "\"" : ""); 8638bcff70bSnathanw 8640c967901Snathanw _sys_write(STDERR_FILENO, buf, (size_t)len); 8658bcff70bSnathanw (void)kill(getpid(), SIGABRT); 8668bcff70bSnathanw 8678bcff70bSnathanw _exit(1); 8688bcff70bSnathanw } 869df277271Snathanw 870df277271Snathanw 871df277271Snathanw void 8720e6c93b9Sdrochner pthread__errorfunc(const char *file, int line, const char *function, 8730e6c93b9Sdrochner const char *msg) 874df277271Snathanw { 875df277271Snathanw char buf[1024]; 8760172694eSnathanw size_t len; 877df277271Snathanw 8780172694eSnathanw if (pthread__diagassert == 0) 879df277271Snathanw return; 880df277271Snathanw 881df277271Snathanw /* 882df277271Snathanw * snprintf should not acquire any locks, or we could 883df277271Snathanw * end up deadlocked if the assert caller held locks. 884df277271Snathanw */ 885df277271Snathanw len = snprintf(buf, 1024, 8860172694eSnathanw "%s: Error detected by libpthread: %s.\n" 8870172694eSnathanw "Detected by file \"%s\", line %d%s%s%s.\n" 8880172694eSnathanw "See pthread(3) for information.\n", 8890172694eSnathanw getprogname(), msg, file, line, 890df277271Snathanw function ? ", function \"" : "", 891df277271Snathanw function ? function : "", 8920172694eSnathanw function ? "\"" : ""); 893df277271Snathanw 8940172694eSnathanw if (pthread__diagassert & DIAGASSERT_STDERR) 8950c967901Snathanw _sys_write(STDERR_FILENO, buf, len); 8960172694eSnathanw 8970172694eSnathanw if (pthread__diagassert & DIAGASSERT_SYSLOG) 8980172694eSnathanw syslog(LOG_DEBUG | LOG_USER, "%s", buf); 8990172694eSnathanw 9000172694eSnathanw if (pthread__diagassert & DIAGASSERT_ABORT) { 901df277271Snathanw (void)kill(getpid(), SIGABRT); 902df277271Snathanw _exit(1); 903df277271Snathanw } 904df277271Snathanw } 9051ac6a89bSad 906fe9718acSad /* 907ded26025Sad * Thread park/unpark operations. The kernel operations are 908ded26025Sad * modelled after a brief description from "Multithreading in 909ded26025Sad * the Solaris Operating Environment": 910fe9718acSad * 911fe9718acSad * http://www.sun.com/software/whitepapers/solaris9/multithread.pdf 912fe9718acSad */ 913fe9718acSad 9141ac6a89bSad #define OOPS(msg) \ 915858097f9Schristos pthread__errorfunc(__FILE__, __LINE__, __func__, msg) 9161ac6a89bSad 9171ac6a89bSad int 9181ac6a89bSad pthread__park(pthread_t self, pthread_spin_t *lock, 919*50fa8db4Sad pthread_queue_t *queue, const struct timespec *abstime, 920*50fa8db4Sad int cancelpt, const void *hint) 9211ac6a89bSad { 9221ac6a89bSad int rv; 9231ac6a89bSad 924792cc0e1Sad SDPRINTF(("(pthread__park %p) queue %p enter\n", self, queue)); 9251ac6a89bSad 926ded26025Sad /* 927ded26025Sad * Wait until we are awoken by a pending unpark operation, 928ded26025Sad * a signal, an unpark posted after we have gone asleep, 929ded26025Sad * or an expired timeout. 930*50fa8db4Sad * 931*50fa8db4Sad * It is fine to test the value of both pt_sleepobj and 932*50fa8db4Sad * pt_sleeponq without holding any locks, because: 933*50fa8db4Sad * 934*50fa8db4Sad * o Only the blocking thread (this thread) ever sets them 935*50fa8db4Sad * to a non-NULL value. 936*50fa8db4Sad * 937*50fa8db4Sad * o Other threads may set them NULL, but if they do so they 938*50fa8db4Sad * must also make this thread return from _lwp_park. 939*50fa8db4Sad * 940*50fa8db4Sad * o _lwp_park, _lwp_unpark and _lwp_unpark_all are system 941*50fa8db4Sad * calls and all make use of spinlocks in the kernel. So 942*50fa8db4Sad * these system calls act as full memory barriers, and will 943*50fa8db4Sad * ensure that the calling CPU's store buffers are drained. 944*50fa8db4Sad * In combination with the spinlock release before unpark, 945*50fa8db4Sad * this means that modification of pt_sleepobj/onq by another 946*50fa8db4Sad * thread will become globally visible before that thread 947*50fa8db4Sad * schedules an unpark operation on this thread. 948ded26025Sad */ 949ded26025Sad rv = 0; 950*50fa8db4Sad while (self->pt_sleepobj != NULL && rv == 0) { 951a5070151Sad if (_lwp_park(abstime, NULL, hint) != 0) { 952ded26025Sad switch (rv = errno) { 9531ac6a89bSad case EINTR: 9541ac6a89bSad case EALREADY: 955ded26025Sad rv = 0; 956ded26025Sad break; 957ded26025Sad case ETIMEDOUT: 9581ac6a89bSad break; 9591ac6a89bSad default: 9601ac6a89bSad OOPS("_lwp_park failed"); 9611ac6a89bSad SDPRINTF(("(pthread__park %p) syscall rv=%d\n", 9621ac6a89bSad self, rv)); 9631ac6a89bSad break; 9641ac6a89bSad } 965ded26025Sad } 9660c61b6a6Sad /* Check for cancellation. */ 9670c61b6a6Sad if (cancelpt && self->pt_cancel) { 9680c61b6a6Sad /* 9690c61b6a6Sad * Ensure visibility of the correct value. 9700c61b6a6Sad * _lwp_park/_lwp_wakeup also provide a 9710c61b6a6Sad * barrier. 9720c61b6a6Sad */ 973*50fa8db4Sad pthread_spinlock(self, &self->pt_lock); 9740c61b6a6Sad if (self->pt_cancel) 9750c61b6a6Sad rv = EINTR; 976*50fa8db4Sad pthread_spinunlock(self, &self->pt_lock); 9770c61b6a6Sad } 978*50fa8db4Sad } 9791ac6a89bSad 980ded26025Sad /* 981ded26025Sad * If we have been awoken early but are still on the queue, 982*50fa8db4Sad * then remove ourself. Again, it's safe to do the test 983*50fa8db4Sad * without holding any locks. 984ded26025Sad */ 985792cc0e1Sad if (self->pt_sleeponq) { 986*50fa8db4Sad pthread_spinlock(self, lock); 987*50fa8db4Sad if (self->pt_sleeponq) { 9881ac6a89bSad PTQ_REMOVE(queue, self, pt_sleep); 9891ac6a89bSad self->pt_sleepobj = NULL; 990ded26025Sad self->pt_sleeponq = 0; 991792cc0e1Sad } 992*50fa8db4Sad pthread_spinunlock(self, lock); 993*50fa8db4Sad } 9941ac6a89bSad 995792cc0e1Sad SDPRINTF(("(pthread__park %p) queue %p exit\n", self, queue)); 9961ac6a89bSad 9971ac6a89bSad return rv; 9981ac6a89bSad } 9991ac6a89bSad 10001ac6a89bSad void 1001792cc0e1Sad pthread__unpark(pthread_t self, pthread_spin_t *lock, 1002*50fa8db4Sad pthread_queue_t *queue, pthread_t target) 10031ac6a89bSad { 10041ac6a89bSad int rv; 10051ac6a89bSad 10060c61b6a6Sad if (target == NULL) { 10070c61b6a6Sad pthread_spinunlock(self, lock); 10080c61b6a6Sad return; 10090c61b6a6Sad } 10100c61b6a6Sad 1011792cc0e1Sad SDPRINTF(("(pthread__unpark %p) queue %p target %p\n", 1012792cc0e1Sad self, queue, target)); 10131ac6a89bSad 1014ded26025Sad /* 1015ded26025Sad * Easy: the thread has already been removed from 1016ded26025Sad * the queue, so just awaken it. 1017ded26025Sad */ 10181ac6a89bSad target->pt_sleepobj = NULL; 1019ded26025Sad target->pt_sleeponq = 0; 1020*50fa8db4Sad 1021*50fa8db4Sad /* 1022*50fa8db4Sad * Releasing the spinlock serves as a store barrier, 1023*50fa8db4Sad * which ensures that all our modifications are visible 1024*50fa8db4Sad * to the thread in pthread__park() before the unpark 1025*50fa8db4Sad * operation is set in motion. 1026*50fa8db4Sad */ 10271ac6a89bSad pthread_spinunlock(self, lock); 1028792cc0e1Sad rv = _lwp_unpark(target->pt_lid, queue); 10291ac6a89bSad 10301ac6a89bSad if (rv != 0 && errno != EALREADY && errno != EINTR) { 10311ac6a89bSad SDPRINTF(("(pthread__unpark %p) syscall rv=%d\n", 10321ac6a89bSad self, rv)); 10331ac6a89bSad OOPS("_lwp_unpark failed"); 10341ac6a89bSad } 10351ac6a89bSad } 10361ac6a89bSad 10371ac6a89bSad void 1038792cc0e1Sad pthread__unpark_all(pthread_t self, pthread_spin_t *lock, 1039*50fa8db4Sad pthread_queue_t *queue) 10401ac6a89bSad { 1041ded26025Sad lwpid_t waiters[PTHREAD__UNPARK_MAX]; 104267513ce0Sad ssize_t n, rv; 1043ded26025Sad pthread_t thread, next; 1044ded26025Sad 1045ded26025Sad if (PTQ_EMPTY(queue)) { 1046ded26025Sad pthread_spinunlock(self, lock); 1047ded26025Sad return; 1048ded26025Sad } 1049ded26025Sad 1050ded26025Sad /* 1051ded26025Sad * First, clear all sleepobj pointers, since we can release the 1052ded26025Sad * spin lock before awkening everybody, and must synchronise with 1053ded26025Sad * pthread__park(). 1054ded26025Sad */ 1055ded26025Sad PTQ_FOREACH(thread, queue, pt_sleep) { 1056ded26025Sad thread->pt_sleepobj = NULL; 1057792cc0e1Sad if (thread == PTQ_NEXT(thread, pt_sleep)) 1058792cc0e1Sad OOPS("unpark: thread linked to self"); 1059ded26025Sad } 10601ac6a89bSad 10611ac6a89bSad for (;;) { 1062ded26025Sad thread = PTQ_FIRST(queue); 1063ded26025Sad for (n = 0; n < pthread__unpark_max && thread != NULL; 1064ded26025Sad thread = next) { 1065ded26025Sad /* 1066ded26025Sad * If the sleepobj pointer is non-NULL, it 1067ded26025Sad * means one of two things: 1068ded26025Sad * 1069ded26025Sad * o The thread has awoken early, spun 1070ded26025Sad * through application code and is 1071ded26025Sad * once more asleep on this object. 1072ded26025Sad * 1073ded26025Sad * o This is a new thread that has blocked 1074ded26025Sad * on the object after we have released 1075ded26025Sad * the interlock in this loop. 1076ded26025Sad * 1077ded26025Sad * In both cases we shouldn't remove the 1078ded26025Sad * thread from the queue. 1079ded26025Sad */ 1080ded26025Sad next = PTQ_NEXT(thread, pt_sleep); 1081ded26025Sad if (thread->pt_sleepobj != NULL) 1082ded26025Sad continue; 1083ded26025Sad thread->pt_sleeponq = 0; 1084ded26025Sad waiters[n++] = thread->pt_lid; 10851ac6a89bSad PTQ_REMOVE(queue, thread, pt_sleep); 1086792cc0e1Sad SDPRINTF(("(pthread__unpark_all %p) queue %p " 1087792cc0e1Sad "unpark %p\n", self, queue, thread)); 10881ac6a89bSad } 1089ded26025Sad 1090*50fa8db4Sad /* 1091*50fa8db4Sad * Releasing the spinlock serves as a store barrier, 1092*50fa8db4Sad * which ensures that all our modifications are visible 1093*50fa8db4Sad * to the thread in pthread__park() before the unpark 1094*50fa8db4Sad * operation is set in motion. 1095*50fa8db4Sad */ 10961ac6a89bSad pthread_spinunlock(self, lock); 1097ded26025Sad switch (n) { 10981ac6a89bSad case 0: 10991ac6a89bSad return; 11001ac6a89bSad case 1: 1101792cc0e1Sad rv = (ssize_t)_lwp_unpark(waiters[0], queue); 11021ac6a89bSad if (rv != 0 && errno != EALREADY && errno != EINTR) { 11031ac6a89bSad OOPS("_lwp_unpark failed"); 11041ac6a89bSad SDPRINTF(("(pthread__unpark_all %p) " 11051ac6a89bSad "syscall rv=%d\n", self, rv)); 11061ac6a89bSad } 11071ac6a89bSad return; 11081ac6a89bSad default: 1109*50fa8db4Sad rv = _lwp_unpark_all(waiters, (size_t)n, queue); 11101ac6a89bSad if (rv != 0 && errno != EINTR) { 11111ac6a89bSad OOPS("_lwp_unpark_all failed"); 11121ac6a89bSad SDPRINTF(("(pthread__unpark_all %p) " 11131ac6a89bSad "syscall rv=%d\n", self, rv)); 11141ac6a89bSad } 11151ac6a89bSad break; 11161ac6a89bSad } 11171ac6a89bSad pthread_spinlock(self, lock); 11181ac6a89bSad } 11191ac6a89bSad } 11201ac6a89bSad 11211ac6a89bSad #undef OOPS 1122