17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50efe5e54Sdv142724 * Common Development and Distribution License (the "License"). 60efe5e54Sdv142724 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22753a6d45SSherry Moore * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * Big Theory Statement for mutual exclusion locking primitives. 287c478bd9Sstevel@tonic-gate * 297c478bd9Sstevel@tonic-gate * A mutex serializes multiple threads so that only one thread 307c478bd9Sstevel@tonic-gate * (the "owner" of the mutex) is active at a time. See mutex(9F) 317c478bd9Sstevel@tonic-gate * for a full description of the interfaces and programming model. 327c478bd9Sstevel@tonic-gate * The rest of this comment describes the implementation. 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * Mutexes come in two flavors: adaptive and spin. mutex_init(9F) 357c478bd9Sstevel@tonic-gate * determines the type based solely on the iblock cookie (PIL) argument. 367c478bd9Sstevel@tonic-gate * PIL > LOCK_LEVEL implies a spin lock; everything else is adaptive. 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * Spin mutexes block interrupts and spin until the lock becomes available. 397c478bd9Sstevel@tonic-gate * A thread may not sleep, or call any function that might sleep, while 407c478bd9Sstevel@tonic-gate * holding a spin mutex. With few exceptions, spin mutexes should only 417c478bd9Sstevel@tonic-gate * be used to synchronize with interrupt handlers. 427c478bd9Sstevel@tonic-gate * 437c478bd9Sstevel@tonic-gate * Adaptive mutexes (the default type) spin if the owner is running on 447c478bd9Sstevel@tonic-gate * another CPU and block otherwise. This policy is based on the assumption 457c478bd9Sstevel@tonic-gate * that mutex hold times are typically short enough that the time spent 467c478bd9Sstevel@tonic-gate * spinning is less than the time it takes to block. If you need mutual 477c478bd9Sstevel@tonic-gate * exclusion semantics with long hold times, consider an rwlock(9F) as 487c478bd9Sstevel@tonic-gate * RW_WRITER. Better still, reconsider the algorithm: if it requires 497c478bd9Sstevel@tonic-gate * mutual exclusion for long periods of time, it's probably not scalable. 507c478bd9Sstevel@tonic-gate * 517c478bd9Sstevel@tonic-gate * Adaptive mutexes are overwhelmingly more common than spin mutexes, 527c478bd9Sstevel@tonic-gate * so mutex_enter() assumes that the lock is adaptive. We get away 537c478bd9Sstevel@tonic-gate * with this by structuring mutexes so that an attempt to acquire a 547c478bd9Sstevel@tonic-gate * spin mutex as adaptive always fails. When mutex_enter() fails 557c478bd9Sstevel@tonic-gate * it punts to mutex_vector_enter(), which does all the hard stuff. 567c478bd9Sstevel@tonic-gate * 577c478bd9Sstevel@tonic-gate * mutex_vector_enter() first checks the type. If it's spin mutex, 587c478bd9Sstevel@tonic-gate * we just call lock_set_spl() and return. If it's an adaptive mutex, 597c478bd9Sstevel@tonic-gate * we check to see what the owner is doing. If the owner is running, 607c478bd9Sstevel@tonic-gate * we spin until the lock becomes available; if not, we mark the lock 617c478bd9Sstevel@tonic-gate * as having waiters and block. 627c478bd9Sstevel@tonic-gate * 637c478bd9Sstevel@tonic-gate * Blocking on a mutex is surprisingly delicate dance because, for speed, 647c478bd9Sstevel@tonic-gate * mutex_exit() doesn't use an atomic instruction. Thus we have to work 657c478bd9Sstevel@tonic-gate * a little harder in the (rarely-executed) blocking path to make sure 667c478bd9Sstevel@tonic-gate * we don't block on a mutex that's just been released -- otherwise we 677c478bd9Sstevel@tonic-gate * might never be woken up. 687c478bd9Sstevel@tonic-gate * 697c478bd9Sstevel@tonic-gate * The logic for synchronizing mutex_vector_enter() with mutex_exit() 707c478bd9Sstevel@tonic-gate * in the face of preemption and relaxed memory ordering is as follows: 717c478bd9Sstevel@tonic-gate * 727c478bd9Sstevel@tonic-gate * (1) Preemption in the middle of mutex_exit() must cause mutex_exit() 737c478bd9Sstevel@tonic-gate * to restart. Each platform must enforce this by checking the 747c478bd9Sstevel@tonic-gate * interrupted PC in the interrupt handler (or on return from trap -- 757c478bd9Sstevel@tonic-gate * whichever is more convenient for the platform). If the PC 767c478bd9Sstevel@tonic-gate * lies within the critical region of mutex_exit(), the interrupt 777c478bd9Sstevel@tonic-gate * handler must reset the PC back to the beginning of mutex_exit(). 787c478bd9Sstevel@tonic-gate * The critical region consists of all instructions up to, but not 797c478bd9Sstevel@tonic-gate * including, the store that clears the lock (which, of course, 807c478bd9Sstevel@tonic-gate * must never be executed twice.) 817c478bd9Sstevel@tonic-gate * 827c478bd9Sstevel@tonic-gate * This ensures that the owner will always check for waiters after 837c478bd9Sstevel@tonic-gate * resuming from a previous preemption. 847c478bd9Sstevel@tonic-gate * 857c478bd9Sstevel@tonic-gate * (2) A thread resuming in mutex_exit() does (at least) the following: 867c478bd9Sstevel@tonic-gate * 877c478bd9Sstevel@tonic-gate * when resuming: set CPU_THREAD = owner 887c478bd9Sstevel@tonic-gate * membar #StoreLoad 897c478bd9Sstevel@tonic-gate * 907c478bd9Sstevel@tonic-gate * in mutex_exit: check waiters bit; do wakeup if set 917c478bd9Sstevel@tonic-gate * membar #LoadStore|#StoreStore 927c478bd9Sstevel@tonic-gate * clear owner 937c478bd9Sstevel@tonic-gate * (at this point, other threads may or may not grab 947c478bd9Sstevel@tonic-gate * the lock, and we may or may not reacquire it) 957c478bd9Sstevel@tonic-gate * 967c478bd9Sstevel@tonic-gate * when blocking: membar #StoreStore (due to disp_lock_enter()) 977c478bd9Sstevel@tonic-gate * set CPU_THREAD = (possibly) someone else 987c478bd9Sstevel@tonic-gate * 997c478bd9Sstevel@tonic-gate * (3) A thread blocking in mutex_vector_enter() does the following: 1007c478bd9Sstevel@tonic-gate * 1017c478bd9Sstevel@tonic-gate * set waiters bit 1027c478bd9Sstevel@tonic-gate * membar #StoreLoad (via membar_enter()) 103575a7426Spt157919 * check CPU_THREAD for owner's t_cpu 104575a7426Spt157919 * continue if owner running 1057c478bd9Sstevel@tonic-gate * membar #LoadLoad (via membar_consumer()) 1067c478bd9Sstevel@tonic-gate * check owner and waiters bit; abort if either changed 1077c478bd9Sstevel@tonic-gate * block 1087c478bd9Sstevel@tonic-gate * 1097c478bd9Sstevel@tonic-gate * Thus the global memory orderings for (2) and (3) are as follows: 1107c478bd9Sstevel@tonic-gate * 1117c478bd9Sstevel@tonic-gate * (2M) mutex_exit() memory order: 1127c478bd9Sstevel@tonic-gate * 1137c478bd9Sstevel@tonic-gate * STORE CPU_THREAD = owner 1147c478bd9Sstevel@tonic-gate * LOAD waiters bit 1157c478bd9Sstevel@tonic-gate * STORE owner = NULL 1167c478bd9Sstevel@tonic-gate * STORE CPU_THREAD = (possibly) someone else 1177c478bd9Sstevel@tonic-gate * 1187c478bd9Sstevel@tonic-gate * (3M) mutex_vector_enter() memory order: 1197c478bd9Sstevel@tonic-gate * 1207c478bd9Sstevel@tonic-gate * STORE waiters bit = 1 1217c478bd9Sstevel@tonic-gate * LOAD CPU_THREAD for each CPU 1227c478bd9Sstevel@tonic-gate * LOAD owner and waiters bit 1237c478bd9Sstevel@tonic-gate * 1247c478bd9Sstevel@tonic-gate * It has been verified by exhaustive simulation that all possible global 1257c478bd9Sstevel@tonic-gate * memory orderings of (2M) interleaved with (3M) result in correct 1267c478bd9Sstevel@tonic-gate * behavior. Moreover, these ordering constraints are minimal: changing 1277c478bd9Sstevel@tonic-gate * the ordering of anything in (2M) or (3M) breaks the algorithm, creating 1287c478bd9Sstevel@tonic-gate * windows for missed wakeups. Note: the possibility that other threads 1297c478bd9Sstevel@tonic-gate * may grab the lock after the owner drops it can be factored out of the 1307c478bd9Sstevel@tonic-gate * memory ordering analysis because mutex_vector_enter() won't block 1317c478bd9Sstevel@tonic-gate * if the lock isn't still owned by the same thread. 1327c478bd9Sstevel@tonic-gate * 1337c478bd9Sstevel@tonic-gate * The only requirements of code outside the mutex implementation are 1347c478bd9Sstevel@tonic-gate * (1) mutex_exit() preemption fixup in interrupt handlers or trap return, 135575a7426Spt157919 * (2) a membar #StoreLoad after setting CPU_THREAD in resume(), 136575a7426Spt157919 * (3) mutex_owner_running() preemption fixup in interrupt handlers 137575a7426Spt157919 * or trap returns. 1387c478bd9Sstevel@tonic-gate * Note: idle threads cannot grab adaptive locks (since they cannot block), 1397c478bd9Sstevel@tonic-gate * so the membar may be safely omitted when resuming an idle thread. 1407c478bd9Sstevel@tonic-gate * 1417c478bd9Sstevel@tonic-gate * When a mutex has waiters, mutex_vector_exit() has several options: 1427c478bd9Sstevel@tonic-gate * 1437c478bd9Sstevel@tonic-gate * (1) Choose a waiter and make that thread the owner before waking it; 1447c478bd9Sstevel@tonic-gate * this is known as "direct handoff" of ownership. 1457c478bd9Sstevel@tonic-gate * 1467c478bd9Sstevel@tonic-gate * (2) Drop the lock and wake one waiter. 1477c478bd9Sstevel@tonic-gate * 1487c478bd9Sstevel@tonic-gate * (3) Drop the lock, clear the waiters bit, and wake all waiters. 1497c478bd9Sstevel@tonic-gate * 1507c478bd9Sstevel@tonic-gate * In many ways (1) is the cleanest solution, but if a lock is moderately 1517c478bd9Sstevel@tonic-gate * contended it defeats the adaptive spin logic. If we make some other 1527c478bd9Sstevel@tonic-gate * thread the owner, but he's not ONPROC yet, then all other threads on 1537c478bd9Sstevel@tonic-gate * other cpus that try to get the lock will conclude that the owner is 1547c478bd9Sstevel@tonic-gate * blocked, so they'll block too. And so on -- it escalates quickly, 1557c478bd9Sstevel@tonic-gate * with every thread taking the blocking path rather than the spin path. 1567c478bd9Sstevel@tonic-gate * Thus, direct handoff is *not* a good idea for adaptive mutexes. 1577c478bd9Sstevel@tonic-gate * 1587c478bd9Sstevel@tonic-gate * Option (2) is the next most natural-seeming option, but it has several 1597c478bd9Sstevel@tonic-gate * annoying properties. If there's more than one waiter, we must preserve 1607c478bd9Sstevel@tonic-gate * the waiters bit on an unheld lock. On cas-capable platforms, where 1617c478bd9Sstevel@tonic-gate * the waiters bit is part of the lock word, this means that both 0x0 1627c478bd9Sstevel@tonic-gate * and 0x1 represent unheld locks, so we have to cas against *both*. 1637c478bd9Sstevel@tonic-gate * Priority inheritance also gets more complicated, because a lock can 1647c478bd9Sstevel@tonic-gate * have waiters but no owner to whom priority can be willed. So while 1657c478bd9Sstevel@tonic-gate * it is possible to make option (2) work, it's surprisingly vile. 1667c478bd9Sstevel@tonic-gate * 1677c478bd9Sstevel@tonic-gate * Option (3), the least-intuitive at first glance, is what we actually do. 1687c478bd9Sstevel@tonic-gate * It has the advantage that because you always wake all waiters, you 1697c478bd9Sstevel@tonic-gate * never have to preserve the waiters bit. Waking all waiters seems like 1707c478bd9Sstevel@tonic-gate * begging for a thundering herd problem, but consider: under option (2), 1717c478bd9Sstevel@tonic-gate * every thread that grabs and drops the lock will wake one waiter -- so 1727c478bd9Sstevel@tonic-gate * if the lock is fairly active, all waiters will be awakened very quickly 1737c478bd9Sstevel@tonic-gate * anyway. Moreover, this is how adaptive locks are *supposed* to work. 1747c478bd9Sstevel@tonic-gate * The blocking case is rare; the more common case (by 3-4 orders of 1757c478bd9Sstevel@tonic-gate * magnitude) is that one or more threads spin waiting to get the lock. 1767c478bd9Sstevel@tonic-gate * Only direct handoff can prevent the thundering herd problem, but as 1777c478bd9Sstevel@tonic-gate * mentioned earlier, that would tend to defeat the adaptive spin logic. 1787c478bd9Sstevel@tonic-gate * In practice, option (3) works well because the blocking case is rare. 1797c478bd9Sstevel@tonic-gate */ 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* 1827c478bd9Sstevel@tonic-gate * delayed lock retry with exponential delay for spin locks 1837c478bd9Sstevel@tonic-gate * 1847c478bd9Sstevel@tonic-gate * It is noted above that for both the spin locks and the adaptive locks, 1857c478bd9Sstevel@tonic-gate * spinning is the dominate mode of operation. So long as there is only 1867c478bd9Sstevel@tonic-gate * one thread waiting on a lock, the naive spin loop works very well in 1877c478bd9Sstevel@tonic-gate * cache based architectures. The lock data structure is pulled into the 1887c478bd9Sstevel@tonic-gate * cache of the processor with the waiting/spinning thread and no further 1897c478bd9Sstevel@tonic-gate * memory traffic is generated until the lock is released. Unfortunately, 1907c478bd9Sstevel@tonic-gate * once two or more threads are waiting on a lock, the naive spin has 1917c478bd9Sstevel@tonic-gate * the property of generating maximum memory traffic from each spinning 1927c478bd9Sstevel@tonic-gate * thread as the spinning threads contend for the lock data structure. 1937c478bd9Sstevel@tonic-gate * 1947c478bd9Sstevel@tonic-gate * By executing a delay loop before retrying a lock, a waiting thread 1957c478bd9Sstevel@tonic-gate * can reduce its memory traffic by a large factor, depending on the 1967c478bd9Sstevel@tonic-gate * size of the delay loop. A large delay loop greatly reduced the memory 1977c478bd9Sstevel@tonic-gate * traffic, but has the drawback of having a period of time when 1987c478bd9Sstevel@tonic-gate * no thread is attempting to gain the lock even though several threads 1997c478bd9Sstevel@tonic-gate * might be waiting. A small delay loop has the drawback of not 2007c478bd9Sstevel@tonic-gate * much reduction in memory traffic, but reduces the potential idle time. 2017c478bd9Sstevel@tonic-gate * The theory of the exponential delay code is to start with a short 2027c478bd9Sstevel@tonic-gate * delay loop and double the waiting time on each iteration, up to 203575a7426Spt157919 * a preselected maximum. 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate #include <sys/param.h> 2077c478bd9Sstevel@tonic-gate #include <sys/time.h> 2087c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 2097c478bd9Sstevel@tonic-gate #include <sys/thread.h> 2107c478bd9Sstevel@tonic-gate #include <sys/debug.h> 2117c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 2127c478bd9Sstevel@tonic-gate #include <sys/sobject.h> 2137c478bd9Sstevel@tonic-gate #include <sys/turnstile.h> 2147c478bd9Sstevel@tonic-gate #include <sys/systm.h> 2157c478bd9Sstevel@tonic-gate #include <sys/mutex_impl.h> 2167c478bd9Sstevel@tonic-gate #include <sys/spl.h> 2177c478bd9Sstevel@tonic-gate #include <sys/lockstat.h> 2187c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 2197c478bd9Sstevel@tonic-gate #include <sys/cpu.h> 2207c478bd9Sstevel@tonic-gate #include <sys/stack.h> 221843e1988Sjohnlev #include <sys/archsystm.h> 222575a7426Spt157919 #include <sys/machsystm.h> 223575a7426Spt157919 #include <sys/x_call.h> 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate /* 2267c478bd9Sstevel@tonic-gate * The sobj_ops vector exports a set of functions needed when a thread 2277c478bd9Sstevel@tonic-gate * is asleep on a synchronization object of this type. 2287c478bd9Sstevel@tonic-gate */ 2297c478bd9Sstevel@tonic-gate static sobj_ops_t mutex_sobj_ops = { 2307c478bd9Sstevel@tonic-gate SOBJ_MUTEX, mutex_owner, turnstile_stay_asleep, turnstile_change_pri 2317c478bd9Sstevel@tonic-gate }; 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate /* 2347c478bd9Sstevel@tonic-gate * If the system panics on a mutex, save the address of the offending 2357c478bd9Sstevel@tonic-gate * mutex in panic_mutex_addr, and save the contents in panic_mutex. 2367c478bd9Sstevel@tonic-gate */ 2377c478bd9Sstevel@tonic-gate static mutex_impl_t panic_mutex; 2387c478bd9Sstevel@tonic-gate static mutex_impl_t *panic_mutex_addr; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate static void 2417c478bd9Sstevel@tonic-gate mutex_panic(char *msg, mutex_impl_t *lp) 2427c478bd9Sstevel@tonic-gate { 2437c478bd9Sstevel@tonic-gate if (panicstr) 2447c478bd9Sstevel@tonic-gate return; 2457c478bd9Sstevel@tonic-gate 246*75d94465SJosef 'Jeff' Sipek if (atomic_cas_ptr(&panic_mutex_addr, NULL, lp) == NULL) 2477c478bd9Sstevel@tonic-gate panic_mutex = *lp; 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate panic("%s, lp=%p owner=%p thread=%p", 2508793b36bSNick Todd msg, (void *)lp, (void *)MUTEX_OWNER(&panic_mutex), 2518793b36bSNick Todd (void *)curthread); 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 254575a7426Spt157919 /* "tunables" for per-platform backoff constants. */ 255575a7426Spt157919 uint_t mutex_backoff_cap = 0; 256575a7426Spt157919 ushort_t mutex_backoff_base = MUTEX_BACKOFF_BASE; 257575a7426Spt157919 ushort_t mutex_cap_factor = MUTEX_CAP_FACTOR; 258575a7426Spt157919 uchar_t mutex_backoff_shift = MUTEX_BACKOFF_SHIFT; 259575a7426Spt157919 260575a7426Spt157919 void 261575a7426Spt157919 mutex_sync(void) 262575a7426Spt157919 { 263575a7426Spt157919 MUTEX_SYNC(); 264575a7426Spt157919 } 265575a7426Spt157919 266575a7426Spt157919 /* calculate the backoff interval */ 267374ae87fSsvemuri uint_t 268575a7426Spt157919 default_lock_backoff(uint_t backoff) 269575a7426Spt157919 { 270575a7426Spt157919 uint_t cap; /* backoff cap calculated */ 271575a7426Spt157919 272575a7426Spt157919 if (backoff == 0) { 273575a7426Spt157919 backoff = mutex_backoff_base; 274575a7426Spt157919 /* first call just sets the base */ 275575a7426Spt157919 return (backoff); 276575a7426Spt157919 } 277575a7426Spt157919 278575a7426Spt157919 /* set cap */ 279575a7426Spt157919 if (mutex_backoff_cap == 0) { 280575a7426Spt157919 /* 281575a7426Spt157919 * For a contended lock, in the worst case a load + cas may 282575a7426Spt157919 * be queued at the controller for each contending CPU. 283575a7426Spt157919 * Therefore, to avoid queueing, the accesses for all CPUS must 284575a7426Spt157919 * be spread out in time over an interval of (ncpu * 285575a7426Spt157919 * cap-factor). Maximum backoff is set to this value, and 286575a7426Spt157919 * actual backoff is a random number from 0 to the current max. 287575a7426Spt157919 */ 288575a7426Spt157919 cap = ncpus_online * mutex_cap_factor; 289575a7426Spt157919 } else { 290575a7426Spt157919 cap = mutex_backoff_cap; 291575a7426Spt157919 } 292575a7426Spt157919 293575a7426Spt157919 /* calculate new backoff value */ 294575a7426Spt157919 backoff <<= mutex_backoff_shift; /* increase backoff */ 295575a7426Spt157919 if (backoff > cap) { 296575a7426Spt157919 if (cap < mutex_backoff_base) 297575a7426Spt157919 backoff = mutex_backoff_base; 298575a7426Spt157919 else 299575a7426Spt157919 backoff = cap; 300575a7426Spt157919 } 301575a7426Spt157919 302575a7426Spt157919 return (backoff); 303575a7426Spt157919 } 304575a7426Spt157919 305575a7426Spt157919 /* 306575a7426Spt157919 * default delay function for mutexes. 307575a7426Spt157919 */ 308374ae87fSsvemuri void 309575a7426Spt157919 default_lock_delay(uint_t backoff) 310575a7426Spt157919 { 311575a7426Spt157919 ulong_t rnd; /* random factor */ 312575a7426Spt157919 uint_t cur_backoff; /* calculated backoff */ 313575a7426Spt157919 uint_t backctr; 314575a7426Spt157919 315575a7426Spt157919 /* 316575a7426Spt157919 * Modify backoff by a random amount to avoid lockstep, and to 317575a7426Spt157919 * make it probable that some thread gets a small backoff, and 318575a7426Spt157919 * re-checks quickly 319575a7426Spt157919 */ 320575a7426Spt157919 rnd = (((long)curthread >> PTR24_LSB) ^ (long)MUTEX_GETTICK()); 321575a7426Spt157919 cur_backoff = (uint_t)(rnd % (backoff - mutex_backoff_base + 1)) + 322575a7426Spt157919 mutex_backoff_base; 323575a7426Spt157919 324575a7426Spt157919 /* 325575a7426Spt157919 * Delay before trying 326575a7426Spt157919 * to touch the mutex data structure. 327575a7426Spt157919 */ 328575a7426Spt157919 for (backctr = cur_backoff; backctr; backctr--) { 329575a7426Spt157919 MUTEX_DELAY(); 330575a7426Spt157919 }; 331575a7426Spt157919 } 332575a7426Spt157919 333575a7426Spt157919 uint_t (*mutex_lock_backoff)(uint_t) = default_lock_backoff; 334575a7426Spt157919 void (*mutex_lock_delay)(uint_t) = default_lock_delay; 335575a7426Spt157919 void (*mutex_delay)(void) = mutex_delay_default; 336575a7426Spt157919 3377c478bd9Sstevel@tonic-gate /* 3387c478bd9Sstevel@tonic-gate * mutex_vector_enter() is called from the assembly mutex_enter() routine 3397c478bd9Sstevel@tonic-gate * if the lock is held or is not of type MUTEX_ADAPTIVE. 3407c478bd9Sstevel@tonic-gate */ 3417c478bd9Sstevel@tonic-gate void 3427c478bd9Sstevel@tonic-gate mutex_vector_enter(mutex_impl_t *lp) 3437c478bd9Sstevel@tonic-gate { 3447c478bd9Sstevel@tonic-gate kthread_id_t owner; 345575a7426Spt157919 kthread_id_t lastowner = MUTEX_NO_OWNER; /* track owner changes */ 3467c478bd9Sstevel@tonic-gate hrtime_t sleep_time = 0; /* how long we slept */ 3479d68b18eSck142721 hrtime_t spin_time = 0; /* how long we spun */ 348575a7426Spt157919 cpu_t *cpup; 3497c478bd9Sstevel@tonic-gate turnstile_t *ts; 3507c478bd9Sstevel@tonic-gate volatile mutex_impl_t *vlp = (volatile mutex_impl_t *)lp; 351575a7426Spt157919 uint_t backoff = 0; /* current backoff */ 352575a7426Spt157919 int changecnt = 0; /* count of owner changes */ 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate ASSERT_STACK_ALIGNED(); 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate if (MUTEX_TYPE_SPIN(lp)) { 3577c478bd9Sstevel@tonic-gate lock_set_spl(&lp->m_spin.m_spinlock, lp->m_spin.m_minspl, 3587c478bd9Sstevel@tonic-gate &lp->m_spin.m_oldspl); 3597c478bd9Sstevel@tonic-gate return; 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate if (!MUTEX_TYPE_ADAPTIVE(lp)) { 3637c478bd9Sstevel@tonic-gate mutex_panic("mutex_enter: bad mutex", lp); 3647c478bd9Sstevel@tonic-gate return; 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* 3687c478bd9Sstevel@tonic-gate * Adaptive mutexes must not be acquired from above LOCK_LEVEL. 3697c478bd9Sstevel@tonic-gate * We can migrate after loading CPU but before checking CPU_ON_INTR, 3707c478bd9Sstevel@tonic-gate * so we must verify by disabling preemption and loading CPU again. 3717c478bd9Sstevel@tonic-gate */ 3727c478bd9Sstevel@tonic-gate cpup = CPU; 3737c478bd9Sstevel@tonic-gate if (CPU_ON_INTR(cpup) && !panicstr) { 3747c478bd9Sstevel@tonic-gate kpreempt_disable(); 3757c478bd9Sstevel@tonic-gate if (CPU_ON_INTR(CPU)) 3767c478bd9Sstevel@tonic-gate mutex_panic("mutex_enter: adaptive at high PIL", lp); 3777c478bd9Sstevel@tonic-gate kpreempt_enable(); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cpup, sys, mutex_adenters, 1); 3817c478bd9Sstevel@tonic-gate 3829d68b18eSck142721 spin_time = LOCKSTAT_START_TIME(LS_MUTEX_ENTER_SPIN); 3839d68b18eSck142721 384575a7426Spt157919 backoff = mutex_lock_backoff(0); /* set base backoff */ 3857c478bd9Sstevel@tonic-gate for (;;) { 386575a7426Spt157919 mutex_lock_delay(backoff); /* backoff delay */ 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate if (panicstr) 3897c478bd9Sstevel@tonic-gate return; 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate if ((owner = MUTEX_OWNER(vlp)) == NULL) { 392575a7426Spt157919 if (mutex_adaptive_tryenter(lp)) { 3937c478bd9Sstevel@tonic-gate break; 394575a7426Spt157919 } 395575a7426Spt157919 /* increase backoff only on failed attempt. */ 396575a7426Spt157919 backoff = mutex_lock_backoff(backoff); 397575a7426Spt157919 changecnt++; 3987c478bd9Sstevel@tonic-gate continue; 399575a7426Spt157919 } else if (lastowner != owner) { 400575a7426Spt157919 lastowner = owner; 401575a7426Spt157919 backoff = mutex_lock_backoff(backoff); 402575a7426Spt157919 changecnt++; 403575a7426Spt157919 } 404575a7426Spt157919 405575a7426Spt157919 if (changecnt >= ncpus_online) { 406575a7426Spt157919 backoff = mutex_lock_backoff(0); 407575a7426Spt157919 changecnt = 0; 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate if (owner == curthread) 4117c478bd9Sstevel@tonic-gate mutex_panic("recursive mutex_enter", lp); 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate /* 4147c478bd9Sstevel@tonic-gate * If lock is held but owner is not yet set, spin. 4157c478bd9Sstevel@tonic-gate * (Only relevant for platforms that don't have cas.) 4167c478bd9Sstevel@tonic-gate */ 4177c478bd9Sstevel@tonic-gate if (owner == MUTEX_NO_OWNER) 4187c478bd9Sstevel@tonic-gate continue; 4197c478bd9Sstevel@tonic-gate 420575a7426Spt157919 if (mutex_owner_running(lp) != NULL) { 421575a7426Spt157919 continue; 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate /* 4257c478bd9Sstevel@tonic-gate * The owner appears not to be running, so block. 4267c478bd9Sstevel@tonic-gate * See the Big Theory Statement for memory ordering issues. 4277c478bd9Sstevel@tonic-gate */ 4287c478bd9Sstevel@tonic-gate ts = turnstile_lookup(lp); 4297c478bd9Sstevel@tonic-gate MUTEX_SET_WAITERS(lp); 4307c478bd9Sstevel@tonic-gate membar_enter(); 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* 4337c478bd9Sstevel@tonic-gate * Recheck whether owner is running after waiters bit hits 4347c478bd9Sstevel@tonic-gate * global visibility (above). If owner is running, spin. 4357c478bd9Sstevel@tonic-gate */ 436575a7426Spt157919 if (mutex_owner_running(lp) != NULL) { 4377c478bd9Sstevel@tonic-gate turnstile_exit(lp); 438575a7426Spt157919 continue; 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate membar_consumer(); 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate /* 4437c478bd9Sstevel@tonic-gate * If owner and waiters bit are unchanged, block. 4447c478bd9Sstevel@tonic-gate */ 4457c478bd9Sstevel@tonic-gate if (MUTEX_OWNER(vlp) == owner && MUTEX_HAS_WAITERS(vlp)) { 4467c478bd9Sstevel@tonic-gate sleep_time -= gethrtime(); 4477c478bd9Sstevel@tonic-gate (void) turnstile_block(ts, TS_WRITER_Q, lp, 4487c478bd9Sstevel@tonic-gate &mutex_sobj_ops, NULL, NULL); 4497c478bd9Sstevel@tonic-gate sleep_time += gethrtime(); 450575a7426Spt157919 /* reset backoff after turnstile */ 451575a7426Spt157919 backoff = mutex_lock_backoff(0); 4527c478bd9Sstevel@tonic-gate } else { 4537c478bd9Sstevel@tonic-gate turnstile_exit(lp); 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate ASSERT(MUTEX_OWNER(lp) == curthread); 4587c478bd9Sstevel@tonic-gate 4590efe5e54Sdv142724 if (sleep_time != 0) { 4600efe5e54Sdv142724 /* 4610efe5e54Sdv142724 * Note, sleep time is the sum of all the sleeping we 4620efe5e54Sdv142724 * did. 4630efe5e54Sdv142724 */ 4647c478bd9Sstevel@tonic-gate LOCKSTAT_RECORD(LS_MUTEX_ENTER_BLOCK, lp, sleep_time); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4679d68b18eSck142721 /* record spin time, don't count sleep time */ 4689d68b18eSck142721 if (spin_time != 0) { 4699d68b18eSck142721 LOCKSTAT_RECORD_TIME(LS_MUTEX_ENTER_SPIN, lp, 4709d68b18eSck142721 spin_time + sleep_time); 471575a7426Spt157919 } 4720efe5e54Sdv142724 4737c478bd9Sstevel@tonic-gate LOCKSTAT_RECORD0(LS_MUTEX_ENTER_ACQUIRE, lp); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate /* 4777c478bd9Sstevel@tonic-gate * mutex_vector_tryenter() is called from the assembly mutex_tryenter() 4787c478bd9Sstevel@tonic-gate * routine if the lock is held or is not of type MUTEX_ADAPTIVE. 4797c478bd9Sstevel@tonic-gate */ 4807c478bd9Sstevel@tonic-gate int 4817c478bd9Sstevel@tonic-gate mutex_vector_tryenter(mutex_impl_t *lp) 4827c478bd9Sstevel@tonic-gate { 4837c478bd9Sstevel@tonic-gate int s; 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate if (MUTEX_TYPE_ADAPTIVE(lp)) 4867c478bd9Sstevel@tonic-gate return (0); /* we already tried in assembly */ 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate if (!MUTEX_TYPE_SPIN(lp)) { 4897c478bd9Sstevel@tonic-gate mutex_panic("mutex_tryenter: bad mutex", lp); 4907c478bd9Sstevel@tonic-gate return (0); 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate s = splr(lp->m_spin.m_minspl); 4947c478bd9Sstevel@tonic-gate if (lock_try(&lp->m_spin.m_spinlock)) { 4957c478bd9Sstevel@tonic-gate lp->m_spin.m_oldspl = (ushort_t)s; 4967c478bd9Sstevel@tonic-gate return (1); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate splx(s); 4997c478bd9Sstevel@tonic-gate return (0); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate /* 5037c478bd9Sstevel@tonic-gate * mutex_vector_exit() is called from mutex_exit() if the lock is not 5047c478bd9Sstevel@tonic-gate * adaptive, has waiters, or is not owned by the current thread (panic). 5057c478bd9Sstevel@tonic-gate */ 5067c478bd9Sstevel@tonic-gate void 5077c478bd9Sstevel@tonic-gate mutex_vector_exit(mutex_impl_t *lp) 5087c478bd9Sstevel@tonic-gate { 5097c478bd9Sstevel@tonic-gate turnstile_t *ts; 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate if (MUTEX_TYPE_SPIN(lp)) { 5127c478bd9Sstevel@tonic-gate lock_clear_splx(&lp->m_spin.m_spinlock, lp->m_spin.m_oldspl); 5137c478bd9Sstevel@tonic-gate return; 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate if (MUTEX_OWNER(lp) != curthread) { 5177c478bd9Sstevel@tonic-gate mutex_panic("mutex_exit: not owner", lp); 5187c478bd9Sstevel@tonic-gate return; 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate ts = turnstile_lookup(lp); 5227c478bd9Sstevel@tonic-gate MUTEX_CLEAR_LOCK_AND_WAITERS(lp); 5237c478bd9Sstevel@tonic-gate if (ts == NULL) 5247c478bd9Sstevel@tonic-gate turnstile_exit(lp); 5257c478bd9Sstevel@tonic-gate else 5267c478bd9Sstevel@tonic-gate turnstile_wakeup(ts, TS_WRITER_Q, ts->ts_waiters, NULL); 5277c478bd9Sstevel@tonic-gate LOCKSTAT_RECORD0(LS_MUTEX_EXIT_RELEASE, lp); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate int 531b5fca8f8Stomee mutex_owned(const kmutex_t *mp) 5327c478bd9Sstevel@tonic-gate { 533b5fca8f8Stomee const mutex_impl_t *lp = (const mutex_impl_t *)mp; 5347c478bd9Sstevel@tonic-gate 53519397407SSherry Moore if (panicstr || quiesce_active) 5367c478bd9Sstevel@tonic-gate return (1); 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate if (MUTEX_TYPE_ADAPTIVE(lp)) 5397c478bd9Sstevel@tonic-gate return (MUTEX_OWNER(lp) == curthread); 5407c478bd9Sstevel@tonic-gate return (LOCK_HELD(&lp->m_spin.m_spinlock)); 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate kthread_t * 544b5fca8f8Stomee mutex_owner(const kmutex_t *mp) 5457c478bd9Sstevel@tonic-gate { 546b5fca8f8Stomee const mutex_impl_t *lp = (const mutex_impl_t *)mp; 5477c478bd9Sstevel@tonic-gate kthread_id_t t; 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate if (MUTEX_TYPE_ADAPTIVE(lp) && (t = MUTEX_OWNER(lp)) != MUTEX_NO_OWNER) 5507c478bd9Sstevel@tonic-gate return (t); 5517c478bd9Sstevel@tonic-gate return (NULL); 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate /* 5557c478bd9Sstevel@tonic-gate * The iblock cookie 'ibc' is the spl level associated with the lock; 5567c478bd9Sstevel@tonic-gate * this alone determines whether the lock will be ADAPTIVE or SPIN. 5577c478bd9Sstevel@tonic-gate * 5587c478bd9Sstevel@tonic-gate * Adaptive mutexes created in zeroed memory do not need to call 5597c478bd9Sstevel@tonic-gate * mutex_init() as their allocation in this fashion guarantees 5607c478bd9Sstevel@tonic-gate * their initialization. 5617c478bd9Sstevel@tonic-gate * eg adaptive mutexes created as static within the BSS or allocated 5627c478bd9Sstevel@tonic-gate * by kmem_zalloc(). 5637c478bd9Sstevel@tonic-gate */ 5647c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5657c478bd9Sstevel@tonic-gate void 5667c478bd9Sstevel@tonic-gate mutex_init(kmutex_t *mp, char *name, kmutex_type_t type, void *ibc) 5677c478bd9Sstevel@tonic-gate { 5687c478bd9Sstevel@tonic-gate mutex_impl_t *lp = (mutex_impl_t *)mp; 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate ASSERT(ibc < (void *)KERNELBASE); /* see 1215173 */ 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate if ((intptr_t)ibc > ipltospl(LOCK_LEVEL) && ibc < (void *)KERNELBASE) { 5737c478bd9Sstevel@tonic-gate ASSERT(type != MUTEX_ADAPTIVE && type != MUTEX_DEFAULT); 5747c478bd9Sstevel@tonic-gate MUTEX_SET_TYPE(lp, MUTEX_SPIN); 5757c478bd9Sstevel@tonic-gate LOCK_INIT_CLEAR(&lp->m_spin.m_spinlock); 5767c478bd9Sstevel@tonic-gate LOCK_INIT_HELD(&lp->m_spin.m_dummylock); 5777c478bd9Sstevel@tonic-gate lp->m_spin.m_minspl = (int)(intptr_t)ibc; 5787c478bd9Sstevel@tonic-gate } else { 5797f30f491Sck142721 #ifdef MUTEX_ALIGN 5807f30f491Sck142721 static int misalign_cnt = 0; 5817f30f491Sck142721 5827f30f491Sck142721 if (((uintptr_t)lp & (uintptr_t)(MUTEX_ALIGN - 1)) && 5837f30f491Sck142721 (misalign_cnt < MUTEX_ALIGN_WARNINGS)) { 5847f30f491Sck142721 /* 5857f30f491Sck142721 * The mutex is not aligned and may cross a cache line. 5867f30f491Sck142721 * This is not supported and may cause a panic. 5877f30f491Sck142721 * Show a warning that the mutex is not aligned 5887f30f491Sck142721 * and attempt to identify the origin. 5897f30f491Sck142721 * Unaligned mutexes are not (supposed to be) 5907f30f491Sck142721 * possible on SPARC. 5917f30f491Sck142721 */ 5927f30f491Sck142721 char *funcname; 5937f30f491Sck142721 ulong_t offset = 0; 5947f30f491Sck142721 5957f30f491Sck142721 funcname = modgetsymname((uintptr_t)caller(), &offset); 5967f30f491Sck142721 cmn_err(CE_WARN, "mutex_init: %p is not %d byte " 5977f30f491Sck142721 "aligned; caller %s+%lx in module %s. " 5987f30f491Sck142721 "This is unsupported and may cause a panic. " 5997f30f491Sck142721 "Please report this to the kernel module supplier.", 6001f7e2746Sck142721 (void *)lp, MUTEX_ALIGN, 6017f30f491Sck142721 funcname ? funcname : "unknown", offset, 6027f30f491Sck142721 mod_containing_pc(caller())); 6037f30f491Sck142721 misalign_cnt++; 6047f30f491Sck142721 if (misalign_cnt >= MUTEX_ALIGN_WARNINGS) { 6057f30f491Sck142721 cmn_err(CE_WARN, "mutex_init: further unaligned" 6067f30f491Sck142721 " mutex warnings will be suppressed."); 6077f30f491Sck142721 } 6087f30f491Sck142721 } 6097f30f491Sck142721 #endif /* MUTEX_ALIGN */ 6107c478bd9Sstevel@tonic-gate ASSERT(type != MUTEX_SPIN); 6117f30f491Sck142721 6127c478bd9Sstevel@tonic-gate MUTEX_SET_TYPE(lp, MUTEX_ADAPTIVE); 6137c478bd9Sstevel@tonic-gate MUTEX_CLEAR_LOCK_AND_WAITERS(lp); 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate void 6187c478bd9Sstevel@tonic-gate mutex_destroy(kmutex_t *mp) 6197c478bd9Sstevel@tonic-gate { 6207c478bd9Sstevel@tonic-gate mutex_impl_t *lp = (mutex_impl_t *)mp; 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate if (lp->m_owner == 0 && !MUTEX_HAS_WAITERS(lp)) { 6237c478bd9Sstevel@tonic-gate MUTEX_DESTROY(lp); 6247c478bd9Sstevel@tonic-gate } else if (MUTEX_TYPE_SPIN(lp)) { 6257c478bd9Sstevel@tonic-gate LOCKSTAT_RECORD0(LS_MUTEX_DESTROY_RELEASE, lp); 6267c478bd9Sstevel@tonic-gate MUTEX_DESTROY(lp); 6277c478bd9Sstevel@tonic-gate } else if (MUTEX_TYPE_ADAPTIVE(lp)) { 6287c478bd9Sstevel@tonic-gate LOCKSTAT_RECORD0(LS_MUTEX_DESTROY_RELEASE, lp); 6297c478bd9Sstevel@tonic-gate if (MUTEX_OWNER(lp) != curthread) 6307c478bd9Sstevel@tonic-gate mutex_panic("mutex_destroy: not owner", lp); 6317c478bd9Sstevel@tonic-gate if (MUTEX_HAS_WAITERS(lp)) { 6327c478bd9Sstevel@tonic-gate turnstile_t *ts = turnstile_lookup(lp); 6337c478bd9Sstevel@tonic-gate turnstile_exit(lp); 6347c478bd9Sstevel@tonic-gate if (ts != NULL) 6357c478bd9Sstevel@tonic-gate mutex_panic("mutex_destroy: has waiters", lp); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate MUTEX_DESTROY(lp); 6387c478bd9Sstevel@tonic-gate } else { 6397c478bd9Sstevel@tonic-gate mutex_panic("mutex_destroy: bad mutex", lp); 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate /* 6447c478bd9Sstevel@tonic-gate * Simple C support for the cases where spin locks miss on the first try. 6457c478bd9Sstevel@tonic-gate */ 6467c478bd9Sstevel@tonic-gate void 6477c478bd9Sstevel@tonic-gate lock_set_spin(lock_t *lp) 6487c478bd9Sstevel@tonic-gate { 649575a7426Spt157919 int loop_count = 0; 650575a7426Spt157919 uint_t backoff = 0; /* current backoff */ 6519d68b18eSck142721 hrtime_t spin_time = 0; /* how long we spun */ 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate if (panicstr) 6547c478bd9Sstevel@tonic-gate return; 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate if (ncpus == 1) 6578793b36bSNick Todd panic("lock_set: %p lock held and only one CPU", (void *)lp); 6587c478bd9Sstevel@tonic-gate 6599d68b18eSck142721 spin_time = LOCKSTAT_START_TIME(LS_LOCK_SET_SPIN); 6609d68b18eSck142721 6617c478bd9Sstevel@tonic-gate while (LOCK_HELD(lp) || !lock_spin_try(lp)) { 6627c478bd9Sstevel@tonic-gate if (panicstr) 6637c478bd9Sstevel@tonic-gate return; 664575a7426Spt157919 loop_count++; 6657c478bd9Sstevel@tonic-gate 666575a7426Spt157919 if (ncpus_online == loop_count) { 667575a7426Spt157919 backoff = mutex_lock_backoff(0); 668575a7426Spt157919 loop_count = 0; 669575a7426Spt157919 } else { 670575a7426Spt157919 backoff = mutex_lock_backoff(backoff); 6717c478bd9Sstevel@tonic-gate } 672575a7426Spt157919 mutex_lock_delay(backoff); 673e603b7d4Spm145316 } 6747c478bd9Sstevel@tonic-gate 6759d68b18eSck142721 LOCKSTAT_RECORD_TIME(LS_LOCK_SET_SPIN, lp, spin_time); 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate LOCKSTAT_RECORD0(LS_LOCK_SET_ACQUIRE, lp); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate void 6817c478bd9Sstevel@tonic-gate lock_set_spl_spin(lock_t *lp, int new_pil, ushort_t *old_pil_addr, int old_pil) 6827c478bd9Sstevel@tonic-gate { 683575a7426Spt157919 int loop_count = 0; 684575a7426Spt157919 uint_t backoff = 0; /* current backoff */ 6859d68b18eSck142721 hrtime_t spin_time = 0; /* how long we spun */ 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate if (panicstr) 6887c478bd9Sstevel@tonic-gate return; 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate if (ncpus == 1) 6918793b36bSNick Todd panic("lock_set_spl: %p lock held and only one CPU", 6928793b36bSNick Todd (void *)lp); 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate ASSERT(new_pil > LOCK_LEVEL); 6957c478bd9Sstevel@tonic-gate 6969d68b18eSck142721 spin_time = LOCKSTAT_START_TIME(LS_LOCK_SET_SPL_SPIN); 6979d68b18eSck142721 6987c478bd9Sstevel@tonic-gate do { 6997c478bd9Sstevel@tonic-gate splx(old_pil); 7007c478bd9Sstevel@tonic-gate while (LOCK_HELD(lp)) { 701575a7426Spt157919 loop_count++; 702575a7426Spt157919 7037c478bd9Sstevel@tonic-gate if (panicstr) { 7047c478bd9Sstevel@tonic-gate *old_pil_addr = (ushort_t)splr(new_pil); 7057c478bd9Sstevel@tonic-gate return; 7067c478bd9Sstevel@tonic-gate } 707575a7426Spt157919 if (ncpus_online == loop_count) { 708575a7426Spt157919 backoff = mutex_lock_backoff(0); 709575a7426Spt157919 loop_count = 0; 710e603b7d4Spm145316 } else { 711575a7426Spt157919 backoff = mutex_lock_backoff(backoff); 7127c478bd9Sstevel@tonic-gate } 713575a7426Spt157919 mutex_lock_delay(backoff); 714e603b7d4Spm145316 } 7157c478bd9Sstevel@tonic-gate old_pil = splr(new_pil); 7167c478bd9Sstevel@tonic-gate } while (!lock_spin_try(lp)); 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate *old_pil_addr = (ushort_t)old_pil; 7197c478bd9Sstevel@tonic-gate 7209d68b18eSck142721 LOCKSTAT_RECORD_TIME(LS_LOCK_SET_SPL_SPIN, lp, spin_time); 7217c478bd9Sstevel@tonic-gate 7229d68b18eSck142721 LOCKSTAT_RECORD0(LS_LOCK_SET_SPL_ACQUIRE, lp); 7237c478bd9Sstevel@tonic-gate } 724