1 /* $NetBSD: linux_ww_mutex.c,v 1.2 2015/05/21 21:55:55 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Taylor R. Campbell. 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: linux_ww_mutex.c,v 1.2 2015/05/21 21:55:55 riastradh Exp $"); 34 35 #include <sys/types.h> 36 #include <sys/atomic.h> 37 #include <sys/condvar.h> 38 #include <sys/lockdebug.h> 39 #include <sys/lwp.h> 40 #include <sys/mutex.h> 41 #include <sys/rbtree.h> 42 43 #include <linux/ww_mutex.h> 44 45 #define WW_WANTLOCK(WW) \ 46 LOCKDEBUG_WANTLOCK((WW)->wwm_debug, (WW), \ 47 (uintptr_t)__builtin_return_address(0), 0) 48 #define WW_LOCKED(WW) \ 49 LOCKDEBUG_LOCKED((WW)->wwm_debug, (WW), NULL, \ 50 (uintptr_t)__builtin_return_address(0), 0) 51 #define WW_UNLOCKED(WW) \ 52 LOCKDEBUG_UNLOCKED((WW)->wwm_debug, (WW), \ 53 (uintptr_t)__builtin_return_address(0), 0) 54 55 static int 56 ww_acquire_ctx_compare(void *cookie __unused, const void *va, const void *vb) 57 { 58 const struct ww_acquire_ctx *const ctx_a = va; 59 const struct ww_acquire_ctx *const ctx_b = vb; 60 61 if (ctx_a->wwx_ticket < ctx_b->wwx_ticket) 62 return -1; 63 if (ctx_a->wwx_ticket > ctx_b->wwx_ticket) 64 return -1; 65 return 0; 66 } 67 68 static int 69 ww_acquire_ctx_compare_key(void *cookie __unused, const void *vn, 70 const void *vk) 71 { 72 const struct ww_acquire_ctx *const ctx = vn; 73 const uint64_t *const ticketp = vk, ticket = *ticketp; 74 75 if (ctx->wwx_ticket < ticket) 76 return -1; 77 if (ctx->wwx_ticket > ticket) 78 return -1; 79 return 0; 80 } 81 82 static const rb_tree_ops_t ww_acquire_ctx_rb_ops = { 83 .rbto_compare_nodes = &ww_acquire_ctx_compare, 84 .rbto_compare_key = &ww_acquire_ctx_compare_key, 85 .rbto_node_offset = offsetof(struct ww_acquire_ctx, wwx_rb_node), 86 .rbto_context = NULL, 87 }; 88 89 void 90 ww_acquire_init(struct ww_acquire_ctx *ctx, struct ww_class *class) 91 { 92 93 ctx->wwx_class = class; 94 ctx->wwx_owner = curlwp; 95 ctx->wwx_ticket = atomic_inc_64_nv(&class->wwc_ticket); 96 ctx->wwx_acquired = 0; 97 ctx->wwx_acquire_done = false; 98 } 99 100 void 101 ww_acquire_done(struct ww_acquire_ctx *ctx) 102 { 103 104 KASSERTMSG((ctx->wwx_owner == curlwp), 105 "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp); 106 107 ctx->wwx_acquire_done = true; 108 } 109 110 void 111 ww_acquire_fini(struct ww_acquire_ctx *ctx) 112 { 113 114 KASSERTMSG((ctx->wwx_owner == curlwp), 115 "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp); 116 KASSERTMSG((ctx->wwx_acquired == 0), "ctx %p still holds %u locks", 117 ctx, ctx->wwx_acquired); 118 119 ctx->wwx_acquired = ~0U; /* Fail if called again. */ 120 ctx->wwx_owner = NULL; 121 } 122 123 #ifdef LOCKDEBUG 124 static void 125 ww_dump(volatile void *cookie) 126 { 127 volatile struct ww_mutex *mutex = cookie; 128 129 printf_nolog("%-13s: ", "state"); 130 switch (mutex->wwm_state) { 131 case WW_UNLOCKED: 132 printf_nolog("unlocked\n"); 133 break; 134 case WW_OWNED: 135 printf_nolog("owned by lwp\n"); 136 printf_nolog("%-13s: %p\n", "owner", mutex->wwm_u.owner); 137 printf_nolog("%-13s: %s\n", "waiters", 138 cv_has_waiters(__UNVOLATILE(&mutex->wwm_cv)) 139 ? "yes" : "no"); 140 break; 141 case WW_CTX: 142 printf_nolog("owned via ctx\n"); 143 printf_nolog("%-13s: %p\n", "context", mutex->wwm_u.ctx); 144 printf_nolog("%-13s: %p\n", "lwp", 145 mutex->wwm_u.ctx->wwx_owner); 146 printf_nolog("%-13s: %s\n", "waiters", 147 cv_has_waiters(__UNVOLATILE(&mutex->wwm_cv)) 148 ? "yes" : "no"); 149 break; 150 case WW_WANTOWN: 151 printf_nolog("owned via ctx\n"); 152 printf_nolog("%-13s: %p\n", "context", mutex->wwm_u.ctx); 153 printf_nolog("%-13s: %p\n", "lwp", 154 mutex->wwm_u.ctx->wwx_owner); 155 printf_nolog("%-13s: %s\n", "waiters", "yes (noctx)"); 156 break; 157 default: 158 printf_nolog("unknown\n"); 159 break; 160 } 161 } 162 163 static lockops_t ww_lockops = { 164 .lo_name = "Wait/wound mutex", 165 .lo_type = LOCKOPS_SLEEP, 166 .lo_dump = ww_dump, 167 }; 168 #endif 169 170 void 171 ww_mutex_init(struct ww_mutex *mutex, struct ww_class *class) 172 { 173 174 /* 175 * XXX Apparently Linux takes these with spin locks held. That 176 * strikes me as a bad idea, but so it is... 177 */ 178 mutex_init(&mutex->wwm_lock, MUTEX_DEFAULT, IPL_VM); 179 mutex->wwm_state = WW_UNLOCKED; 180 mutex->wwm_class = class; 181 rb_tree_init(&mutex->wwm_waiters, &ww_acquire_ctx_rb_ops); 182 cv_init(&mutex->wwm_cv, "linuxwwm"); 183 #ifdef LOCKDEBUG 184 mutex->wwm_debug = LOCKDEBUG_ALLOC(mutex, &ww_lockops, 185 (uintptr_t)__builtin_return_address(0)); 186 #endif 187 } 188 189 void 190 ww_mutex_destroy(struct ww_mutex *mutex) 191 { 192 193 KASSERT(mutex->wwm_state == WW_UNLOCKED); 194 195 #ifdef LOCKDEBUG 196 LOCKDEBUG_FREE(mutex->wwm_debug, mutex); 197 #endif 198 cv_destroy(&mutex->wwm_cv); 199 #if 0 200 rb_tree_destroy(&mutex->wwm_waiters, &ww_acquire_ctx_rb_ops); 201 #endif 202 KASSERT(mutex->wwm_state == WW_UNLOCKED); 203 mutex_destroy(&mutex->wwm_lock); 204 } 205 206 /* 207 * XXX WARNING: This returns true if it is locked by ANYONE. Does not 208 * mean `Do I hold this lock?' (answering which really requires an 209 * acquire context). 210 */ 211 bool 212 ww_mutex_is_locked(struct ww_mutex *mutex) 213 { 214 int locked; 215 216 mutex_enter(&mutex->wwm_lock); 217 switch (mutex->wwm_state) { 218 case WW_UNLOCKED: 219 locked = false; 220 break; 221 case WW_OWNED: 222 case WW_CTX: 223 case WW_WANTOWN: 224 locked = true; 225 break; 226 default: 227 panic("wait/wound mutex %p in bad state: %d", mutex, 228 (int)mutex->wwm_state); 229 } 230 mutex_exit(&mutex->wwm_lock); 231 232 return locked; 233 } 234 235 static void 236 ww_mutex_state_wait(struct ww_mutex *mutex, enum ww_mutex_state state) 237 { 238 239 KASSERT(mutex->wwm_state == state); 240 do cv_wait(&mutex->wwm_cv, &mutex->wwm_lock); 241 while (mutex->wwm_state == state); 242 } 243 244 static int 245 ww_mutex_state_wait_sig(struct ww_mutex *mutex, enum ww_mutex_state state) 246 { 247 int ret; 248 249 KASSERT(mutex->wwm_state == state); 250 do { 251 /* XXX errno NetBSD->Linux */ 252 ret = -cv_wait_sig(&mutex->wwm_cv, &mutex->wwm_lock); 253 if (ret) 254 break; 255 } while (mutex->wwm_state == state); 256 257 return ret; 258 } 259 260 static void 261 ww_mutex_lock_wait(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx) 262 { 263 struct ww_acquire_ctx *collision __diagused; 264 265 KASSERT(mutex_owned(&mutex->wwm_lock)); 266 267 KASSERT((mutex->wwm_state == WW_CTX) || 268 (mutex->wwm_state == WW_WANTOWN)); 269 KASSERT(mutex->wwm_u.ctx != ctx); 270 KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class), 271 "ww mutex class mismatch: %p != %p", 272 ctx->wwx_class, mutex->wwm_u.ctx->wwx_class); 273 KASSERTMSG((mutex->wwm_u.ctx->wwx_ticket != ctx->wwx_ticket), 274 "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)", 275 ctx->wwx_ticket, ctx, 276 mutex->wwm_u.ctx->wwx_ticket, mutex->wwm_u.ctx); 277 278 collision = rb_tree_insert_node(&mutex->wwm_waiters, ctx); 279 KASSERTMSG((collision == ctx), 280 "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)", 281 ctx->wwx_ticket, ctx, collision->wwx_ticket, collision); 282 283 do cv_wait(&mutex->wwm_cv, &mutex->wwm_lock); 284 while (!(((mutex->wwm_state == WW_CTX) || 285 (mutex->wwm_state == WW_WANTOWN)) && 286 (mutex->wwm_u.ctx == ctx))); 287 288 rb_tree_remove_node(&mutex->wwm_waiters, ctx); 289 } 290 291 static int 292 ww_mutex_lock_wait_sig(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx) 293 { 294 struct ww_acquire_ctx *collision __diagused; 295 int ret; 296 297 KASSERT(mutex_owned(&mutex->wwm_lock)); 298 299 KASSERT((mutex->wwm_state == WW_CTX) || 300 (mutex->wwm_state == WW_WANTOWN)); 301 KASSERT(mutex->wwm_u.ctx != ctx); 302 KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class), 303 "ww mutex class mismatch: %p != %p", 304 ctx->wwx_class, mutex->wwm_u.ctx->wwx_class); 305 KASSERTMSG((mutex->wwm_u.ctx->wwx_ticket != ctx->wwx_ticket), 306 "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)", 307 ctx->wwx_ticket, ctx, 308 mutex->wwm_u.ctx->wwx_ticket, mutex->wwm_u.ctx); 309 310 collision = rb_tree_insert_node(&mutex->wwm_waiters, ctx); 311 KASSERTMSG((collision == ctx), 312 "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)", 313 ctx->wwx_ticket, ctx, collision->wwx_ticket, collision); 314 315 do { 316 /* XXX errno NetBSD->Linux */ 317 ret = -cv_wait_sig(&mutex->wwm_cv, &mutex->wwm_lock); 318 if (ret) 319 goto out; 320 } while (!(((mutex->wwm_state == WW_CTX) || 321 (mutex->wwm_state == WW_WANTOWN)) && 322 (mutex->wwm_u.ctx == ctx))); 323 324 out: rb_tree_remove_node(&mutex->wwm_waiters, ctx); 325 return ret; 326 } 327 328 static void 329 ww_mutex_lock_noctx(struct ww_mutex *mutex) 330 { 331 332 mutex_enter(&mutex->wwm_lock); 333 retry: switch (mutex->wwm_state) { 334 case WW_UNLOCKED: 335 mutex->wwm_state = WW_OWNED; 336 mutex->wwm_u.owner = curlwp; 337 WW_LOCKED(mutex); 338 break; 339 case WW_OWNED: 340 KASSERTMSG((mutex->wwm_u.owner != curlwp), 341 "locking %p against myself: %p", mutex, curlwp); 342 ww_mutex_state_wait(mutex, WW_OWNED); 343 goto retry; 344 case WW_CTX: 345 KASSERT(mutex->wwm_u.ctx != NULL); 346 mutex->wwm_state = WW_WANTOWN; 347 /* FALLTHROUGH */ 348 case WW_WANTOWN: 349 KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp), 350 "locking %p against myself: %p", mutex, curlwp); 351 ww_mutex_state_wait(mutex, WW_WANTOWN); 352 goto retry; 353 default: 354 panic("wait/wound mutex %p in bad state: %d", 355 mutex, (int)mutex->wwm_state); 356 } 357 KASSERT(mutex->wwm_state == WW_OWNED); 358 KASSERT(mutex->wwm_u.owner == curlwp); 359 mutex_exit(&mutex->wwm_lock); 360 } 361 362 static int 363 ww_mutex_lock_noctx_sig(struct ww_mutex *mutex) 364 { 365 int ret; 366 367 mutex_enter(&mutex->wwm_lock); 368 retry: switch (mutex->wwm_state) { 369 case WW_UNLOCKED: 370 mutex->wwm_state = WW_OWNED; 371 mutex->wwm_u.owner = curlwp; 372 WW_LOCKED(mutex); 373 break; 374 case WW_OWNED: 375 KASSERTMSG((mutex->wwm_u.owner != curlwp), 376 "locking %p against myself: %p", mutex, curlwp); 377 ret = ww_mutex_state_wait_sig(mutex, WW_OWNED); 378 if (ret) 379 goto out; 380 goto retry; 381 case WW_CTX: 382 KASSERT(mutex->wwm_u.ctx != NULL); 383 mutex->wwm_state = WW_WANTOWN; 384 /* FALLTHROUGH */ 385 case WW_WANTOWN: 386 KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp), 387 "locking %p against myself: %p", mutex, curlwp); 388 ret = ww_mutex_state_wait_sig(mutex, WW_WANTOWN); 389 if (ret) 390 goto out; 391 goto retry; 392 default: 393 panic("wait/wound mutex %p in bad state: %d", 394 mutex, (int)mutex->wwm_state); 395 } 396 KASSERT(mutex->wwm_state == WW_OWNED); 397 KASSERT(mutex->wwm_u.owner == curlwp); 398 ret = 0; 399 out: mutex_exit(&mutex->wwm_lock); 400 return ret; 401 } 402 403 int 404 ww_mutex_lock(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx) 405 { 406 407 /* 408 * We do not WW_WANTLOCK at the beginning because we may 409 * correctly already hold it, if we have a context, in which 410 * case we must return EALREADY to the caller. 411 */ 412 ASSERT_SLEEPABLE(); 413 414 if (ctx == NULL) { 415 WW_WANTLOCK(mutex); 416 ww_mutex_lock_noctx(mutex); 417 return 0; 418 } 419 420 KASSERTMSG((ctx->wwx_owner == curlwp), 421 "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp); 422 KASSERTMSG(!ctx->wwx_acquire_done, 423 "ctx %p done acquiring locks, can't acquire more", ctx); 424 KASSERTMSG((ctx->wwx_acquired != ~0U), 425 "ctx %p finished, can't be used any more", ctx); 426 KASSERTMSG((ctx->wwx_class == mutex->wwm_class), 427 "ctx %p in class %p, mutex %p in class %p", 428 ctx, ctx->wwx_class, mutex, mutex->wwm_class); 429 430 mutex_enter(&mutex->wwm_lock); 431 retry: switch (mutex->wwm_state) { 432 case WW_UNLOCKED: 433 WW_WANTLOCK(mutex); 434 mutex->wwm_state = WW_CTX; 435 mutex->wwm_u.ctx = ctx; 436 WW_LOCKED(mutex); 437 goto locked; 438 case WW_OWNED: 439 WW_WANTLOCK(mutex); 440 KASSERTMSG((mutex->wwm_u.owner != curlwp), 441 "locking %p against myself: %p", mutex, curlwp); 442 ww_mutex_state_wait(mutex, WW_OWNED); 443 goto retry; 444 case WW_CTX: 445 break; 446 case WW_WANTOWN: 447 ww_mutex_state_wait(mutex, WW_WANTOWN); 448 goto retry; 449 default: 450 panic("wait/wound mutex %p in bad state: %d", 451 mutex, (int)mutex->wwm_state); 452 } 453 454 KASSERT(mutex->wwm_state == WW_CTX); 455 KASSERT(mutex->wwm_u.ctx != NULL); 456 KASSERT((mutex->wwm_u.ctx == ctx) || 457 (mutex->wwm_u.ctx->wwx_owner != curlwp)); 458 459 if (mutex->wwm_u.ctx == ctx) { 460 /* 461 * We already own it. Yes, this can happen correctly 462 * for objects whose locking order is determined by 463 * userland. 464 */ 465 mutex_exit(&mutex->wwm_lock); 466 return -EALREADY; 467 } 468 469 /* 470 * We do not own it. We can safely assert to LOCKDEBUG that we 471 * want it. 472 */ 473 WW_WANTLOCK(mutex); 474 475 if (mutex->wwm_u.ctx->wwx_ticket < ctx->wwx_ticket) { 476 /* 477 * Owned by a higher-priority party. Tell the caller 478 * to unlock everything and start over. 479 */ 480 KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class), 481 "ww mutex class mismatch: %p != %p", 482 ctx->wwx_class, mutex->wwm_u.ctx->wwx_class); 483 mutex_exit(&mutex->wwm_lock); 484 return -EDEADLK; 485 } 486 487 /* 488 * Owned by a lower-priority party. Ask that party to wake us 489 * when it is done or it realizes it needs to back off. 490 */ 491 ww_mutex_lock_wait(mutex, ctx); 492 493 locked: ctx->wwx_acquired++; 494 KASSERT((mutex->wwm_state == WW_CTX) || 495 (mutex->wwm_state == WW_WANTOWN)); 496 KASSERT(mutex->wwm_u.ctx == ctx); 497 mutex_exit(&mutex->wwm_lock); 498 return 0; 499 } 500 501 int 502 ww_mutex_lock_interruptible(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx) 503 { 504 int ret; 505 506 /* 507 * We do not WW_WANTLOCK at the beginning because we may 508 * correctly already hold it, if we have a context, in which 509 * case we must return EALREADY to the caller. 510 */ 511 ASSERT_SLEEPABLE(); 512 513 if (ctx == NULL) { 514 WW_WANTLOCK(mutex); 515 return ww_mutex_lock_noctx_sig(mutex); 516 } 517 518 KASSERTMSG((ctx->wwx_owner == curlwp), 519 "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp); 520 KASSERTMSG(!ctx->wwx_acquire_done, 521 "ctx %p done acquiring locks, can't acquire more", ctx); 522 KASSERTMSG((ctx->wwx_acquired != ~0U), 523 "ctx %p finished, can't be used any more", ctx); 524 KASSERTMSG((ctx->wwx_class == mutex->wwm_class), 525 "ctx %p in class %p, mutex %p in class %p", 526 ctx, ctx->wwx_class, mutex, mutex->wwm_class); 527 528 mutex_enter(&mutex->wwm_lock); 529 retry: switch (mutex->wwm_state) { 530 case WW_UNLOCKED: 531 WW_WANTLOCK(mutex); 532 mutex->wwm_state = WW_CTX; 533 mutex->wwm_u.ctx = ctx; 534 WW_LOCKED(mutex); 535 goto locked; 536 case WW_OWNED: 537 WW_WANTLOCK(mutex); 538 KASSERTMSG((mutex->wwm_u.owner != curlwp), 539 "locking %p against myself: %p", mutex, curlwp); 540 ret = ww_mutex_state_wait_sig(mutex, WW_OWNED); 541 if (ret) 542 goto out; 543 goto retry; 544 case WW_CTX: 545 break; 546 case WW_WANTOWN: 547 ret = ww_mutex_state_wait_sig(mutex, WW_WANTOWN); 548 if (ret) 549 goto out; 550 goto retry; 551 default: 552 panic("wait/wound mutex %p in bad state: %d", 553 mutex, (int)mutex->wwm_state); 554 } 555 556 KASSERT(mutex->wwm_state == WW_CTX); 557 KASSERT(mutex->wwm_u.ctx != NULL); 558 KASSERT((mutex->wwm_u.ctx == ctx) || 559 (mutex->wwm_u.ctx->wwx_owner != curlwp)); 560 561 if (mutex->wwm_u.ctx == ctx) { 562 /* 563 * We already own it. Yes, this can happen correctly 564 * for objects whose locking order is determined by 565 * userland. 566 */ 567 mutex_exit(&mutex->wwm_lock); 568 return -EALREADY; 569 } 570 571 /* 572 * We do not own it. We can safely assert to LOCKDEBUG that we 573 * want it. 574 */ 575 WW_WANTLOCK(mutex); 576 577 if (mutex->wwm_u.ctx->wwx_ticket < ctx->wwx_ticket) { 578 /* 579 * Owned by a higher-priority party. Tell the caller 580 * to unlock everything and start over. 581 */ 582 KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class), 583 "ww mutex class mismatch: %p != %p", 584 ctx->wwx_class, mutex->wwm_u.ctx->wwx_class); 585 mutex_exit(&mutex->wwm_lock); 586 return -EDEADLK; 587 } 588 589 /* 590 * Owned by a lower-priority party. Ask that party to wake us 591 * when it is done or it realizes it needs to back off. 592 */ 593 ret = ww_mutex_lock_wait_sig(mutex, ctx); 594 if (ret) 595 goto out; 596 597 locked: KASSERT((mutex->wwm_state == WW_CTX) || 598 (mutex->wwm_state == WW_WANTOWN)); 599 KASSERT(mutex->wwm_u.ctx == ctx); 600 ctx->wwx_acquired++; 601 ret = 0; 602 out: mutex_exit(&mutex->wwm_lock); 603 return ret; 604 } 605 606 void 607 ww_mutex_lock_slow(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx) 608 { 609 610 /* Caller must not try to lock against self here. */ 611 WW_WANTLOCK(mutex); 612 ASSERT_SLEEPABLE(); 613 614 if (ctx == NULL) { 615 ww_mutex_lock_noctx(mutex); 616 return; 617 } 618 619 KASSERTMSG((ctx->wwx_owner == curlwp), 620 "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp); 621 KASSERTMSG(!ctx->wwx_acquire_done, 622 "ctx %p done acquiring locks, can't acquire more", ctx); 623 KASSERTMSG((ctx->wwx_acquired != ~0U), 624 "ctx %p finished, can't be used any more", ctx); 625 KASSERTMSG((ctx->wwx_acquired == 0), 626 "ctx %p still holds %u locks, not allowed in slow path", 627 ctx, ctx->wwx_acquired); 628 KASSERTMSG((ctx->wwx_class == mutex->wwm_class), 629 "ctx %p in class %p, mutex %p in class %p", 630 ctx, ctx->wwx_class, mutex, mutex->wwm_class); 631 632 mutex_enter(&mutex->wwm_lock); 633 retry: switch (mutex->wwm_state) { 634 case WW_UNLOCKED: 635 mutex->wwm_state = WW_CTX; 636 mutex->wwm_u.ctx = ctx; 637 WW_LOCKED(mutex); 638 goto locked; 639 case WW_OWNED: 640 KASSERTMSG((mutex->wwm_u.owner != curlwp), 641 "locking %p against myself: %p", mutex, curlwp); 642 ww_mutex_state_wait(mutex, WW_OWNED); 643 goto retry; 644 case WW_CTX: 645 break; 646 case WW_WANTOWN: 647 ww_mutex_state_wait(mutex, WW_WANTOWN); 648 goto retry; 649 default: 650 panic("wait/wound mutex %p in bad state: %d", 651 mutex, (int)mutex->wwm_state); 652 } 653 654 KASSERT(mutex->wwm_state == WW_CTX); 655 KASSERT(mutex->wwm_u.ctx != NULL); 656 KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp), 657 "locking %p against myself: %p", mutex, curlwp); 658 659 /* 660 * Owned by another party, of any priority. Ask that party to 661 * wake us when it's done. 662 */ 663 ww_mutex_lock_wait(mutex, ctx); 664 665 locked: KASSERT((mutex->wwm_state == WW_CTX) || 666 (mutex->wwm_state == WW_WANTOWN)); 667 KASSERT(mutex->wwm_u.ctx == ctx); 668 ctx->wwx_acquired++; 669 mutex_exit(&mutex->wwm_lock); 670 } 671 672 int 673 ww_mutex_lock_slow_interruptible(struct ww_mutex *mutex, 674 struct ww_acquire_ctx *ctx) 675 { 676 int ret; 677 678 WW_WANTLOCK(mutex); 679 ASSERT_SLEEPABLE(); 680 681 if (ctx == NULL) 682 return ww_mutex_lock_noctx_sig(mutex); 683 684 KASSERTMSG((ctx->wwx_owner == curlwp), 685 "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp); 686 KASSERTMSG(!ctx->wwx_acquire_done, 687 "ctx %p done acquiring locks, can't acquire more", ctx); 688 KASSERTMSG((ctx->wwx_acquired != ~0U), 689 "ctx %p finished, can't be used any more", ctx); 690 KASSERTMSG((ctx->wwx_acquired == 0), 691 "ctx %p still holds %u locks, not allowed in slow path", 692 ctx, ctx->wwx_acquired); 693 KASSERTMSG((ctx->wwx_class == mutex->wwm_class), 694 "ctx %p in class %p, mutex %p in class %p", 695 ctx, ctx->wwx_class, mutex, mutex->wwm_class); 696 697 mutex_enter(&mutex->wwm_lock); 698 retry: switch (mutex->wwm_state) { 699 case WW_UNLOCKED: 700 mutex->wwm_state = WW_CTX; 701 mutex->wwm_u.ctx = ctx; 702 WW_LOCKED(mutex); 703 goto locked; 704 case WW_OWNED: 705 KASSERTMSG((mutex->wwm_u.owner != curlwp), 706 "locking %p against myself: %p", mutex, curlwp); 707 ret = ww_mutex_state_wait_sig(mutex, WW_OWNED); 708 if (ret) 709 goto out; 710 goto retry; 711 case WW_CTX: 712 break; 713 case WW_WANTOWN: 714 ret = ww_mutex_state_wait_sig(mutex, WW_WANTOWN); 715 if (ret) 716 goto out; 717 goto retry; 718 default: 719 panic("wait/wound mutex %p in bad state: %d", 720 mutex, (int)mutex->wwm_state); 721 } 722 723 KASSERT(mutex->wwm_state == WW_CTX); 724 KASSERT(mutex->wwm_u.ctx != NULL); 725 KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp), 726 "locking %p against myself: %p", mutex, curlwp); 727 728 /* 729 * Owned by another party, of any priority. Ask that party to 730 * wake us when it's done. 731 */ 732 ret = ww_mutex_lock_wait_sig(mutex, ctx); 733 if (ret) 734 goto out; 735 736 locked: KASSERT((mutex->wwm_state == WW_CTX) || 737 (mutex->wwm_state == WW_WANTOWN)); 738 KASSERT(mutex->wwm_u.ctx == ctx); 739 ctx->wwx_acquired++; 740 ret = 0; 741 out: mutex_exit(&mutex->wwm_lock); 742 return ret; 743 } 744 745 int 746 ww_mutex_trylock(struct ww_mutex *mutex) 747 { 748 int ret; 749 750 mutex_enter(&mutex->wwm_lock); 751 if (mutex->wwm_state == WW_UNLOCKED) { 752 mutex->wwm_state = WW_OWNED; 753 mutex->wwm_u.owner = curlwp; 754 WW_WANTLOCK(mutex); 755 WW_LOCKED(mutex); 756 ret = 1; 757 } else { 758 KASSERTMSG(((mutex->wwm_state != WW_OWNED) || 759 (mutex->wwm_u.owner != curlwp)), 760 "locking %p against myself: %p", mutex, curlwp); 761 KASSERTMSG(((mutex->wwm_state != WW_CTX) || 762 (mutex->wwm_u.ctx->wwx_owner != curlwp)), 763 "locking %p against myself: %p", mutex, curlwp); 764 KASSERTMSG(((mutex->wwm_state != WW_WANTOWN) || 765 (mutex->wwm_u.ctx->wwx_owner != curlwp)), 766 "locking %p against myself: %p", mutex, curlwp); 767 ret = 0; 768 } 769 mutex_exit(&mutex->wwm_lock); 770 771 return ret; 772 } 773 774 static void 775 ww_mutex_unlock_release(struct ww_mutex *mutex) 776 { 777 778 KASSERT(mutex_owned(&mutex->wwm_lock)); 779 KASSERT((mutex->wwm_state == WW_CTX) || 780 (mutex->wwm_state == WW_WANTOWN)); 781 KASSERT(mutex->wwm_u.ctx != NULL); 782 KASSERTMSG((mutex->wwm_u.ctx->wwx_owner == curlwp), 783 "ww_mutex %p ctx %p held by %p, not by self (%p)", 784 mutex, mutex->wwm_u.ctx, mutex->wwm_u.ctx->wwx_owner, 785 curlwp); 786 KASSERT(mutex->wwm_u.ctx->wwx_acquired != ~0U); 787 mutex->wwm_u.ctx->wwx_acquired--; 788 mutex->wwm_u.ctx = NULL; 789 } 790 791 void 792 ww_mutex_unlock(struct ww_mutex *mutex) 793 { 794 struct ww_acquire_ctx *ctx; 795 796 mutex_enter(&mutex->wwm_lock); 797 KASSERT(mutex->wwm_state != WW_UNLOCKED); 798 switch (mutex->wwm_state) { 799 case WW_UNLOCKED: 800 panic("unlocking unlocked wait/wound mutex: %p", mutex); 801 case WW_OWNED: 802 /* Let the context lockers fight over it. */ 803 mutex->wwm_u.owner = NULL; 804 mutex->wwm_state = WW_UNLOCKED; 805 break; 806 case WW_CTX: 807 ww_mutex_unlock_release(mutex); 808 /* 809 * If there are any waiters with contexts, grant the 810 * lock to the highest-priority one. Otherwise, just 811 * unlock it. 812 */ 813 if ((ctx = RB_TREE_MIN(&mutex->wwm_waiters)) != NULL) { 814 mutex->wwm_state = WW_CTX; 815 mutex->wwm_u.ctx = ctx; 816 } else { 817 mutex->wwm_state = WW_UNLOCKED; 818 } 819 break; 820 case WW_WANTOWN: 821 ww_mutex_unlock_release(mutex); 822 /* Let the non-context lockers fight over it. */ 823 mutex->wwm_state = WW_UNLOCKED; 824 break; 825 } 826 WW_UNLOCKED(mutex); 827 cv_broadcast(&mutex->wwm_cv); 828 mutex_exit(&mutex->wwm_lock); 829 } 830