1 /*- 2 * Copyright (c) 2007 Attilio Rao <attilio@freebsd.org> 3 * Copyright (c) 2001 Jason Evans <jasone@freebsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice(s), this list of conditions and the following disclaimer as 11 * the first lines of this file unmodified other than the possible 12 * addition of one or more copyright notices. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice(s), this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 27 * DAMAGE. 28 */ 29 30 /* 31 * Shared/exclusive locks. This implementation attempts to ensure 32 * deterministic lock granting behavior, so that slocks and xlocks are 33 * interleaved. 34 * 35 * Priority propagation will not generally raise the priority of lock holders, 36 * so should not be relied upon in combination with sx locks. 37 */ 38 39 #include "opt_ddb.h" 40 #include "opt_hwpmc_hooks.h" 41 #include "opt_kdtrace.h" 42 #include "opt_no_adaptive_sx.h" 43 44 #include <sys/cdefs.h> 45 __FBSDID("$FreeBSD$"); 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/ktr.h> 50 #include <sys/lock.h> 51 #include <sys/mutex.h> 52 #include <sys/proc.h> 53 #include <sys/sleepqueue.h> 54 #include <sys/sx.h> 55 #include <sys/sysctl.h> 56 57 #if defined(SMP) && !defined(NO_ADAPTIVE_SX) 58 #include <machine/cpu.h> 59 #endif 60 61 #ifdef DDB 62 #include <ddb/ddb.h> 63 #endif 64 65 #if defined(SMP) && !defined(NO_ADAPTIVE_SX) 66 #define ADAPTIVE_SX 67 #endif 68 69 CTASSERT((SX_NOADAPTIVE & LO_CLASSFLAGS) == SX_NOADAPTIVE); 70 71 #ifdef HWPMC_HOOKS 72 #include <sys/pmckern.h> 73 PMC_SOFT_DECLARE( , , lock, failed); 74 #endif 75 76 /* Handy macros for sleep queues. */ 77 #define SQ_EXCLUSIVE_QUEUE 0 78 #define SQ_SHARED_QUEUE 1 79 80 /* 81 * Variations on DROP_GIANT()/PICKUP_GIANT() for use in this file. We 82 * drop Giant anytime we have to sleep or if we adaptively spin. 83 */ 84 #define GIANT_DECLARE \ 85 int _giantcnt = 0; \ 86 WITNESS_SAVE_DECL(Giant) \ 87 88 #define GIANT_SAVE() do { \ 89 if (mtx_owned(&Giant)) { \ 90 WITNESS_SAVE(&Giant.lock_object, Giant); \ 91 while (mtx_owned(&Giant)) { \ 92 _giantcnt++; \ 93 mtx_unlock(&Giant); \ 94 } \ 95 } \ 96 } while (0) 97 98 #define GIANT_RESTORE() do { \ 99 if (_giantcnt > 0) { \ 100 mtx_assert(&Giant, MA_NOTOWNED); \ 101 while (_giantcnt--) \ 102 mtx_lock(&Giant); \ 103 WITNESS_RESTORE(&Giant.lock_object, Giant); \ 104 } \ 105 } while (0) 106 107 /* 108 * Returns true if an exclusive lock is recursed. It assumes 109 * curthread currently has an exclusive lock. 110 */ 111 #define sx_recurse lock_object.lo_data 112 #define sx_recursed(sx) ((sx)->sx_recurse != 0) 113 114 static void assert_sx(const struct lock_object *lock, int what); 115 #ifdef DDB 116 static void db_show_sx(const struct lock_object *lock); 117 #endif 118 static void lock_sx(struct lock_object *lock, int how); 119 #ifdef KDTRACE_HOOKS 120 static int owner_sx(const struct lock_object *lock, struct thread **owner); 121 #endif 122 static int unlock_sx(struct lock_object *lock); 123 124 struct lock_class lock_class_sx = { 125 .lc_name = "sx", 126 .lc_flags = LC_SLEEPLOCK | LC_SLEEPABLE | LC_RECURSABLE | LC_UPGRADABLE, 127 .lc_assert = assert_sx, 128 #ifdef DDB 129 .lc_ddb_show = db_show_sx, 130 #endif 131 .lc_lock = lock_sx, 132 .lc_unlock = unlock_sx, 133 #ifdef KDTRACE_HOOKS 134 .lc_owner = owner_sx, 135 #endif 136 }; 137 138 #ifndef INVARIANTS 139 #define _sx_assert(sx, what, file, line) 140 #endif 141 142 #ifdef ADAPTIVE_SX 143 static u_int asx_retries = 10; 144 static u_int asx_loops = 10000; 145 static SYSCTL_NODE(_debug, OID_AUTO, sx, CTLFLAG_RD, NULL, "sxlock debugging"); 146 SYSCTL_UINT(_debug_sx, OID_AUTO, retries, CTLFLAG_RW, &asx_retries, 0, ""); 147 SYSCTL_UINT(_debug_sx, OID_AUTO, loops, CTLFLAG_RW, &asx_loops, 0, ""); 148 #endif 149 150 void 151 assert_sx(const struct lock_object *lock, int what) 152 { 153 154 sx_assert((const struct sx *)lock, what); 155 } 156 157 void 158 lock_sx(struct lock_object *lock, int how) 159 { 160 struct sx *sx; 161 162 sx = (struct sx *)lock; 163 if (how) 164 sx_xlock(sx); 165 else 166 sx_slock(sx); 167 } 168 169 int 170 unlock_sx(struct lock_object *lock) 171 { 172 struct sx *sx; 173 174 sx = (struct sx *)lock; 175 sx_assert(sx, SA_LOCKED | SA_NOTRECURSED); 176 if (sx_xlocked(sx)) { 177 sx_xunlock(sx); 178 return (1); 179 } else { 180 sx_sunlock(sx); 181 return (0); 182 } 183 } 184 185 #ifdef KDTRACE_HOOKS 186 int 187 owner_sx(const struct lock_object *lock, struct thread **owner) 188 { 189 const struct sx *sx = (const struct sx *)lock; 190 uintptr_t x = sx->sx_lock; 191 192 *owner = (struct thread *)SX_OWNER(x); 193 return ((x & SX_LOCK_SHARED) != 0 ? (SX_SHARERS(x) != 0) : 194 (*owner != NULL)); 195 } 196 #endif 197 198 void 199 sx_sysinit(void *arg) 200 { 201 struct sx_args *sargs = arg; 202 203 sx_init_flags(sargs->sa_sx, sargs->sa_desc, sargs->sa_flags); 204 } 205 206 void 207 sx_init_flags(struct sx *sx, const char *description, int opts) 208 { 209 int flags; 210 211 MPASS((opts & ~(SX_QUIET | SX_RECURSE | SX_NOWITNESS | SX_DUPOK | 212 SX_NOPROFILE | SX_NOADAPTIVE)) == 0); 213 ASSERT_ATOMIC_LOAD_PTR(sx->sx_lock, 214 ("%s: sx_lock not aligned for %s: %p", __func__, description, 215 &sx->sx_lock)); 216 217 flags = LO_SLEEPABLE | LO_UPGRADABLE; 218 if (opts & SX_DUPOK) 219 flags |= LO_DUPOK; 220 if (opts & SX_NOPROFILE) 221 flags |= LO_NOPROFILE; 222 if (!(opts & SX_NOWITNESS)) 223 flags |= LO_WITNESS; 224 if (opts & SX_RECURSE) 225 flags |= LO_RECURSABLE; 226 if (opts & SX_QUIET) 227 flags |= LO_QUIET; 228 229 flags |= opts & SX_NOADAPTIVE; 230 sx->sx_lock = SX_LOCK_UNLOCKED; 231 sx->sx_recurse = 0; 232 lock_init(&sx->lock_object, &lock_class_sx, description, NULL, flags); 233 } 234 235 void 236 sx_destroy(struct sx *sx) 237 { 238 239 KASSERT(sx->sx_lock == SX_LOCK_UNLOCKED, ("sx lock still held")); 240 KASSERT(sx->sx_recurse == 0, ("sx lock still recursed")); 241 sx->sx_lock = SX_LOCK_DESTROYED; 242 lock_destroy(&sx->lock_object); 243 } 244 245 int 246 _sx_slock(struct sx *sx, int opts, const char *file, int line) 247 { 248 int error = 0; 249 250 if (SCHEDULER_STOPPED()) 251 return (0); 252 MPASS(curthread != NULL); 253 KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, 254 ("sx_slock() of destroyed sx @ %s:%d", file, line)); 255 WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER, file, line, NULL); 256 error = __sx_slock(sx, opts, file, line); 257 if (!error) { 258 LOCK_LOG_LOCK("SLOCK", &sx->lock_object, 0, 0, file, line); 259 WITNESS_LOCK(&sx->lock_object, 0, file, line); 260 curthread->td_locks++; 261 } 262 263 return (error); 264 } 265 266 int 267 sx_try_slock_(struct sx *sx, const char *file, int line) 268 { 269 uintptr_t x; 270 271 if (SCHEDULER_STOPPED()) 272 return (1); 273 274 for (;;) { 275 x = sx->sx_lock; 276 KASSERT(x != SX_LOCK_DESTROYED, 277 ("sx_try_slock() of destroyed sx @ %s:%d", file, line)); 278 if (!(x & SX_LOCK_SHARED)) 279 break; 280 if (atomic_cmpset_acq_ptr(&sx->sx_lock, x, x + SX_ONE_SHARER)) { 281 LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 1, file, line); 282 WITNESS_LOCK(&sx->lock_object, LOP_TRYLOCK, file, line); 283 curthread->td_locks++; 284 return (1); 285 } 286 } 287 288 LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 0, file, line); 289 return (0); 290 } 291 292 int 293 _sx_xlock(struct sx *sx, int opts, const char *file, int line) 294 { 295 int error = 0; 296 297 if (SCHEDULER_STOPPED()) 298 return (0); 299 MPASS(curthread != NULL); 300 KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, 301 ("sx_xlock() of destroyed sx @ %s:%d", file, line)); 302 WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE, file, 303 line, NULL); 304 error = __sx_xlock(sx, curthread, opts, file, line); 305 if (!error) { 306 LOCK_LOG_LOCK("XLOCK", &sx->lock_object, 0, sx->sx_recurse, 307 file, line); 308 WITNESS_LOCK(&sx->lock_object, LOP_EXCLUSIVE, file, line); 309 curthread->td_locks++; 310 } 311 312 return (error); 313 } 314 315 int 316 sx_try_xlock_(struct sx *sx, const char *file, int line) 317 { 318 int rval; 319 320 if (SCHEDULER_STOPPED()) 321 return (1); 322 323 MPASS(curthread != NULL); 324 KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, 325 ("sx_try_xlock() of destroyed sx @ %s:%d", file, line)); 326 327 if (sx_xlocked(sx) && 328 (sx->lock_object.lo_flags & LO_RECURSABLE) != 0) { 329 sx->sx_recurse++; 330 atomic_set_ptr(&sx->sx_lock, SX_LOCK_RECURSED); 331 rval = 1; 332 } else 333 rval = atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED, 334 (uintptr_t)curthread); 335 LOCK_LOG_TRY("XLOCK", &sx->lock_object, 0, rval, file, line); 336 if (rval) { 337 WITNESS_LOCK(&sx->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK, 338 file, line); 339 curthread->td_locks++; 340 } 341 342 return (rval); 343 } 344 345 void 346 _sx_sunlock(struct sx *sx, const char *file, int line) 347 { 348 349 if (SCHEDULER_STOPPED()) 350 return; 351 MPASS(curthread != NULL); 352 KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, 353 ("sx_sunlock() of destroyed sx @ %s:%d", file, line)); 354 _sx_assert(sx, SA_SLOCKED, file, line); 355 curthread->td_locks--; 356 WITNESS_UNLOCK(&sx->lock_object, 0, file, line); 357 LOCK_LOG_LOCK("SUNLOCK", &sx->lock_object, 0, 0, file, line); 358 __sx_sunlock(sx, file, line); 359 LOCKSTAT_PROFILE_RELEASE_LOCK(LS_SX_SUNLOCK_RELEASE, sx); 360 } 361 362 void 363 _sx_xunlock(struct sx *sx, const char *file, int line) 364 { 365 366 if (SCHEDULER_STOPPED()) 367 return; 368 MPASS(curthread != NULL); 369 KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, 370 ("sx_xunlock() of destroyed sx @ %s:%d", file, line)); 371 _sx_assert(sx, SA_XLOCKED, file, line); 372 curthread->td_locks--; 373 WITNESS_UNLOCK(&sx->lock_object, LOP_EXCLUSIVE, file, line); 374 LOCK_LOG_LOCK("XUNLOCK", &sx->lock_object, 0, sx->sx_recurse, file, 375 line); 376 if (!sx_recursed(sx)) 377 LOCKSTAT_PROFILE_RELEASE_LOCK(LS_SX_XUNLOCK_RELEASE, sx); 378 __sx_xunlock(sx, curthread, file, line); 379 } 380 381 /* 382 * Try to do a non-blocking upgrade from a shared lock to an exclusive lock. 383 * This will only succeed if this thread holds a single shared lock. 384 * Return 1 if if the upgrade succeed, 0 otherwise. 385 */ 386 int 387 sx_try_upgrade_(struct sx *sx, const char *file, int line) 388 { 389 uintptr_t x; 390 int success; 391 392 if (SCHEDULER_STOPPED()) 393 return (1); 394 395 KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, 396 ("sx_try_upgrade() of destroyed sx @ %s:%d", file, line)); 397 _sx_assert(sx, SA_SLOCKED, file, line); 398 399 /* 400 * Try to switch from one shared lock to an exclusive lock. We need 401 * to maintain the SX_LOCK_EXCLUSIVE_WAITERS flag if set so that 402 * we will wake up the exclusive waiters when we drop the lock. 403 */ 404 x = sx->sx_lock & SX_LOCK_EXCLUSIVE_WAITERS; 405 success = atomic_cmpset_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) | x, 406 (uintptr_t)curthread | x); 407 LOCK_LOG_TRY("XUPGRADE", &sx->lock_object, 0, success, file, line); 408 if (success) { 409 WITNESS_UPGRADE(&sx->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK, 410 file, line); 411 LOCKSTAT_RECORD0(LS_SX_TRYUPGRADE_UPGRADE, sx); 412 } 413 return (success); 414 } 415 416 /* 417 * Downgrade an unrecursed exclusive lock into a single shared lock. 418 */ 419 void 420 sx_downgrade_(struct sx *sx, const char *file, int line) 421 { 422 uintptr_t x; 423 int wakeup_swapper; 424 425 if (SCHEDULER_STOPPED()) 426 return; 427 428 KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, 429 ("sx_downgrade() of destroyed sx @ %s:%d", file, line)); 430 _sx_assert(sx, SA_XLOCKED | SA_NOTRECURSED, file, line); 431 #ifndef INVARIANTS 432 if (sx_recursed(sx)) 433 panic("downgrade of a recursed lock"); 434 #endif 435 436 WITNESS_DOWNGRADE(&sx->lock_object, 0, file, line); 437 438 /* 439 * Try to switch from an exclusive lock with no shared waiters 440 * to one sharer with no shared waiters. If there are 441 * exclusive waiters, we don't need to lock the sleep queue so 442 * long as we preserve the flag. We do one quick try and if 443 * that fails we grab the sleepq lock to keep the flags from 444 * changing and do it the slow way. 445 * 446 * We have to lock the sleep queue if there are shared waiters 447 * so we can wake them up. 448 */ 449 x = sx->sx_lock; 450 if (!(x & SX_LOCK_SHARED_WAITERS) && 451 atomic_cmpset_rel_ptr(&sx->sx_lock, x, SX_SHARERS_LOCK(1) | 452 (x & SX_LOCK_EXCLUSIVE_WAITERS))) { 453 LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line); 454 return; 455 } 456 457 /* 458 * Lock the sleep queue so we can read the waiters bits 459 * without any races and wakeup any shared waiters. 460 */ 461 sleepq_lock(&sx->lock_object); 462 463 /* 464 * Preserve SX_LOCK_EXCLUSIVE_WAITERS while downgraded to a single 465 * shared lock. If there are any shared waiters, wake them up. 466 */ 467 wakeup_swapper = 0; 468 x = sx->sx_lock; 469 atomic_store_rel_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) | 470 (x & SX_LOCK_EXCLUSIVE_WAITERS)); 471 if (x & SX_LOCK_SHARED_WAITERS) 472 wakeup_swapper = sleepq_broadcast(&sx->lock_object, SLEEPQ_SX, 473 0, SQ_SHARED_QUEUE); 474 sleepq_release(&sx->lock_object); 475 476 LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line); 477 LOCKSTAT_RECORD0(LS_SX_DOWNGRADE_DOWNGRADE, sx); 478 479 if (wakeup_swapper) 480 kick_proc0(); 481 } 482 483 /* 484 * This function represents the so-called 'hard case' for sx_xlock 485 * operation. All 'easy case' failures are redirected to this. Note 486 * that ideally this would be a static function, but it needs to be 487 * accessible from at least sx.h. 488 */ 489 int 490 _sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts, const char *file, 491 int line) 492 { 493 GIANT_DECLARE; 494 #ifdef ADAPTIVE_SX 495 volatile struct thread *owner; 496 u_int i, spintries = 0; 497 #endif 498 uintptr_t x; 499 #ifdef LOCK_PROFILING 500 uint64_t waittime = 0; 501 int contested = 0; 502 #endif 503 int error = 0; 504 #ifdef KDTRACE_HOOKS 505 uint64_t spin_cnt = 0; 506 uint64_t sleep_cnt = 0; 507 int64_t sleep_time = 0; 508 #endif 509 510 if (SCHEDULER_STOPPED()) 511 return (0); 512 513 /* If we already hold an exclusive lock, then recurse. */ 514 if (sx_xlocked(sx)) { 515 KASSERT((sx->lock_object.lo_flags & LO_RECURSABLE) != 0, 516 ("_sx_xlock_hard: recursed on non-recursive sx %s @ %s:%d\n", 517 sx->lock_object.lo_name, file, line)); 518 sx->sx_recurse++; 519 atomic_set_ptr(&sx->sx_lock, SX_LOCK_RECURSED); 520 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 521 CTR2(KTR_LOCK, "%s: %p recursing", __func__, sx); 522 return (0); 523 } 524 525 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 526 CTR5(KTR_LOCK, "%s: %s contested (lock=%p) at %s:%d", __func__, 527 sx->lock_object.lo_name, (void *)sx->sx_lock, file, line); 528 529 while (!atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED, tid)) { 530 #ifdef KDTRACE_HOOKS 531 spin_cnt++; 532 #endif 533 #ifdef HWPMC_HOOKS 534 PMC_SOFT_CALL( , , lock, failed); 535 #endif 536 lock_profile_obtain_lock_failed(&sx->lock_object, &contested, 537 &waittime); 538 #ifdef ADAPTIVE_SX 539 /* 540 * If the lock is write locked and the owner is 541 * running on another CPU, spin until the owner stops 542 * running or the state of the lock changes. 543 */ 544 x = sx->sx_lock; 545 if ((sx->lock_object.lo_flags & SX_NOADAPTIVE) == 0) { 546 if ((x & SX_LOCK_SHARED) == 0) { 547 x = SX_OWNER(x); 548 owner = (struct thread *)x; 549 if (TD_IS_RUNNING(owner)) { 550 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 551 CTR3(KTR_LOCK, 552 "%s: spinning on %p held by %p", 553 __func__, sx, owner); 554 GIANT_SAVE(); 555 while (SX_OWNER(sx->sx_lock) == x && 556 TD_IS_RUNNING(owner)) { 557 cpu_spinwait(); 558 #ifdef KDTRACE_HOOKS 559 spin_cnt++; 560 #endif 561 } 562 continue; 563 } 564 } else if (SX_SHARERS(x) && spintries < asx_retries) { 565 GIANT_SAVE(); 566 spintries++; 567 for (i = 0; i < asx_loops; i++) { 568 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 569 CTR4(KTR_LOCK, 570 "%s: shared spinning on %p with %u and %u", 571 __func__, sx, spintries, i); 572 x = sx->sx_lock; 573 if ((x & SX_LOCK_SHARED) == 0 || 574 SX_SHARERS(x) == 0) 575 break; 576 cpu_spinwait(); 577 #ifdef KDTRACE_HOOKS 578 spin_cnt++; 579 #endif 580 } 581 if (i != asx_loops) 582 continue; 583 } 584 } 585 #endif 586 587 sleepq_lock(&sx->lock_object); 588 x = sx->sx_lock; 589 590 /* 591 * If the lock was released while spinning on the 592 * sleep queue chain lock, try again. 593 */ 594 if (x == SX_LOCK_UNLOCKED) { 595 sleepq_release(&sx->lock_object); 596 continue; 597 } 598 599 #ifdef ADAPTIVE_SX 600 /* 601 * The current lock owner might have started executing 602 * on another CPU (or the lock could have changed 603 * owners) while we were waiting on the sleep queue 604 * chain lock. If so, drop the sleep queue lock and try 605 * again. 606 */ 607 if (!(x & SX_LOCK_SHARED) && 608 (sx->lock_object.lo_flags & SX_NOADAPTIVE) == 0) { 609 owner = (struct thread *)SX_OWNER(x); 610 if (TD_IS_RUNNING(owner)) { 611 sleepq_release(&sx->lock_object); 612 continue; 613 } 614 } 615 #endif 616 617 /* 618 * If an exclusive lock was released with both shared 619 * and exclusive waiters and a shared waiter hasn't 620 * woken up and acquired the lock yet, sx_lock will be 621 * set to SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS. 622 * If we see that value, try to acquire it once. Note 623 * that we have to preserve SX_LOCK_EXCLUSIVE_WAITERS 624 * as there are other exclusive waiters still. If we 625 * fail, restart the loop. 626 */ 627 if (x == (SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS)) { 628 if (atomic_cmpset_acq_ptr(&sx->sx_lock, 629 SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS, 630 tid | SX_LOCK_EXCLUSIVE_WAITERS)) { 631 sleepq_release(&sx->lock_object); 632 CTR2(KTR_LOCK, "%s: %p claimed by new writer", 633 __func__, sx); 634 break; 635 } 636 sleepq_release(&sx->lock_object); 637 continue; 638 } 639 640 /* 641 * Try to set the SX_LOCK_EXCLUSIVE_WAITERS. If we fail, 642 * than loop back and retry. 643 */ 644 if (!(x & SX_LOCK_EXCLUSIVE_WAITERS)) { 645 if (!atomic_cmpset_ptr(&sx->sx_lock, x, 646 x | SX_LOCK_EXCLUSIVE_WAITERS)) { 647 sleepq_release(&sx->lock_object); 648 continue; 649 } 650 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 651 CTR2(KTR_LOCK, "%s: %p set excl waiters flag", 652 __func__, sx); 653 } 654 655 /* 656 * Since we have been unable to acquire the exclusive 657 * lock and the exclusive waiters flag is set, we have 658 * to sleep. 659 */ 660 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 661 CTR2(KTR_LOCK, "%s: %p blocking on sleep queue", 662 __func__, sx); 663 664 #ifdef KDTRACE_HOOKS 665 sleep_time -= lockstat_nsecs(); 666 #endif 667 GIANT_SAVE(); 668 sleepq_add(&sx->lock_object, NULL, sx->lock_object.lo_name, 669 SLEEPQ_SX | ((opts & SX_INTERRUPTIBLE) ? 670 SLEEPQ_INTERRUPTIBLE : 0), SQ_EXCLUSIVE_QUEUE); 671 if (!(opts & SX_INTERRUPTIBLE)) 672 sleepq_wait(&sx->lock_object, 0); 673 else 674 error = sleepq_wait_sig(&sx->lock_object, 0); 675 #ifdef KDTRACE_HOOKS 676 sleep_time += lockstat_nsecs(); 677 sleep_cnt++; 678 #endif 679 if (error) { 680 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 681 CTR2(KTR_LOCK, 682 "%s: interruptible sleep by %p suspended by signal", 683 __func__, sx); 684 break; 685 } 686 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 687 CTR2(KTR_LOCK, "%s: %p resuming from sleep queue", 688 __func__, sx); 689 } 690 691 GIANT_RESTORE(); 692 if (!error) 693 LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_SX_XLOCK_ACQUIRE, sx, 694 contested, waittime, file, line); 695 #ifdef KDTRACE_HOOKS 696 if (sleep_time) 697 LOCKSTAT_RECORD1(LS_SX_XLOCK_BLOCK, sx, sleep_time); 698 if (spin_cnt > sleep_cnt) 699 LOCKSTAT_RECORD1(LS_SX_XLOCK_SPIN, sx, (spin_cnt - sleep_cnt)); 700 #endif 701 return (error); 702 } 703 704 /* 705 * This function represents the so-called 'hard case' for sx_xunlock 706 * operation. All 'easy case' failures are redirected to this. Note 707 * that ideally this would be a static function, but it needs to be 708 * accessible from at least sx.h. 709 */ 710 void 711 _sx_xunlock_hard(struct sx *sx, uintptr_t tid, const char *file, int line) 712 { 713 uintptr_t x; 714 int queue, wakeup_swapper; 715 716 if (SCHEDULER_STOPPED()) 717 return; 718 719 MPASS(!(sx->sx_lock & SX_LOCK_SHARED)); 720 721 /* If the lock is recursed, then unrecurse one level. */ 722 if (sx_xlocked(sx) && sx_recursed(sx)) { 723 if ((--sx->sx_recurse) == 0) 724 atomic_clear_ptr(&sx->sx_lock, SX_LOCK_RECURSED); 725 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 726 CTR2(KTR_LOCK, "%s: %p unrecursing", __func__, sx); 727 return; 728 } 729 MPASS(sx->sx_lock & (SX_LOCK_SHARED_WAITERS | 730 SX_LOCK_EXCLUSIVE_WAITERS)); 731 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 732 CTR2(KTR_LOCK, "%s: %p contested", __func__, sx); 733 734 sleepq_lock(&sx->lock_object); 735 x = SX_LOCK_UNLOCKED; 736 737 /* 738 * The wake up algorithm here is quite simple and probably not 739 * ideal. It gives precedence to shared waiters if they are 740 * present. For this condition, we have to preserve the 741 * state of the exclusive waiters flag. 742 * If interruptible sleeps left the shared queue empty avoid a 743 * starvation for the threads sleeping on the exclusive queue by giving 744 * them precedence and cleaning up the shared waiters bit anyway. 745 */ 746 if ((sx->sx_lock & SX_LOCK_SHARED_WAITERS) != 0 && 747 sleepq_sleepcnt(&sx->lock_object, SQ_SHARED_QUEUE) != 0) { 748 queue = SQ_SHARED_QUEUE; 749 x |= (sx->sx_lock & SX_LOCK_EXCLUSIVE_WAITERS); 750 } else 751 queue = SQ_EXCLUSIVE_QUEUE; 752 753 /* Wake up all the waiters for the specific queue. */ 754 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 755 CTR3(KTR_LOCK, "%s: %p waking up all threads on %s queue", 756 __func__, sx, queue == SQ_SHARED_QUEUE ? "shared" : 757 "exclusive"); 758 atomic_store_rel_ptr(&sx->sx_lock, x); 759 wakeup_swapper = sleepq_broadcast(&sx->lock_object, SLEEPQ_SX, 0, 760 queue); 761 sleepq_release(&sx->lock_object); 762 if (wakeup_swapper) 763 kick_proc0(); 764 } 765 766 /* 767 * This function represents the so-called 'hard case' for sx_slock 768 * operation. All 'easy case' failures are redirected to this. Note 769 * that ideally this would be a static function, but it needs to be 770 * accessible from at least sx.h. 771 */ 772 int 773 _sx_slock_hard(struct sx *sx, int opts, const char *file, int line) 774 { 775 GIANT_DECLARE; 776 #ifdef ADAPTIVE_SX 777 volatile struct thread *owner; 778 #endif 779 #ifdef LOCK_PROFILING 780 uint64_t waittime = 0; 781 int contested = 0; 782 #endif 783 uintptr_t x; 784 int error = 0; 785 #ifdef KDTRACE_HOOKS 786 uint64_t spin_cnt = 0; 787 uint64_t sleep_cnt = 0; 788 int64_t sleep_time = 0; 789 #endif 790 791 if (SCHEDULER_STOPPED()) 792 return (0); 793 794 /* 795 * As with rwlocks, we don't make any attempt to try to block 796 * shared locks once there is an exclusive waiter. 797 */ 798 for (;;) { 799 #ifdef KDTRACE_HOOKS 800 spin_cnt++; 801 #endif 802 x = sx->sx_lock; 803 804 /* 805 * If no other thread has an exclusive lock then try to bump up 806 * the count of sharers. Since we have to preserve the state 807 * of SX_LOCK_EXCLUSIVE_WAITERS, if we fail to acquire the 808 * shared lock loop back and retry. 809 */ 810 if (x & SX_LOCK_SHARED) { 811 MPASS(!(x & SX_LOCK_SHARED_WAITERS)); 812 if (atomic_cmpset_acq_ptr(&sx->sx_lock, x, 813 x + SX_ONE_SHARER)) { 814 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 815 CTR4(KTR_LOCK, 816 "%s: %p succeed %p -> %p", __func__, 817 sx, (void *)x, 818 (void *)(x + SX_ONE_SHARER)); 819 break; 820 } 821 continue; 822 } 823 #ifdef HWPMC_HOOKS 824 PMC_SOFT_CALL( , , lock, failed); 825 #endif 826 lock_profile_obtain_lock_failed(&sx->lock_object, &contested, 827 &waittime); 828 829 #ifdef ADAPTIVE_SX 830 /* 831 * If the owner is running on another CPU, spin until 832 * the owner stops running or the state of the lock 833 * changes. 834 */ 835 if ((sx->lock_object.lo_flags & SX_NOADAPTIVE) == 0) { 836 x = SX_OWNER(x); 837 owner = (struct thread *)x; 838 if (TD_IS_RUNNING(owner)) { 839 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 840 CTR3(KTR_LOCK, 841 "%s: spinning on %p held by %p", 842 __func__, sx, owner); 843 GIANT_SAVE(); 844 while (SX_OWNER(sx->sx_lock) == x && 845 TD_IS_RUNNING(owner)) { 846 #ifdef KDTRACE_HOOKS 847 spin_cnt++; 848 #endif 849 cpu_spinwait(); 850 } 851 continue; 852 } 853 } 854 #endif 855 856 /* 857 * Some other thread already has an exclusive lock, so 858 * start the process of blocking. 859 */ 860 sleepq_lock(&sx->lock_object); 861 x = sx->sx_lock; 862 863 /* 864 * The lock could have been released while we spun. 865 * In this case loop back and retry. 866 */ 867 if (x & SX_LOCK_SHARED) { 868 sleepq_release(&sx->lock_object); 869 continue; 870 } 871 872 #ifdef ADAPTIVE_SX 873 /* 874 * If the owner is running on another CPU, spin until 875 * the owner stops running or the state of the lock 876 * changes. 877 */ 878 if (!(x & SX_LOCK_SHARED) && 879 (sx->lock_object.lo_flags & SX_NOADAPTIVE) == 0) { 880 owner = (struct thread *)SX_OWNER(x); 881 if (TD_IS_RUNNING(owner)) { 882 sleepq_release(&sx->lock_object); 883 continue; 884 } 885 } 886 #endif 887 888 /* 889 * Try to set the SX_LOCK_SHARED_WAITERS flag. If we 890 * fail to set it drop the sleep queue lock and loop 891 * back. 892 */ 893 if (!(x & SX_LOCK_SHARED_WAITERS)) { 894 if (!atomic_cmpset_ptr(&sx->sx_lock, x, 895 x | SX_LOCK_SHARED_WAITERS)) { 896 sleepq_release(&sx->lock_object); 897 continue; 898 } 899 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 900 CTR2(KTR_LOCK, "%s: %p set shared waiters flag", 901 __func__, sx); 902 } 903 904 /* 905 * Since we have been unable to acquire the shared lock, 906 * we have to sleep. 907 */ 908 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 909 CTR2(KTR_LOCK, "%s: %p blocking on sleep queue", 910 __func__, sx); 911 912 #ifdef KDTRACE_HOOKS 913 sleep_time -= lockstat_nsecs(); 914 #endif 915 GIANT_SAVE(); 916 sleepq_add(&sx->lock_object, NULL, sx->lock_object.lo_name, 917 SLEEPQ_SX | ((opts & SX_INTERRUPTIBLE) ? 918 SLEEPQ_INTERRUPTIBLE : 0), SQ_SHARED_QUEUE); 919 if (!(opts & SX_INTERRUPTIBLE)) 920 sleepq_wait(&sx->lock_object, 0); 921 else 922 error = sleepq_wait_sig(&sx->lock_object, 0); 923 #ifdef KDTRACE_HOOKS 924 sleep_time += lockstat_nsecs(); 925 sleep_cnt++; 926 #endif 927 if (error) { 928 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 929 CTR2(KTR_LOCK, 930 "%s: interruptible sleep by %p suspended by signal", 931 __func__, sx); 932 break; 933 } 934 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 935 CTR2(KTR_LOCK, "%s: %p resuming from sleep queue", 936 __func__, sx); 937 } 938 if (error == 0) 939 LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_SX_SLOCK_ACQUIRE, sx, 940 contested, waittime, file, line); 941 #ifdef KDTRACE_HOOKS 942 if (sleep_time) 943 LOCKSTAT_RECORD1(LS_SX_XLOCK_BLOCK, sx, sleep_time); 944 if (spin_cnt > sleep_cnt) 945 LOCKSTAT_RECORD1(LS_SX_XLOCK_SPIN, sx, (spin_cnt - sleep_cnt)); 946 #endif 947 GIANT_RESTORE(); 948 return (error); 949 } 950 951 /* 952 * This function represents the so-called 'hard case' for sx_sunlock 953 * operation. All 'easy case' failures are redirected to this. Note 954 * that ideally this would be a static function, but it needs to be 955 * accessible from at least sx.h. 956 */ 957 void 958 _sx_sunlock_hard(struct sx *sx, const char *file, int line) 959 { 960 uintptr_t x; 961 int wakeup_swapper; 962 963 if (SCHEDULER_STOPPED()) 964 return; 965 966 for (;;) { 967 x = sx->sx_lock; 968 969 /* 970 * We should never have sharers while at least one thread 971 * holds a shared lock. 972 */ 973 KASSERT(!(x & SX_LOCK_SHARED_WAITERS), 974 ("%s: waiting sharers", __func__)); 975 976 /* 977 * See if there is more than one shared lock held. If 978 * so, just drop one and return. 979 */ 980 if (SX_SHARERS(x) > 1) { 981 if (atomic_cmpset_rel_ptr(&sx->sx_lock, x, 982 x - SX_ONE_SHARER)) { 983 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 984 CTR4(KTR_LOCK, 985 "%s: %p succeeded %p -> %p", 986 __func__, sx, (void *)x, 987 (void *)(x - SX_ONE_SHARER)); 988 break; 989 } 990 continue; 991 } 992 993 /* 994 * If there aren't any waiters for an exclusive lock, 995 * then try to drop it quickly. 996 */ 997 if (!(x & SX_LOCK_EXCLUSIVE_WAITERS)) { 998 MPASS(x == SX_SHARERS_LOCK(1)); 999 if (atomic_cmpset_rel_ptr(&sx->sx_lock, 1000 SX_SHARERS_LOCK(1), SX_LOCK_UNLOCKED)) { 1001 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 1002 CTR2(KTR_LOCK, "%s: %p last succeeded", 1003 __func__, sx); 1004 break; 1005 } 1006 continue; 1007 } 1008 1009 /* 1010 * At this point, there should just be one sharer with 1011 * exclusive waiters. 1012 */ 1013 MPASS(x == (SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS)); 1014 1015 sleepq_lock(&sx->lock_object); 1016 1017 /* 1018 * Wake up semantic here is quite simple: 1019 * Just wake up all the exclusive waiters. 1020 * Note that the state of the lock could have changed, 1021 * so if it fails loop back and retry. 1022 */ 1023 if (!atomic_cmpset_rel_ptr(&sx->sx_lock, 1024 SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS, 1025 SX_LOCK_UNLOCKED)) { 1026 sleepq_release(&sx->lock_object); 1027 continue; 1028 } 1029 if (LOCK_LOG_TEST(&sx->lock_object, 0)) 1030 CTR2(KTR_LOCK, "%s: %p waking up all thread on" 1031 "exclusive queue", __func__, sx); 1032 wakeup_swapper = sleepq_broadcast(&sx->lock_object, SLEEPQ_SX, 1033 0, SQ_EXCLUSIVE_QUEUE); 1034 sleepq_release(&sx->lock_object); 1035 if (wakeup_swapper) 1036 kick_proc0(); 1037 break; 1038 } 1039 } 1040 1041 #ifdef INVARIANT_SUPPORT 1042 #ifndef INVARIANTS 1043 #undef _sx_assert 1044 #endif 1045 1046 /* 1047 * In the non-WITNESS case, sx_assert() can only detect that at least 1048 * *some* thread owns an slock, but it cannot guarantee that *this* 1049 * thread owns an slock. 1050 */ 1051 void 1052 _sx_assert(const struct sx *sx, int what, const char *file, int line) 1053 { 1054 #ifndef WITNESS 1055 int slocked = 0; 1056 #endif 1057 1058 if (panicstr != NULL) 1059 return; 1060 switch (what) { 1061 case SA_SLOCKED: 1062 case SA_SLOCKED | SA_NOTRECURSED: 1063 case SA_SLOCKED | SA_RECURSED: 1064 #ifndef WITNESS 1065 slocked = 1; 1066 /* FALLTHROUGH */ 1067 #endif 1068 case SA_LOCKED: 1069 case SA_LOCKED | SA_NOTRECURSED: 1070 case SA_LOCKED | SA_RECURSED: 1071 #ifdef WITNESS 1072 witness_assert(&sx->lock_object, what, file, line); 1073 #else 1074 /* 1075 * If some other thread has an exclusive lock or we 1076 * have one and are asserting a shared lock, fail. 1077 * Also, if no one has a lock at all, fail. 1078 */ 1079 if (sx->sx_lock == SX_LOCK_UNLOCKED || 1080 (!(sx->sx_lock & SX_LOCK_SHARED) && (slocked || 1081 sx_xholder(sx) != curthread))) 1082 panic("Lock %s not %slocked @ %s:%d\n", 1083 sx->lock_object.lo_name, slocked ? "share " : "", 1084 file, line); 1085 1086 if (!(sx->sx_lock & SX_LOCK_SHARED)) { 1087 if (sx_recursed(sx)) { 1088 if (what & SA_NOTRECURSED) 1089 panic("Lock %s recursed @ %s:%d\n", 1090 sx->lock_object.lo_name, file, 1091 line); 1092 } else if (what & SA_RECURSED) 1093 panic("Lock %s not recursed @ %s:%d\n", 1094 sx->lock_object.lo_name, file, line); 1095 } 1096 #endif 1097 break; 1098 case SA_XLOCKED: 1099 case SA_XLOCKED | SA_NOTRECURSED: 1100 case SA_XLOCKED | SA_RECURSED: 1101 if (sx_xholder(sx) != curthread) 1102 panic("Lock %s not exclusively locked @ %s:%d\n", 1103 sx->lock_object.lo_name, file, line); 1104 if (sx_recursed(sx)) { 1105 if (what & SA_NOTRECURSED) 1106 panic("Lock %s recursed @ %s:%d\n", 1107 sx->lock_object.lo_name, file, line); 1108 } else if (what & SA_RECURSED) 1109 panic("Lock %s not recursed @ %s:%d\n", 1110 sx->lock_object.lo_name, file, line); 1111 break; 1112 case SA_UNLOCKED: 1113 #ifdef WITNESS 1114 witness_assert(&sx->lock_object, what, file, line); 1115 #else 1116 /* 1117 * If we hold an exclusve lock fail. We can't 1118 * reliably check to see if we hold a shared lock or 1119 * not. 1120 */ 1121 if (sx_xholder(sx) == curthread) 1122 panic("Lock %s exclusively locked @ %s:%d\n", 1123 sx->lock_object.lo_name, file, line); 1124 #endif 1125 break; 1126 default: 1127 panic("Unknown sx lock assertion: %d @ %s:%d", what, file, 1128 line); 1129 } 1130 } 1131 #endif /* INVARIANT_SUPPORT */ 1132 1133 #ifdef DDB 1134 static void 1135 db_show_sx(const struct lock_object *lock) 1136 { 1137 struct thread *td; 1138 const struct sx *sx; 1139 1140 sx = (const struct sx *)lock; 1141 1142 db_printf(" state: "); 1143 if (sx->sx_lock == SX_LOCK_UNLOCKED) 1144 db_printf("UNLOCKED\n"); 1145 else if (sx->sx_lock == SX_LOCK_DESTROYED) { 1146 db_printf("DESTROYED\n"); 1147 return; 1148 } else if (sx->sx_lock & SX_LOCK_SHARED) 1149 db_printf("SLOCK: %ju\n", (uintmax_t)SX_SHARERS(sx->sx_lock)); 1150 else { 1151 td = sx_xholder(sx); 1152 db_printf("XLOCK: %p (tid %d, pid %d, \"%s\")\n", td, 1153 td->td_tid, td->td_proc->p_pid, td->td_name); 1154 if (sx_recursed(sx)) 1155 db_printf(" recursed: %d\n", sx->sx_recurse); 1156 } 1157 1158 db_printf(" waiters: "); 1159 switch(sx->sx_lock & 1160 (SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS)) { 1161 case SX_LOCK_SHARED_WAITERS: 1162 db_printf("shared\n"); 1163 break; 1164 case SX_LOCK_EXCLUSIVE_WAITERS: 1165 db_printf("exclusive\n"); 1166 break; 1167 case SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS: 1168 db_printf("exclusive and shared\n"); 1169 break; 1170 default: 1171 db_printf("none\n"); 1172 } 1173 } 1174 1175 /* 1176 * Check to see if a thread that is blocked on a sleep queue is actually 1177 * blocked on an sx lock. If so, output some details and return true. 1178 * If the lock has an exclusive owner, return that in *ownerp. 1179 */ 1180 int 1181 sx_chain(struct thread *td, struct thread **ownerp) 1182 { 1183 struct sx *sx; 1184 1185 /* 1186 * Check to see if this thread is blocked on an sx lock. 1187 * First, we check the lock class. If that is ok, then we 1188 * compare the lock name against the wait message. 1189 */ 1190 sx = td->td_wchan; 1191 if (LOCK_CLASS(&sx->lock_object) != &lock_class_sx || 1192 sx->lock_object.lo_name != td->td_wmesg) 1193 return (0); 1194 1195 /* We think we have an sx lock, so output some details. */ 1196 db_printf("blocked on sx \"%s\" ", td->td_wmesg); 1197 *ownerp = sx_xholder(sx); 1198 if (sx->sx_lock & SX_LOCK_SHARED) 1199 db_printf("SLOCK (count %ju)\n", 1200 (uintmax_t)SX_SHARERS(sx->sx_lock)); 1201 else 1202 db_printf("XLOCK\n"); 1203 return (1); 1204 } 1205 #endif 1206