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