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
mutex_panic(char * msg,mutex_impl_t * lp)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
mutex_sync(void)261575a7426Spt157919 mutex_sync(void)
262575a7426Spt157919 {
263575a7426Spt157919 MUTEX_SYNC();
264575a7426Spt157919 }
265575a7426Spt157919
266575a7426Spt157919 /* calculate the backoff interval */
267374ae87fSsvemuri uint_t
default_lock_backoff(uint_t backoff)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
default_lock_delay(uint_t backoff)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
mutex_vector_enter(mutex_impl_t * lp)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
mutex_vector_tryenter(mutex_impl_t * lp)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
mutex_vector_exit(mutex_impl_t * lp)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
mutex_owned(const kmutex_t * mp)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 *
mutex_owner(const kmutex_t * mp)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
mutex_init(kmutex_t * mp,char * name,kmutex_type_t type,void * ibc)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
mutex_destroy(kmutex_t * mp)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
lock_set_spin(lock_t * lp)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
lock_set_spl_spin(lock_t * lp,int new_pil,ushort_t * old_pil_addr,int old_pil)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