1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22/* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#pragma ident "%Z%%M% %I% %E% SMI" 28 29#if defined(lint) 30#include <sys/types.h> 31#include <sys/thread.h> 32#include <sys/cpuvar.h> 33#else /* lint */ 34#include "assym.h" 35#endif /* lint */ 36 37#include <sys/t_lock.h> 38#include <sys/mutex.h> 39#include <sys/mutex_impl.h> 40#include <sys/rwlock_impl.h> 41#include <sys/asm_linkage.h> 42#include <sys/machlock.h> 43#include <sys/machthread.h> 44#include <sys/lockstat.h> 45 46/* #define DEBUG */ 47 48#ifdef DEBUG 49#include <sys/machparam.h> 50#endif /* DEBUG */ 51 52/************************************************************************ 53 * ATOMIC OPERATIONS 54 */ 55 56/* 57 * uint8_t ldstub(uint8_t *cp) 58 * 59 * Store 0xFF at the specified location, and return its previous content. 60 */ 61 62#if defined(lint) 63uint8_t 64ldstub(uint8_t *cp) 65{ 66 uint8_t rv; 67 rv = *cp; 68 *cp = 0xFF; 69 return rv; 70} 71#else /* lint */ 72 73 ENTRY(ldstub) 74 retl 75 ldstub [%o0], %o0 76 SET_SIZE(ldstub) 77 78#endif /* lint */ 79 80/************************************************************************ 81 * MEMORY BARRIERS -- see atomic.h for full descriptions. 82 */ 83 84#if defined(lint) 85 86void 87membar_enter(void) 88{} 89 90void 91membar_exit(void) 92{} 93 94void 95membar_producer(void) 96{} 97 98void 99membar_consumer(void) 100{} 101 102#else /* lint */ 103 104#ifdef SF_ERRATA_51 105 .align 32 106 ENTRY(membar_return) 107 retl 108 nop 109 SET_SIZE(membar_return) 110#define MEMBAR_RETURN ba,pt %icc, membar_return 111#else 112#define MEMBAR_RETURN retl 113#endif 114 115 ENTRY(membar_enter) 116 MEMBAR_RETURN 117 membar #StoreLoad|#StoreStore 118 SET_SIZE(membar_enter) 119 120 ENTRY(membar_exit) 121 MEMBAR_RETURN 122 membar #LoadStore|#StoreStore 123 SET_SIZE(membar_exit) 124 125 ENTRY(membar_producer) 126 MEMBAR_RETURN 127 membar #StoreStore 128 SET_SIZE(membar_producer) 129 130 ENTRY(membar_consumer) 131 MEMBAR_RETURN 132 membar #LoadLoad 133 SET_SIZE(membar_consumer) 134 135#endif /* lint */ 136 137/************************************************************************ 138 * MINIMUM LOCKS 139 */ 140 141#if defined(lint) 142 143/* 144 * lock_try(lp), ulock_try(lp) 145 * - returns non-zero on success. 146 * - doesn't block interrupts so don't use this to spin on a lock. 147 * - uses "0xFF is busy, anything else is free" model. 148 * 149 * ulock_try() is for a lock in the user address space. 150 * For all V7/V8 sparc systems they are same since the kernel and 151 * user are mapped in a user' context. 152 * For V9 platforms the lock_try and ulock_try are different impl. 153 */ 154 155int 156lock_try(lock_t *lp) 157{ 158 return (0xFF ^ ldstub(lp)); 159} 160 161int 162lock_spin_try(lock_t *lp) 163{ 164 return (0xFF ^ ldstub(lp)); 165} 166 167void 168lock_set(lock_t *lp) 169{ 170 extern void lock_set_spin(lock_t *); 171 172 if (!lock_try(lp)) 173 lock_set_spin(lp); 174 membar_enter(); 175} 176 177void 178lock_clear(lock_t *lp) 179{ 180 membar_exit(); 181 *lp = 0; 182} 183 184int 185ulock_try(lock_t *lp) 186{ 187 return (0xFF ^ ldstub(lp)); 188} 189 190void 191ulock_clear(lock_t *lp) 192{ 193 membar_exit(); 194 *lp = 0; 195} 196 197#else /* lint */ 198 199 .align 32 200 ENTRY(lock_try) 201 ldstub [%o0], %o1 ! try to set lock, get value in %o1 202 brnz,pn %o1, 1f 203 membar #LoadLoad 204.lock_try_lockstat_patch_point: 205 retl 206 or %o0, 1, %o0 ! ensure lo32 != 0 2071: 208 retl 209 clr %o0 210 SET_SIZE(lock_try) 211 212 .align 32 213 ENTRY(lock_spin_try) 214 ldstub [%o0], %o1 ! try to set lock, get value in %o1 215 brnz,pn %o1, 1f 216 membar #LoadLoad 217 retl 218 or %o0, 1, %o0 ! ensure lo32 != 0 2191: 220 retl 221 clr %o0 222 SET_SIZE(lock_spin_try) 223 224 .align 32 225 ENTRY(lock_set) 226 ldstub [%o0], %o1 227 brnz,pn %o1, 1f ! go to C for the hard case 228 membar #LoadLoad 229.lock_set_lockstat_patch_point: 230 retl 231 nop 2321: 233 sethi %hi(lock_set_spin), %o2 ! load up for jump to C 234 jmp %o2 + %lo(lock_set_spin) 235 nop ! delay: do nothing 236 SET_SIZE(lock_set) 237 238 ENTRY(lock_clear) 239 membar #LoadStore|#StoreStore 240.lock_clear_lockstat_patch_point: 241 retl 242 clrb [%o0] 243 SET_SIZE(lock_clear) 244 245 .align 32 246 ENTRY(ulock_try) 247 ldstuba [%o0]ASI_USER, %o1 ! try to set lock, get value in %o1 248 xor %o1, 0xff, %o0 ! delay - return non-zero if success 249 retl 250 membar #LoadLoad 251 SET_SIZE(ulock_try) 252 253 ENTRY(ulock_clear) 254 membar #LoadStore|#StoreStore 255 retl 256 stba %g0, [%o0]ASI_USER ! clear lock 257 SET_SIZE(ulock_clear) 258 259#endif /* lint */ 260 261 262/* 263 * lock_set_spl(lp, new_pil, *old_pil_addr) 264 * Sets pil to new_pil, grabs lp, stores old pil in *old_pil_addr. 265 */ 266 267#if defined(lint) 268 269/* ARGSUSED */ 270void 271lock_set_spl(lock_t *lp, int new_pil, u_short *old_pil_addr) 272{ 273 extern int splr(int); 274 extern void lock_set_spl_spin(lock_t *, int, u_short *, int); 275 int old_pil; 276 277 old_pil = splr(new_pil); 278 if (!lock_try(lp)) { 279 lock_set_spl_spin(lp, new_pil, old_pil_addr, old_pil); 280 } else { 281 *old_pil_addr = (u_short)old_pil; 282 membar_enter(); 283 } 284} 285 286#else /* lint */ 287 288 ENTRY(lock_set_spl) 289 rdpr %pil, %o3 ! %o3 = current pil 290 cmp %o3, %o1 ! is current pil high enough? 291 bl,a,pt %icc, 1f ! if not, write %pil in delay 292 wrpr %g0, %o1, %pil 2931: 294 ldstub [%o0], %o4 ! try the lock 295 brnz,pn %o4, 2f ! go to C for the miss case 296 membar #LoadLoad 297.lock_set_spl_lockstat_patch_point: 298 retl 299 sth %o3, [%o2] ! delay - save original pil 3002: 301 sethi %hi(lock_set_spl_spin), %o5 ! load up jmp to C 302 jmp %o5 + %lo(lock_set_spl_spin) ! jmp to lock_set_spl_spin 303 nop ! delay: do nothing 304 SET_SIZE(lock_set_spl) 305 306#endif /* lint */ 307 308/* 309 * lock_clear_splx(lp, s) 310 */ 311 312#if defined(lint) 313 314void 315lock_clear_splx(lock_t *lp, int s) 316{ 317 extern void splx(int); 318 319 lock_clear(lp); 320 splx(s); 321} 322 323#else /* lint */ 324 325 ENTRY(lock_clear_splx) 326 ldn [THREAD_REG + T_CPU], %o2 ! get CPU pointer 327 membar #LoadStore|#StoreStore 328 ld [%o2 + CPU_BASE_SPL], %o2 329 clrb [%o0] ! clear lock 330 cmp %o2, %o1 ! compare new to base 331 movl %xcc, %o1, %o2 ! use new pri if base is less 332.lock_clear_splx_lockstat_patch_point: 333 retl 334 wrpr %g0, %o2, %pil 335 SET_SIZE(lock_clear_splx) 336 337#endif /* lint */ 338 339/* 340 * mutex_enter() and mutex_exit(). 341 * 342 * These routines handle the simple cases of mutex_enter() (adaptive 343 * lock, not held) and mutex_exit() (adaptive lock, held, no waiters). 344 * If anything complicated is going on we punt to mutex_vector_enter(). 345 * 346 * mutex_tryenter() is similar to mutex_enter() but returns zero if 347 * the lock cannot be acquired, nonzero on success. 348 * 349 * If mutex_exit() gets preempted in the window between checking waiters 350 * and clearing the lock, we can miss wakeups. Disabling preemption 351 * in the mutex code is prohibitively expensive, so instead we detect 352 * mutex preemption by examining the trapped PC in the interrupt path. 353 * If we interrupt a thread in mutex_exit() that has not yet cleared 354 * the lock, pil_interrupt() resets its PC back to the beginning of 355 * mutex_exit() so it will check again for waiters when it resumes. 356 * 357 * The lockstat code below is activated when the lockstat driver 358 * calls lockstat_hot_patch() to hot-patch the kernel mutex code. 359 * Note that we don't need to test lockstat_event_mask here -- we won't 360 * patch this code in unless we're gathering ADAPTIVE_HOLD lockstats. 361 */ 362 363#if defined (lint) 364 365/* ARGSUSED */ 366void 367mutex_enter(kmutex_t *lp) 368{} 369 370/* ARGSUSED */ 371int 372mutex_tryenter(kmutex_t *lp) 373{ return (0); } 374 375/* ARGSUSED */ 376void 377mutex_exit(kmutex_t *lp) 378{} 379 380#else 381 .align 32 382 ENTRY(mutex_enter) 383 mov THREAD_REG, %o1 384 casx [%o0], %g0, %o1 ! try to acquire as adaptive 385 brnz,pn %o1, 1f ! locked or wrong type 386 membar #LoadLoad 387.mutex_enter_lockstat_patch_point: 388 retl 389 nop 3901: 391 sethi %hi(mutex_vector_enter), %o2 ! load up for jump to C 392 jmp %o2 + %lo(mutex_vector_enter) 393 nop 394 SET_SIZE(mutex_enter) 395 396 ENTRY(mutex_tryenter) 397 mov THREAD_REG, %o1 398 casx [%o0], %g0, %o1 ! try to acquire as adaptive 399 brnz,pn %o1, 1f ! locked or wrong type continue 400 membar #LoadLoad 401.mutex_tryenter_lockstat_patch_point: 402 retl 403 or %o0, 1, %o0 ! ensure lo32 != 0 4041: 405 sethi %hi(mutex_vector_tryenter), %o2 ! hi bits 406 jmp %o2 + %lo(mutex_vector_tryenter) ! go to C 407 nop 408 SET_SIZE(mutex_tryenter) 409 410 ENTRY(mutex_adaptive_tryenter) 411 mov THREAD_REG, %o1 412 casx [%o0], %g0, %o1 ! try to acquire as adaptive 413 brnz,pn %o1, 0f ! locked or wrong type 414 membar #LoadLoad 415 retl 416 or %o0, 1, %o0 ! ensure lo32 != 0 4170: 418 retl 419 mov %g0, %o0 420 SET_SIZE(mutex_adaptive_tryenter) 421 422 .global mutex_exit_critical_size 423 .global mutex_exit_critical_start 424 425mutex_exit_critical_size = .mutex_exit_critical_end - mutex_exit_critical_start 426 427 .align 32 428 429 ENTRY(mutex_exit) 430mutex_exit_critical_start: ! If we are interrupted, restart here 431 ldn [%o0], %o1 ! get the owner field 432 membar #LoadStore|#StoreStore 433 cmp THREAD_REG, %o1 ! do we own lock with no waiters? 434 be,a,pt %ncc, 1f ! if so, drive on ... 435 stn %g0, [%o0] ! delay: clear lock if we owned it 436.mutex_exit_critical_end: ! for pil_interrupt() hook 437 ba,a,pt %xcc, mutex_vector_exit ! go to C for the hard cases 4381: 439.mutex_exit_lockstat_patch_point: 440 retl 441 nop 442 SET_SIZE(mutex_exit) 443 444#endif /* lint */ 445 446/* 447 * rw_enter() and rw_exit(). 448 * 449 * These routines handle the simple cases of rw_enter (write-locking an unheld 450 * lock or read-locking a lock that's neither write-locked nor write-wanted) 451 * and rw_exit (no waiters or not the last reader). If anything complicated 452 * is going on we punt to rw_enter_sleep() and rw_exit_wakeup(), respectively. 453 */ 454#if defined(lint) 455 456/* ARGSUSED */ 457void 458rw_enter(krwlock_t *lp, krw_t rw) 459{} 460 461/* ARGSUSED */ 462void 463rw_exit(krwlock_t *lp) 464{} 465 466#else 467 468 .align 16 469 ENTRY(rw_enter) 470 cmp %o1, RW_WRITER ! entering as writer? 471 be,a,pn %icc, 2f ! if so, go do it ... 472 or THREAD_REG, RW_WRITE_LOCKED, %o5 ! delay: %o5 = owner 473 ld [THREAD_REG + T_KPRI_REQ], %o3 ! begin THREAD_KPRI_REQUEST() 474 ldn [%o0], %o4 ! %o4 = old lock value 475 inc %o3 ! bump kpri 476 st %o3, [THREAD_REG + T_KPRI_REQ] ! store new kpri 4771: 478 andcc %o4, RW_WRITE_CLAIMED, %g0 ! write-locked or write-wanted? 479 bz,pt %xcc, 3f ! if so, prepare to block 480 add %o4, RW_READ_LOCK, %o5 ! delay: increment hold count 481 sethi %hi(rw_enter_sleep), %o2 ! load up jump 482 jmp %o2 + %lo(rw_enter_sleep) ! jmp to rw_enter_sleep 483 nop ! delay: do nothing 4843: 485 casx [%o0], %o4, %o5 ! try to grab read lock 486 cmp %o4, %o5 ! did we get it? 487 bne,pn %xcc, 1b ! if not, try again 488 mov %o5, %o4 ! delay: %o4 = old lock value 489 membar #LoadLoad 490.rw_read_enter_lockstat_patch_point: 491 retl 492 nop 4932: 494 casx [%o0], %g0, %o5 ! try to grab write lock 495 brz,pt %o5, 4f ! branch around if we got it 496 membar #LoadLoad ! done regardless of where we go 497 sethi %hi(rw_enter_sleep), %o2 498 jmp %o2 + %lo(rw_enter_sleep) ! jump to rw_enter_sleep if not 499 nop ! delay: do nothing 5004: 501.rw_write_enter_lockstat_patch_point: 502 retl 503 nop 504 SET_SIZE(rw_enter) 505 506 .align 16 507 ENTRY(rw_exit) 508 ldn [%o0], %o4 ! %o4 = old lock value 509 membar #LoadStore|#StoreStore ! membar_exit() 510 subcc %o4, RW_READ_LOCK, %o5 ! %o5 = new lock value if reader 511 bnz,pn %xcc, 2f ! single reader, no waiters? 512 clr %o1 5131: 514 ld [THREAD_REG + T_KPRI_REQ], %g1 ! begin THREAD_KPRI_RELEASE() 515 srl %o4, RW_HOLD_COUNT_SHIFT, %o3 ! %o3 = hold count (lockstat) 516 casx [%o0], %o4, %o5 ! try to drop lock 517 cmp %o4, %o5 ! did we succeed? 518 bne,pn %xcc, rw_exit_wakeup ! if not, go to C 519 dec %g1 ! delay: drop kpri 520.rw_read_exit_lockstat_patch_point: 521 retl 522 st %g1, [THREAD_REG + T_KPRI_REQ] ! delay: store new kpri 5232: 524 andcc %o4, RW_WRITE_LOCKED, %g0 ! are we a writer? 525 bnz,a,pt %xcc, 3f 526 or THREAD_REG, RW_WRITE_LOCKED, %o4 ! delay: %o4 = owner 527 cmp %o5, RW_READ_LOCK ! would lock still be held? 528 bge,pt %xcc, 1b ! if so, go ahead and drop it 529 nop 530 ba,pt %xcc, rw_exit_wakeup ! otherwise, wake waiters 531 nop 5323: 533 casx [%o0], %o4, %o1 ! try to drop write lock 534 cmp %o4, %o1 ! did we succeed? 535 bne,pn %xcc, rw_exit_wakeup ! if not, go to C 536 nop 537.rw_write_exit_lockstat_patch_point: 538 retl 539 nop 540 SET_SIZE(rw_exit) 541 542#endif 543 544#if defined(lint) 545 546void 547lockstat_hot_patch(void) 548{} 549 550#else 551 552#define RETL 0x81c3e008 553#define NOP 0x01000000 554#define BA 0x10800000 555 556#define DISP22 ((1 << 22) - 1) 557#define ANNUL 0x20000000 558 559#define HOT_PATCH_COMMON(addr, event, normal_instr, annul, rs) \ 560 ba 1f; \ 561 rd %pc, %o0; \ 562 save %sp, -SA(MINFRAME), %sp; \ 563 set lockstat_probemap, %l1; \ 564 ld [%l1 + (event * DTRACE_IDSIZE)], %o0; \ 565 brz,pn %o0, 0f; \ 566 ldub [THREAD_REG + T_LOCKSTAT], %l0; \ 567 add %l0, 1, %l2; \ 568 stub %l2, [THREAD_REG + T_LOCKSTAT]; \ 569 set lockstat_probe, %g1; \ 570 ld [%l1 + (event * DTRACE_IDSIZE)], %o0; \ 571 brz,a,pn %o0, 0f; \ 572 stub %l0, [THREAD_REG + T_LOCKSTAT]; \ 573 ldn [%g1], %g2; \ 574 mov rs, %o2; \ 575 jmpl %g2, %o7; \ 576 mov %i0, %o1; \ 577 stub %l0, [THREAD_REG + T_LOCKSTAT]; \ 5780: ret; \ 579 restore %g0, 1, %o0; /* for mutex_tryenter / lock_try */ \ 5801: set addr, %o1; \ 581 sub %o0, %o1, %o0; \ 582 srl %o0, 2, %o0; \ 583 inc %o0; \ 584 set DISP22, %o1; \ 585 and %o1, %o0, %o0; \ 586 set BA, %o1; \ 587 or %o1, %o0, %o0; \ 588 sethi %hi(annul), %o2; \ 589 add %o0, %o2, %o2; \ 590 set addr, %o0; \ 591 set normal_instr, %o1; \ 592 ld [%i0 + (event * DTRACE_IDSIZE)], %o3; \ 593 tst %o3; \ 594 movnz %icc, %o2, %o1; \ 595 call hot_patch_kernel_text; \ 596 mov 4, %o2; \ 597 membar #Sync 598 599#define HOT_PATCH(addr, event, normal_instr) \ 600 HOT_PATCH_COMMON(addr, event, normal_instr, 0, %i1) 601 602#define HOT_PATCH_ARG(addr, event, normal_instr, arg) \ 603 HOT_PATCH_COMMON(addr, event, normal_instr, 0, arg) 604 605#define HOT_PATCH_ANNULLED(addr, event, normal_instr) \ 606 HOT_PATCH_COMMON(addr, event, normal_instr, ANNUL, %i1) 607 608 ENTRY(lockstat_hot_patch) 609 save %sp, -SA(MINFRAME), %sp 610 set lockstat_probemap, %i0 611 HOT_PATCH(.mutex_enter_lockstat_patch_point, 612 LS_MUTEX_ENTER_ACQUIRE, RETL) 613 HOT_PATCH_ANNULLED(.mutex_tryenter_lockstat_patch_point, 614 LS_MUTEX_TRYENTER_ACQUIRE, RETL) 615 HOT_PATCH(.mutex_exit_lockstat_patch_point, 616 LS_MUTEX_EXIT_RELEASE, RETL) 617 HOT_PATCH(.rw_write_enter_lockstat_patch_point, 618 LS_RW_ENTER_ACQUIRE, RETL) 619 HOT_PATCH(.rw_read_enter_lockstat_patch_point, 620 LS_RW_ENTER_ACQUIRE, RETL) 621 HOT_PATCH_ARG(.rw_write_exit_lockstat_patch_point, 622 LS_RW_EXIT_RELEASE, RETL, RW_WRITER) 623 HOT_PATCH_ARG(.rw_read_exit_lockstat_patch_point, 624 LS_RW_EXIT_RELEASE, RETL, RW_READER) 625 HOT_PATCH(.lock_set_lockstat_patch_point, 626 LS_LOCK_SET_ACQUIRE, RETL) 627 HOT_PATCH_ANNULLED(.lock_try_lockstat_patch_point, 628 LS_LOCK_TRY_ACQUIRE, RETL) 629 HOT_PATCH(.lock_clear_lockstat_patch_point, 630 LS_LOCK_CLEAR_RELEASE, RETL) 631 HOT_PATCH(.lock_set_spl_lockstat_patch_point, 632 LS_LOCK_SET_SPL_ACQUIRE, RETL) 633 HOT_PATCH(.lock_clear_splx_lockstat_patch_point, 634 LS_LOCK_CLEAR_SPLX_RELEASE, RETL) 635 ret 636 restore 637 SET_SIZE(lockstat_hot_patch) 638 639#endif /* lint */ 640 641/* 642 * asm_mutex_spin_enter(mutex_t *) 643 * 644 * For use by assembly interrupt handler only. 645 * Does not change spl, since the interrupt handler is assumed to be 646 * running at high level already. 647 * Traps may be off, so cannot panic. 648 * Does not keep statistics on the lock. 649 * 650 * Entry: %l6 - points to mutex 651 * %l7 - address of call (returns to %l7+8) 652 * Uses: %l6, %l5 653 */ 654#ifndef lint 655 .align 16 656 ENTRY_NP(asm_mutex_spin_enter) 657 ldstub [%l6 + M_SPINLOCK], %l5 ! try to set lock, get value in %l5 6581: 659 tst %l5 660 bnz 3f ! lock already held - go spin 661 nop 6622: 663 jmp %l7 + 8 ! return 664 membar #LoadLoad 665 ! 666 ! Spin on lock without using an atomic operation to prevent the caches 667 ! from unnecessarily moving ownership of the line around. 668 ! 6693: 670 ldub [%l6 + M_SPINLOCK], %l5 6714: 672 tst %l5 673 bz,a 1b ! lock appears to be free, try again 674 ldstub [%l6 + M_SPINLOCK], %l5 ! delay slot - try to set lock 675 676 sethi %hi(panicstr) , %l5 677 ldn [%l5 + %lo(panicstr)], %l5 678 tst %l5 679 bnz 2b ! after panic, feign success 680 nop 681 b 4b 682 ldub [%l6 + M_SPINLOCK], %l5 ! delay - reload lock 683 SET_SIZE(asm_mutex_spin_enter) 684#endif /* lint */ 685 686/* 687 * asm_mutex_spin_exit(mutex_t *) 688 * 689 * For use by assembly interrupt handler only. 690 * Does not change spl, since the interrupt handler is assumed to be 691 * running at high level already. 692 * 693 * Entry: %l6 - points to mutex 694 * %l7 - address of call (returns to %l7+8) 695 * Uses: none 696 */ 697#ifndef lint 698 ENTRY_NP(asm_mutex_spin_exit) 699 membar #LoadStore|#StoreStore 700 jmp %l7 + 8 ! return 701 clrb [%l6 + M_SPINLOCK] ! delay - clear lock 702 SET_SIZE(asm_mutex_spin_exit) 703#endif /* lint */ 704 705/* 706 * thread_onproc() 707 * Set thread in onproc state for the specified CPU. 708 * Also set the thread lock pointer to the CPU's onproc lock. 709 * Since the new lock isn't held, the store ordering is important. 710 * If not done in assembler, the compiler could reorder the stores. 711 */ 712#if defined(lint) 713 714void 715thread_onproc(kthread_id_t t, cpu_t *cp) 716{ 717 t->t_state = TS_ONPROC; 718 t->t_lockp = &cp->cpu_thread_lock; 719} 720 721#else /* lint */ 722 723 ENTRY(thread_onproc) 724 set TS_ONPROC, %o2 ! TS_ONPROC state 725 st %o2, [%o0 + T_STATE] ! store state 726 add %o1, CPU_THREAD_LOCK, %o3 ! pointer to disp_lock while running 727 retl ! return 728 stn %o3, [%o0 + T_LOCKP] ! delay - store new lock pointer 729 SET_SIZE(thread_onproc) 730 731#endif /* lint */ 732