1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22/* 23 * @OSF_COPYRIGHT@ 24 */ 25/* 26 * Mach Operating System 27 * Copyright (c) 1989 Carnegie-Mellon University 28 * All rights reserved. The CMU software License Agreement specifies 29 * the terms and conditions for use and redistribution. 30 */ 31 32#include <mach_rt.h> 33#include <platforms.h> 34#include <mach_ldebug.h> 35#include <i386/asm.h> 36 37#include "assym.s" 38 39#define PAUSE rep; nop 40 41/* 42 * When performance isn't the only concern, it's 43 * nice to build stack frames... 44 */ 45#define BUILD_STACK_FRAMES (GPROF || \ 46 ((MACH_LDEBUG || ETAP_LOCK_TRACE) && MACH_KDB)) 47 48#if BUILD_STACK_FRAMES 49 50/* STack-frame-relative: */ 51#define L_PC B_PC 52#define L_ARG0 B_ARG0 53#define L_ARG1 B_ARG1 54 55#define LEAF_ENTRY(name) \ 56 Entry(name); \ 57 FRAME; \ 58 MCOUNT 59 60#define LEAF_ENTRY2(n1,n2) \ 61 Entry(n1); \ 62 Entry(n2); \ 63 FRAME; \ 64 MCOUNT 65 66#define LEAF_RET \ 67 EMARF; \ 68 ret 69 70#else /* BUILD_STACK_FRAMES */ 71 72/* Stack-pointer-relative: */ 73#define L_PC S_PC 74#define L_ARG0 S_ARG0 75#define L_ARG1 S_ARG1 76 77#define LEAF_ENTRY(name) \ 78 Entry(name) 79 80#define LEAF_ENTRY2(n1,n2) \ 81 Entry(n1); \ 82 Entry(n2) 83 84#define LEAF_RET \ 85 ret 86 87#endif /* BUILD_STACK_FRAMES */ 88 89 90/* Non-leaf routines always have a stack frame: */ 91 92#define NONLEAF_ENTRY(name) \ 93 Entry(name); \ 94 FRAME; \ 95 MCOUNT 96 97#define NONLEAF_ENTRY2(n1,n2) \ 98 Entry(n1); \ 99 Entry(n2); \ 100 FRAME; \ 101 MCOUNT 102 103#define NONLEAF_RET \ 104 EMARF; \ 105 ret 106 107 108#define M_ILK (%edx) 109#define M_LOCKED MUTEX_LOCKED(%edx) 110#define M_WAITERS MUTEX_WAITERS(%edx) 111#define M_PROMOTED_PRI MUTEX_PROMOTED_PRI(%edx) 112#define M_ITAG MUTEX_ITAG(%edx) 113#define M_PTR MUTEX_PTR(%edx) 114#if MACH_LDEBUG 115#define M_TYPE MUTEX_TYPE(%edx) 116#define M_PC MUTEX_PC(%edx) 117#define M_THREAD MUTEX_THREAD(%edx) 118#endif /* MACH_LDEBUG */ 119 120#include <i386/mp.h> 121#define CX(addr,reg) addr(,reg,4) 122 123#if MACH_LDEBUG 124/* 125 * Routines for general lock debugging. 126 */ 127#define S_TYPE SLOCK_TYPE(%edx) 128#define S_PC SLOCK_PC(%edx) 129#define S_THREAD SLOCK_THREAD(%edx) 130#define S_DURATIONH SLOCK_DURATIONH(%edx) 131#define S_DURATIONL SLOCK_DURATIONL(%edx) 132 133/* 134 * Checks for expected lock types and calls "panic" on 135 * mismatch. Detects calls to Mutex functions with 136 * type simplelock and vice versa. 137 */ 138#define CHECK_MUTEX_TYPE() \ 139 cmpl $ MUTEX_TAG,M_TYPE ; \ 140 je 1f ; \ 141 pushl $2f ; \ 142 call EXT(panic) ; \ 143 hlt ; \ 144 .data ; \ 1452: String "not a mutex!" ; \ 146 .text ; \ 1471: 148 149#define CHECK_SIMPLE_LOCK_TYPE() \ 150 cmpl $ USLOCK_TAG,S_TYPE ; \ 151 je 1f ; \ 152 pushl $2f ; \ 153 call EXT(panic) ; \ 154 hlt ; \ 155 .data ; \ 1562: String "not a simple lock!" ; \ 157 .text ; \ 1581: 159 160/* 161 * If one or more simplelocks are currently held by a thread, 162 * an attempt to acquire a mutex will cause this check to fail 163 * (since a mutex lock may context switch, holding a simplelock 164 * is not a good thing). 165 */ 166#if MACH_RT 167#define CHECK_PREEMPTION_LEVEL() \ 168 cmpl $0,%gs:CPU_PREEMPTION_LEVEL ; \ 169 je 1f ; \ 170 pushl $2f ; \ 171 call EXT(panic) ; \ 172 hlt ; \ 173 .data ; \ 1742: String "preemption_level != 0!" ; \ 175 .text ; \ 1761: 177#else /* MACH_RT */ 178#define CHECK_PREEMPTION_LEVEL() 179#endif /* MACH_RT */ 180 181#define CHECK_NO_SIMPLELOCKS() \ 182 cmpl $0,%gs:CPU_SIMPLE_LOCK_COUNT ; \ 183 je 1f ; \ 184 pushl $2f ; \ 185 call EXT(panic) ; \ 186 hlt ; \ 187 .data ; \ 1882: String "simple_locks_held!" ; \ 189 .text ; \ 1901: 191 192/* 193 * Verifies return to the correct thread in "unlock" situations. 194 */ 195#define CHECK_THREAD(thd) \ 196 movl %gs:CPU_ACTIVE_THREAD,%ecx ; \ 197 testl %ecx,%ecx ; \ 198 je 1f ; \ 199 cmpl %ecx,thd ; \ 200 je 1f ; \ 201 pushl $2f ; \ 202 call EXT(panic) ; \ 203 hlt ; \ 204 .data ; \ 2052: String "wrong thread!" ; \ 206 .text ; \ 2071: 208 209#define CHECK_MYLOCK(thd) \ 210 movl %gs:CPU_ACTIVE_THREAD,%ecx ; \ 211 testl %ecx,%ecx ; \ 212 je 1f ; \ 213 cmpl %ecx,thd ; \ 214 jne 1f ; \ 215 pushl $2f ; \ 216 call EXT(panic) ; \ 217 hlt ; \ 218 .data ; \ 2192: String "mylock attempt!" ; \ 220 .text ; \ 2211: 222 223#define METER_SIMPLE_LOCK_LOCK(reg) \ 224 pushl reg ; \ 225 call EXT(meter_simple_lock) ; \ 226 popl reg 227 228#define METER_SIMPLE_LOCK_UNLOCK(reg) \ 229 pushl reg ; \ 230 call EXT(meter_simple_unlock) ; \ 231 popl reg 232 233#else /* MACH_LDEBUG */ 234#define CHECK_MUTEX_TYPE() 235#define CHECK_SIMPLE_LOCK_TYPE 236#define CHECK_THREAD(thd) 237#define CHECK_PREEMPTION_LEVEL() 238#define CHECK_NO_SIMPLELOCKS() 239#define CHECK_MYLOCK(thd) 240#define METER_SIMPLE_LOCK_LOCK(reg) 241#define METER_SIMPLE_LOCK_UNLOCK(reg) 242#endif /* MACH_LDEBUG */ 243 244 245/* 246 * void hw_lock_init(hw_lock_t) 247 * 248 * Initialize a hardware lock. 249 */ 250LEAF_ENTRY(hw_lock_init) 251 movl L_ARG0,%edx /* fetch lock pointer */ 252 movl $0,0(%edx) /* clear the lock */ 253 LEAF_RET 254 255/* 256 * void hw_lock_lock(hw_lock_t) 257 * 258 * Acquire lock, spinning until it becomes available. 259 * MACH_RT: also return with preemption disabled. 260 */ 261LEAF_ENTRY(hw_lock_lock) 262 movl L_ARG0,%edx /* fetch lock pointer */ 263 264 movl L_PC,%ecx 2651: DISABLE_PREEMPTION 266 movl 0(%edx), %eax 267 testl %eax,%eax /* lock locked? */ 268 jne 3f /* branch if so */ 269 lock; cmpxchgl %ecx,0(%edx) /* try to acquire the HW lock */ 270 jne 3f 271 movl $1,%eax /* In case this was a timeout call */ 272 LEAF_RET /* if yes, then nothing left to do */ 273 2743: ENABLE_PREEMPTION /* no reason we can't be preemptable */ 275 PAUSE /* pause for hyper-threading */ 276 jmp 1b /* try again */ 277 278/* 279 * unsigned int hw_lock_to(hw_lock_t, unsigned int) 280 * 281 * Acquire lock, spinning until it becomes available or timeout. 282 * MACH_RT: also return with preemption disabled. 283 */ 284LEAF_ENTRY(hw_lock_to) 2851: 286 movl L_ARG0,%edx /* fetch lock pointer */ 287 movl L_PC,%ecx 288 /* 289 * Attempt to grab the lock immediately 290 * - fastpath without timeout nonsense. 291 */ 292 DISABLE_PREEMPTION 293 movl 0(%edx), %eax 294 testl %eax,%eax /* lock locked? */ 295 jne 2f /* branch if so */ 296 lock; cmpxchgl %ecx,0(%edx) /* try to acquire the HW lock */ 297 jne 2f /* branch on failure */ 298 movl $1,%eax 299 LEAF_RET 300 3012: 302#define INNER_LOOP_COUNT 1000 303 /* 304 * Failed to get the lock so set the timeout 305 * and then spin re-checking the lock but pausing 306 * every so many (INNER_LOOP_COUNT) spins to check for timeout. 307 */ 308 movl L_ARG1,%ecx /* fetch timeout */ 309 push %edi 310 push %ebx 311 mov %edx,%edi 312 313 rdtsc /* read cyclecount into %edx:%eax */ 314 addl %ecx,%eax /* fetch and timeout */ 315 adcl $0,%edx /* add carry */ 316 mov %edx,%ecx 317 mov %eax,%ebx /* %ecx:%ebx is the timeout expiry */ 3183: 319 ENABLE_PREEMPTION /* no reason not to be preempted now */ 3204: 321 /* 322 * The inner-loop spin to look for the lock being freed. 323 */ 324 mov $(INNER_LOOP_COUNT),%edx 3255: 326 PAUSE /* pause for hyper-threading */ 327 movl 0(%edi),%eax /* spin checking lock value in cache */ 328 testl %eax,%eax 329 je 6f /* zero => unlocked, try to grab it */ 330 decl %edx /* decrement inner loop count */ 331 jnz 5b /* time to check for timeout? */ 332 333 /* 334 * Here after spinning INNER_LOOP_COUNT times, check for timeout 335 */ 336 rdtsc /* cyclecount into %edx:%eax */ 337 cmpl %ecx,%edx /* compare high-order 32-bits */ 338 jb 4b /* continue spinning if less, or */ 339 cmpl %ebx,%eax /* compare low-order 32-bits */ 340 jb 5b /* continue if less, else bail */ 341 xor %eax,%eax /* with 0 return value */ 342 pop %ebx 343 pop %edi 344 LEAF_RET 345 3466: 347 /* 348 * Here to try to grab the lock that now appears to be free 349 * after contention. 350 */ 351 movl 8+L_PC,%edx /* calling pc (8+ for pushed regs) */ 352 DISABLE_PREEMPTION 353 lock; cmpxchgl %edx,0(%edi) /* try to acquire the HW lock */ 354 jne 3b /* no - spin again */ 355 movl $1,%eax /* yes */ 356 pop %ebx 357 pop %edi 358 LEAF_RET 359 360/* 361 * void hw_lock_unlock(hw_lock_t) 362 * 363 * Unconditionally release lock. 364 * MACH_RT: release preemption level. 365 */ 366LEAF_ENTRY(hw_lock_unlock) 367 movl L_ARG0,%edx /* fetch lock pointer */ 368 movl $0,0(%edx) /* clear the lock */ 369 ENABLE_PREEMPTION 370 LEAF_RET 371 372/* 373 * unsigned int hw_lock_try(hw_lock_t) 374 * MACH_RT: returns with preemption disabled on success. 375 */ 376LEAF_ENTRY(hw_lock_try) 377 movl L_ARG0,%edx /* fetch lock pointer */ 378 379 movl L_PC,%ecx 380 DISABLE_PREEMPTION 381 movl 0(%edx),%eax 382 testl %eax,%eax 383 jne 1f 384 lock; cmpxchgl %ecx,0(%edx) /* try to acquire the HW lock */ 385 jne 1f 386 387 movl $1,%eax /* success */ 388 LEAF_RET 389 3901: ENABLE_PREEMPTION /* failure: release preemption... */ 391 xorl %eax,%eax /* ...and return failure */ 392 LEAF_RET 393 394/* 395 * unsigned int hw_lock_held(hw_lock_t) 396 * MACH_RT: doesn't change preemption state. 397 * N.B. Racy, of course. 398 */ 399LEAF_ENTRY(hw_lock_held) 400 movl L_ARG0,%edx /* fetch lock pointer */ 401 402 movl 0(%edx),%eax /* check lock value */ 403 testl %eax,%eax 404 movl $1,%ecx 405 cmovne %ecx,%eax /* 0 => unlocked, 1 => locked */ 406 LEAF_RET 407 408LEAF_ENTRY(mutex_init) 409 movl L_ARG0,%edx /* fetch lock pointer */ 410 xorl %eax,%eax 411 movl %eax,M_ILK /* clear interlock */ 412 movl %eax,M_LOCKED /* clear locked flag */ 413 movw %ax,M_WAITERS /* init waiter count */ 414 movw %ax,M_PROMOTED_PRI 415 416#if MACH_LDEBUG 417 movl $ MUTEX_TAG,M_TYPE /* set lock type */ 418 movl %eax,M_PC /* init caller pc */ 419 movl %eax,M_THREAD /* and owning thread */ 420#endif 421 422 LEAF_RET 423 424NONLEAF_ENTRY2(mutex_lock,_mutex_lock) 425 426 movl B_ARG0,%edx /* fetch lock pointer */ 427 428 CHECK_MUTEX_TYPE() 429 CHECK_NO_SIMPLELOCKS() 430 CHECK_PREEMPTION_LEVEL() 431 432 pushf /* save interrupt state */ 433 cli /* disable interrupts */ 434 435ml_retry: 436 movl B_PC,%ecx 437 438ml_get_hw: 439 movl M_ILK,%eax /* read interlock */ 440 testl %eax,%eax /* unlocked? */ 441 je 1f /* yes - attempt to lock it */ 442 PAUSE /* no - pause */ 443 jmp ml_get_hw /* try again */ 4441: 445 lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */ 446 jne ml_get_hw /* branch on failure to retry */ 447 448 movl M_LOCKED,%ecx /* get lock owner */ 449 testl %ecx,%ecx /* is the mutex locked? */ 450 jne ml_fail /* yes, we lose */ 451 movl %gs:CPU_ACTIVE_THREAD,%ecx 452 movl %ecx,M_LOCKED 453 454#if MACH_LDEBUG 455 movl %ecx,M_THREAD 456 movl B_PC,%ecx 457 movl %ecx,M_PC 458#endif 459 460 pushl %edx /* save mutex address */ 461 pushl %edx 462 call EXT(lck_mtx_lock_acquire) 463 addl $4,%esp 464 popl %edx /* restore mutex address */ 465 466 xorl %eax,%eax 467 movl %eax,M_ILK 468 469 popf /* restore interrupt state */ 470 471 NONLEAF_RET 472 473ml_fail: 474ml_block: 475 CHECK_MYLOCK(M_THREAD) 476 pushl M_LOCKED 477 pushl %edx /* push mutex address */ 478 call EXT(lck_mtx_lock_wait) /* wait for the lock */ 479 addl $8,%esp 480 movl B_ARG0,%edx /* refetch mutex address */ 481 jmp ml_retry /* and try again */ 482 483NONLEAF_ENTRY2(mutex_try,_mutex_try) 484 485 movl B_ARG0,%edx /* fetch lock pointer */ 486 487 CHECK_MUTEX_TYPE() 488 CHECK_NO_SIMPLELOCKS() 489 490 movl B_PC,%ecx 491 492 pushf /* save interrupt state */ 493 cli /* disable interrupts */ 494 495mt_get_hw: 496 movl M_ILK,%eax /* read interlock */ 497 testl %eax,%eax /* unlocked? */ 498 je 1f /* yes - attempt to lock it */ 499 PAUSE /* no - pause */ 500 jmp mt_get_hw /* try again */ 5011: 502 lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */ 503 jne mt_get_hw /* branch on failure to retry */ 504 505 movl M_LOCKED,%ecx /* get lock owner */ 506 testl %ecx,%ecx /* is the mutex locked? */ 507 jne mt_fail /* yes, we lose */ 508 movl %gs:CPU_ACTIVE_THREAD,%ecx 509 movl %ecx,M_LOCKED 510 511#if MACH_LDEBUG 512 movl %ecx,M_THREAD 513 movl B_PC,%ecx 514 movl %ecx,M_PC 515#endif 516 517 pushl %edx /* save mutex address */ 518 pushl %edx 519 call EXT(lck_mtx_lock_acquire) 520 addl $4,%esp 521 popl %edx /* restore mutex address */ 522 523 xorl %eax,%eax 524 movl %eax,M_ILK 525 526 popf /* restore interrupt state */ 527 528 movl $1,%eax 529 530 NONLEAF_RET 531 532mt_fail: 533 xorl %eax,%eax 534 movl %eax,M_ILK 535 536 popf /* restore interrupt state */ 537 538 xorl %eax,%eax 539 540 NONLEAF_RET 541 542NONLEAF_ENTRY(mutex_unlock) 543 movl B_ARG0,%edx /* fetch lock pointer */ 544 545 CHECK_MUTEX_TYPE() 546 CHECK_THREAD(M_THREAD) 547 548 movl B_PC,%ecx 549 550 pushf /* save interrupt state */ 551 cli /* disable interrupts */ 552 553mu_get_hw: 554 movl M_ILK,%eax /* read interlock */ 555 testl %eax,%eax /* unlocked? */ 556 je 1f /* yes - attempt to lock it */ 557 PAUSE /* no - pause */ 558 jmp mu_get_hw /* try again */ 5591: 560 lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */ 561 jne mu_get_hw /* branch on failure to retry */ 562 563 cmpw $0,M_WAITERS /* are there any waiters? */ 564 jne mu_wakeup /* yes, more work to do */ 565 566mu_doit: 567 568#if MACH_LDEBUG 569 movl $0,M_THREAD /* disown thread */ 570#endif 571 572 xorl %ecx,%ecx 573 movl %ecx,M_LOCKED /* unlock the mutex */ 574 575 movl %ecx,M_ILK 576 577 popf /* restore interrupt state */ 578 579 NONLEAF_RET 580 581mu_wakeup: 582 pushl M_LOCKED 583 pushl %edx /* push mutex address */ 584 call EXT(lck_mtx_unlock_wakeup)/* yes, wake a thread */ 585 addl $8,%esp 586 movl B_ARG0,%edx /* restore lock pointer */ 587 jmp mu_doit 588 589/* 590 * lck_mtx_lock() 591 * lck_mtx_try_lock() 592 * lck_mutex_unlock() 593 * 594 * These are variants of mutex_lock(), mutex_try() and mutex_unlock() without 595 * DEBUG checks (which require fields not present in lck_mtx_t's). 596 */ 597NONLEAF_ENTRY(lck_mtx_lock) 598 599 movl B_ARG0,%edx /* fetch lock pointer */ 600 cmpl $(MUTEX_IND),M_ITAG /* is this indirect? */ 601 cmove M_PTR,%edx /* yes - take indirection */ 602 603 CHECK_NO_SIMPLELOCKS() 604 CHECK_PREEMPTION_LEVEL() 605 606 pushf /* save interrupt state */ 607 cli /* disable interrupts */ 608 609lml_retry: 610 movl B_PC,%ecx 611 612lml_get_hw: 613 movl M_ILK,%eax /* read interlock */ 614 testl %eax,%eax /* unlocked? */ 615 je 1f /* yes - attempt to lock it */ 616 PAUSE /* no - pause */ 617 jmp lml_get_hw /* try again */ 6181: 619 lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */ 620 jne lml_get_hw /* branch on failure to retry */ 621 622 movl M_LOCKED,%ecx /* get lock owner */ 623 testl %ecx,%ecx /* is the mutex locked? */ 624 jne lml_fail /* yes, we lose */ 625 movl %gs:CPU_ACTIVE_THREAD,%ecx 626 movl %ecx,M_LOCKED 627 628 pushl %edx /* save mutex address */ 629 pushl %edx 630 call EXT(lck_mtx_lock_acquire) 631 addl $4,%esp 632 popl %edx /* restore mutex address */ 633 634 xorl %eax,%eax 635 movl %eax,M_ILK 636 637 popf /* restore interrupt state */ 638 639 NONLEAF_RET 640 641lml_fail: 642 CHECK_MYLOCK(M_THREAD) 643 pushl %edx /* save mutex address */ 644 pushl M_LOCKED 645 pushl %edx /* push mutex address */ 646 call EXT(lck_mtx_lock_wait) /* wait for the lock */ 647 addl $8,%esp 648 popl %edx /* restore mutex address */ 649 jmp lml_retry /* and try again */ 650 651NONLEAF_ENTRY(lck_mtx_try_lock) 652 653 movl B_ARG0,%edx /* fetch lock pointer */ 654 cmpl $(MUTEX_IND),M_ITAG /* is this indirect? */ 655 cmove M_PTR,%edx /* yes - take indirection */ 656 657 CHECK_NO_SIMPLELOCKS() 658 CHECK_PREEMPTION_LEVEL() 659 660 movl B_PC,%ecx 661 662 pushf /* save interrupt state */ 663 cli /* disable interrupts */ 664 665lmt_get_hw: 666 movl M_ILK,%eax /* read interlock */ 667 testl %eax,%eax /* unlocked? */ 668 je 1f /* yes - attempt to lock it */ 669 PAUSE /* no - pause */ 670 jmp lmt_get_hw /* try again */ 6711: 672 lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */ 673 jne lmt_get_hw /* branch on failure to retry */ 674 675 movl M_LOCKED,%ecx /* get lock owner */ 676 testl %ecx,%ecx /* is the mutex locked? */ 677 jne lmt_fail /* yes, we lose */ 678 movl %gs:CPU_ACTIVE_THREAD,%ecx 679 movl %ecx,M_LOCKED 680 681 pushl %edx /* save mutex address */ 682 pushl %edx 683 call EXT(lck_mtx_lock_acquire) 684 addl $4,%esp 685 popl %edx /* restore mutex address */ 686 687 xorl %eax,%eax 688 movl %eax,M_ILK 689 690 popf /* restore interrupt state */ 691 692 movl $1,%eax /* return success */ 693 NONLEAF_RET 694 695lmt_fail: 696 xorl %eax,%eax 697 movl %eax,M_ILK 698 699 popf /* restore interrupt state */ 700 701 xorl %eax,%eax /* return failure */ 702 NONLEAF_RET 703 704NONLEAF_ENTRY(lck_mtx_unlock) 705 706 movl B_ARG0,%edx /* fetch lock pointer */ 707 cmpl $(MUTEX_IND),M_ITAG /* is this indirect? */ 708 cmove M_PTR,%edx /* yes - take indirection */ 709 710 movl B_PC,%ecx 711 712 pushf /* save interrupt state */ 713 cli /* disable interrupts */ 714 715lmu_get_hw: 716 movl M_ILK,%eax /* read interlock */ 717 testl %eax,%eax /* unlocked? */ 718 je 1f /* yes - attempt to lock it */ 719 PAUSE /* no - pause */ 720 jmp lmu_get_hw /* try again */ 7211: 722 lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */ 723 jne lmu_get_hw /* branch on failure to retry */ 724 725 cmpw $0,M_WAITERS /* are there any waiters? */ 726 jne lmu_wakeup /* yes, more work to do */ 727 728lmu_doit: 729 xorl %ecx,%ecx 730 movl %ecx,M_LOCKED /* unlock the mutex */ 731 732 movl %ecx,M_ILK 733 734 popf /* restore interrupt state */ 735 736 NONLEAF_RET 737 738lmu_wakeup: 739 pushl %edx /* save mutex address */ 740 pushl M_LOCKED 741 pushl %edx /* push mutex address */ 742 call EXT(lck_mtx_unlock_wakeup)/* yes, wake a thread */ 743 addl $8,%esp 744 popl %edx /* restore mutex pointer */ 745 jmp lmu_doit 746 747LEAF_ENTRY(lck_mtx_ilk_unlock) 748 movl L_ARG0,%edx /* no indirection here */ 749 750 xorl %eax,%eax 751 movl %eax,M_ILK 752 753 LEAF_RET 754 755LEAF_ENTRY(_disable_preemption) 756#if MACH_RT 757 _DISABLE_PREEMPTION 758#endif /* MACH_RT */ 759 LEAF_RET 760 761LEAF_ENTRY(_enable_preemption) 762#if MACH_RT 763#if MACH_ASSERT 764 cmpl $0,%gs:CPU_PREEMPTION_LEVEL 765 jg 1f 766 pushl %gs:CPU_PREEMPTION_LEVEL 767 pushl $2f 768 call EXT(panic) 769 hlt 770 .data 7712: String "_enable_preemption: preemption_level(%d) < 0!" 772 .text 7731: 774#endif /* MACH_ASSERT */ 775 _ENABLE_PREEMPTION 776#endif /* MACH_RT */ 777 LEAF_RET 778 779LEAF_ENTRY(_enable_preemption_no_check) 780#if MACH_RT 781#if MACH_ASSERT 782 cmpl $0,%gs:CPU_PREEMPTION_LEVEL 783 jg 1f 784 pushl $2f 785 call EXT(panic) 786 hlt 787 .data 7882: String "_enable_preemption_no_check: preemption_level <= 0!" 789 .text 7901: 791#endif /* MACH_ASSERT */ 792 _ENABLE_PREEMPTION_NO_CHECK 793#endif /* MACH_RT */ 794 LEAF_RET 795 796 797LEAF_ENTRY(_mp_disable_preemption) 798#if MACH_RT 799 _DISABLE_PREEMPTION 800#endif /* MACH_RT */ 801 LEAF_RET 802 803LEAF_ENTRY(_mp_enable_preemption) 804#if MACH_RT 805#if MACH_ASSERT 806 cmpl $0,%gs:CPU_PREEMPTION_LEVEL 807 jg 1f 808 pushl %gs:CPU_PREEMPTION_LEVEL 809 pushl $2f 810 call EXT(panic) 811 hlt 812 .data 8132: String "_mp_enable_preemption: preemption_level (%d) <= 0!" 814 .text 8151: 816#endif /* MACH_ASSERT */ 817 _ENABLE_PREEMPTION 818#endif /* MACH_RT */ 819 LEAF_RET 820 821LEAF_ENTRY(_mp_enable_preemption_no_check) 822#if MACH_RT 823#if MACH_ASSERT 824 cmpl $0,%gs:CPU_PREEMPTION_LEVEL 825 jg 1f 826 pushl $2f 827 call EXT(panic) 828 hlt 829 .data 8302: String "_mp_enable_preemption_no_check: preemption_level <= 0!" 831 .text 8321: 833#endif /* MACH_ASSERT */ 834 _ENABLE_PREEMPTION_NO_CHECK 835#endif /* MACH_RT */ 836 LEAF_RET 837 838 839LEAF_ENTRY(i_bit_set) 840 movl L_ARG0,%edx 841 movl L_ARG1,%eax 842 lock 843 bts %dl,(%eax) 844 LEAF_RET 845 846LEAF_ENTRY(i_bit_clear) 847 movl L_ARG0,%edx 848 movl L_ARG1,%eax 849 lock 850 btr %dl,(%eax) 851 LEAF_RET 852 853LEAF_ENTRY(bit_lock) 854 movl L_ARG0,%ecx 855 movl L_ARG1,%eax 8561: 857 lock 858 bts %ecx,(%eax) 859 jb 1b 860 LEAF_RET 861 862LEAF_ENTRY(bit_lock_try) 863 movl L_ARG0,%ecx 864 movl L_ARG1,%eax 865 lock 866 bts %ecx,(%eax) 867 jb bit_lock_failed 868 LEAF_RET /* %eax better not be null ! */ 869bit_lock_failed: 870 xorl %eax,%eax 871 LEAF_RET 872 873LEAF_ENTRY(bit_unlock) 874 movl L_ARG0,%ecx 875 movl L_ARG1,%eax 876 lock 877 btr %ecx,(%eax) 878 LEAF_RET 879

