1 /* $NetBSD: kern_rwlock.c,v 1.77 2026/08/16 21:52:42 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2002, 2006, 2007, 2008, 2009, 2019, 2020, 2023 5 * The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jason R. Thorpe and Andrew Doran. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Kernel reader/writer lock implementation, modeled after those 35 * found in Solaris, a description of which can be found in: 36 * 37 * Solaris Internals: Core Kernel Architecture, Jim Mauro and 38 * Richard McDougall. 39 * 40 * The NetBSD implementation differs from that described in the book, in 41 * that the locks are partially adaptive. Lock waiters spin wait while a 42 * lock is write held and the holder is still running on a CPU. The method 43 * of choosing which threads to awaken when a lock is released also differs, 44 * mainly to take account of the partially adaptive behaviour. 45 */ 46 47 #include <sys/cdefs.h> 48 __KERNEL_RCSID(0, "$NetBSD: kern_rwlock.c,v 1.77 2026/08/16 21:52:42 riastradh Exp $"); 49 50 #include "opt_lockdebug.h" 51 52 #define __RWLOCK_PRIVATE 53 54 #include <sys/param.h> 55 56 #include <sys/atomic.h> 57 #include <sys/cpu.h> 58 #include <sys/lock.h> 59 #include <sys/lockdebug.h> 60 #include <sys/proc.h> 61 #include <sys/pserialize.h> 62 #include <sys/rwlock.h> 63 #include <sys/sched.h> 64 #include <sys/sleepq.h> 65 #include <sys/syncobj.h> 66 #include <sys/systm.h> 67 68 #include <dev/lockstat.h> 69 70 #include <machine/rwlock.h> 71 72 /* 73 * LOCKDEBUG 74 */ 75 76 #define RW_DEBUG_P(rw) (((rw)->rw_owner & RW_NODEBUG) == 0) 77 78 #define RW_WANTLOCK(rw, op, owantedp) \ 79 LOCKDEBUG_WANTLOCK(RW_DEBUG_P(rw), (rw), \ 80 (uintptr_t)__builtin_return_address(0), op == RW_READER, owantedp); 81 #define RW_LOCKED(rw, op, owantedp) \ 82 LOCKDEBUG_LOCKED(RW_DEBUG_P(rw), (rw), NULL, \ 83 (uintptr_t)__builtin_return_address(0), op == RW_READER, owantedp); 84 #define RW_UNLOCKED(rw, op) \ 85 LOCKDEBUG_UNLOCKED(RW_DEBUG_P(rw), (rw), \ 86 (uintptr_t)__builtin_return_address(0), op == RW_READER); 87 88 /* 89 * DIAGNOSTIC 90 */ 91 92 #if defined(DIAGNOSTIC) 93 #define RW_ASSERT(rw, cond) \ 94 do { \ 95 if (__predict_false(!(cond))) \ 96 rw_abort(__func__, __LINE__, rw, "assertion failed: " #cond);\ 97 } while (/* CONSTCOND */ 0) 98 #else 99 #define RW_ASSERT(rw, cond) /* nothing */ 100 #endif /* DIAGNOSTIC */ 101 102 /* 103 * For platforms that do not provide stubs, or for the LOCKDEBUG case. 104 */ 105 #ifdef LOCKDEBUG 106 #undef __HAVE_RW_STUBS 107 #endif 108 109 #ifndef __HAVE_RW_STUBS 110 __strong_alias(rw_enter,rw_vector_enter); 111 __strong_alias(rw_exit,rw_vector_exit); 112 __strong_alias(rw_tryenter,rw_vector_tryenter); 113 #endif 114 115 static void rw_abort(const char *, size_t, krwlock_t *, const char *); 116 static void rw_dump(const volatile void *, lockop_printer_t); 117 static lwp_t *rw_owner(wchan_t); 118 119 lockops_t rwlock_lockops = { 120 .lo_name = "Reader / writer lock", 121 .lo_type = LOCKOPS_SLEEP, 122 .lo_dump = rw_dump, 123 }; 124 125 /* 126 * Give rwlock holders an extra-high priority boost on-blocking due to 127 * direct handoff. XXX To be revisited. 128 */ 129 syncobj_t rw_syncobj = { 130 .sobj_name = "rwlock", 131 .sobj_flag = SOBJ_SLEEPQ_SORTED, 132 .sobj_boostpri = PRI_KTHREAD, 133 .sobj_unsleep = turnstile_unsleep, 134 .sobj_changepri = turnstile_changepri, 135 .sobj_lendpri = sleepq_lendpri, 136 .sobj_owner = rw_owner, 137 }; 138 139 /* 140 * rw_cas: 141 * 142 * Do an atomic compare-and-swap on the lock word. 143 */ 144 static inline uintptr_t 145 rw_cas(krwlock_t *rw, uintptr_t o, uintptr_t n) 146 { 147 148 return (uintptr_t)atomic_cas_ptr((volatile void *)&rw->rw_owner, 149 (void *)o, (void *)n); 150 } 151 152 /* 153 * rw_swap: 154 * 155 * Do an atomic swap of the lock word. This is used only when it's 156 * known that the lock word is set up such that it can't be changed 157 * behind us (assert this), so there's no point considering the result. 158 */ 159 static inline void 160 rw_swap(krwlock_t *rw, uintptr_t o, uintptr_t n) 161 { 162 163 n = (uintptr_t)atomic_swap_ptr((volatile void *)&rw->rw_owner, 164 (void *)n); 165 166 RW_ASSERT(rw, n == o); 167 RW_ASSERT(rw, (o & RW_HAS_WAITERS) != 0); 168 } 169 170 /* 171 * rw_dump: 172 * 173 * Dump the contents of a rwlock structure. 174 */ 175 static void 176 rw_dump(const volatile void *cookie, lockop_printer_t pr) 177 { 178 const volatile krwlock_t *rw = cookie; 179 180 pr("owner/count : %#018lx flags : %#018x\n", 181 (long)RW_OWNER(rw), (int)RW_FLAGS(rw)); 182 } 183 184 /* 185 * rw_abort: 186 * 187 * Dump information about an error and panic the system. This 188 * generates a lot of machine code in the DIAGNOSTIC case, so 189 * we ask the compiler to not inline it. 190 */ 191 static void __noinline 192 rw_abort(const char *func, size_t line, krwlock_t *rw, const char *msg) 193 { 194 195 if (__predict_false(panicstr != NULL)) 196 return; 197 198 LOCKDEBUG_ABORT(func, line, rw, &rwlock_lockops, msg); 199 } 200 201 /* 202 * rw_init: 203 * 204 * Initialize a rwlock for use. 205 */ 206 void 207 _rw_init(krwlock_t *rw, uintptr_t return_address) 208 { 209 210 #ifdef LOCKDEBUG 211 /* XXX only because the assembly stubs can't handle RW_NODEBUG */ 212 if (LOCKDEBUG_ALLOC(rw, &rwlock_lockops, return_address)) 213 rw->rw_owner = 0; 214 else 215 rw->rw_owner = RW_NODEBUG; 216 #else 217 rw->rw_owner = 0; 218 #endif 219 } 220 221 void 222 rw_init(krwlock_t *rw) 223 { 224 225 _rw_init(rw, (uintptr_t)__builtin_return_address(0)); 226 } 227 228 /* 229 * rw_destroy: 230 * 231 * Tear down a rwlock. 232 */ 233 void 234 rw_destroy(krwlock_t *rw) 235 { 236 237 RW_ASSERT(rw, (rw->rw_owner & ~RW_NODEBUG) == 0); 238 LOCKDEBUG_FREE((rw->rw_owner & RW_NODEBUG) == 0, rw); 239 } 240 241 /* 242 * rw_oncpu: 243 * 244 * Return true if an rwlock owner is running on a CPU in the system. 245 * If the target is waiting on the kernel big lock, then we must 246 * release it. This is necessary to avoid deadlock. 247 */ 248 static bool 249 rw_oncpu(uintptr_t owner) 250 { 251 #ifdef MULTIPROCESSOR 252 struct cpu_info *ci; 253 lwp_t *l; 254 255 KASSERT(kpreempt_disabled()); 256 257 if ((owner & (RW_WRITE_LOCKED|RW_HAS_WAITERS)) != RW_WRITE_LOCKED) { 258 return false; 259 } 260 261 /* 262 * See lwp_dtor() why dereference of the LWP pointer is safe. 263 * We must have kernel preemption disabled for that. 264 */ 265 l = (lwp_t *)(owner & RW_THREAD); 266 ci = l->l_cpu; 267 268 if (ci && ci->ci_curlwp == l) { 269 /* Target is running; do we need to block? */ 270 return (ci->ci_biglock_wanted != l); 271 } 272 #endif 273 /* Not running. It may be safe to block now. */ 274 return false; 275 } 276 277 /* 278 * rw_vector_enter: 279 * 280 * Acquire a rwlock. 281 */ 282 void 283 rw_vector_enter(krwlock_t *rw, const krw_t op) 284 { 285 uintptr_t owner, incr, need_wait, set_wait, curthread, next; 286 turnstile_t *ts; 287 int queue; 288 lwp_t *l; 289 volatile void *owanted; 290 LOCKSTAT_TIMER(slptime); 291 LOCKSTAT_TIMER(slpcnt); 292 LOCKSTAT_TIMER(spintime); 293 LOCKSTAT_COUNTER(spincnt); 294 LOCKSTAT_FLAG(lsflag); 295 296 l = curlwp; 297 curthread = (uintptr_t)l; 298 299 RW_ASSERT(rw, !cpu_intr_p()); 300 RW_ASSERT(rw, curthread != 0); 301 RW_WANTLOCK(rw, op, &owanted); 302 303 if (__predict_true(panicstr == NULL)) { 304 KDASSERT(pserialize_not_in_read_section()); 305 LOCKDEBUG_BARRIER(&kernel_lock, 1); 306 } 307 308 /* 309 * We play a slight trick here. If we're a reader, we want 310 * increment the read count. If we're a writer, we want to 311 * set the owner field and the WRITE_LOCKED bit. 312 * 313 * In the latter case, we expect those bits to be zero, 314 * therefore we can use an add operation to set them, which 315 * means an add operation for both cases. 316 */ 317 if (__predict_true(op == RW_READER)) { 318 incr = RW_READ_INCR; 319 set_wait = RW_HAS_WAITERS; 320 need_wait = RW_WRITE_LOCKED | RW_WRITE_WANTED; 321 queue = TS_READER_Q; 322 } else { 323 RW_ASSERT(rw, op == RW_WRITER); 324 incr = curthread | RW_WRITE_LOCKED; 325 set_wait = RW_HAS_WAITERS | RW_WRITE_WANTED; 326 need_wait = RW_WRITE_LOCKED | RW_THREAD; 327 queue = TS_WRITER_Q; 328 } 329 330 LOCKSTAT_ENTER(lsflag); 331 332 KPREEMPT_DISABLE(curlwp); 333 for (owner = rw->rw_owner;;) { 334 /* 335 * Read the lock owner field. If the need-to-wait 336 * indicator is clear, then try to acquire the lock. 337 */ 338 if ((owner & need_wait) == 0) { 339 next = rw_cas(rw, owner, (owner + incr) & 340 ~RW_WRITE_WANTED); 341 if (__predict_true(next == owner)) { 342 /* Got it! */ 343 membar_acquire(); 344 break; 345 } 346 347 /* 348 * Didn't get it -- spin around again (we'll 349 * probably sleep on the next iteration). 350 */ 351 owner = next; 352 continue; 353 } 354 if (__predict_false(RW_OWNER(rw) == curthread)) { 355 rw_abort(__func__, __LINE__, rw, 356 "locking against myself"); 357 } 358 /* 359 * If the lock owner is running on another CPU, and 360 * there are no existing waiters, then spin. 361 */ 362 if (rw_oncpu(owner)) { 363 LOCKSTAT_START_TIMER(lsflag, spintime); 364 u_int count = SPINLOCK_BACKOFF_MIN; 365 do { 366 KPREEMPT_ENABLE(curlwp); 367 SPINLOCK_BACKOFF(count); 368 KPREEMPT_DISABLE(curlwp); 369 owner = rw->rw_owner; 370 } while (rw_oncpu(owner)); 371 LOCKSTAT_STOP_TIMER(lsflag, spintime); 372 LOCKSTAT_COUNT(spincnt, 1); 373 if ((owner & need_wait) == 0) 374 continue; 375 } 376 377 /* 378 * Grab the turnstile chain lock. Once we have that, we 379 * can adjust the waiter bits and sleep queue. 380 */ 381 ts = turnstile_lookup(rw); 382 383 /* 384 * Mark the rwlock as having waiters. If the set fails, 385 * then we may not need to sleep and should spin again. 386 * Reload rw_owner because turnstile_lookup() may have 387 * spun on the turnstile chain lock. 388 */ 389 owner = rw->rw_owner; 390 if ((owner & need_wait) == 0 || rw_oncpu(owner)) { 391 turnstile_exit(rw); 392 continue; 393 } 394 next = rw_cas(rw, owner, owner | set_wait); 395 /* XXX membar? */ 396 if (__predict_false(next != owner)) { 397 turnstile_exit(rw); 398 owner = next; 399 continue; 400 } 401 402 LOCKSTAT_START_TIMER(lsflag, slptime); 403 turnstile_block(ts, queue, rw, &rw_syncobj); 404 LOCKSTAT_STOP_TIMER(lsflag, slptime); 405 LOCKSTAT_COUNT(slpcnt, 1); 406 407 /* 408 * No need for a memory barrier because of context switch. 409 * If not handed the lock, then spin again. 410 */ 411 if (op == RW_READER || (rw->rw_owner & RW_THREAD) == curthread) 412 break; 413 414 owner = rw->rw_owner; 415 } 416 KPREEMPT_ENABLE(curlwp); 417 418 LOCKSTAT_EVENT_RA(lsflag, rw, LB_RWLOCK | 419 (op == RW_WRITER ? LB_SLEEP1 : LB_SLEEP2), slpcnt, slptime, 420 (l->l_rwcallsite != 0 ? l->l_rwcallsite : 421 (uintptr_t)__builtin_return_address(0))); 422 LOCKSTAT_EVENT_RA(lsflag, rw, LB_RWLOCK | LB_SPIN, spincnt, spintime, 423 (l->l_rwcallsite != 0 ? l->l_rwcallsite : 424 (uintptr_t)__builtin_return_address(0))); 425 LOCKSTAT_EXIT(lsflag); 426 427 RW_ASSERT(rw, (op != RW_READER && RW_OWNER(rw) == curthread) || 428 (op == RW_READER && RW_COUNT(rw) != 0)); 429 RW_LOCKED(rw, op, &owanted); 430 } 431 432 /* 433 * rw_vector_exit: 434 * 435 * Release a rwlock. 436 */ 437 void 438 rw_vector_exit(krwlock_t *rw) 439 { 440 uintptr_t curthread, owner, decr, newown, next; 441 turnstile_t *ts; 442 int rcnt, wcnt; 443 lwp_t *l; 444 445 l = curlwp; 446 curthread = (uintptr_t)l; 447 RW_ASSERT(rw, curthread != 0); 448 449 /* 450 * Again, we use a trick. Since we used an add operation to 451 * set the required lock bits, we can use a subtract to clear 452 * them, which makes the read-release and write-release path 453 * the same. 454 */ 455 owner = rw->rw_owner; 456 if (__predict_false((owner & RW_WRITE_LOCKED) != 0)) { 457 RW_UNLOCKED(rw, RW_WRITER); 458 RW_ASSERT(rw, RW_OWNER(rw) == curthread); 459 decr = curthread | RW_WRITE_LOCKED; 460 } else { 461 RW_UNLOCKED(rw, RW_READER); 462 RW_ASSERT(rw, RW_COUNT(rw) != 0); 463 decr = RW_READ_INCR; 464 } 465 466 /* 467 * Compute what we expect the new value of the lock to be. Only 468 * proceed to do direct handoff if there are waiters, and if the 469 * lock would become unowned. 470 */ 471 membar_release(); 472 for (;;) { 473 newown = (owner - decr); 474 if ((newown & (RW_THREAD | RW_HAS_WAITERS)) == RW_HAS_WAITERS) 475 break; 476 next = rw_cas(rw, owner, newown); 477 if (__predict_true(next == owner)) 478 return; 479 owner = next; 480 } 481 482 /* 483 * Grab the turnstile chain lock. This gets the interlock 484 * on the sleep queue. Once we have that, we can adjust the 485 * waiter bits. 486 */ 487 ts = turnstile_lookup(rw); 488 owner = rw->rw_owner; 489 RW_ASSERT(rw, ts != NULL); 490 RW_ASSERT(rw, (owner & RW_HAS_WAITERS) != 0); 491 492 wcnt = TS_WAITERS(ts, TS_WRITER_Q); 493 rcnt = TS_WAITERS(ts, TS_READER_Q); 494 495 /* 496 * Give the lock away. 497 * 498 * If we are releasing a write lock, then prefer to wake all 499 * outstanding readers. Otherwise, wake one writer if there 500 * are outstanding readers, or all writers if there are no 501 * pending readers. If waking one specific writer, the writer 502 * is handed the lock here. If waking multiple writers, we 503 * set WRITE_WANTED to block out new readers, and let them 504 * do the work of acquiring the lock in rw_vector_enter(). 505 */ 506 if (rcnt == 0 || decr == RW_READ_INCR) { 507 RW_ASSERT(rw, wcnt != 0); 508 RW_ASSERT(rw, (owner & RW_WRITE_WANTED) != 0); 509 510 if (rcnt != 0) { 511 /* Give the lock to the longest waiting writer. */ 512 l = TS_FIRST(ts, TS_WRITER_Q); 513 newown = (uintptr_t)l | (owner & RW_NODEBUG); 514 newown |= RW_WRITE_LOCKED | RW_HAS_WAITERS; 515 if (wcnt > 1) 516 newown |= RW_WRITE_WANTED; 517 rw_swap(rw, owner, newown); 518 turnstile_wakeup(ts, TS_WRITER_Q, 1, l); 519 } else { 520 /* Wake all writers and let them fight it out. */ 521 newown = owner & RW_NODEBUG; 522 newown |= RW_WRITE_WANTED; 523 rw_swap(rw, owner, newown); 524 turnstile_wakeup(ts, TS_WRITER_Q, wcnt, NULL); 525 } 526 } else { 527 RW_ASSERT(rw, rcnt != 0); 528 529 /* 530 * Give the lock to all blocked readers. If there 531 * is a writer waiting, new readers that arrive 532 * after the release will be blocked out. 533 */ 534 newown = owner & RW_NODEBUG; 535 newown += rcnt << RW_READ_COUNT_SHIFT; 536 if (wcnt != 0) 537 newown |= RW_HAS_WAITERS | RW_WRITE_WANTED; 538 539 /* Wake up all sleeping readers. */ 540 rw_swap(rw, owner, newown); 541 turnstile_wakeup(ts, TS_READER_Q, rcnt, NULL); 542 } 543 } 544 545 /* 546 * rw_vector_tryenter: 547 * 548 * Try to acquire a rwlock. 549 */ 550 int 551 rw_vector_tryenter(krwlock_t *rw, const krw_t op) 552 { 553 uintptr_t curthread, owner, incr, need_wait, next; 554 lwp_t *l; 555 556 l = curlwp; 557 curthread = (uintptr_t)l; 558 559 RW_ASSERT(rw, curthread != 0); 560 561 if (op == RW_READER) { 562 incr = RW_READ_INCR; 563 need_wait = RW_WRITE_LOCKED | RW_WRITE_WANTED; 564 } else { 565 RW_ASSERT(rw, op == RW_WRITER); 566 incr = curthread | RW_WRITE_LOCKED; 567 need_wait = RW_WRITE_LOCKED | RW_THREAD; 568 } 569 570 for (owner = rw->rw_owner;; owner = next) { 571 if (__predict_false((owner & need_wait) != 0)) 572 return 0; 573 next = rw_cas(rw, owner, owner + incr); 574 if (__predict_true(next == owner)) { 575 /* Got it! */ 576 break; 577 } 578 } 579 580 RW_WANTLOCK(rw, op, NULL); 581 RW_LOCKED(rw, op, NULL); 582 RW_ASSERT(rw, (op != RW_READER && RW_OWNER(rw) == curthread) || 583 (op == RW_READER && RW_COUNT(rw) != 0)); 584 585 membar_acquire(); 586 return 1; 587 } 588 589 /* 590 * rw_downgrade: 591 * 592 * Downgrade a write lock to a read lock. 593 */ 594 void 595 rw_downgrade(krwlock_t *rw) 596 { 597 uintptr_t owner, newown, next, curthread __diagused; 598 turnstile_t *ts; 599 int rcnt, wcnt; 600 lwp_t *l; 601 602 l = curlwp; 603 curthread = (uintptr_t)l; 604 RW_ASSERT(rw, curthread != 0); 605 RW_ASSERT(rw, (rw->rw_owner & RW_WRITE_LOCKED) != 0); 606 RW_ASSERT(rw, RW_OWNER(rw) == curthread); 607 RW_UNLOCKED(rw, RW_WRITER); 608 609 membar_release(); 610 for (owner = rw->rw_owner;; owner = next) { 611 /* 612 * If there are no waiters we can do this the easy way. Try 613 * swapping us down to one read hold. If it fails, the lock 614 * condition has changed and we most likely now have 615 * waiters. 616 */ 617 if ((owner & RW_HAS_WAITERS) == 0) { 618 newown = (owner & RW_NODEBUG); 619 next = rw_cas(rw, owner, newown + RW_READ_INCR); 620 if (__predict_true(next == owner)) { 621 RW_WANTLOCK(rw, RW_READER, NULL); 622 RW_LOCKED(rw, RW_READER, NULL); 623 RW_ASSERT(rw, 624 (rw->rw_owner & RW_WRITE_LOCKED) == 0); 625 RW_ASSERT(rw, RW_COUNT(rw) != 0); 626 return; 627 } 628 continue; 629 } 630 631 /* 632 * Grab the turnstile chain lock. This gets the interlock 633 * on the sleep queue. Once we have that, we can adjust the 634 * waiter bits. 635 */ 636 ts = turnstile_lookup(rw); 637 RW_ASSERT(rw, ts != NULL); 638 639 rcnt = TS_WAITERS(ts, TS_READER_Q); 640 wcnt = TS_WAITERS(ts, TS_WRITER_Q); 641 642 if (rcnt == 0) { 643 /* 644 * If there are no readers, just preserve the 645 * waiters bits, swap us down to one read hold and 646 * return. 647 */ 648 RW_ASSERT(rw, wcnt != 0); 649 RW_ASSERT(rw, (rw->rw_owner & RW_WRITE_WANTED) != 0); 650 RW_ASSERT(rw, (rw->rw_owner & RW_HAS_WAITERS) != 0); 651 652 newown = owner & RW_NODEBUG; 653 newown |= RW_READ_INCR | RW_HAS_WAITERS | 654 RW_WRITE_WANTED; 655 next = rw_cas(rw, owner, newown); 656 turnstile_exit(rw); 657 if (__predict_true(next == owner)) 658 break; 659 } else { 660 /* 661 * Give the lock to all blocked readers. We may 662 * retain one read hold if downgrading. If there is 663 * a writer waiting, new readers will be blocked 664 * out. 665 */ 666 newown = owner & RW_NODEBUG; 667 newown += (rcnt << RW_READ_COUNT_SHIFT) + RW_READ_INCR; 668 if (wcnt != 0) 669 newown |= RW_HAS_WAITERS | RW_WRITE_WANTED; 670 671 next = rw_cas(rw, owner, newown); 672 if (__predict_true(next == owner)) { 673 /* Wake up all sleeping readers. */ 674 turnstile_wakeup(ts, TS_READER_Q, rcnt, NULL); 675 break; 676 } 677 turnstile_exit(rw); 678 } 679 } 680 681 RW_WANTLOCK(rw, RW_READER, NULL); 682 RW_LOCKED(rw, RW_READER, NULL); 683 RW_ASSERT(rw, (rw->rw_owner & RW_WRITE_LOCKED) == 0); 684 RW_ASSERT(rw, RW_COUNT(rw) != 0); 685 } 686 687 /* 688 * rw_tryupgrade: 689 * 690 * Try to upgrade a read lock to a write lock. We must be the only 691 * reader. 692 */ 693 int 694 rw_tryupgrade(krwlock_t *rw) 695 { 696 uintptr_t owner, curthread, newown, next; 697 struct lwp *l; 698 699 l = curlwp; 700 curthread = (uintptr_t)l; 701 RW_ASSERT(rw, curthread != 0); 702 RW_ASSERT(rw, rw_read_held(rw)); 703 704 for (owner = RW_READ_INCR;; owner = next) { 705 newown = curthread | RW_WRITE_LOCKED | (owner & ~RW_THREAD); 706 next = rw_cas(rw, owner, newown); 707 if (__predict_true(next == owner)) { 708 membar_acquire(); 709 break; 710 } 711 RW_ASSERT(rw, (next & RW_WRITE_LOCKED) == 0); 712 if (__predict_false((next & RW_THREAD) != RW_READ_INCR)) { 713 RW_ASSERT(rw, (next & RW_THREAD) != 0); 714 return 0; 715 } 716 } 717 718 RW_UNLOCKED(rw, RW_READER); 719 RW_WANTLOCK(rw, RW_WRITER, NULL); 720 RW_LOCKED(rw, RW_WRITER, NULL); 721 RW_ASSERT(rw, rw->rw_owner & RW_WRITE_LOCKED); 722 RW_ASSERT(rw, RW_OWNER(rw) == curthread); 723 724 return 1; 725 } 726 727 /* 728 * rw_read_held: 729 * 730 * Returns true if the rwlock is held for reading. Must only be 731 * used for diagnostic assertions, and never be used to make 732 * decisions about how to use a rwlock. 733 */ 734 int 735 rw_read_held(krwlock_t *rw) 736 { 737 uintptr_t owner; 738 739 if (rw == NULL) 740 return 0; 741 owner = rw->rw_owner; 742 return (owner & RW_WRITE_LOCKED) == 0 && (owner & RW_THREAD) != 0; 743 } 744 745 /* 746 * rw_write_held: 747 * 748 * Returns true if the rwlock is held for writing. Must only be 749 * used for diagnostic assertions, and never be used to make 750 * decisions about how to use a rwlock. 751 */ 752 int 753 rw_write_held(krwlock_t *rw) 754 { 755 756 if (rw == NULL) 757 return 0; 758 return (rw->rw_owner & (RW_WRITE_LOCKED | RW_THREAD)) == 759 (RW_WRITE_LOCKED | (uintptr_t)curlwp); 760 } 761 762 /* 763 * rw_lock_held: 764 * 765 * Returns true if the rwlock is held for reading or writing. Must 766 * only be used for diagnostic assertions, and never be used to make 767 * decisions about how to use a rwlock. 768 */ 769 int 770 rw_lock_held(krwlock_t *rw) 771 { 772 773 if (rw == NULL) 774 return 0; 775 return (rw->rw_owner & RW_THREAD) != 0; 776 } 777 778 /* 779 * rw_lock_op: 780 * 781 * For a rwlock that is known to be held by the caller, return 782 * RW_READER or RW_WRITER to describe the hold type. 783 */ 784 krw_t 785 rw_lock_op(krwlock_t *rw) 786 { 787 788 RW_ASSERT(rw, rw_lock_held(rw)); 789 790 return (rw->rw_owner & RW_WRITE_LOCKED) != 0 ? RW_WRITER : RW_READER; 791 } 792 793 /* 794 * rw_owner: 795 * 796 * Return the current owner of an RW lock, but only if it is write 797 * held. Used for priority inheritance. 798 */ 799 static lwp_t * 800 rw_owner(wchan_t obj) 801 { 802 krwlock_t *rw = (void *)(uintptr_t)obj; /* discard qualifiers */ 803 uintptr_t owner = rw->rw_owner; 804 805 if ((owner & RW_WRITE_LOCKED) == 0) 806 return NULL; 807 808 return (void *)(owner & RW_THREAD); 809 } 810