1 /* $NetBSD: pthread.c,v 1.188 2025/10/06 13:12:29 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2002, 2003, 2006, 2007, 2008, 2020 5 * The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Nathan J. Williams and Andrew Doran. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __RCSID("$NetBSD: pthread.c,v 1.188 2025/10/06 13:12:29 riastradh Exp $"); 35 36 #define __EXPOSE_STACK 1 37 38 /* Need to use libc-private names for atomic operations. */ 39 #include "../../common/lib/libc/atomic/atomic_op_namespace.h" 40 41 #include <sys/param.h> 42 #include <sys/exec_elf.h> 43 #include <sys/mman.h> 44 #include <sys/lwp.h> 45 #include <sys/lwpctl.h> 46 #include <sys/resource.h> 47 #include <sys/sysctl.h> 48 #include <sys/tls.h> 49 #include <uvm/uvm_param.h> 50 51 #include <assert.h> 52 #include <dlfcn.h> 53 #include <err.h> 54 #include <errno.h> 55 #include <lwp.h> 56 #include <signal.h> 57 #include <stdatomic.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <stddef.h> 61 #include <string.h> 62 #include <syslog.h> 63 #include <ucontext.h> 64 #include <unistd.h> 65 #include <sched.h> 66 67 #include "atexit.h" 68 #include "pthread.h" 69 #include "pthread_int.h" 70 #include "pthread_makelwp.h" 71 #include "reentrant.h" 72 73 #define atomic_load_relaxed(p) \ 74 atomic_load_explicit(p, memory_order_relaxed) 75 76 #define atomic_store_relaxed(p, v) \ 77 atomic_store_explicit(p, v, memory_order_relaxed) 78 79 #define atomic_store_release(p, v) \ 80 atomic_store_explicit(p, v, memory_order_release) 81 82 __BEGIN_DECLS 83 void _malloc_thread_cleanup(void) __weak; 84 __END_DECLS 85 86 pthread_rwlock_t pthread__alltree_lock = PTHREAD_RWLOCK_INITIALIZER; 87 static rb_tree_t pthread__alltree; 88 89 static signed int pthread__cmp(void *, const void *, const void *); 90 91 static const rb_tree_ops_t pthread__alltree_ops = { 92 .rbto_compare_nodes = pthread__cmp, 93 .rbto_compare_key = pthread__cmp, 94 .rbto_node_offset = offsetof(struct __pthread_st, pt_alltree), 95 .rbto_context = NULL 96 }; 97 98 static void pthread__create_tramp(void *); 99 static void pthread__initthread(pthread_t); 100 static void pthread__scrubthread(pthread_t, char *, int); 101 static void pthread__initmain(pthread_t *); 102 static void pthread__reap(pthread_t); 103 104 void pthread__init(void); 105 106 int pthread__started; 107 int __uselibcstub = 1; 108 pthread_mutex_t pthread__deadqueue_lock = PTHREAD_MUTEX_INITIALIZER; 109 pthread_queue_t pthread__deadqueue; 110 pthread_queue_t pthread__allqueue; 111 112 static pthread_attr_t pthread_default_attr; 113 static lwpctl_t pthread__dummy_lwpctl = { .lc_curcpu = LWPCTL_CPU_NONE }; 114 115 enum { 116 DIAGASSERT_ABORT = 1<<0, 117 DIAGASSERT_STDERR = 1<<1, 118 DIAGASSERT_SYSLOG = 1<<2 119 }; 120 121 static int pthread__diagassert; 122 123 int pthread__concurrency; 124 int pthread__nspins; 125 size_t pthread__unpark_max = PTHREAD__UNPARK_MAX; 126 int pthread__dbg; /* set by libpthread_dbg if active */ 127 128 /* 129 * We have to initialize the pthread_stack* variables here because 130 * mutexes are used before pthread_init() and thus pthread__initmain() 131 * are called. Since mutexes only save the stack pointer and not a 132 * pointer to the thread data, it is safe to change the mapping from 133 * stack pointer to thread data afterwards. 134 */ 135 size_t pthread__stacksize; 136 size_t pthread__guardsize; 137 size_t pthread__pagesize; 138 static struct __pthread_st *pthread__main; 139 static size_t __pthread_st_size; 140 141 int _sys___sigprocmask14(int, const sigset_t *, sigset_t *); 142 143 __strong_alias(__libc_thr_self,pthread_self) 144 __strong_alias(__libc_thr_create,pthread_create) 145 __strong_alias(__libc_thr_detach,pthread_detach) 146 __strong_alias(__libc_thr_join,pthread_join) 147 __strong_alias(__libc_thr_exit,pthread_exit) 148 __strong_alias(__libc_thr_errno,pthread__errno) 149 __strong_alias(__libc_thr_setcancelstate,pthread_setcancelstate) 150 __strong_alias(__libc_thr_equal,pthread_equal) 151 __strong_alias(__libc_thr_init,pthread__init) 152 153 /* 154 * Static library kludge. Place a reference to a symbol any library 155 * file which does not already have a reference here. 156 */ 157 extern int pthread__cancel_stub_binder; 158 159 void *pthread__static_lib_binder[] = { 160 &pthread__cancel_stub_binder, 161 pthread_cond_init, 162 pthread_mutex_init, 163 pthread_rwlock_init, 164 pthread_barrier_init, 165 pthread_key_create, 166 pthread_setspecific, 167 }; 168 169 #define NHASHLOCK 64 170 171 static union hashlock { 172 pthread_mutex_t mutex; 173 char pad[64]; 174 } hashlocks[NHASHLOCK] __aligned(64); 175 176 static void 177 pthread__prefork(void) 178 { 179 pthread_mutex_lock(&pthread__deadqueue_lock); 180 } 181 182 static void 183 pthread__fork_parent(void) 184 { 185 pthread_mutex_unlock(&pthread__deadqueue_lock); 186 } 187 188 static void 189 pthread__fork_child(void) 190 { 191 struct __pthread_st *self = pthread__self(); 192 193 pthread_mutex_init(&pthread__deadqueue_lock, NULL); 194 195 /* lwpctl state is not copied across fork. */ 196 if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &self->pt_lwpctl)) { 197 err(EXIT_FAILURE, "_lwp_ctl"); 198 } 199 self->pt_lid = _lwp_self(); 200 } 201 202 /* 203 * This needs to be started by the library loading code, before main() 204 * gets to run, for various things that use the state of the initial thread 205 * to work properly (thread-specific data is an application-visible example; 206 * spinlock counts for mutexes is an internal example). 207 */ 208 void 209 pthread__init(void) 210 { 211 pthread_t first; 212 char *p; 213 int mib[2]; 214 unsigned int value; 215 ssize_t slen; 216 size_t len; 217 extern int __isthreaded; 218 219 /* 220 * Allocate pthread_keys descriptors before 221 * resetting __uselibcstub because otherwise 222 * malloc() will call pthread_keys_create() 223 * while pthread_keys descriptors are not 224 * yet allocated. 225 */ 226 pthread__main = pthread_tsd_init(&__pthread_st_size); 227 if (pthread__main == NULL) 228 err(EXIT_FAILURE, "Cannot allocate pthread storage"); 229 230 __uselibcstub = 0; 231 232 pthread__pagesize = (size_t)sysconf(_SC_PAGESIZE); 233 pthread__concurrency = (int)sysconf(_SC_NPROCESSORS_CONF); 234 235 mib[0] = CTL_VM; 236 mib[1] = VM_THREAD_GUARD_SIZE; 237 len = sizeof(value); 238 if (sysctl(mib, __arraycount(mib), &value, &len, NULL, 0) == 0) 239 pthread__guardsize = value; 240 else 241 pthread__guardsize = pthread__pagesize; 242 243 /* Initialize locks first; they're needed elsewhere. */ 244 pthread__lockprim_init(); 245 for (int i = 0; i < NHASHLOCK; i++) { 246 pthread_mutex_init(&hashlocks[i].mutex, NULL); 247 } 248 249 /* Fetch parameters. */ 250 slen = _lwp_unpark_all(NULL, 0, NULL); 251 if (slen < 0) 252 err(EXIT_FAILURE, "_lwp_unpark_all"); 253 if ((size_t)slen < pthread__unpark_max) 254 pthread__unpark_max = slen; 255 256 /* Basic data structure setup */ 257 pthread_attr_init(&pthread_default_attr); 258 PTQ_INIT(&pthread__allqueue); 259 PTQ_INIT(&pthread__deadqueue); 260 261 rb_tree_init(&pthread__alltree, &pthread__alltree_ops); 262 263 /* Create the thread structure corresponding to main() */ 264 pthread__initmain(&first); 265 pthread__initthread(first); 266 pthread__scrubthread(first, NULL, 0); 267 268 first->pt_lid = _lwp_self(); 269 PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq); 270 (void)rb_tree_insert_node(&pthread__alltree, first); 271 272 if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &first->pt_lwpctl) != 0) { 273 err(EXIT_FAILURE, "_lwp_ctl"); 274 } 275 276 /* Start subsystems */ 277 PTHREAD_MD_INIT 278 279 for (p = pthread__getenv("PTHREAD_DIAGASSERT"); p && *p; p++) { 280 switch (*p) { 281 case 'a': 282 pthread__diagassert |= DIAGASSERT_ABORT; 283 break; 284 case 'A': 285 pthread__diagassert &= ~DIAGASSERT_ABORT; 286 break; 287 case 'e': 288 pthread__diagassert |= DIAGASSERT_STDERR; 289 break; 290 case 'E': 291 pthread__diagassert &= ~DIAGASSERT_STDERR; 292 break; 293 case 'l': 294 pthread__diagassert |= DIAGASSERT_SYSLOG; 295 break; 296 case 'L': 297 pthread__diagassert &= ~DIAGASSERT_SYSLOG; 298 break; 299 } 300 } 301 302 /* Tell libc that we're here and it should role-play accordingly. */ 303 pthread_atfork(pthread__prefork, pthread__fork_parent, pthread__fork_child); 304 __isthreaded = 1; 305 } 306 307 /* General-purpose thread data structure sanitization. */ 308 /* ARGSUSED */ 309 static void 310 pthread__initthread(pthread_t t) 311 { 312 313 t->pt_self = t; 314 t->pt_magic = PT_MAGIC; 315 t->pt_sleepobj = NULL; 316 t->pt_havespecific = 0; 317 t->pt_lwpctl = &pthread__dummy_lwpctl; 318 319 memcpy(&t->pt_lockops, pthread__lock_ops, sizeof(t->pt_lockops)); 320 pthread_mutex_init(&t->pt_lock, NULL); 321 PTQ_INIT(&t->pt_cleanup_stack); 322 } 323 324 static void 325 pthread__scrubthread(pthread_t t, char *name, int flags) 326 { 327 328 t->pt_state = PT_STATE_RUNNING; 329 t->pt_exitval = NULL; 330 t->pt_flags = flags; 331 t->pt_cancel = 0; 332 t->pt_errno = 0; 333 t->pt_name = name; 334 t->pt_lid = 0; 335 } 336 337 static int 338 pthread__getstack(pthread_t newthread, const pthread_attr_t *attr) 339 { 340 void *stackbase, *stackbase2, *redzone; 341 size_t stacksize, guardsize; 342 bool allocated; 343 344 if (attr != NULL) { 345 pthread_attr_getstack(attr, &stackbase, &stacksize); 346 if (stackbase == NULL) 347 pthread_attr_getguardsize(attr, &guardsize); 348 else 349 guardsize = 0; 350 } else { 351 stackbase = NULL; 352 stacksize = 0; 353 guardsize = pthread__guardsize; 354 } 355 if (stacksize == 0) 356 stacksize = pthread__stacksize; 357 358 if (newthread->pt_stack_allocated) { 359 if (stackbase == NULL && 360 newthread->pt_stack.ss_size == stacksize && 361 newthread->pt_guardsize == guardsize) 362 return 0; 363 stackbase2 = newthread->pt_stack.ss_sp; 364 #ifndef __MACHINE_STACK_GROWS_UP 365 stackbase2 = (char *)stackbase2 - newthread->pt_guardsize; 366 #endif 367 munmap(stackbase2, 368 newthread->pt_stack.ss_size + newthread->pt_guardsize); 369 newthread->pt_stack.ss_sp = NULL; 370 newthread->pt_stack.ss_size = 0; 371 newthread->pt_guardsize = 0; 372 newthread->pt_stack_allocated = false; 373 } 374 375 newthread->pt_stack_allocated = false; 376 377 if (stackbase == NULL) { 378 stacksize = ((stacksize - 1) | (pthread__pagesize - 1)) + 1; 379 guardsize = ((guardsize - 1) | (pthread__pagesize - 1)) + 1; 380 stackbase = mmap(NULL, stacksize + guardsize, 381 PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, (off_t)0); 382 if (stackbase == MAP_FAILED) 383 return ENOMEM; 384 allocated = true; 385 } else { 386 allocated = false; 387 } 388 #ifdef __MACHINE_STACK_GROWS_UP 389 redzone = (char *)stackbase + stacksize; 390 stackbase2 = (char *)stackbase; 391 #else 392 redzone = (char *)stackbase; 393 stackbase2 = (char *)stackbase + guardsize; 394 #endif 395 if (allocated && guardsize && 396 mprotect(redzone, guardsize, PROT_NONE) == -1) { 397 munmap(stackbase, stacksize + guardsize); 398 return EPERM; 399 } 400 newthread->pt_stack.ss_size = stacksize; 401 newthread->pt_stack.ss_sp = stackbase2; 402 newthread->pt_guardsize = guardsize; 403 newthread->pt_stack_allocated = allocated; 404 return 0; 405 } 406 407 int 408 pthread_create(pthread_t *thread, const pthread_attr_t *attr, 409 void *(*startfunc)(void *), void *arg) 410 { 411 pthread_t newthread; 412 pthread_attr_t nattr; 413 struct pthread_attr_private *p; 414 char * volatile name; 415 unsigned long flag; 416 void *private_area; 417 int ret; 418 419 if (__predict_false(__uselibcstub)) { 420 pthread__errorfunc(__FILE__, __LINE__, __func__, 421 "pthread_create() requires linking with -lpthread"); 422 return __libc_thr_create_stub(thread, attr, startfunc, arg); 423 } 424 425 if (attr == NULL) 426 nattr = pthread_default_attr; 427 else if (attr->pta_magic == PT_ATTR_MAGIC) 428 nattr = *attr; 429 else 430 return EINVAL; 431 432 if (!pthread__started) { 433 /* 434 * Force the _lwp_park symbol to be resolved before we 435 * begin any activity that might rely on concurrent 436 * wakeups. 437 * 438 * This is necessary because rtld itself uses _lwp_park 439 * and _lwp_unpark internally for its own locking: If 440 * we wait to resolve _lwp_park until there is an 441 * _lwp_unpark from another thread pending in the 442 * current lwp (for example, pthread_mutex_unlock or 443 * pthread_cond_signal), rtld's internal use of 444 * _lwp_park might consume the pending unpark. The 445 * result is a deadlock where libpthread and rtld have 446 * both correctly used _lwp_park and _lwp_unpark for 447 * themselves, but rtld has consumed the wakeup meant 448 * for libpthread so it is lost to libpthread. 449 * 450 * For the very first thread, before pthread__started 451 * is set to true, pthread__self()->pt_lid should have 452 * been initialized in pthread__init by the time we get 453 * here to the correct lid so we go to sleep and wake 454 * ourselves at the same time as a no-op. 455 */ 456 _lwp_park(CLOCK_REALTIME, 0, NULL, pthread__self()->pt_lid, 457 NULL, NULL); 458 } 459 460 pthread__started = 1; 461 462 /* Fetch misc. attributes from the attr structure. */ 463 name = NULL; 464 if ((p = nattr.pta_private) != NULL) 465 if (p->ptap_name[0] != '\0') 466 if ((name = strdup(p->ptap_name)) == NULL) 467 return ENOMEM; 468 469 newthread = NULL; 470 471 /* 472 * Try to reclaim a dead thread. 473 */ 474 if (!PTQ_EMPTY(&pthread__deadqueue)) { 475 pthread_mutex_lock(&pthread__deadqueue_lock); 476 PTQ_FOREACH(newthread, &pthread__deadqueue, pt_deadq) { 477 /* Still running? */ 478 if (_lwp_kill(newthread->pt_lid, 0) == -1 && 479 errno == ESRCH) 480 break; 481 } 482 if (newthread) 483 PTQ_REMOVE(&pthread__deadqueue, newthread, pt_deadq); 484 pthread_mutex_unlock(&pthread__deadqueue_lock); 485 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) 486 if (newthread && newthread->pt_tls) { 487 _rtld_tls_free(newthread->pt_tls); 488 newthread->pt_tls = NULL; 489 } 490 #endif 491 } 492 493 /* 494 * If necessary set up a stack, allocate space for a pthread_st, 495 * and initialize it. 496 */ 497 if (newthread == NULL) { 498 newthread = calloc(1, __pthread_st_size); 499 if (newthread == NULL) { 500 free(name); 501 return ENOMEM; 502 } 503 newthread->pt_stack_allocated = false; 504 505 if (pthread__getstack(newthread, attr)) { 506 free(newthread); 507 free(name); 508 return ENOMEM; 509 } 510 511 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) 512 newthread->pt_tls = NULL; 513 #endif 514 515 /* Add to list of all threads. */ 516 pthread_rwlock_wrlock(&pthread__alltree_lock); 517 PTQ_INSERT_TAIL(&pthread__allqueue, newthread, pt_allq); 518 (void)rb_tree_insert_node(&pthread__alltree, newthread); 519 pthread_rwlock_unlock(&pthread__alltree_lock); 520 521 /* Will be reset by the thread upon exit. */ 522 pthread__initthread(newthread); 523 } else { 524 if (pthread__getstack(newthread, attr)) { 525 pthread_mutex_lock(&pthread__deadqueue_lock); 526 PTQ_INSERT_TAIL(&pthread__deadqueue, newthread, pt_deadq); 527 pthread_mutex_unlock(&pthread__deadqueue_lock); 528 return ENOMEM; 529 } 530 } 531 532 /* 533 * Create the new LWP. 534 */ 535 pthread__scrubthread(newthread, name, nattr.pta_flags); 536 newthread->pt_func = startfunc; 537 newthread->pt_arg = arg; 538 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) 539 private_area = newthread->pt_tls = _rtld_tls_allocate(); 540 newthread->pt_tls->tcb_pthread = newthread; 541 #else 542 private_area = newthread; 543 #endif 544 545 flag = 0; 546 if ((newthread->pt_flags & PT_FLAG_SUSPENDED) != 0 || 547 (nattr.pta_flags & PT_FLAG_EXPLICIT_SCHED) != 0) 548 flag |= LWP_SUSPENDED; 549 if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0) 550 flag |= LWP_DETACHED; 551 552 ret = pthread__makelwp(pthread__create_tramp, newthread, private_area, 553 newthread->pt_stack.ss_sp, newthread->pt_stack.ss_size, 554 flag, &newthread->pt_lid); 555 if (ret != 0) { 556 ret = errno; 557 pthread_mutex_lock(&newthread->pt_lock); 558 /* Will unlock and free name. */ 559 pthread__reap(newthread); 560 return ret; 561 } 562 563 if ((nattr.pta_flags & PT_FLAG_EXPLICIT_SCHED) != 0) { 564 if (p != NULL) { 565 (void)pthread_setschedparam(newthread, p->ptap_policy, 566 &p->ptap_sp); 567 } 568 if ((newthread->pt_flags & PT_FLAG_SUSPENDED) == 0) { 569 (void)_lwp_continue(newthread->pt_lid); 570 } 571 } 572 573 *thread = newthread; 574 575 return 0; 576 } 577 578 579 __dead static void 580 pthread__create_tramp(void *cookie) 581 { 582 pthread_t self; 583 void *retval; 584 void *junk __unused; 585 586 self = cookie; 587 588 /* 589 * Throw away some stack in a feeble attempt to reduce cache 590 * thrash. May help for SMT processors. XXX We should not 591 * be allocating stacks on fixed 2MB boundaries. Needs a 592 * thread register or decent thread local storage. 593 */ 594 junk = alloca(((unsigned)self->pt_lid & 7) << 8); 595 596 if (self->pt_name != NULL) { 597 pthread_mutex_lock(&self->pt_lock); 598 if (self->pt_name != NULL) 599 (void)_lwp_setname(0, self->pt_name); 600 pthread_mutex_unlock(&self->pt_lock); 601 } 602 603 if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &self->pt_lwpctl)) { 604 err(EXIT_FAILURE, "_lwp_ctl"); 605 } 606 607 retval = (*self->pt_func)(self->pt_arg); 608 609 pthread_exit(retval); 610 611 /*NOTREACHED*/ 612 pthread__abort(); 613 } 614 615 int 616 pthread_suspend_np(pthread_t thread) 617 { 618 pthread_t self; 619 620 pthread__error(EINVAL, "Invalid thread", 621 thread->pt_magic == PT_MAGIC); 622 623 self = pthread__self(); 624 if (self == thread) { 625 return EDEADLK; 626 } 627 if (pthread__find(thread) != 0) 628 return ESRCH; 629 if (_lwp_suspend(thread->pt_lid) == 0) 630 return 0; 631 return errno; 632 } 633 634 int 635 pthread_resume_np(pthread_t thread) 636 { 637 638 pthread__error(EINVAL, "Invalid thread", 639 thread->pt_magic == PT_MAGIC); 640 641 if (pthread__find(thread) != 0) 642 return ESRCH; 643 if (_lwp_continue(thread->pt_lid) == 0) 644 return 0; 645 return errno; 646 } 647 648 void 649 pthread_exit(void *retval) 650 { 651 pthread_t self; 652 struct pt_clean_t *cleanup; 653 654 if (__predict_false(__uselibcstub)) { 655 __libc_thr_exit_stub(retval); 656 goto out; 657 } 658 659 self = pthread__self(); 660 661 /* Disable cancellability. */ 662 atomic_store_relaxed(&self->pt_cancel, PT_CANCEL_DISABLED); 663 664 /* Call any cancellation cleanup handlers */ 665 if (!PTQ_EMPTY(&self->pt_cleanup_stack)) { 666 while (!PTQ_EMPTY(&self->pt_cleanup_stack)) { 667 cleanup = PTQ_FIRST(&self->pt_cleanup_stack); 668 PTQ_REMOVE(&self->pt_cleanup_stack, cleanup, ptc_next); 669 (*cleanup->ptc_cleanup)(cleanup->ptc_arg); 670 } 671 } 672 673 __cxa_thread_run_atexit(); 674 675 /* Perform cleanup of thread-specific data */ 676 pthread__destroy_tsd(self); 677 678 if (_malloc_thread_cleanup) 679 _malloc_thread_cleanup(); 680 681 /* 682 * Signal our exit. Our stack and pthread_t won't be reused until 683 * pthread_create() can see from kernel info that this LWP is gone. 684 */ 685 pthread_mutex_lock(&self->pt_lock); 686 self->pt_exitval = retval; 687 if (self->pt_flags & PT_FLAG_DETACHED) { 688 /* pthread__reap() will drop the lock. */ 689 pthread__reap(self); 690 _lwp_exit(); 691 } else { 692 self->pt_state = PT_STATE_ZOMBIE; 693 pthread_mutex_unlock(&self->pt_lock); 694 /* Note: name will be freed by the joiner. */ 695 _lwp_exit(); 696 } 697 698 out: 699 /*NOTREACHED*/ 700 pthread__abort(); 701 exit(1); 702 } 703 704 705 int 706 pthread_join(pthread_t thread, void **valptr) 707 { 708 pthread_t self; 709 710 pthread__error(EINVAL, "Invalid thread", 711 thread->pt_magic == PT_MAGIC); 712 713 self = pthread__self(); 714 715 if (pthread__find(thread) != 0) 716 return ESRCH; 717 718 if (thread == self) 719 return EDEADLK; 720 721 /* IEEE Std 1003.1 says pthread_join() never returns EINTR. */ 722 for (;;) { 723 pthread__testcancel(self); 724 if (_lwp_wait(thread->pt_lid, NULL) == 0) 725 break; 726 if (errno != EINTR) 727 return errno; 728 } 729 730 /* 731 * Don't test for cancellation again. The spec is that if 732 * cancelled, pthread_join() must not have succeeded. 733 */ 734 pthread_mutex_lock(&thread->pt_lock); 735 if (thread->pt_state != PT_STATE_ZOMBIE) { 736 pthread__errorfunc(__FILE__, __LINE__, __func__, 737 "not a zombie"); 738 } 739 if (valptr != NULL) 740 *valptr = thread->pt_exitval; 741 742 /* pthread__reap() will drop the lock. */ 743 pthread__reap(thread); 744 return 0; 745 } 746 747 static void 748 pthread__reap(pthread_t thread) 749 { 750 char *name; 751 752 name = thread->pt_name; 753 thread->pt_name = NULL; 754 thread->pt_state = PT_STATE_DEAD; 755 pthread_mutex_unlock(&thread->pt_lock); 756 757 pthread_mutex_lock(&pthread__deadqueue_lock); 758 PTQ_INSERT_HEAD(&pthread__deadqueue, thread, pt_deadq); 759 pthread_mutex_unlock(&pthread__deadqueue_lock); 760 761 if (name != NULL) 762 free(name); 763 } 764 765 int 766 pthread_equal(pthread_t t1, pthread_t t2) 767 { 768 769 if (__predict_false(__uselibcstub)) 770 return __libc_thr_equal_stub(t1, t2); 771 772 pthread__error(0, "Invalid thread", 773 (t1 != NULL) && (t1->pt_magic == PT_MAGIC)); 774 775 pthread__error(0, "Invalid thread", 776 (t2 != NULL) && (t2->pt_magic == PT_MAGIC)); 777 778 /* Nothing special here. */ 779 return (t1 == t2); 780 } 781 782 783 int 784 pthread_detach(pthread_t thread) 785 { 786 int error; 787 788 pthread__error(EINVAL, "Invalid thread", 789 thread->pt_magic == PT_MAGIC); 790 791 if (pthread__find(thread) != 0) 792 return ESRCH; 793 794 pthread_mutex_lock(&thread->pt_lock); 795 if ((thread->pt_flags & PT_FLAG_DETACHED) != 0) { 796 error = EINVAL; 797 } else { 798 error = _lwp_detach(thread->pt_lid); 799 if (error == 0) 800 thread->pt_flags |= PT_FLAG_DETACHED; 801 else 802 error = errno; 803 } 804 if (thread->pt_state == PT_STATE_ZOMBIE) { 805 /* pthread__reap() will drop the lock. */ 806 pthread__reap(thread); 807 } else 808 pthread_mutex_unlock(&thread->pt_lock); 809 return error; 810 } 811 812 813 int 814 pthread_getname_np(pthread_t thread, char *name, size_t len) 815 { 816 817 pthread__error(EINVAL, "Invalid thread", 818 thread->pt_magic == PT_MAGIC); 819 820 if (pthread__find(thread) != 0) 821 return ESRCH; 822 823 pthread_mutex_lock(&thread->pt_lock); 824 if (thread->pt_name == NULL) 825 name[0] = '\0'; 826 else 827 strlcpy(name, thread->pt_name, len); 828 pthread_mutex_unlock(&thread->pt_lock); 829 830 return 0; 831 } 832 833 834 int 835 pthread_setname_np(pthread_t thread, const char *name, void *arg) 836 { 837 char *oldname, *cp, newname[PTHREAD_MAX_NAMELEN_NP]; 838 int namelen; 839 840 pthread__error(EINVAL, "Invalid thread", 841 thread->pt_magic == PT_MAGIC); 842 843 if (pthread__find(thread) != 0) 844 return ESRCH; 845 846 namelen = snprintf(newname, sizeof(newname), name, arg); 847 if (namelen >= PTHREAD_MAX_NAMELEN_NP) 848 return EINVAL; 849 850 cp = strdup(newname); 851 if (cp == NULL) 852 return ENOMEM; 853 854 pthread_mutex_lock(&thread->pt_lock); 855 oldname = thread->pt_name; 856 thread->pt_name = cp; 857 (void)_lwp_setname(thread->pt_lid, cp); 858 pthread_mutex_unlock(&thread->pt_lock); 859 860 if (oldname != NULL) 861 free(oldname); 862 863 return 0; 864 } 865 866 867 pthread_t 868 pthread_self(void) 869 { 870 if (__predict_false(__uselibcstub)) 871 return (pthread_t)__libc_thr_self_stub(); 872 873 return pthread__self(); 874 } 875 876 877 int 878 pthread_cancel(pthread_t thread) 879 { 880 unsigned old, new; 881 bool wake; 882 883 pthread__error(EINVAL, "Invalid thread", 884 thread->pt_magic == PT_MAGIC); 885 886 if (pthread__find(thread) != 0) 887 return ESRCH; 888 889 /* 890 * membar_release matches membar_acquire in 891 * pthread_setcancelstate and pthread__testcancel. 892 */ 893 membar_release(); 894 895 do { 896 old = atomic_load_relaxed(&thread->pt_cancel); 897 new = old | PT_CANCEL_PENDING; 898 wake = false; 899 if ((old & PT_CANCEL_DISABLED) == 0) { 900 new |= PT_CANCEL_CANCELLED; 901 wake = true; 902 } 903 } while (__predict_false(!atomic_compare_exchange_weak_explicit( 904 &thread->pt_cancel, &old, new, 905 memory_order_relaxed, memory_order_relaxed))); 906 907 if (wake) 908 _lwp_wakeup(thread->pt_lid); 909 910 return 0; 911 } 912 913 914 int 915 pthread_setcancelstate(int state, int *oldstate) 916 { 917 pthread_t self; 918 unsigned flags, old, new; 919 bool cancelled; 920 921 if (__predict_false(__uselibcstub)) 922 return __libc_thr_setcancelstate_stub(state, oldstate); 923 924 self = pthread__self(); 925 926 switch (state) { 927 case PTHREAD_CANCEL_ENABLE: 928 flags = 0; 929 break; 930 case PTHREAD_CANCEL_DISABLE: 931 flags = PT_CANCEL_DISABLED; 932 break; 933 default: 934 return EINVAL; 935 } 936 937 do { 938 old = atomic_load_relaxed(&self->pt_cancel); 939 new = (old & ~PT_CANCEL_DISABLED) | flags; 940 /* 941 * If we disable while cancelled, switch back to 942 * pending so future cancellation tests will not fire 943 * until enabled again. 944 * 945 * If a cancellation was requested while cancellation 946 * was disabled, note that fact for future 947 * cancellation tests. 948 */ 949 cancelled = false; 950 if (__predict_false((flags | (old & PT_CANCEL_CANCELLED)) == 951 (PT_CANCEL_DISABLED|PT_CANCEL_CANCELLED))) { 952 new &= ~PT_CANCEL_CANCELLED; 953 new |= PT_CANCEL_PENDING; 954 } else if (__predict_false((flags | 955 (old & PT_CANCEL_PENDING)) == 956 PT_CANCEL_PENDING)) { 957 new |= PT_CANCEL_CANCELLED; 958 /* This is not a deferred cancellation point. */ 959 if (__predict_false(old & PT_CANCEL_ASYNC)) 960 cancelled = true; 961 } 962 } while (__predict_false(!atomic_compare_exchange_weak_explicit( 963 &self->pt_cancel, &old, new, 964 memory_order_relaxed, memory_order_relaxed))); 965 966 /* 967 * If we transitioned from PTHREAD_CANCEL_DISABLED to 968 * PTHREAD_CANCEL_ENABLED, there was a pending cancel, and we 969 * are configured with asynchronous cancellation, we are now 970 * cancelled -- make it happen. 971 */ 972 if (__predict_false(cancelled)) { 973 /* 974 * membar_acquire matches membar_release in 975 * pthread_cancel. 976 */ 977 membar_acquire(); 978 pthread__cancelled(); 979 } 980 981 if (oldstate) { 982 if (old & PT_CANCEL_DISABLED) 983 *oldstate = PTHREAD_CANCEL_DISABLE; 984 else 985 *oldstate = PTHREAD_CANCEL_ENABLE; 986 } 987 988 return 0; 989 } 990 991 992 int 993 pthread_setcanceltype(int type, int *oldtype) 994 { 995 pthread_t self; 996 unsigned flags, old, new; 997 bool cancelled; 998 999 self = pthread__self(); 1000 1001 switch (type) { 1002 case PTHREAD_CANCEL_DEFERRED: 1003 flags = 0; 1004 break; 1005 case PTHREAD_CANCEL_ASYNCHRONOUS: 1006 flags = PT_CANCEL_ASYNC; 1007 break; 1008 default: 1009 return EINVAL; 1010 } 1011 1012 do { 1013 old = atomic_load_relaxed(&self->pt_cancel); 1014 new = (old & ~PT_CANCEL_ASYNC) | flags; 1015 cancelled = false; 1016 if (__predict_false((flags | (old & PT_CANCEL_CANCELLED)) == 1017 (PT_CANCEL_ASYNC|PT_CANCEL_CANCELLED))) 1018 cancelled = true; 1019 } while (__predict_false(!atomic_compare_exchange_weak_explicit( 1020 &self->pt_cancel, &old, new, 1021 memory_order_relaxed, memory_order_relaxed))); 1022 1023 if (__predict_false(cancelled)) { 1024 membar_acquire(); 1025 pthread__cancelled(); 1026 } 1027 1028 if (oldtype != NULL) { 1029 if (old & PT_CANCEL_ASYNC) 1030 *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS; 1031 else 1032 *oldtype = PTHREAD_CANCEL_DEFERRED; 1033 } 1034 1035 return 0; 1036 } 1037 1038 1039 void 1040 pthread_testcancel(void) 1041 { 1042 pthread_t self; 1043 1044 self = pthread__self(); 1045 1046 pthread__testcancel(self); 1047 } 1048 1049 1050 /* 1051 * POSIX requires that certain functions return an error rather than 1052 * invoking undefined behavior even when handed completely bogus 1053 * pthread_t values, e.g. stack garbage. 1054 */ 1055 int 1056 pthread__find(pthread_t id) 1057 { 1058 pthread_t target; 1059 int error; 1060 1061 pthread_rwlock_rdlock(&pthread__alltree_lock); 1062 target = rb_tree_find_node(&pthread__alltree, id); 1063 error = (target && target->pt_state != PT_STATE_DEAD) ? 0 : ESRCH; 1064 pthread_rwlock_unlock(&pthread__alltree_lock); 1065 1066 return error; 1067 } 1068 1069 1070 void 1071 pthread__testcancel(pthread_t self) 1072 { 1073 1074 /* 1075 * We use atomic_load_relaxed and then a conditional 1076 * membar_acquire, rather than atomic_load_acquire, in order to 1077 * avoid incurring the cost of an acquire barrier in the common 1078 * case of not having been cancelled. 1079 * 1080 * membar_acquire matches membar_release in pthread_cancel. 1081 */ 1082 if (__predict_false(atomic_load_relaxed(&self->pt_cancel) & 1083 PT_CANCEL_CANCELLED)) { 1084 membar_acquire(); 1085 pthread__cancelled(); 1086 } 1087 } 1088 1089 1090 void 1091 pthread__cancelled(void) 1092 { 1093 1094 pthread_exit(PTHREAD_CANCELED); 1095 } 1096 1097 1098 void 1099 pthread__cleanup_push(void (*cleanup)(void *), void *arg, void *store) 1100 { 1101 pthread_t self; 1102 struct pt_clean_t *entry; 1103 1104 self = pthread__self(); 1105 entry = store; 1106 entry->ptc_cleanup = cleanup; 1107 entry->ptc_arg = arg; 1108 PTQ_INSERT_HEAD(&self->pt_cleanup_stack, entry, ptc_next); 1109 } 1110 1111 1112 void 1113 pthread__cleanup_pop(int ex, void *store) 1114 { 1115 pthread_t self; 1116 struct pt_clean_t *entry; 1117 1118 self = pthread__self(); 1119 entry = store; 1120 1121 PTQ_REMOVE(&self->pt_cleanup_stack, entry, ptc_next); 1122 if (ex) 1123 (*entry->ptc_cleanup)(entry->ptc_arg); 1124 } 1125 1126 1127 int * 1128 pthread__errno(void) 1129 { 1130 pthread_t self; 1131 1132 if (__predict_false(__uselibcstub)) { 1133 pthread__errorfunc(__FILE__, __LINE__, __func__, 1134 "pthread__errno() requires linking with -lpthread"); 1135 return __libc_thr_errno_stub(); 1136 } 1137 1138 self = pthread__self(); 1139 1140 return &(self->pt_errno); 1141 } 1142 1143 ssize_t _sys_write(int, const void *, size_t); 1144 1145 void 1146 pthread__assertfunc(const char *file, int line, const char *function, 1147 const char *expr) 1148 { 1149 char buf[1024]; 1150 int len; 1151 1152 /* 1153 * snprintf_ss should not acquire any locks, or we could 1154 * end up deadlocked if the assert caller held locks. 1155 */ 1156 len = snprintf_ss(buf, 1024, 1157 "assertion \"%s\" failed: file \"%s\", line %d%s%s%s\n", 1158 expr, file, line, 1159 function ? ", function \"" : "", 1160 function ? function : "", 1161 function ? "\"" : ""); 1162 1163 _sys_write(STDERR_FILENO, buf, (size_t)len); 1164 (void)raise(SIGABRT); 1165 _exit(1); 1166 } 1167 1168 1169 void 1170 pthread__errorfunc(const char *file, int line, const char *function, 1171 const char *msg, ...) 1172 { 1173 char buf[1024]; 1174 char buf2[1024]; 1175 size_t len; 1176 va_list ap; 1177 1178 if (pthread__diagassert == 0) 1179 return; 1180 1181 va_start(ap, msg); 1182 vsnprintf_ss(buf2, sizeof(buf2), msg, ap); 1183 va_end(ap); 1184 1185 /* 1186 * snprintf_ss should not acquire any locks, or we could 1187 * end up deadlocked if the assert caller held locks. 1188 */ 1189 len = snprintf_ss(buf, sizeof(buf), 1190 "%s: Error detected by libpthread: %s.\n" 1191 "Detected by file \"%s\", line %d%s%s%s.\n" 1192 "See pthread(3) for information.\n", 1193 getprogname(), buf2, file, line, 1194 function ? ", function \"" : "", 1195 function ? function : "", 1196 function ? "\"" : ""); 1197 1198 if (pthread__diagassert & DIAGASSERT_STDERR) 1199 _sys_write(STDERR_FILENO, buf, len); 1200 1201 if (pthread__diagassert & DIAGASSERT_SYSLOG) 1202 syslog(LOG_DEBUG | LOG_USER, "%s", buf); 1203 1204 if (pthread__diagassert & DIAGASSERT_ABORT) { 1205 (void)raise(SIGABRT); 1206 _exit(1); 1207 } 1208 } 1209 1210 /* 1211 * Thread park/unpark operations. The kernel operations are 1212 * modelled after a brief description from "Multithreading in 1213 * the Solaris Operating Environment": 1214 * 1215 * http://www.sun.com/software/whitepapers/solaris9/multithread.pdf 1216 */ 1217 1218 int 1219 pthread__park(pthread_t self, pthread_mutex_t *lock, 1220 pthread_queue_t *queue, const struct timespec *abstime, 1221 int cancelpt) 1222 { 1223 int rv, error; 1224 1225 pthread_mutex_unlock(lock); 1226 1227 /* 1228 * Wait until we are awoken by a pending unpark operation, 1229 * a signal, an unpark posted after we have gone asleep, 1230 * or an expired timeout. 1231 * 1232 * It is fine to test the value of pt_sleepobj without 1233 * holding any locks, because: 1234 * 1235 * o Only the blocking thread (this thread) ever sets it 1236 * to a non-NULL value. 1237 * 1238 * o Other threads may set it NULL, but if they do so they 1239 * must also make this thread return from _lwp_park. 1240 * 1241 * o _lwp_park, _lwp_unpark and _lwp_unpark_all are system 1242 * calls and all make use of spinlocks in the kernel. So 1243 * these system calls act as full memory barriers. 1244 */ 1245 rv = 0; 1246 do { 1247 /* 1248 * If we deferred unparking a thread, arrange to 1249 * have _lwp_park() restart it before blocking. 1250 */ 1251 error = _lwp_park(CLOCK_REALTIME, TIMER_ABSTIME, 1252 __UNCONST(abstime), 0, NULL, NULL); 1253 if (error != 0) { 1254 switch (rv = errno) { 1255 case EINTR: 1256 case EALREADY: 1257 rv = 0; 1258 break; 1259 case ETIMEDOUT: 1260 break; 1261 default: 1262 pthread__errorfunc(__FILE__, __LINE__, 1263 __func__, "_lwp_park failed: %d", errno); 1264 break; 1265 } 1266 } 1267 /* Check for cancellation. */ 1268 if (cancelpt && 1269 (atomic_load_relaxed(&self->pt_cancel) & 1270 PT_CANCEL_CANCELLED)) 1271 rv = EINTR; 1272 } while (self->pt_sleepobj != NULL && rv == 0); 1273 return rv; 1274 } 1275 1276 void 1277 pthread__unpark(pthread_queue_t *queue, pthread_t self, 1278 pthread_mutex_t *interlock) 1279 { 1280 pthread_t target; 1281 1282 target = PTQ_FIRST(queue); 1283 target->pt_sleepobj = NULL; 1284 PTQ_REMOVE(queue, target, pt_sleep); 1285 (void)_lwp_unpark(target->pt_lid, NULL); 1286 } 1287 1288 void 1289 pthread__unpark_all(pthread_queue_t *queue, pthread_t self, 1290 pthread_mutex_t *interlock) 1291 { 1292 lwpid_t lids[PTHREAD__UNPARK_MAX]; 1293 const size_t mlid = pthread__unpark_max; 1294 pthread_t target; 1295 size_t nlid = 0; 1296 1297 PTQ_FOREACH(target, queue, pt_sleep) { 1298 if (nlid == mlid) { 1299 (void)_lwp_unpark_all(lids, nlid, NULL); 1300 nlid = 0; 1301 } 1302 target->pt_sleepobj = NULL; 1303 lids[nlid++] = target->pt_lid; 1304 } 1305 PTQ_INIT(queue); 1306 if (nlid == 1) { 1307 (void)_lwp_unpark(lids[0], NULL); 1308 } else if (nlid > 1) { 1309 (void)_lwp_unpark_all(lids, nlid, NULL); 1310 } 1311 } 1312 1313 #undef OOPS 1314 1315 static void 1316 pthread__initmainstack(void) 1317 { 1318 struct rlimit slimit; 1319 const AuxInfo *aux; 1320 size_t size, len; 1321 int mib[2]; 1322 unsigned int value; 1323 1324 _DIAGASSERT(_dlauxinfo() != NULL); 1325 1326 if (getrlimit(RLIMIT_STACK, &slimit) == -1) 1327 err(EXIT_FAILURE, 1328 "Couldn't get stack resource consumption limits"); 1329 size = slimit.rlim_cur; 1330 pthread__main->pt_stack.ss_size = size; 1331 pthread__main->pt_guardsize = pthread__pagesize; 1332 1333 mib[0] = CTL_VM; 1334 mib[1] = VM_GUARD_SIZE; 1335 len = sizeof(value); 1336 if (sysctl(mib, __arraycount(mib), &value, &len, NULL, 0) == 0) 1337 pthread__main->pt_guardsize = value; 1338 1339 for (aux = _dlauxinfo(); aux->a_type != AT_NULL; ++aux) { 1340 if (aux->a_type == AT_STACKBASE) { 1341 #ifdef __MACHINE_STACK_GROWS_UP 1342 pthread__main->pt_stack.ss_sp = (void *)aux->a_v; 1343 #else 1344 pthread__main->pt_stack.ss_sp = (char *)aux->a_v - size; 1345 #endif 1346 break; 1347 } 1348 } 1349 pthread__copy_tsd(pthread__main); 1350 } 1351 1352 /* 1353 * Set up the slightly special stack for the "initial" thread, which 1354 * runs on the normal system stack, and thus gets slightly different 1355 * treatment. 1356 */ 1357 static void 1358 pthread__initmain(pthread_t *newt) 1359 { 1360 char *value; 1361 1362 pthread__initmainstack(); 1363 1364 value = pthread__getenv("PTHREAD_STACKSIZE"); 1365 if (value != NULL) { 1366 pthread__stacksize = atoi(value) * 1024; 1367 if (pthread__stacksize > pthread__main->pt_stack.ss_size) 1368 pthread__stacksize = pthread__main->pt_stack.ss_size; 1369 } 1370 if (pthread__stacksize == 0) 1371 pthread__stacksize = pthread__main->pt_stack.ss_size; 1372 pthread__stacksize += pthread__pagesize - 1; 1373 pthread__stacksize &= ~(pthread__pagesize - 1); 1374 if (pthread__stacksize < 4 * pthread__pagesize) 1375 errx(1, "Stacksize limit is too low, minimum %zd kbyte.", 1376 4 * pthread__pagesize / 1024); 1377 1378 *newt = pthread__main; 1379 #if defined(_PTHREAD_GETTCB_EXT) 1380 pthread__main->pt_tls = _PTHREAD_GETTCB_EXT(); 1381 #elif defined(__HAVE___LWP_GETTCB_FAST) 1382 pthread__main->pt_tls = __lwp_gettcb_fast(); 1383 #else 1384 pthread__main->pt_tls = _lwp_getprivate(); 1385 #endif 1386 pthread__main->pt_tls->tcb_pthread = pthread__main; 1387 } 1388 1389 static signed int 1390 /*ARGSUSED*/ 1391 pthread__cmp(void *ctx, const void *n1, const void *n2) 1392 { 1393 const uintptr_t p1 = (const uintptr_t)n1; 1394 const uintptr_t p2 = (const uintptr_t)n2; 1395 1396 if (p1 < p2) 1397 return -1; 1398 if (p1 > p2) 1399 return 1; 1400 return 0; 1401 } 1402 1403 /* Because getenv() wants to use locks. */ 1404 char * 1405 pthread__getenv(const char *name) 1406 { 1407 extern char **environ; 1408 size_t l_name, offset; 1409 1410 if (issetugid()) 1411 return (NULL); 1412 1413 l_name = strlen(name); 1414 for (offset = 0; environ[offset] != NULL; offset++) { 1415 if (strncmp(name, environ[offset], l_name) == 0 && 1416 environ[offset][l_name] == '=') { 1417 return environ[offset] + l_name + 1; 1418 } 1419 } 1420 1421 return NULL; 1422 } 1423 1424 pthread_mutex_t * 1425 pthread__hashlock(volatile const void *p) 1426 { 1427 uintptr_t v; 1428 1429 v = (uintptr_t)p; 1430 return &hashlocks[((v >> 9) ^ (v >> 3)) & (NHASHLOCK - 1)].mutex; 1431 } 1432 1433 int 1434 pthread__checkpri(int pri) 1435 { 1436 static int havepri; 1437 static long min, max; 1438 1439 if (!havepri) { 1440 min = sysconf(_SC_SCHED_PRI_MIN); 1441 max = sysconf(_SC_SCHED_PRI_MAX); 1442 havepri = 1; 1443 } 1444 return (pri < min || pri > max) ? EINVAL : 0; 1445 } 1446