1 /* $NetBSD: pthread_mutex.c,v 1.84 2026/05/06 09:03:08 yamt Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2003, 2006, 2007, 2008, 2020 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Nathan J. Williams, by Jason R. Thorpe, and by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * To track threads waiting for mutexes to be released, we use lockless 34 * lists built on atomic operations and memory barriers. 35 * 36 * A simple spinlock would be faster and make the code easier to 37 * follow, but spinlocks are problematic in userspace. If a thread is 38 * preempted by the kernel while holding a spinlock, any other thread 39 * attempting to acquire that spinlock will needlessly busy wait. 40 * 41 * There is no good way to know that the holding thread is no longer 42 * running, nor to request a wake-up once it has begun running again. 43 * Of more concern, threads in the SCHED_FIFO class do not have a 44 * limited time quantum and so could spin forever, preventing the 45 * thread holding the spinlock from getting CPU time: it would never 46 * be released. 47 */ 48 49 #include <sys/cdefs.h> 50 __RCSID("$NetBSD: pthread_mutex.c,v 1.84 2026/05/06 09:03:08 yamt Exp $"); 51 52 /* Need to use libc-private names for atomic operations. */ 53 #include "../../common/lib/libc/atomic/atomic_op_namespace.h" 54 55 #include <sys/types.h> 56 #include <sys/lwpctl.h> 57 #include <sys/sched.h> 58 #include <sys/lock.h> 59 60 #include <errno.h> 61 #include <limits.h> 62 #include <stdlib.h> 63 #include <time.h> 64 #include <string.h> 65 #include <stdio.h> 66 67 #include "pthread.h" 68 #include "pthread_int.h" 69 #include "reentrant.h" 70 71 #define MUTEX_RECURSIVE_BIT ((uintptr_t)0x02) 72 #define MUTEX_PROTECT_BIT ((uintptr_t)0x08) 73 #define MUTEX_THREAD ((uintptr_t)~0x0f) 74 75 #define MUTEX_RECURSIVE(x) ((uintptr_t)(x) & MUTEX_RECURSIVE_BIT) 76 #define MUTEX_PROTECT(x) ((uintptr_t)(x) & MUTEX_PROTECT_BIT) 77 #define MUTEX_OWNER(x) ((uintptr_t)(x) & MUTEX_THREAD) 78 79 #define MUTEX_GET_TYPE(x) \ 80 ((int)(((uintptr_t)(x) & 0x000000ff) >> 0)) 81 #define MUTEX_SET_TYPE(x, t) \ 82 (x) = (void *)(((uintptr_t)(x) & ~0x000000ff) | ((t) << 0)) 83 #define MUTEX_GET_PROTOCOL(x) \ 84 ((int)(((uintptr_t)(x) & 0x0000ff00) >> 8)) 85 #define MUTEX_SET_PROTOCOL(x, p) \ 86 (x) = (void *)(((uintptr_t)(x) & ~0x0000ff00) | ((p) << 8)) 87 #define MUTEX_GET_CEILING(x) \ 88 ((int)(((uintptr_t)(x) & 0x00ff0000) >> 16)) 89 #define MUTEX_SET_CEILING(x, c) \ 90 (x) = (void *)(((uintptr_t)(x) & ~0x00ff0000) | ((c) << 16)) 91 92 #if __GNUC_PREREQ__(3, 0) 93 #define NOINLINE __attribute ((noinline)) 94 #else 95 #define NOINLINE /* nothing */ 96 #endif 97 98 static void pthread__mutex_wakeup(pthread_t, struct pthread__waiter *); 99 static int pthread__mutex_lock_slow(pthread_mutex_t *, 100 const struct timespec *); 101 static void pthread__mutex_pause(void); 102 103 int _pthread_mutex_held_np(pthread_mutex_t *); 104 pthread_t _pthread_mutex_owner_np(pthread_mutex_t *); 105 106 __weak_alias(pthread_mutex_held_np,_pthread_mutex_held_np) 107 __weak_alias(pthread_mutex_owner_np,_pthread_mutex_owner_np) 108 109 __strong_alias(__libc_mutex_init,pthread_mutex_init) 110 __strong_alias(__libc_mutex_lock,pthread_mutex_lock) 111 __strong_alias(__libc_mutex_trylock,pthread_mutex_trylock) 112 __strong_alias(__libc_mutex_unlock,pthread_mutex_unlock) 113 __strong_alias(__libc_mutex_destroy,pthread_mutex_destroy) 114 115 __strong_alias(__libc_mutexattr_init,pthread_mutexattr_init) 116 __strong_alias(__libc_mutexattr_destroy,pthread_mutexattr_destroy) 117 __strong_alias(__libc_mutexattr_settype,pthread_mutexattr_settype) 118 119 int 120 pthread_mutex_init(pthread_mutex_t *ptm, const pthread_mutexattr_t *attr) 121 { 122 uintptr_t type, proto, val, ceil; 123 124 #if 0 125 /* 126 * Always initialize the mutex structure, maybe be used later 127 * and the cost should be minimal. 128 */ 129 if (__predict_false(__uselibcstub)) 130 return __libc_mutex_init_stub(ptm, attr); 131 #endif 132 133 pthread__error(EINVAL, "Invalid mutes attribute", 134 attr == NULL || attr->ptma_magic == _PT_MUTEXATTR_MAGIC); 135 136 if (attr == NULL) { 137 type = PTHREAD_MUTEX_NORMAL; 138 proto = PTHREAD_PRIO_NONE; 139 ceil = 0; 140 } else { 141 val = (uintptr_t)attr->ptma_private; 142 143 type = MUTEX_GET_TYPE(val); 144 proto = MUTEX_GET_PROTOCOL(val); 145 ceil = MUTEX_GET_CEILING(val); 146 } 147 switch (type) { 148 case PTHREAD_MUTEX_ERRORCHECK: 149 __cpu_simple_lock_set(&ptm->ptm_errorcheck); 150 ptm->ptm_owner = NULL; 151 break; 152 case PTHREAD_MUTEX_RECURSIVE: 153 __cpu_simple_lock_clear(&ptm->ptm_errorcheck); 154 ptm->ptm_owner = (void *)MUTEX_RECURSIVE_BIT; 155 break; 156 default: 157 __cpu_simple_lock_clear(&ptm->ptm_errorcheck); 158 ptm->ptm_owner = NULL; 159 break; 160 } 161 switch (proto) { 162 case PTHREAD_PRIO_PROTECT: 163 val = (uintptr_t)ptm->ptm_owner; 164 val |= MUTEX_PROTECT_BIT; 165 ptm->ptm_owner = (void *)val; 166 break; 167 168 } 169 ptm->ptm_magic = _PT_MUTEX_MAGIC; 170 ptm->ptm_waiters = NULL; 171 ptm->ptm_recursed = 0; 172 ptm->ptm_ceiling = (unsigned char)ceil; 173 174 return 0; 175 } 176 177 int 178 pthread_mutex_destroy(pthread_mutex_t *ptm) 179 { 180 181 if (__predict_false(__uselibcstub)) 182 return __libc_mutex_destroy_stub(ptm); 183 184 pthread__error(EINVAL, "Invalid mutex", 185 ptm->ptm_magic == _PT_MUTEX_MAGIC); 186 pthread__error(EBUSY, "Destroying locked mutex", 187 MUTEX_OWNER(ptm->ptm_owner) == 0); 188 189 ptm->ptm_magic = _PT_MUTEX_DEAD; 190 return 0; 191 } 192 193 int 194 pthread_mutex_lock(pthread_mutex_t *ptm) 195 { 196 pthread_t self; 197 void *val; 198 199 if (__predict_false(__uselibcstub)) 200 return __libc_mutex_lock_stub(ptm); 201 202 pthread__error(EINVAL, "Invalid mutex", 203 ptm->ptm_magic == _PT_MUTEX_MAGIC); 204 205 self = pthread__self(); 206 val = atomic_cas_ptr(&ptm->ptm_owner, NULL, self); 207 if (__predict_true(val == NULL)) { 208 #ifndef PTHREAD__ATOMIC_IS_MEMBAR 209 membar_enter(); 210 #endif 211 return 0; 212 } 213 return pthread__mutex_lock_slow(ptm, NULL); 214 } 215 216 int 217 pthread_mutex_timedlock(pthread_mutex_t* ptm, const struct timespec *ts) 218 { 219 pthread_t self; 220 void *val; 221 222 pthread__error(EINVAL, "Invalid mutex", 223 ptm->ptm_magic == _PT_MUTEX_MAGIC); 224 225 self = pthread__self(); 226 val = atomic_cas_ptr(&ptm->ptm_owner, NULL, self); 227 if (__predict_true(val == NULL)) { 228 #ifndef PTHREAD__ATOMIC_IS_MEMBAR 229 membar_enter(); 230 #endif 231 return 0; 232 } 233 return pthread__mutex_lock_slow(ptm, ts); 234 } 235 236 /* We want function call overhead. */ 237 NOINLINE static void 238 pthread__mutex_pause(void) 239 { 240 241 pthread__smt_pause(); 242 } 243 244 /* 245 * Spin while the holder is running. 'lwpctl' gives us the true 246 * status of the thread. 247 */ 248 NOINLINE static void * 249 pthread__mutex_spin(pthread_mutex_t *ptm, pthread_t owner) 250 { 251 pthread_t thread; 252 unsigned int count, i; 253 254 for (count = 2;; owner = ptm->ptm_owner) { 255 thread = (pthread_t)MUTEX_OWNER(owner); 256 if (thread == NULL) 257 break; 258 if (thread->pt_lwpctl->lc_curcpu == LWPCTL_CPU_NONE) 259 break; 260 if (count < 128) 261 count += count; 262 for (i = count; i != 0; i--) 263 pthread__mutex_pause(); 264 } 265 266 return owner; 267 } 268 269 NOINLINE static int 270 pthread__mutex_lock_slow(pthread_mutex_t *ptm, const struct timespec *ts) 271 { 272 void *newval, *owner, *next; 273 struct pthread__waiter waiter; 274 pthread_t self; 275 int serrno; 276 int error; 277 278 owner = ptm->ptm_owner; 279 self = pthread__self(); 280 serrno = errno; 281 282 pthread__assert(self->pt_lid != 0); 283 284 /* Recursive or errorcheck? */ 285 if (MUTEX_OWNER(owner) == (uintptr_t)self) { 286 if (MUTEX_RECURSIVE(owner)) { 287 if (ptm->ptm_recursed == INT_MAX) 288 return EAGAIN; 289 ptm->ptm_recursed++; 290 return 0; 291 } 292 if (__SIMPLELOCK_LOCKED_P(&ptm->ptm_errorcheck)) 293 return EDEADLK; 294 } 295 296 /* priority protect */ 297 if (MUTEX_PROTECT(owner) && _sched_protect(ptm->ptm_ceiling) == -1) { 298 error = errno; 299 errno = serrno; 300 return error; 301 } 302 303 for (;;) { 304 /* If it has become free, try to acquire it again. */ 305 if (MUTEX_OWNER(owner) == 0) { 306 newval = (void *)((uintptr_t)self | (uintptr_t)owner); 307 next = atomic_cas_ptr(&ptm->ptm_owner, owner, newval); 308 if (__predict_false(next != owner)) { 309 owner = next; 310 continue; 311 } 312 errno = serrno; 313 #ifndef PTHREAD__ATOMIC_IS_MEMBAR 314 membar_enter(); 315 #endif 316 return 0; 317 } else if (MUTEX_OWNER(owner) != (uintptr_t)self) { 318 /* Spin while the owner is running. */ 319 owner = pthread__mutex_spin(ptm, owner); 320 if (MUTEX_OWNER(owner) == 0) { 321 continue; 322 } 323 } 324 325 /* 326 * Nope, still held. Add thread to the list of waiters. 327 * Issue a memory barrier to ensure stores to 'waiter' 328 * are visible before we enter the list. 329 */ 330 waiter.next = ptm->ptm_waiters; 331 waiter.lid = self->pt_lid; 332 #ifndef PTHREAD__ATOMIC_IS_MEMBAR 333 membar_producer(); 334 #endif 335 next = atomic_cas_ptr(&ptm->ptm_waiters, waiter.next, &waiter); 336 if (next != waiter.next) { 337 owner = ptm->ptm_owner; 338 continue; 339 } 340 341 /* 342 * If the mutex has become free since entering self onto the 343 * waiters list, need to wake everybody up (including self) 344 * and retry. It's possible to race with an unlocking 345 * thread, so self may have already been awoken. 346 */ 347 #ifndef PTHREAD__ATOMIC_IS_MEMBAR 348 membar_enter(); 349 #endif 350 if (MUTEX_OWNER(ptm->ptm_owner) == 0) { 351 pthread__mutex_wakeup(self, 352 atomic_swap_ptr(&ptm->ptm_waiters, NULL)); 353 } 354 355 /* 356 * We must not proceed until told that we are no longer 357 * waiting (via waiter.lid being set to zero). Otherwise 358 * it's unsafe to re-enter "waiter" onto the waiters list. 359 */ 360 while (waiter.lid != 0) { 361 error = _lwp_park(CLOCK_REALTIME, TIMER_ABSTIME, 362 __UNCONST(ts), 0, NULL, NULL); 363 if (error < 0 && errno == ETIMEDOUT) { 364 /* Remove self from waiters list */ 365 pthread__mutex_wakeup(self, 366 atomic_swap_ptr(&ptm->ptm_waiters, NULL)); 367 368 /* 369 * Might have raced with another thread to 370 * do the wakeup. In any case there will be 371 * a wakeup for sure. Eat it and wait for 372 * waiter.lid to clear. 373 */ 374 while (waiter.lid != 0) { 375 (void)_lwp_park(CLOCK_MONOTONIC, 0, 376 NULL, 0, NULL, NULL); 377 } 378 379 /* Priority protect */ 380 if (MUTEX_PROTECT(owner)) 381 (void)_sched_protect(-1); 382 errno = serrno; 383 return ETIMEDOUT; 384 } 385 } 386 owner = ptm->ptm_owner; 387 } 388 } 389 390 int 391 pthread_mutex_trylock(pthread_mutex_t *ptm) 392 { 393 pthread_t self; 394 void *val, *new, *next; 395 396 if (__predict_false(__uselibcstub)) 397 return __libc_mutex_trylock_stub(ptm); 398 399 pthread__error(EINVAL, "Invalid mutex", 400 ptm->ptm_magic == _PT_MUTEX_MAGIC); 401 402 self = pthread__self(); 403 val = atomic_cas_ptr(&ptm->ptm_owner, NULL, self); 404 if (__predict_true(val == NULL)) { 405 #ifndef PTHREAD__ATOMIC_IS_MEMBAR 406 membar_enter(); 407 #endif 408 return 0; 409 } 410 411 if (MUTEX_RECURSIVE(val)) { 412 if (MUTEX_OWNER(val) == 0) { 413 new = (void *)((uintptr_t)self | (uintptr_t)val); 414 next = atomic_cas_ptr(&ptm->ptm_owner, val, new); 415 if (__predict_true(next == val)) { 416 #ifndef PTHREAD__ATOMIC_IS_MEMBAR 417 membar_enter(); 418 #endif 419 return 0; 420 } 421 } 422 if (MUTEX_OWNER(val) == (uintptr_t)self) { 423 if (ptm->ptm_recursed == INT_MAX) 424 return EAGAIN; 425 ptm->ptm_recursed++; 426 return 0; 427 } 428 } 429 430 return EBUSY; 431 } 432 433 int 434 pthread_mutex_unlock(pthread_mutex_t *ptm) 435 { 436 pthread_t self; 437 void *val, *newval; 438 int error; 439 440 if (__predict_false(__uselibcstub)) 441 return __libc_mutex_unlock_stub(ptm); 442 443 pthread__error(EINVAL, "Invalid mutex", 444 ptm->ptm_magic == _PT_MUTEX_MAGIC); 445 446 #ifndef PTHREAD__ATOMIC_IS_MEMBAR 447 membar_exit(); 448 #endif 449 error = 0; 450 self = pthread__self(); 451 newval = NULL; 452 453 val = atomic_cas_ptr(&ptm->ptm_owner, self, newval); 454 if (__predict_false(val != self)) { 455 bool weown = (MUTEX_OWNER(val) == (uintptr_t)self); 456 if (__SIMPLELOCK_LOCKED_P(&ptm->ptm_errorcheck)) { 457 if (!weown) { 458 error = EPERM; 459 newval = val; 460 } else { 461 newval = NULL; 462 } 463 } else if (MUTEX_RECURSIVE(val)) { 464 if (!weown) { 465 error = EPERM; 466 newval = val; 467 } else if (ptm->ptm_recursed) { 468 ptm->ptm_recursed--; 469 newval = val; 470 } else { 471 newval = (pthread_t)MUTEX_RECURSIVE_BIT; 472 } 473 } else { 474 pthread__error(EPERM, 475 "Unlocking unlocked mutex", (val != NULL)); 476 pthread__error(EPERM, 477 "Unlocking mutex owned by another thread", weown); 478 newval = NULL; 479 } 480 481 /* 482 * Release the mutex. If there appear to be waiters, then 483 * wake them up. 484 */ 485 if (newval != val) { 486 val = atomic_swap_ptr(&ptm->ptm_owner, newval); 487 if (__predict_false(MUTEX_PROTECT(val))) { 488 /* restore elevated priority */ 489 (void)_sched_protect(-1); 490 } 491 } 492 } 493 494 /* 495 * Finally, wake any waiters and return. 496 */ 497 #ifndef PTHREAD__ATOMIC_IS_MEMBAR 498 membar_enter(); 499 #endif 500 if (MUTEX_OWNER(newval) == 0 && ptm->ptm_waiters != NULL) { 501 pthread__mutex_wakeup(self, 502 atomic_swap_ptr(&ptm->ptm_waiters, NULL)); 503 } 504 return error; 505 } 506 507 /* 508 * pthread__mutex_wakeup: unpark threads waiting for us 509 */ 510 511 static void 512 pthread__mutex_wakeup(pthread_t self, struct pthread__waiter *cur) 513 { 514 lwpid_t lids[PTHREAD__UNPARK_MAX]; 515 const size_t mlid = pthread__unpark_max; 516 struct pthread__waiter *next; 517 size_t nlid; 518 519 /* 520 * Pull waiters from the queue and add to our list. Use a memory 521 * barrier to ensure that we safely read the value of waiter->next 522 * before the awoken thread sees waiter->lid being cleared. 523 */ 524 membar_datadep_consumer(); /* for alpha */ 525 for (nlid = 0; cur != NULL; cur = next) { 526 if (nlid == mlid) { 527 (void)_lwp_unpark_all(lids, nlid, NULL); 528 nlid = 0; 529 } 530 next = cur->next; 531 pthread__assert(cur->lid != 0); 532 lids[nlid++] = cur->lid; 533 membar_exit(); 534 cur->lid = 0; 535 /* No longer safe to touch 'cur' */ 536 } 537 if (nlid == 1) { 538 (void)_lwp_unpark(lids[0], NULL); 539 } else if (nlid > 1) { 540 (void)_lwp_unpark_all(lids, nlid, NULL); 541 } 542 } 543 544 int 545 pthread_mutexattr_init(pthread_mutexattr_t *attr) 546 { 547 #if 0 548 if (__predict_false(__uselibcstub)) 549 return __libc_mutexattr_init_stub(attr); 550 #endif 551 552 attr->ptma_magic = _PT_MUTEXATTR_MAGIC; 553 attr->ptma_private = (void *)PTHREAD_MUTEX_DEFAULT; 554 return 0; 555 } 556 557 int 558 pthread_mutexattr_destroy(pthread_mutexattr_t *attr) 559 { 560 if (__predict_false(__uselibcstub)) 561 return __libc_mutexattr_destroy_stub(attr); 562 563 pthread__error(EINVAL, "Invalid mutex attribute", 564 attr->ptma_magic == _PT_MUTEXATTR_MAGIC); 565 566 attr->ptma_magic = _PT_MUTEXATTR_DEAD; 567 568 return 0; 569 } 570 571 int 572 pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *typep) 573 { 574 575 pthread__error(EINVAL, "Invalid mutex attribute", 576 attr->ptma_magic == _PT_MUTEXATTR_MAGIC); 577 578 *typep = MUTEX_GET_TYPE(attr->ptma_private); 579 return 0; 580 } 581 582 int 583 pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) 584 { 585 586 if (__predict_false(__uselibcstub)) 587 return __libc_mutexattr_settype_stub(attr, type); 588 589 pthread__error(EINVAL, "Invalid mutex attribute", 590 attr->ptma_magic == _PT_MUTEXATTR_MAGIC); 591 592 switch (type) { 593 case PTHREAD_MUTEX_NORMAL: 594 case PTHREAD_MUTEX_ERRORCHECK: 595 case PTHREAD_MUTEX_RECURSIVE: 596 MUTEX_SET_TYPE(attr->ptma_private, type); 597 return 0; 598 default: 599 return EINVAL; 600 } 601 } 602 603 int 604 pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int*proto) 605 { 606 607 pthread__error(EINVAL, "Invalid mutex attribute", 608 attr->ptma_magic == _PT_MUTEXATTR_MAGIC); 609 610 *proto = MUTEX_GET_PROTOCOL(attr->ptma_private); 611 return 0; 612 } 613 614 int 615 pthread_mutexattr_setprotocol(pthread_mutexattr_t* attr, int proto) 616 { 617 618 pthread__error(EINVAL, "Invalid mutex attribute", 619 attr->ptma_magic == _PT_MUTEXATTR_MAGIC); 620 621 switch (proto) { 622 case PTHREAD_PRIO_NONE: 623 case PTHREAD_PRIO_PROTECT: 624 MUTEX_SET_PROTOCOL(attr->ptma_private, proto); 625 return 0; 626 case PTHREAD_PRIO_INHERIT: 627 return ENOTSUP; 628 default: 629 return EINVAL; 630 } 631 } 632 633 int 634 pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *ceil) 635 { 636 637 pthread__error(EINVAL, "Invalid mutex attribute", 638 attr->ptma_magic == _PT_MUTEXATTR_MAGIC); 639 640 *ceil = MUTEX_GET_CEILING(attr->ptma_private); 641 return 0; 642 } 643 644 int 645 pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int ceil) 646 { 647 648 pthread__error(EINVAL, "Invalid mutex attribute", 649 attr->ptma_magic == _PT_MUTEXATTR_MAGIC); 650 651 if (ceil & ~0xff) 652 return EINVAL; 653 654 MUTEX_SET_CEILING(attr->ptma_private, ceil); 655 return 0; 656 } 657 658 #ifdef _PTHREAD_PSHARED 659 int 660 pthread_mutexattr_getpshared(const pthread_mutexattr_t * __restrict attr, 661 int * __restrict pshared) 662 { 663 664 pthread__error(EINVAL, "Invalid mutex attribute", 665 attr->ptma_magic == _PT_MUTEXATTR_MAGIC); 666 667 *pshared = PTHREAD_PROCESS_PRIVATE; 668 return 0; 669 } 670 671 int 672 pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) 673 { 674 675 pthread__error(EINVAL, "Invalid mutex attribute", 676 attr->ptma_magic == _PT_MUTEXATTR_MAGIC); 677 678 switch(pshared) { 679 case PTHREAD_PROCESS_PRIVATE: 680 return 0; 681 case PTHREAD_PROCESS_SHARED: 682 return ENOSYS; 683 } 684 return EINVAL; 685 } 686 #endif 687 688 /* 689 * In order to avoid unnecessary contention on interlocking mutexes, we try 690 * to defer waking up threads until we unlock the mutex. The threads will 691 * be woken up when the calling thread (self) releases the mutex. 692 */ 693 void 694 pthread__mutex_deferwake(pthread_t self, pthread_mutex_t *ptm, 695 struct pthread__waiter *head) 696 { 697 struct pthread__waiter *tail, *n, *o; 698 699 pthread__assert(head != NULL); 700 701 if (__predict_false(ptm == NULL || 702 MUTEX_OWNER(ptm->ptm_owner) != (uintptr_t)self)) { 703 pthread__mutex_wakeup(self, head); 704 return; 705 } 706 707 /* This is easy if no existing waiters on mutex. */ 708 if (atomic_cas_ptr(&ptm->ptm_waiters, NULL, head) == NULL) { 709 return; 710 } 711 712 /* Oops need to append. Find the tail of the new queue. */ 713 for (tail = head; tail->next != NULL; tail = tail->next) { 714 /* nothing */ 715 } 716 717 /* Append atomically. */ 718 for (o = ptm->ptm_waiters;; o = n) { 719 tail->next = o; 720 #ifndef PTHREAD__ATOMIC_IS_MEMBAR 721 membar_producer(); 722 #endif 723 n = atomic_cas_ptr(&ptm->ptm_waiters, o, head); 724 if (__predict_true(n == o)) { 725 break; 726 } 727 } 728 } 729 730 int 731 pthread_mutex_getprioceiling(const pthread_mutex_t *ptm, int *ceil) 732 { 733 734 pthread__error(EINVAL, "Invalid mutex", 735 ptm->ptm_magic == _PT_MUTEX_MAGIC); 736 737 *ceil = ptm->ptm_ceiling; 738 return 0; 739 } 740 741 int 742 pthread_mutex_setprioceiling(pthread_mutex_t *ptm, int ceil, int *old_ceil) 743 { 744 int error; 745 746 pthread__error(EINVAL, "Invalid mutex", 747 ptm->ptm_magic == _PT_MUTEX_MAGIC); 748 749 error = pthread_mutex_lock(ptm); 750 if (error == 0) { 751 *old_ceil = ptm->ptm_ceiling; 752 /*check range*/ 753 ptm->ptm_ceiling = ceil; 754 pthread_mutex_unlock(ptm); 755 } 756 return error; 757 } 758 759 int 760 _pthread_mutex_held_np(pthread_mutex_t *ptm) 761 { 762 763 return MUTEX_OWNER(ptm->ptm_owner) == (uintptr_t)pthread__self(); 764 } 765 766 pthread_t 767 _pthread_mutex_owner_np(pthread_mutex_t *ptm) 768 { 769 770 return (pthread_t)MUTEX_OWNER(ptm->ptm_owner); 771 } 772