1 /* 2 * Copyright (c) 2009 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 /* 35 * Implement fast persistent locks based on atomic_cmpset_int() with 36 * semantics similar to lockmgr locks but faster and taking up much less 37 * space. Taken from HAMMER's lock implementation. 38 * 39 * These are meant to complement our LWKT tokens. Tokens are only held 40 * while the thread is running. Mutexes can be held across blocking 41 * conditions. 42 * 43 * Most of the support is in sys/mutex[2].h. We mostly provide backoff 44 * functions here. 45 */ 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/kernel.h> 50 #include <sys/sysctl.h> 51 #include <sys/thread.h> 52 53 #include <machine/cpufunc.h> 54 55 #include <sys/thread2.h> 56 #include <sys/mutex2.h> 57 58 static __int64_t mtx_contention_count; 59 static __int64_t mtx_collision_count; 60 static __int64_t mtx_wakeup_count; 61 62 SYSCTL_QUAD(_kern, OID_AUTO, mtx_contention_count, CTLFLAG_RW, 63 &mtx_contention_count, 0, ""); 64 SYSCTL_QUAD(_kern, OID_AUTO, mtx_collision_count, CTLFLAG_RW, 65 &mtx_collision_count, 0, ""); 66 SYSCTL_QUAD(_kern, OID_AUTO, mtx_wakeup_count, CTLFLAG_RW, 67 &mtx_wakeup_count, 0, ""); 68 69 static void mtx_chain_link(mtx_t mtx); 70 static void mtx_delete_link(mtx_t mtx, mtx_link_t link); 71 72 /* 73 * Exclusive-lock a mutex, block until acquired. Recursion is allowed. 74 * 75 * Returns 0 on success, or the tsleep() return code on failure. 76 * An error can only be returned if PCATCH is specified in the flags. 77 */ 78 static __inline int 79 __mtx_lock_ex(mtx_t mtx, mtx_link_t link, const char *ident, int flags, int to) 80 { 81 u_int lock; 82 u_int nlock; 83 int error; 84 85 for (;;) { 86 lock = mtx->mtx_lock; 87 if (lock == 0) { 88 nlock = MTX_EXCLUSIVE | 1; 89 if (atomic_cmpset_int(&mtx->mtx_lock, 0, nlock)) { 90 mtx->mtx_owner = curthread; 91 error = 0; 92 break; 93 } 94 } else if ((lock & MTX_EXCLUSIVE) && 95 mtx->mtx_owner == curthread) { 96 KKASSERT((lock & MTX_MASK) != MTX_MASK); 97 nlock = lock + 1; 98 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) { 99 error = 0; 100 break; 101 } 102 } else { 103 /* 104 * Clearing MTX_EXLINK in lock causes us to loop until 105 * MTX_EXLINK is available. However, to avoid 106 * unnecessary cpu cache traffic we poll instead. 107 * 108 * Setting MTX_EXLINK in nlock causes us to loop until 109 * we can acquire MTX_EXLINK. 110 * 111 * Also set MTX_EXWANTED coincident with EXLINK, if 112 * not already set. 113 */ 114 thread_t td; 115 116 if (lock & MTX_EXLINK) { 117 cpu_pause(); 118 ++mtx_collision_count; 119 continue; 120 } 121 td = curthread; 122 /*lock &= ~MTX_EXLINK;*/ 123 nlock = lock | MTX_EXWANTED | MTX_EXLINK; 124 ++td->td_critcount; 125 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) { 126 /* 127 * Check for early abort 128 */ 129 if (link->state == MTX_LINK_ABORTED) { 130 atomic_clear_int(&mtx->mtx_lock, 131 MTX_EXLINK); 132 --td->td_critcount; 133 error = ENOLCK; 134 if (mtx->mtx_link == NULL) { 135 atomic_clear_int(&mtx->mtx_lock, 136 MTX_EXWANTED); 137 } 138 break; 139 } 140 141 /* 142 * Success. Link in our structure then 143 * release EXLINK and sleep. 144 */ 145 link->owner = td; 146 link->state = MTX_LINK_LINKED; 147 if (mtx->mtx_link) { 148 link->next = mtx->mtx_link; 149 link->prev = link->next->prev; 150 link->next->prev = link; 151 link->prev->next = link; 152 } else { 153 link->next = link; 154 link->prev = link; 155 mtx->mtx_link = link; 156 } 157 tsleep_interlock(link, 0); 158 atomic_clear_int(&mtx->mtx_lock, MTX_EXLINK); 159 --td->td_critcount; 160 161 error = tsleep(link, flags, ident, to); 162 ++mtx_contention_count; 163 164 /* 165 * Normal unlink, we should own the exclusive 166 * lock now. 167 */ 168 if (link->state == MTX_LINK_LINKED) 169 mtx_delete_link(mtx, link); 170 if (link->state == MTX_LINK_ACQUIRED) { 171 KKASSERT(mtx->mtx_owner == link->owner); 172 error = 0; 173 break; 174 } 175 176 /* 177 * Aborted lock (mtx_abort_ex called). 178 */ 179 if (link->state == MTX_LINK_ABORTED) { 180 error = ENOLCK; 181 break; 182 } 183 184 /* 185 * tsleep error, else retry. 186 */ 187 if (error) 188 break; 189 } else { 190 --td->td_critcount; 191 } 192 } 193 ++mtx_collision_count; 194 } 195 return (error); 196 } 197 198 int 199 _mtx_lock_ex_link(mtx_t mtx, mtx_link_t link, 200 const char *ident, int flags, int to) 201 { 202 return(__mtx_lock_ex(mtx, link, ident, flags, to)); 203 } 204 205 int 206 _mtx_lock_ex(mtx_t mtx, const char *ident, int flags, int to) 207 { 208 struct mtx_link link; 209 210 mtx_link_init(&link); 211 return(__mtx_lock_ex(mtx, &link, ident, flags, to)); 212 } 213 214 int 215 _mtx_lock_ex_quick(mtx_t mtx, const char *ident) 216 { 217 struct mtx_link link; 218 219 mtx_link_init(&link); 220 return(__mtx_lock_ex(mtx, &link, ident, 0, 0)); 221 } 222 223 /* 224 * Share-lock a mutex, block until acquired. Recursion is allowed. 225 * 226 * Returns 0 on success, or the tsleep() return code on failure. 227 * An error can only be returned if PCATCH is specified in the flags. 228 * 229 * NOTE: Shared locks get a mass-wakeup so if the tsleep fails we 230 * do not have to chain the wakeup(). 231 */ 232 static __inline int 233 __mtx_lock_sh(mtx_t mtx, const char *ident, int flags, int to) 234 { 235 u_int lock; 236 u_int nlock; 237 int error; 238 239 for (;;) { 240 lock = mtx->mtx_lock; 241 if ((lock & MTX_EXCLUSIVE) == 0) { 242 KKASSERT((lock & MTX_MASK) != MTX_MASK); 243 nlock = lock + 1; 244 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) { 245 error = 0; 246 break; 247 } 248 } else { 249 nlock = lock | MTX_SHWANTED; 250 tsleep_interlock(mtx, 0); 251 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) { 252 error = tsleep(mtx, flags, ident, to); 253 if (error) 254 break; 255 ++mtx_contention_count; 256 /* retry */ 257 } else { 258 crit_enter(); 259 tsleep_remove(curthread); 260 crit_exit(); 261 } 262 } 263 ++mtx_collision_count; 264 } 265 return (error); 266 } 267 268 int 269 _mtx_lock_sh(mtx_t mtx, const char *ident, int flags, int to) 270 { 271 return (__mtx_lock_sh(mtx, ident, flags, to)); 272 } 273 274 int 275 _mtx_lock_sh_quick(mtx_t mtx, const char *ident) 276 { 277 return (__mtx_lock_sh(mtx, ident, 0, 0)); 278 } 279 280 /* 281 * Get an exclusive spinlock the hard way. 282 */ 283 void 284 _mtx_spinlock(mtx_t mtx) 285 { 286 u_int lock; 287 u_int nlock; 288 int bb = 1; 289 int bo; 290 291 for (;;) { 292 lock = mtx->mtx_lock; 293 if (lock == 0) { 294 nlock = MTX_EXCLUSIVE | 1; 295 if (atomic_cmpset_int(&mtx->mtx_lock, 0, nlock)) { 296 mtx->mtx_owner = curthread; 297 break; 298 } 299 } else if ((lock & MTX_EXCLUSIVE) && 300 mtx->mtx_owner == curthread) { 301 KKASSERT((lock & MTX_MASK) != MTX_MASK); 302 nlock = lock + 1; 303 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) 304 break; 305 } else { 306 /* MWAIT here */ 307 if (bb < 1000) 308 ++bb; 309 cpu_pause(); 310 for (bo = 0; bo < bb; ++bo) 311 ; 312 ++mtx_contention_count; 313 } 314 cpu_pause(); 315 ++mtx_collision_count; 316 } 317 } 318 319 /* 320 * Attempt to acquire a spinlock, if we fail we must undo the 321 * gd->gd_spinlocks/gd->gd_curthead->td_critcount predisposition. 322 * 323 * Returns 0 on success, EAGAIN on failure. 324 */ 325 int 326 _mtx_spinlock_try(mtx_t mtx) 327 { 328 globaldata_t gd = mycpu; 329 u_int lock; 330 u_int nlock; 331 int res = 0; 332 333 for (;;) { 334 lock = mtx->mtx_lock; 335 if (lock == 0) { 336 nlock = MTX_EXCLUSIVE | 1; 337 if (atomic_cmpset_int(&mtx->mtx_lock, 0, nlock)) { 338 mtx->mtx_owner = gd->gd_curthread; 339 break; 340 } 341 } else if ((lock & MTX_EXCLUSIVE) && 342 mtx->mtx_owner == gd->gd_curthread) { 343 KKASSERT((lock & MTX_MASK) != MTX_MASK); 344 nlock = lock + 1; 345 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) 346 break; 347 } else { 348 --gd->gd_spinlocks; 349 cpu_ccfence(); 350 --gd->gd_curthread->td_critcount; 351 res = EAGAIN; 352 break; 353 } 354 cpu_pause(); 355 ++mtx_collision_count; 356 } 357 return res; 358 } 359 360 #if 0 361 362 void 363 _mtx_spinlock_sh(mtx_t mtx) 364 { 365 u_int lock; 366 u_int nlock; 367 int bb = 1; 368 int bo; 369 370 for (;;) { 371 lock = mtx->mtx_lock; 372 if ((lock & MTX_EXCLUSIVE) == 0) { 373 KKASSERT((lock & MTX_MASK) != MTX_MASK); 374 nlock = lock + 1; 375 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) 376 break; 377 } else { 378 /* MWAIT here */ 379 if (bb < 1000) 380 ++bb; 381 cpu_pause(); 382 for (bo = 0; bo < bb; ++bo) 383 ; 384 ++mtx_contention_count; 385 } 386 cpu_pause(); 387 ++mtx_collision_count; 388 } 389 } 390 391 #endif 392 393 int 394 _mtx_lock_ex_try(mtx_t mtx) 395 { 396 u_int lock; 397 u_int nlock; 398 int error = 0; 399 400 for (;;) { 401 lock = mtx->mtx_lock; 402 if (lock == 0) { 403 nlock = MTX_EXCLUSIVE | 1; 404 if (atomic_cmpset_int(&mtx->mtx_lock, 0, nlock)) { 405 mtx->mtx_owner = curthread; 406 break; 407 } 408 } else if ((lock & MTX_EXCLUSIVE) && 409 mtx->mtx_owner == curthread) { 410 KKASSERT((lock & MTX_MASK) != MTX_MASK); 411 nlock = lock + 1; 412 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) 413 break; 414 } else { 415 error = EAGAIN; 416 break; 417 } 418 cpu_pause(); 419 ++mtx_collision_count; 420 } 421 return (error); 422 } 423 424 int 425 _mtx_lock_sh_try(mtx_t mtx) 426 { 427 u_int lock; 428 u_int nlock; 429 int error = 0; 430 431 for (;;) { 432 lock = mtx->mtx_lock; 433 if ((lock & MTX_EXCLUSIVE) == 0) { 434 KKASSERT((lock & MTX_MASK) != MTX_MASK); 435 nlock = lock + 1; 436 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) 437 break; 438 } else { 439 error = EAGAIN; 440 break; 441 } 442 cpu_pause(); 443 ++mtx_collision_count; 444 } 445 return (error); 446 } 447 448 /* 449 * If the lock is held exclusively it must be owned by the caller. If the 450 * lock is already a shared lock this operation is a NOP. A panic will 451 * occur if the lock is not held either shared or exclusive. 452 * 453 * The exclusive count is converted to a shared count. 454 */ 455 void 456 _mtx_downgrade(mtx_t mtx) 457 { 458 u_int lock; 459 u_int nlock; 460 461 for (;;) { 462 lock = mtx->mtx_lock; 463 if ((lock & MTX_EXCLUSIVE) == 0) { 464 KKASSERT((lock & MTX_MASK) > 0); 465 break; 466 } 467 KKASSERT(mtx->mtx_owner == curthread); 468 nlock = lock & ~(MTX_EXCLUSIVE | MTX_SHWANTED); 469 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) { 470 if (lock & MTX_SHWANTED) { 471 wakeup(mtx); 472 ++mtx_wakeup_count; 473 } 474 break; 475 } 476 cpu_pause(); 477 ++mtx_collision_count; 478 } 479 } 480 481 /* 482 * Upgrade a shared lock to an exclusive lock. The upgrade will fail if 483 * the shared lock has a count other then 1. Optimize the most likely case 484 * but note that a single cmpset can fail due to WANTED races. 485 * 486 * If the lock is held exclusively it must be owned by the caller and 487 * this function will simply return without doing anything. A panic will 488 * occur if the lock is held exclusively by someone other then the caller. 489 * 490 * Returns 0 on success, EDEADLK on failure. 491 */ 492 int 493 _mtx_upgrade_try(mtx_t mtx) 494 { 495 u_int lock; 496 u_int nlock; 497 int error = 0; 498 499 for (;;) { 500 lock = mtx->mtx_lock; 501 502 if ((lock & ~MTX_EXWANTED) == 1) { 503 nlock = lock | MTX_EXCLUSIVE; 504 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) { 505 mtx->mtx_owner = curthread; 506 break; 507 } 508 } else if (lock & MTX_EXCLUSIVE) { 509 KKASSERT(mtx->mtx_owner == curthread); 510 break; 511 } else { 512 error = EDEADLK; 513 break; 514 } 515 cpu_pause(); 516 ++mtx_collision_count; 517 } 518 return (error); 519 } 520 521 /* 522 * Unlock a lock. The caller must hold the lock either shared or exclusive. 523 * 524 * Any release which makes the lock available when others want an exclusive 525 * lock causes us to chain the owner to the next exclusive lock instead of 526 * releasing the lock. 527 */ 528 void 529 _mtx_unlock(mtx_t mtx) 530 { 531 u_int lock; 532 u_int nlock; 533 534 for (;;) { 535 lock = mtx->mtx_lock; 536 nlock = lock & ~(MTX_SHWANTED | MTX_EXLINK); 537 538 if (nlock == 1) { 539 /* 540 * Last release, shared lock, no exclusive waiters. 541 */ 542 nlock = lock & MTX_EXLINK; 543 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) 544 break; 545 } else if (nlock == (MTX_EXCLUSIVE | 1)) { 546 /* 547 * Last release, exclusive lock, no exclusive waiters. 548 * Wake up any shared waiters. 549 */ 550 mtx->mtx_owner = NULL; 551 nlock = lock & MTX_EXLINK; 552 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) { 553 if (lock & MTX_SHWANTED) { 554 wakeup(mtx); 555 ++mtx_wakeup_count; 556 } 557 break; 558 } 559 } else if (nlock == (MTX_EXWANTED | 1)) { 560 /* 561 * Last release, shared lock, with exclusive 562 * waiters. 563 * 564 * Wait for EXLINK to clear, then acquire it. 565 * We could use the cmpset for this but polling 566 * is better on the cpu caches. 567 * 568 * Acquire an exclusive lock leaving the lockcount 569 * set to 1, and get EXLINK for access to mtx_link. 570 */ 571 thread_t td; 572 573 if (lock & MTX_EXLINK) { 574 cpu_pause(); 575 ++mtx_collision_count; 576 continue; 577 } 578 td = curthread; 579 /*lock &= ~MTX_EXLINK;*/ 580 nlock |= MTX_EXLINK | MTX_EXCLUSIVE; 581 nlock |= (lock & MTX_SHWANTED); 582 ++td->td_critcount; 583 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) { 584 mtx_chain_link(mtx); 585 --td->td_critcount; 586 break; 587 } 588 --td->td_critcount; 589 } else if (nlock == (MTX_EXCLUSIVE | MTX_EXWANTED | 1)) { 590 /* 591 * Last release, exclusive lock, with exclusive 592 * waiters. 593 * 594 * leave the exclusive lock intact and the lockcount 595 * set to 1, and get EXLINK for access to mtx_link. 596 */ 597 thread_t td; 598 599 if (lock & MTX_EXLINK) { 600 cpu_pause(); 601 ++mtx_collision_count; 602 continue; 603 } 604 td = curthread; 605 /*lock &= ~MTX_EXLINK;*/ 606 nlock |= MTX_EXLINK; 607 nlock |= (lock & MTX_SHWANTED); 608 ++td->td_critcount; 609 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) { 610 mtx_chain_link(mtx); 611 --td->td_critcount; 612 break; 613 } 614 --td->td_critcount; 615 } else { 616 /* 617 * Not the last release (shared or exclusive) 618 */ 619 nlock = lock - 1; 620 KKASSERT((nlock & MTX_MASK) != MTX_MASK); 621 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) 622 break; 623 } 624 cpu_pause(); 625 ++mtx_collision_count; 626 } 627 } 628 629 /* 630 * Chain mtx_chain_link. Called with the lock held exclusively with a 631 * single ref count, and also with MTX_EXLINK held. 632 */ 633 static void 634 mtx_chain_link(mtx_t mtx) 635 { 636 mtx_link_t link; 637 u_int lock; 638 u_int nlock; 639 u_int clock; /* bits we own and want to clear */ 640 641 /* 642 * Chain the exclusive lock to the next link. The caller cleared 643 * SHWANTED so if there is no link we have to wake up any shared 644 * waiters. 645 */ 646 clock = MTX_EXLINK; 647 if ((link = mtx->mtx_link) != NULL) { 648 KKASSERT(link->state == MTX_LINK_LINKED); 649 if (link->next == link) { 650 mtx->mtx_link = NULL; 651 clock |= MTX_EXWANTED; 652 } else { 653 mtx->mtx_link = link->next; 654 link->next->prev = link->prev; 655 link->prev->next = link->next; 656 } 657 link->state = MTX_LINK_ACQUIRED; 658 mtx->mtx_owner = link->owner; 659 } else { 660 /* 661 * Chain was empty, release the exclusive lock's last count 662 * as well the bits shown. 663 */ 664 clock |= MTX_EXCLUSIVE | MTX_EXWANTED | MTX_SHWANTED | 1; 665 } 666 667 /* 668 * We have to uset cmpset here to deal with MTX_SHWANTED. If 669 * we just clear the bits we can miss a wakeup or, worse, 670 * leave mtx_lock unlocked with MTX_SHWANTED still set. 671 */ 672 for (;;) { 673 lock = mtx->mtx_lock; 674 nlock = lock & ~clock; 675 676 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) { 677 if (link) { 678 /* 679 * Wakeup new exclusive holder. Leave 680 * SHWANTED intact. 681 */ 682 wakeup(link); 683 } else if (lock & MTX_SHWANTED) { 684 /* 685 * Signal any shared waiters (and we also 686 * clear SHWANTED). 687 */ 688 mtx->mtx_owner = NULL; 689 wakeup(mtx); 690 ++mtx_wakeup_count; 691 } 692 break; 693 } 694 cpu_pause(); 695 ++mtx_collision_count; 696 } 697 } 698 699 /* 700 * Delete a link structure after tsleep has failed. This code is not 701 * in the critical path as most exclusive waits are chained. 702 */ 703 static 704 void 705 mtx_delete_link(mtx_t mtx, mtx_link_t link) 706 { 707 thread_t td = curthread; 708 u_int lock; 709 u_int nlock; 710 711 /* 712 * Acquire MTX_EXLINK. 713 * 714 * Do not use cmpxchg to wait for EXLINK to clear as this might 715 * result in too much cpu cache traffic. 716 */ 717 ++td->td_critcount; 718 for (;;) { 719 lock = mtx->mtx_lock; 720 if (lock & MTX_EXLINK) { 721 cpu_pause(); 722 ++mtx_collision_count; 723 continue; 724 } 725 /* lock &= ~MTX_EXLINK; */ 726 nlock = lock | MTX_EXLINK; 727 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) 728 break; 729 cpu_pause(); 730 ++mtx_collision_count; 731 } 732 733 /* 734 * Delete the link and release EXLINK. 735 */ 736 if (link->state == MTX_LINK_LINKED) { 737 if (link->next == link) { 738 mtx->mtx_link = NULL; 739 } else { 740 mtx->mtx_link = link->next; 741 link->next->prev = link->prev; 742 link->prev->next = link->next; 743 } 744 link->state = MTX_LINK_IDLE; 745 } 746 atomic_clear_int(&mtx->mtx_lock, MTX_EXLINK); 747 --td->td_critcount; 748 } 749 750 /* 751 * Abort a mutex locking operation, causing mtx_lock_ex_link() to 752 * return ENOLCK. This may be called at any time after the 753 * mtx_link is initialized, including both before and after the call 754 * to mtx_lock_ex_link(). 755 */ 756 void 757 mtx_abort_ex_link(mtx_t mtx, mtx_link_t link) 758 { 759 thread_t td = curthread; 760 u_int lock; 761 u_int nlock; 762 763 /* 764 * Acquire MTX_EXLINK 765 */ 766 ++td->td_critcount; 767 for (;;) { 768 lock = mtx->mtx_lock; 769 if (lock & MTX_EXLINK) { 770 cpu_pause(); 771 ++mtx_collision_count; 772 continue; 773 } 774 /* lock &= ~MTX_EXLINK; */ 775 nlock = lock | MTX_EXLINK; 776 if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) 777 break; 778 cpu_pause(); 779 ++mtx_collision_count; 780 } 781 782 /* 783 * Do the abort 784 */ 785 switch(link->state) { 786 case MTX_LINK_IDLE: 787 /* 788 * Link not started yet 789 */ 790 link->state = MTX_LINK_ABORTED; 791 break; 792 case MTX_LINK_LINKED: 793 /* 794 * de-link, mark aborted, and wakeup the thread. 795 */ 796 if (link->next == link) { 797 mtx->mtx_link = NULL; 798 } else { 799 mtx->mtx_link = link->next; 800 link->next->prev = link->prev; 801 link->prev->next = link->next; 802 } 803 link->state = MTX_LINK_ABORTED; 804 wakeup(link); 805 break; 806 case MTX_LINK_ACQUIRED: 807 /* 808 * Too late, the lock was acquired. Let it complete. 809 */ 810 break; 811 default: 812 /* 813 * link already aborted, do nothing. 814 */ 815 break; 816 } 817 atomic_clear_int(&mtx->mtx_lock, MTX_EXLINK); 818 --td->td_critcount; 819 } 820