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