1 /* $NetBSD: kern_rwlock.c,v 1.13 2007/12/04 09:13:59 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 2002, 2006, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe and Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Kernel reader/writer lock implementation, modeled after those 41 * found in Solaris, a description of which can be found in: 42 * 43 * Solaris Internals: Core Kernel Architecture, Jim Mauro and 44 * Richard McDougall. 45 */ 46 47 #include <sys/cdefs.h> 48 __KERNEL_RCSID(0, "$NetBSD: kern_rwlock.c,v 1.13 2007/12/04 09:13:59 ad Exp $"); 49 50 #include "opt_multiprocessor.h" 51 52 #define __RWLOCK_PRIVATE 53 54 #include <sys/param.h> 55 #include <sys/proc.h> 56 #include <sys/rwlock.h> 57 #include <sys/sched.h> 58 #include <sys/sleepq.h> 59 #include <sys/systm.h> 60 #include <sys/lockdebug.h> 61 #include <sys/cpu.h> 62 63 #include <dev/lockstat.h> 64 65 /* 66 * LOCKDEBUG 67 */ 68 69 #if defined(LOCKDEBUG) 70 71 #define RW_WANTLOCK(rw, op) \ 72 LOCKDEBUG_WANTLOCK(RW_DEBUG_P(rw), (rw), \ 73 (uintptr_t)__builtin_return_address(0), op == RW_READER); 74 #define RW_LOCKED(rw, op) \ 75 LOCKDEBUG_LOCKED(RW_DEBUG_P(rw), (rw), \ 76 (uintptr_t)__builtin_return_address(0), op == RW_READER); 77 #define RW_UNLOCKED(rw, op) \ 78 LOCKDEBUG_UNLOCKED(RW_DEBUG_P(rw), (rw), \ 79 (uintptr_t)__builtin_return_address(0), op == RW_READER); 80 #define RW_DASSERT(rw, cond) \ 81 do { \ 82 if (!(cond)) \ 83 rw_abort(rw, __func__, "assertion failed: " #cond); \ 84 } while (/* CONSTCOND */ 0); 85 86 #else /* LOCKDEBUG */ 87 88 #define RW_WANTLOCK(rw, op) /* nothing */ 89 #define RW_LOCKED(rw, op) /* nothing */ 90 #define RW_UNLOCKED(rw, op) /* nothing */ 91 #define RW_DASSERT(rw, cond) /* nothing */ 92 93 #endif /* LOCKDEBUG */ 94 95 /* 96 * DIAGNOSTIC 97 */ 98 99 #if defined(DIAGNOSTIC) 100 101 #define RW_ASSERT(rw, cond) \ 102 do { \ 103 if (!(cond)) \ 104 rw_abort(rw, __func__, "assertion failed: " #cond); \ 105 } while (/* CONSTCOND */ 0) 106 107 #else 108 109 #define RW_ASSERT(rw, cond) /* nothing */ 110 111 #endif /* DIAGNOSTIC */ 112 113 /* 114 * For platforms that use 'simple' RW locks. 115 */ 116 #ifdef __HAVE_SIMPLE_RW_LOCKS 117 #define RW_ACQUIRE(rw, old, new) RW_CAS1(&(rw)->rw_owner, old, new) 118 #define RW_RELEASE(rw, old, new) RW_CAS1(&(rw)->rw_owner, old, new) 119 #define RW_SETDEBUG(rw, on) ((rw)->rw_owner |= (on) ? RW_DEBUG : 0) 120 #define RW_DEBUG_P(rw) (((rw)->rw_owner & RW_DEBUG) != 0) 121 #if defined(LOCKDEBUG) 122 #define RW_INHERITDEBUG(new, old) (new) |= (old) & RW_DEBUG 123 #else /* defined(LOCKDEBUG) */ 124 #define RW_INHERITDEBUG(new, old) /* nothing */ 125 #endif /* defined(LOCKDEBUG) */ 126 127 static inline int 128 RW_CAS1(volatile uintptr_t *ptr, uintptr_t old, uintptr_t new) 129 { 130 131 RW_INHERITDEBUG(new, old); 132 return RW_CAS(ptr, old, new); 133 } 134 135 static inline int 136 RW_SET_WAITERS(krwlock_t *rw, uintptr_t need, uintptr_t set) 137 { 138 uintptr_t old; 139 140 if (((old = rw->rw_owner) & need) == 0) 141 return 0; 142 return RW_CAS(&rw->rw_owner, old, old | set); 143 } 144 #endif /* __HAVE_SIMPLE_RW_LOCKS */ 145 146 /* 147 * For platforms that do not provide stubs, or for the LOCKDEBUG case. 148 */ 149 #ifdef LOCKDEBUG 150 #undef __HAVE_RW_STUBS 151 #endif 152 153 #ifndef __HAVE_RW_STUBS 154 __strong_alias(rw_enter,rw_vector_enter); 155 __strong_alias(rw_exit,rw_vector_exit); 156 #endif 157 158 static void rw_dump(volatile void *); 159 static lwp_t *rw_owner(wchan_t); 160 161 lockops_t rwlock_lockops = { 162 "Reader / writer lock", 163 1, 164 rw_dump 165 }; 166 167 syncobj_t rw_syncobj = { 168 SOBJ_SLEEPQ_SORTED, 169 turnstile_unsleep, 170 turnstile_changepri, 171 sleepq_lendpri, 172 rw_owner, 173 }; 174 175 /* 176 * rw_dump: 177 * 178 * Dump the contents of a rwlock structure. 179 */ 180 static void 181 rw_dump(volatile void *cookie) 182 { 183 volatile krwlock_t *rw = cookie; 184 185 printf_nolog("owner/count : %#018lx flags : %#018x\n", 186 (long)RW_OWNER(rw), (int)RW_FLAGS(rw)); 187 } 188 189 /* 190 * rw_abort: 191 * 192 * Dump information about an error and panic the system. This 193 * generates a lot of machine code in the DIAGNOSTIC case, so 194 * we ask the compiler to not inline it. 195 */ 196 #if __GNUC_PREREQ__(3, 0) 197 __attribute ((noinline)) 198 #endif 199 static void 200 rw_abort(krwlock_t *rw, const char *func, const char *msg) 201 { 202 203 if (panicstr != NULL) 204 return; 205 206 LOCKDEBUG_ABORT(rw, &rwlock_lockops, func, msg); 207 } 208 209 /* 210 * rw_init: 211 * 212 * Initialize a rwlock for use. 213 */ 214 void 215 rw_init(krwlock_t *rw) 216 { 217 bool dodebug; 218 219 memset(rw, 0, sizeof(*rw)); 220 221 dodebug = LOCKDEBUG_ALLOC(rw, &rwlock_lockops, 222 (uintptr_t)__builtin_return_address(0)); 223 RW_SETDEBUG(rw, dodebug); 224 } 225 226 /* 227 * rw_destroy: 228 * 229 * Tear down a rwlock. 230 */ 231 void 232 rw_destroy(krwlock_t *rw) 233 { 234 235 RW_ASSERT(rw, (rw->rw_owner & ~RW_DEBUG) == 0); 236 LOCKDEBUG_FREE(RW_DEBUG_P(rw), rw); 237 } 238 239 /* 240 * rw_vector_enter: 241 * 242 * Acquire a rwlock. 243 */ 244 void 245 rw_vector_enter(krwlock_t *rw, const krw_t op) 246 { 247 uintptr_t owner, incr, need_wait, set_wait, curthread; 248 turnstile_t *ts; 249 int queue; 250 lwp_t *l; 251 LOCKSTAT_TIMER(slptime); 252 LOCKSTAT_FLAG(lsflag); 253 254 l = curlwp; 255 curthread = (uintptr_t)l; 256 257 RW_ASSERT(rw, !cpu_intr_p()); 258 RW_ASSERT(rw, curthread != 0); 259 RW_WANTLOCK(rw, op); 260 261 if (panicstr == NULL) { 262 LOCKDEBUG_BARRIER(&kernel_lock, 1); 263 } 264 265 /* 266 * We play a slight trick here. If we're a reader, we want 267 * increment the read count. If we're a writer, we want to 268 * set the owner field and whe WRITE_LOCKED bit. 269 * 270 * In the latter case, we expect those bits to be zero, 271 * therefore we can use an add operation to set them, which 272 * means an add operation for both cases. 273 */ 274 if (__predict_true(op == RW_READER)) { 275 incr = RW_READ_INCR; 276 set_wait = RW_HAS_WAITERS; 277 need_wait = RW_WRITE_LOCKED | RW_WRITE_WANTED; 278 queue = TS_READER_Q; 279 } else { 280 RW_DASSERT(rw, op == RW_WRITER); 281 incr = curthread | RW_WRITE_LOCKED; 282 set_wait = RW_HAS_WAITERS | RW_WRITE_WANTED; 283 need_wait = RW_WRITE_LOCKED | RW_THREAD; 284 queue = TS_WRITER_Q; 285 } 286 287 LOCKSTAT_ENTER(lsflag); 288 289 for (;;) { 290 /* 291 * Read the lock owner field. If the need-to-wait 292 * indicator is clear, then try to acquire the lock. 293 */ 294 owner = rw->rw_owner; 295 if ((owner & need_wait) == 0) { 296 if (RW_ACQUIRE(rw, owner, owner + incr)) { 297 /* Got it! */ 298 break; 299 } 300 301 /* 302 * Didn't get it -- spin around again (we'll 303 * probably sleep on the next iteration). 304 */ 305 continue; 306 } 307 308 if (panicstr != NULL) 309 return; 310 if (RW_OWNER(rw) == curthread) 311 rw_abort(rw, __func__, "locking against myself"); 312 313 /* 314 * Grab the turnstile chain lock. Once we have that, we 315 * can adjust the waiter bits and sleep queue. 316 */ 317 ts = turnstile_lookup(rw); 318 319 /* 320 * Mark the rwlock as having waiters. If the set fails, 321 * then we may not need to sleep and should spin again. 322 */ 323 if (!RW_SET_WAITERS(rw, need_wait, set_wait)) { 324 turnstile_exit(rw); 325 continue; 326 } 327 328 LOCKSTAT_START_TIMER(lsflag, slptime); 329 330 turnstile_block(ts, queue, rw, &rw_syncobj); 331 332 /* If we wake up and arrive here, we've been handed the lock. */ 333 RW_RECEIVE(rw); 334 335 LOCKSTAT_STOP_TIMER(lsflag, slptime); 336 LOCKSTAT_EVENT(lsflag, rw, 337 LB_RWLOCK | (op == RW_WRITER ? LB_SLEEP1 : LB_SLEEP2), 338 1, slptime); 339 340 break; 341 } 342 343 LOCKSTAT_EXIT(lsflag); 344 345 RW_DASSERT(rw, (op != RW_READER && RW_OWNER(rw) == curthread) || 346 (op == RW_READER && RW_COUNT(rw) != 0)); 347 RW_LOCKED(rw, op); 348 } 349 350 /* 351 * rw_vector_exit: 352 * 353 * Release a rwlock. 354 */ 355 void 356 rw_vector_exit(krwlock_t *rw) 357 { 358 uintptr_t curthread, owner, decr, new; 359 turnstile_t *ts; 360 int rcnt, wcnt; 361 lwp_t *l; 362 363 curthread = (uintptr_t)curlwp; 364 RW_ASSERT(rw, curthread != 0); 365 366 if (panicstr != NULL) 367 return; 368 369 /* 370 * Again, we use a trick. Since we used an add operation to 371 * set the required lock bits, we can use a subtract to clear 372 * them, which makes the read-release and write-release path 373 * the same. 374 */ 375 owner = rw->rw_owner; 376 if (__predict_false((owner & RW_WRITE_LOCKED) != 0)) { 377 RW_UNLOCKED(rw, RW_WRITER); 378 RW_DASSERT(rw, (rw->rw_owner & RW_WRITE_LOCKED) != 0); 379 RW_ASSERT(rw, RW_OWNER(rw) == curthread); 380 decr = curthread | RW_WRITE_LOCKED; 381 } else { 382 RW_UNLOCKED(rw, RW_READER); 383 RW_ASSERT(rw, (rw->rw_owner & RW_WRITE_LOCKED) == 0); 384 RW_ASSERT(rw, RW_COUNT(rw) != 0); 385 decr = RW_READ_INCR; 386 } 387 388 /* 389 * Compute what we expect the new value of the lock to be. Only 390 * proceed to do direct handoff if there are waiters, and if the 391 * lock would become unowned. 392 */ 393 for (;; owner = rw->rw_owner) { 394 new = (owner - decr); 395 if ((new & (RW_THREAD | RW_HAS_WAITERS)) == RW_HAS_WAITERS) 396 break; 397 if (RW_RELEASE(rw, owner, new)) 398 return; 399 } 400 401 for (;;) { 402 /* 403 * Grab the turnstile chain lock. This gets the interlock 404 * on the sleep queue. Once we have that, we can adjust the 405 * waiter bits. 406 */ 407 ts = turnstile_lookup(rw); 408 RW_DASSERT(rw, ts != NULL); 409 RW_DASSERT(rw, (rw->rw_owner & RW_HAS_WAITERS) != 0); 410 411 owner = rw->rw_owner; 412 wcnt = TS_WAITERS(ts, TS_WRITER_Q); 413 rcnt = TS_WAITERS(ts, TS_READER_Q); 414 415 /* 416 * Give the lock away. 417 * 418 * If we are releasing a write lock, then wake all 419 * outstanding readers. If we are releasing a read 420 * lock, then wake one writer. 421 */ 422 if (rcnt == 0 || (decr == RW_READ_INCR && wcnt != 0)) { 423 RW_DASSERT(rw, wcnt != 0); 424 RW_DASSERT(rw, (rw->rw_owner & RW_WRITE_WANTED) != 0); 425 426 /* 427 * Give the lock to the longest waiting 428 * writer. 429 */ 430 l = TS_FIRST(ts, TS_WRITER_Q); 431 new = (uintptr_t)l | RW_WRITE_LOCKED; 432 433 if (wcnt > 1) 434 new |= RW_HAS_WAITERS | RW_WRITE_WANTED; 435 else if (rcnt != 0) 436 new |= RW_HAS_WAITERS; 437 438 RW_GIVE(rw); 439 if (!RW_RELEASE(rw, owner, new)) { 440 /* Oops, try again. */ 441 turnstile_exit(rw); 442 continue; 443 } 444 445 /* Wake the writer. */ 446 turnstile_wakeup(ts, TS_WRITER_Q, 1, l); 447 } else { 448 RW_DASSERT(rw, rcnt != 0); 449 450 /* 451 * Give the lock to all blocked readers. If there 452 * is a writer waiting, new readers that arrive 453 * after the release will be blocked out. 454 */ 455 new = rcnt << RW_READ_COUNT_SHIFT; 456 if (wcnt != 0) 457 new |= RW_HAS_WAITERS | RW_WRITE_WANTED; 458 459 RW_GIVE(rw); 460 if (!RW_RELEASE(rw, owner, new)) { 461 /* Oops, try again. */ 462 turnstile_exit(rw); 463 continue; 464 } 465 466 /* Wake up all sleeping readers. */ 467 turnstile_wakeup(ts, TS_READER_Q, rcnt, NULL); 468 } 469 470 break; 471 } 472 } 473 474 /* 475 * rw_tryenter: 476 * 477 * Try to acquire a rwlock. 478 */ 479 int 480 rw_tryenter(krwlock_t *rw, const krw_t op) 481 { 482 uintptr_t curthread, owner, incr, need_wait; 483 484 curthread = (uintptr_t)curlwp; 485 486 RW_ASSERT(rw, curthread != 0); 487 RW_WANTLOCK(rw, op); 488 489 if (op == RW_READER) { 490 incr = RW_READ_INCR; 491 need_wait = RW_WRITE_LOCKED | RW_WRITE_WANTED; 492 } else { 493 RW_DASSERT(rw, op == RW_WRITER); 494 incr = curthread | RW_WRITE_LOCKED; 495 need_wait = RW_WRITE_LOCKED | RW_THREAD; 496 } 497 498 for (;;) { 499 owner = rw->rw_owner; 500 if ((owner & need_wait) == 0) { 501 if (RW_ACQUIRE(rw, owner, owner + incr)) { 502 /* Got it! */ 503 break; 504 } 505 continue; 506 } 507 return 0; 508 } 509 510 RW_LOCKED(rw, op); 511 RW_DASSERT(rw, (op != RW_READER && RW_OWNER(rw) == curthread) || 512 (op == RW_READER && RW_COUNT(rw) != 0)); 513 514 return 1; 515 } 516 517 /* 518 * rw_downgrade: 519 * 520 * Downgrade a write lock to a read lock. 521 */ 522 void 523 rw_downgrade(krwlock_t *rw) 524 { 525 uintptr_t owner, curthread, new; 526 turnstile_t *ts; 527 int rcnt, wcnt; 528 529 curthread = (uintptr_t)curlwp; 530 RW_ASSERT(rw, curthread != 0); 531 RW_DASSERT(rw, (rw->rw_owner & RW_WRITE_LOCKED) != 0); 532 RW_ASSERT(rw, RW_OWNER(rw) == curthread); 533 RW_UNLOCKED(rw, RW_WRITER); 534 535 owner = rw->rw_owner; 536 if ((owner & RW_HAS_WAITERS) == 0) { 537 /* 538 * There are no waiters, so we can do this the easy way. 539 * Try swapping us down to one read hold. If it fails, the 540 * lock condition has changed and we most likely now have 541 * waiters. 542 */ 543 if (RW_RELEASE(rw, owner, RW_READ_INCR)) { 544 RW_LOCKED(rw, RW_READER); 545 RW_DASSERT(rw, (rw->rw_owner & RW_WRITE_LOCKED) == 0); 546 RW_DASSERT(rw, RW_COUNT(rw) != 0); 547 return; 548 } 549 } 550 551 /* 552 * Grab the turnstile chain lock. This gets the interlock 553 * on the sleep queue. Once we have that, we can adjust the 554 * waiter bits. 555 */ 556 for (;;) { 557 ts = turnstile_lookup(rw); 558 RW_DASSERT(rw, ts != NULL); 559 560 owner = rw->rw_owner; 561 rcnt = TS_WAITERS(ts, TS_READER_Q); 562 wcnt = TS_WAITERS(ts, TS_WRITER_Q); 563 564 /* 565 * If there are no readers, just preserve the waiters 566 * bits, swap us down to one read hold and return. 567 */ 568 if (rcnt == 0) { 569 RW_DASSERT(rw, wcnt != 0); 570 RW_DASSERT(rw, (rw->rw_owner & RW_WRITE_WANTED) != 0); 571 RW_DASSERT(rw, (rw->rw_owner & RW_HAS_WAITERS) != 0); 572 573 new = RW_READ_INCR | RW_HAS_WAITERS | RW_WRITE_WANTED; 574 if (!RW_RELEASE(rw, owner, new)) { 575 /* Oops, try again. */ 576 turnstile_exit(ts); 577 continue; 578 } 579 break; 580 } 581 582 /* 583 * Give the lock to all blocked readers. We may 584 * retain one read hold if downgrading. If there 585 * is a writer waiting, new readers will be blocked 586 * out. 587 */ 588 new = (rcnt << RW_READ_COUNT_SHIFT) + RW_READ_INCR; 589 if (wcnt != 0) 590 new |= RW_HAS_WAITERS | RW_WRITE_WANTED; 591 592 RW_GIVE(rw); 593 if (!RW_RELEASE(rw, owner, new)) { 594 /* Oops, try again. */ 595 turnstile_exit(rw); 596 continue; 597 } 598 599 /* Wake up all sleeping readers. */ 600 turnstile_wakeup(ts, TS_READER_Q, rcnt, NULL); 601 break; 602 } 603 604 RW_LOCKED(rw, RW_READER); 605 RW_DASSERT(rw, (rw->rw_owner & RW_WRITE_LOCKED) == 0); 606 RW_DASSERT(rw, RW_COUNT(rw) != 0); 607 } 608 609 /* 610 * rw_tryupgrade: 611 * 612 * Try to upgrade a read lock to a write lock. We must be the 613 * only reader. 614 */ 615 int 616 rw_tryupgrade(krwlock_t *rw) 617 { 618 uintptr_t owner, curthread, new; 619 620 curthread = (uintptr_t)curlwp; 621 RW_ASSERT(rw, curthread != 0); 622 RW_WANTLOCK(rw, RW_WRITER); 623 624 for (;;) { 625 owner = rw->rw_owner; 626 RW_ASSERT(rw, (owner & RW_WRITE_LOCKED) == 0); 627 if ((owner & RW_THREAD) != RW_READ_INCR) { 628 RW_ASSERT(rw, (owner & RW_THREAD) != 0); 629 return 0; 630 } 631 new = curthread | RW_WRITE_LOCKED | (owner & ~RW_THREAD); 632 if (RW_ACQUIRE(rw, owner, new)) 633 break; 634 } 635 636 RW_UNLOCKED(rw, RW_READER); 637 RW_LOCKED(rw, RW_WRITER); 638 RW_DASSERT(rw, rw->rw_owner & RW_WRITE_LOCKED); 639 RW_DASSERT(rw, RW_OWNER(rw) == curthread); 640 641 return 1; 642 } 643 644 /* 645 * rw_read_held: 646 * 647 * Returns true if the rwlock is held for reading. Must only be 648 * used for diagnostic assertions, and never be used to make 649 * decisions about how to use a rwlock. 650 */ 651 int 652 rw_read_held(krwlock_t *rw) 653 { 654 uintptr_t owner; 655 656 if (panicstr != NULL) 657 return 1; 658 659 owner = rw->rw_owner; 660 return (owner & RW_WRITE_LOCKED) == 0 && (owner & RW_THREAD) != 0; 661 } 662 663 /* 664 * rw_write_held: 665 * 666 * Returns true if the rwlock is held for writing. Must only be 667 * used for diagnostic assertions, and never be used to make 668 * decisions about how to use a rwlock. 669 */ 670 int 671 rw_write_held(krwlock_t *rw) 672 { 673 674 if (panicstr != NULL) 675 return 1; 676 677 return (rw->rw_owner & RW_WRITE_LOCKED) != 0; 678 } 679 680 /* 681 * rw_lock_held: 682 * 683 * Returns true if the rwlock is held for reading or writing. Must 684 * only be used for diagnostic assertions, and never be used to make 685 * decisions about how to use a rwlock. 686 */ 687 int 688 rw_lock_held(krwlock_t *rw) 689 { 690 691 if (panicstr != NULL) 692 return 1; 693 694 return (rw->rw_owner & RW_THREAD) != 0; 695 } 696 697 /* 698 * rw_owner: 699 * 700 * Return the current owner of an RW lock, but only if it is write 701 * held. Used for priority inheritance. 702 */ 703 static lwp_t * 704 rw_owner(wchan_t obj) 705 { 706 krwlock_t *rw = (void *)(uintptr_t)obj; /* discard qualifiers */ 707 uintptr_t owner = rw->rw_owner; 708 709 if ((owner & RW_WRITE_LOCKED) == 0) 710 return NULL; 711 712 return (void *)(owner & RW_THREAD); 713 } 714