]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - sys/kern/kern_sx.c
[SA-14:25] Fix kernel stack disclosure in setlogin(2) / getlogin(2).
[FreeBSD/releng/9.3.git] / sys / kern / kern_sx.c
1 /*-
2  * Copyright (c) 2007 Attilio Rao <attilio@freebsd.org>
3  * Copyright (c) 2001 Jason Evans <jasone@freebsd.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice(s), this list of conditions and the following disclaimer as
11  *    the first lines of this file unmodified other than the possible
12  *    addition of one or more copyright notices.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice(s), this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
27  * DAMAGE.
28  */
29
30 /*
31  * Shared/exclusive locks.  This implementation attempts to ensure
32  * deterministic lock granting behavior, so that slocks and xlocks are
33  * interleaved.
34  *
35  * Priority propagation will not generally raise the priority of lock holders,
36  * so should not be relied upon in combination with sx locks.
37  */
38
39 #include "opt_ddb.h"
40 #include "opt_hwpmc_hooks.h"
41 #include "opt_kdtrace.h"
42 #include "opt_no_adaptive_sx.h"
43
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kdb.h>
50 #include <sys/ktr.h>
51 #include <sys/lock.h>
52 #include <sys/mutex.h>
53 #include <sys/proc.h>
54 #include <sys/sleepqueue.h>
55 #include <sys/sx.h>
56 #include <sys/sysctl.h>
57
58 #if defined(SMP) && !defined(NO_ADAPTIVE_SX)
59 #include <machine/cpu.h>
60 #endif
61
62 #ifdef DDB
63 #include <ddb/ddb.h>
64 #endif
65
66 #if defined(SMP) && !defined(NO_ADAPTIVE_SX)
67 #define ADAPTIVE_SX
68 #endif
69
70 CTASSERT((SX_NOADAPTIVE & LO_CLASSFLAGS) == SX_NOADAPTIVE);
71
72 #ifdef HWPMC_HOOKS
73 #include <sys/pmckern.h>
74 PMC_SOFT_DECLARE( , , lock, failed);
75 #endif
76
77 /* Handy macros for sleep queues. */
78 #define SQ_EXCLUSIVE_QUEUE      0
79 #define SQ_SHARED_QUEUE         1
80
81 #ifdef ADAPTIVE_SX
82 #define ASX_RETRIES             10
83 #define ASX_LOOPS               10000
84 #endif
85
86 /*
87  * Variations on DROP_GIANT()/PICKUP_GIANT() for use in this file.  We
88  * drop Giant anytime we have to sleep or if we adaptively spin.
89  */
90 #define GIANT_DECLARE                                                   \
91         int _giantcnt = 0;                                              \
92         WITNESS_SAVE_DECL(Giant)                                        \
93
94 #define GIANT_SAVE() do {                                               \
95         if (mtx_owned(&Giant)) {                                        \
96                 WITNESS_SAVE(&Giant.lock_object, Giant);                \
97                 while (mtx_owned(&Giant)) {                             \
98                         _giantcnt++;                                    \
99                         mtx_unlock(&Giant);                             \
100                 }                                                       \
101         }                                                               \
102 } while (0)
103
104 #define GIANT_RESTORE() do {                                            \
105         if (_giantcnt > 0) {                                            \
106                 mtx_assert(&Giant, MA_NOTOWNED);                        \
107                 while (_giantcnt--)                                     \
108                         mtx_lock(&Giant);                               \
109                 WITNESS_RESTORE(&Giant.lock_object, Giant);             \
110         }                                                               \
111 } while (0)
112
113 /*
114  * Returns true if an exclusive lock is recursed.  It assumes
115  * curthread currently has an exclusive lock.
116  */
117 #define sx_recurse              lock_object.lo_data
118 #define sx_recursed(sx)         ((sx)->sx_recurse != 0)
119
120 static void     assert_sx(struct lock_object *lock, int what);
121 #ifdef DDB
122 static void     db_show_sx(struct lock_object *lock);
123 #endif
124 static void     lock_sx(struct lock_object *lock, int how);
125 #ifdef KDTRACE_HOOKS
126 static int      owner_sx(struct lock_object *lock, struct thread **owner);
127 #endif
128 static int      unlock_sx(struct lock_object *lock);
129
130 struct lock_class lock_class_sx = {
131         .lc_name = "sx",
132         .lc_flags = LC_SLEEPLOCK | LC_SLEEPABLE | LC_RECURSABLE | LC_UPGRADABLE,
133         .lc_assert = assert_sx,
134 #ifdef DDB
135         .lc_ddb_show = db_show_sx,
136 #endif
137         .lc_lock = lock_sx,
138         .lc_unlock = unlock_sx,
139 #ifdef KDTRACE_HOOKS
140         .lc_owner = owner_sx,
141 #endif
142 };
143
144 #ifndef INVARIANTS
145 #define _sx_assert(sx, what, file, line)
146 #endif
147
148 void
149 assert_sx(struct lock_object *lock, int what)
150 {
151
152         sx_assert((struct sx *)lock, what);
153 }
154
155 void
156 lock_sx(struct lock_object *lock, int how)
157 {
158         struct sx *sx;
159
160         sx = (struct sx *)lock;
161         if (how)
162                 sx_xlock(sx);
163         else
164                 sx_slock(sx);
165 }
166
167 int
168 unlock_sx(struct lock_object *lock)
169 {
170         struct sx *sx;
171
172         sx = (struct sx *)lock;
173         sx_assert(sx, SA_LOCKED | SA_NOTRECURSED);
174         if (sx_xlocked(sx)) {
175                 sx_xunlock(sx);
176                 return (1);
177         } else {
178                 sx_sunlock(sx);
179                 return (0);
180         }
181 }
182
183 #ifdef KDTRACE_HOOKS
184 int
185 owner_sx(struct lock_object *lock, struct thread **owner)
186 {
187         struct sx *sx = (struct sx *)lock;
188         uintptr_t x = sx->sx_lock;
189
190         *owner = (struct thread *)SX_OWNER(x);
191         return ((x & SX_LOCK_SHARED) != 0 ? (SX_SHARERS(x) != 0) :
192             (*owner != NULL));
193 }
194 #endif
195
196 void
197 sx_sysinit(void *arg)
198 {
199         struct sx_args *sargs = arg;
200
201         sx_init_flags(sargs->sa_sx, sargs->sa_desc, sargs->sa_flags);
202 }
203
204 void
205 sx_init_flags(struct sx *sx, const char *description, int opts)
206 {
207         int flags;
208
209         MPASS((opts & ~(SX_QUIET | SX_RECURSE | SX_NOWITNESS | SX_DUPOK |
210             SX_NOPROFILE | SX_NOADAPTIVE)) == 0);
211         ASSERT_ATOMIC_LOAD_PTR(sx->sx_lock,
212             ("%s: sx_lock not aligned for %s: %p", __func__, description,
213             &sx->sx_lock));
214
215         flags = LO_SLEEPABLE | LO_UPGRADABLE;
216         if (opts & SX_DUPOK)
217                 flags |= LO_DUPOK;
218         if (opts & SX_NOPROFILE)
219                 flags |= LO_NOPROFILE;
220         if (!(opts & SX_NOWITNESS))
221                 flags |= LO_WITNESS;
222         if (opts & SX_RECURSE)
223                 flags |= LO_RECURSABLE;
224         if (opts & SX_QUIET)
225                 flags |= LO_QUIET;
226
227         flags |= opts & SX_NOADAPTIVE;
228         sx->sx_lock = SX_LOCK_UNLOCKED;
229         sx->sx_recurse = 0;
230         lock_init(&sx->lock_object, &lock_class_sx, description, NULL, flags);
231 }
232
233 void
234 sx_destroy(struct sx *sx)
235 {
236
237         KASSERT(sx->sx_lock == SX_LOCK_UNLOCKED, ("sx lock still held"));
238         KASSERT(sx->sx_recurse == 0, ("sx lock still recursed"));
239         sx->sx_lock = SX_LOCK_DESTROYED;
240         lock_destroy(&sx->lock_object);
241 }
242
243 int
244 _sx_slock(struct sx *sx, int opts, const char *file, int line)
245 {
246         int error = 0;
247
248         if (SCHEDULER_STOPPED())
249                 return (0);
250         KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread),
251             ("sx_slock() by idle thread %p on sx %s @ %s:%d",
252             curthread, sx->lock_object.lo_name, file, line));
253         KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
254             ("sx_slock() of destroyed sx @ %s:%d", file, line));
255         WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER, file, line, NULL);
256         error = __sx_slock(sx, opts, file, line);
257         if (!error) {
258                 LOCK_LOG_LOCK("SLOCK", &sx->lock_object, 0, 0, file, line);
259                 WITNESS_LOCK(&sx->lock_object, 0, file, line);
260                 curthread->td_locks++;
261         }
262
263         return (error);
264 }
265
266 int
267 _sx_try_slock(struct sx *sx, const char *file, int line)
268 {
269         uintptr_t x;
270
271         if (SCHEDULER_STOPPED())
272                 return (1);
273
274         KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread),
275             ("sx_try_slock() by idle thread %p on sx %s @ %s:%d",
276             curthread, sx->lock_object.lo_name, file, line));
277
278         for (;;) {
279                 x = sx->sx_lock;
280                 KASSERT(x != SX_LOCK_DESTROYED,
281                     ("sx_try_slock() of destroyed sx @ %s:%d", file, line));
282                 if (!(x & SX_LOCK_SHARED))
283                         break;
284                 if (atomic_cmpset_acq_ptr(&sx->sx_lock, x, x + SX_ONE_SHARER)) {
285                         LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 1, file, line);
286                         WITNESS_LOCK(&sx->lock_object, LOP_TRYLOCK, file, line);
287                         curthread->td_locks++;
288                         return (1);
289                 }
290         }
291
292         LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 0, file, line);
293         return (0);
294 }
295
296 int
297 _sx_xlock(struct sx *sx, int opts, const char *file, int line)
298 {
299         int error = 0;
300
301         if (SCHEDULER_STOPPED())
302                 return (0);
303         KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread),
304             ("sx_xlock() by idle thread %p on sx %s @ %s:%d",
305             curthread, sx->lock_object.lo_name, file, line));
306         KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
307             ("sx_xlock() of destroyed sx @ %s:%d", file, line));
308         WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE, file,
309             line, NULL);
310         error = __sx_xlock(sx, curthread, opts, file, line);
311         if (!error) {
312                 LOCK_LOG_LOCK("XLOCK", &sx->lock_object, 0, sx->sx_recurse,
313                     file, line);
314                 WITNESS_LOCK(&sx->lock_object, LOP_EXCLUSIVE, file, line);
315                 curthread->td_locks++;
316         }
317
318         return (error);
319 }
320
321 int
322 _sx_try_xlock(struct sx *sx, const char *file, int line)
323 {
324         int rval;
325
326         if (SCHEDULER_STOPPED())
327                 return (1);
328
329         KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread),
330             ("sx_try_xlock() by idle thread %p on sx %s @ %s:%d",
331             curthread, sx->lock_object.lo_name, file, line));
332         KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
333             ("sx_try_xlock() of destroyed sx @ %s:%d", file, line));
334
335         if (sx_xlocked(sx) &&
336             (sx->lock_object.lo_flags & LO_RECURSABLE) != 0) {
337                 sx->sx_recurse++;
338                 atomic_set_ptr(&sx->sx_lock, SX_LOCK_RECURSED);
339                 rval = 1;
340         } else
341                 rval = atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED,
342                     (uintptr_t)curthread);
343         LOCK_LOG_TRY("XLOCK", &sx->lock_object, 0, rval, file, line);
344         if (rval) {
345                 WITNESS_LOCK(&sx->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
346                     file, line);
347                 curthread->td_locks++;
348         }
349
350         return (rval);
351 }
352
353 void
354 _sx_sunlock(struct sx *sx, const char *file, int line)
355 {
356
357         if (SCHEDULER_STOPPED())
358                 return;
359         KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
360             ("sx_sunlock() of destroyed sx @ %s:%d", file, line));
361         _sx_assert(sx, SA_SLOCKED, file, line);
362         curthread->td_locks--;
363         WITNESS_UNLOCK(&sx->lock_object, 0, file, line);
364         LOCK_LOG_LOCK("SUNLOCK", &sx->lock_object, 0, 0, file, line);
365         __sx_sunlock(sx, file, line);
366         LOCKSTAT_PROFILE_RELEASE_LOCK(LS_SX_SUNLOCK_RELEASE, sx);
367 }
368
369 void
370 _sx_xunlock(struct sx *sx, const char *file, int line)
371 {
372
373         if (SCHEDULER_STOPPED())
374                 return;
375         KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
376             ("sx_xunlock() of destroyed sx @ %s:%d", file, line));
377         _sx_assert(sx, SA_XLOCKED, file, line);
378         curthread->td_locks--;
379         WITNESS_UNLOCK(&sx->lock_object, LOP_EXCLUSIVE, file, line);
380         LOCK_LOG_LOCK("XUNLOCK", &sx->lock_object, 0, sx->sx_recurse, file,
381             line);
382         if (!sx_recursed(sx))
383                 LOCKSTAT_PROFILE_RELEASE_LOCK(LS_SX_XUNLOCK_RELEASE, sx);
384         __sx_xunlock(sx, curthread, file, line);
385 }
386
387 /*
388  * Try to do a non-blocking upgrade from a shared lock to an exclusive lock.
389  * This will only succeed if this thread holds a single shared lock.
390  * Return 1 if if the upgrade succeed, 0 otherwise.
391  */
392 int
393 _sx_try_upgrade(struct sx *sx, const char *file, int line)
394 {
395         uintptr_t x;
396         int success;
397
398         if (SCHEDULER_STOPPED())
399                 return (1);
400
401         KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
402             ("sx_try_upgrade() of destroyed sx @ %s:%d", file, line));
403         _sx_assert(sx, SA_SLOCKED, file, line);
404
405         /*
406          * Try to switch from one shared lock to an exclusive lock.  We need
407          * to maintain the SX_LOCK_EXCLUSIVE_WAITERS flag if set so that
408          * we will wake up the exclusive waiters when we drop the lock.
409          */
410         x = sx->sx_lock & SX_LOCK_EXCLUSIVE_WAITERS;
411         success = atomic_cmpset_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) | x,
412             (uintptr_t)curthread | x);
413         LOCK_LOG_TRY("XUPGRADE", &sx->lock_object, 0, success, file, line);
414         if (success) {
415                 WITNESS_UPGRADE(&sx->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
416                     file, line);
417                 LOCKSTAT_RECORD0(LS_SX_TRYUPGRADE_UPGRADE, sx);
418         }
419         return (success);
420 }
421
422 /*
423  * Downgrade an unrecursed exclusive lock into a single shared lock.
424  */
425 void
426 _sx_downgrade(struct sx *sx, const char *file, int line)
427 {
428         uintptr_t x;
429         int wakeup_swapper;
430
431         if (SCHEDULER_STOPPED())
432                 return;
433
434         KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
435             ("sx_downgrade() of destroyed sx @ %s:%d", file, line));
436         _sx_assert(sx, SA_XLOCKED | SA_NOTRECURSED, file, line);
437 #ifndef INVARIANTS
438         if (sx_recursed(sx))
439                 panic("downgrade of a recursed lock");
440 #endif
441
442         WITNESS_DOWNGRADE(&sx->lock_object, 0, file, line);
443
444         /*
445          * Try to switch from an exclusive lock with no shared waiters
446          * to one sharer with no shared waiters.  If there are
447          * exclusive waiters, we don't need to lock the sleep queue so
448          * long as we preserve the flag.  We do one quick try and if
449          * that fails we grab the sleepq lock to keep the flags from
450          * changing and do it the slow way.
451          *
452          * We have to lock the sleep queue if there are shared waiters
453          * so we can wake them up.
454          */
455         x = sx->sx_lock;
456         if (!(x & SX_LOCK_SHARED_WAITERS) &&
457             atomic_cmpset_rel_ptr(&sx->sx_lock, x, SX_SHARERS_LOCK(1) |
458             (x & SX_LOCK_EXCLUSIVE_WAITERS))) {
459                 LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line);
460                 return;
461         }
462
463         /*
464          * Lock the sleep queue so we can read the waiters bits
465          * without any races and wakeup any shared waiters.
466          */
467         sleepq_lock(&sx->lock_object);
468
469         /*
470          * Preserve SX_LOCK_EXCLUSIVE_WAITERS while downgraded to a single
471          * shared lock.  If there are any shared waiters, wake them up.
472          */
473         wakeup_swapper = 0;
474         x = sx->sx_lock;
475         atomic_store_rel_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) |
476             (x & SX_LOCK_EXCLUSIVE_WAITERS));
477         if (x & SX_LOCK_SHARED_WAITERS)
478                 wakeup_swapper = sleepq_broadcast(&sx->lock_object, SLEEPQ_SX,
479                     0, SQ_SHARED_QUEUE);
480         sleepq_release(&sx->lock_object);
481
482         LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line);
483         LOCKSTAT_RECORD0(LS_SX_DOWNGRADE_DOWNGRADE, sx);
484
485         if (wakeup_swapper)
486                 kick_proc0();
487 }
488
489 /*
490  * This function represents the so-called 'hard case' for sx_xlock
491  * operation.  All 'easy case' failures are redirected to this.  Note
492  * that ideally this would be a static function, but it needs to be
493  * accessible from at least sx.h.
494  */
495 int
496 _sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts, const char *file,
497     int line)
498 {
499         GIANT_DECLARE;
500 #ifdef ADAPTIVE_SX
501         volatile struct thread *owner;
502         u_int i, spintries = 0;
503 #endif
504         uintptr_t x;
505 #ifdef LOCK_PROFILING
506         uint64_t waittime = 0;
507         int contested = 0;
508 #endif
509         int error = 0;
510 #ifdef  KDTRACE_HOOKS
511         uint64_t spin_cnt = 0;
512         uint64_t sleep_cnt = 0;
513         int64_t sleep_time = 0;
514 #endif
515
516         if (SCHEDULER_STOPPED())
517                 return (0);
518
519         /* If we already hold an exclusive lock, then recurse. */
520         if (sx_xlocked(sx)) {
521                 KASSERT((sx->lock_object.lo_flags & LO_RECURSABLE) != 0,
522             ("_sx_xlock_hard: recursed on non-recursive sx %s @ %s:%d\n",
523                     sx->lock_object.lo_name, file, line));
524                 sx->sx_recurse++;
525                 atomic_set_ptr(&sx->sx_lock, SX_LOCK_RECURSED);
526                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
527                         CTR2(KTR_LOCK, "%s: %p recursing", __func__, sx);
528                 return (0);
529         }
530
531         if (LOCK_LOG_TEST(&sx->lock_object, 0))
532                 CTR5(KTR_LOCK, "%s: %s contested (lock=%p) at %s:%d", __func__,
533                     sx->lock_object.lo_name, (void *)sx->sx_lock, file, line);
534
535         while (!atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED, tid)) {
536 #ifdef KDTRACE_HOOKS
537                 spin_cnt++;
538 #endif
539 #ifdef HWPMC_HOOKS
540                 PMC_SOFT_CALL( , , lock, failed);
541 #endif
542                 lock_profile_obtain_lock_failed(&sx->lock_object, &contested,
543                     &waittime);
544 #ifdef ADAPTIVE_SX
545                 /*
546                  * If the lock is write locked and the owner is
547                  * running on another CPU, spin until the owner stops
548                  * running or the state of the lock changes.
549                  */
550                 x = sx->sx_lock;
551                 if ((sx->lock_object.lo_flags & SX_NOADAPTIVE) == 0) {
552                         if ((x & SX_LOCK_SHARED) == 0) {
553                                 x = SX_OWNER(x);
554                                 owner = (struct thread *)x;
555                                 if (TD_IS_RUNNING(owner)) {
556                                         if (LOCK_LOG_TEST(&sx->lock_object, 0))
557                                                 CTR3(KTR_LOCK,
558                                             "%s: spinning on %p held by %p",
559                                                     __func__, sx, owner);
560                                         GIANT_SAVE();
561                                         while (SX_OWNER(sx->sx_lock) == x &&
562                                             TD_IS_RUNNING(owner)) {
563                                                 cpu_spinwait();
564 #ifdef KDTRACE_HOOKS
565                                                 spin_cnt++;
566 #endif
567                                         }
568                                         continue;
569                                 }
570                         } else if (SX_SHARERS(x) && spintries < ASX_RETRIES) {
571                                 GIANT_SAVE();
572                                 spintries++;
573                                 for (i = 0; i < ASX_LOOPS; i++) {
574                                         if (LOCK_LOG_TEST(&sx->lock_object, 0))
575                                                 CTR4(KTR_LOCK,
576                                     "%s: shared spinning on %p with %u and %u",
577                                                     __func__, sx, spintries, i);
578                                         x = sx->sx_lock;
579                                         if ((x & SX_LOCK_SHARED) == 0 ||
580                                             SX_SHARERS(x) == 0)
581                                                 break;
582                                         cpu_spinwait();
583 #ifdef KDTRACE_HOOKS
584                                         spin_cnt++;
585 #endif
586                                 }
587                                 if (i != ASX_LOOPS)
588                                         continue;
589                         }
590                 }
591 #endif
592
593                 sleepq_lock(&sx->lock_object);
594                 x = sx->sx_lock;
595
596                 /*
597                  * If the lock was released while spinning on the
598                  * sleep queue chain lock, try again.
599                  */
600                 if (x == SX_LOCK_UNLOCKED) {
601                         sleepq_release(&sx->lock_object);
602                         continue;
603                 }
604
605 #ifdef ADAPTIVE_SX
606                 /*
607                  * The current lock owner might have started executing
608                  * on another CPU (or the lock could have changed
609                  * owners) while we were waiting on the sleep queue
610                  * chain lock.  If so, drop the sleep queue lock and try
611                  * again.
612                  */
613                 if (!(x & SX_LOCK_SHARED) &&
614                     (sx->lock_object.lo_flags & SX_NOADAPTIVE) == 0) {
615                         owner = (struct thread *)SX_OWNER(x);
616                         if (TD_IS_RUNNING(owner)) {
617                                 sleepq_release(&sx->lock_object);
618                                 continue;
619                         }
620                 }
621 #endif
622
623                 /*
624                  * If an exclusive lock was released with both shared
625                  * and exclusive waiters and a shared waiter hasn't
626                  * woken up and acquired the lock yet, sx_lock will be
627                  * set to SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS.
628                  * If we see that value, try to acquire it once.  Note
629                  * that we have to preserve SX_LOCK_EXCLUSIVE_WAITERS
630                  * as there are other exclusive waiters still.  If we
631                  * fail, restart the loop.
632                  */
633                 if (x == (SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS)) {
634                         if (atomic_cmpset_acq_ptr(&sx->sx_lock,
635                             SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS,
636                             tid | SX_LOCK_EXCLUSIVE_WAITERS)) {
637                                 sleepq_release(&sx->lock_object);
638                                 CTR2(KTR_LOCK, "%s: %p claimed by new writer",
639                                     __func__, sx);
640                                 break;
641                         }
642                         sleepq_release(&sx->lock_object);
643                         continue;
644                 }
645
646                 /*
647                  * Try to set the SX_LOCK_EXCLUSIVE_WAITERS.  If we fail,
648                  * than loop back and retry.
649                  */
650                 if (!(x & SX_LOCK_EXCLUSIVE_WAITERS)) {
651                         if (!atomic_cmpset_ptr(&sx->sx_lock, x,
652                             x | SX_LOCK_EXCLUSIVE_WAITERS)) {
653                                 sleepq_release(&sx->lock_object);
654                                 continue;
655                         }
656                         if (LOCK_LOG_TEST(&sx->lock_object, 0))
657                                 CTR2(KTR_LOCK, "%s: %p set excl waiters flag",
658                                     __func__, sx);
659                 }
660
661                 /*
662                  * Since we have been unable to acquire the exclusive
663                  * lock and the exclusive waiters flag is set, we have
664                  * to sleep.
665                  */
666                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
667                         CTR2(KTR_LOCK, "%s: %p blocking on sleep queue",
668                             __func__, sx);
669
670 #ifdef KDTRACE_HOOKS
671                 sleep_time -= lockstat_nsecs();
672 #endif
673                 GIANT_SAVE();
674                 sleepq_add(&sx->lock_object, NULL, sx->lock_object.lo_name,
675                     SLEEPQ_SX | ((opts & SX_INTERRUPTIBLE) ?
676                     SLEEPQ_INTERRUPTIBLE : 0), SQ_EXCLUSIVE_QUEUE);
677                 if (!(opts & SX_INTERRUPTIBLE))
678                         sleepq_wait(&sx->lock_object, 0);
679                 else
680                         error = sleepq_wait_sig(&sx->lock_object, 0);
681 #ifdef KDTRACE_HOOKS
682                 sleep_time += lockstat_nsecs();
683                 sleep_cnt++;
684 #endif
685                 if (error) {
686                         if (LOCK_LOG_TEST(&sx->lock_object, 0))
687                                 CTR2(KTR_LOCK,
688                         "%s: interruptible sleep by %p suspended by signal",
689                                     __func__, sx);
690                         break;
691                 }
692                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
693                         CTR2(KTR_LOCK, "%s: %p resuming from sleep queue",
694                             __func__, sx);
695         }
696
697         GIANT_RESTORE();
698         if (!error)
699                 LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_SX_XLOCK_ACQUIRE, sx,
700                     contested, waittime, file, line);
701 #ifdef KDTRACE_HOOKS
702         if (sleep_time)
703                 LOCKSTAT_RECORD1(LS_SX_XLOCK_BLOCK, sx, sleep_time);
704         if (spin_cnt > sleep_cnt)
705                 LOCKSTAT_RECORD1(LS_SX_XLOCK_SPIN, sx, (spin_cnt - sleep_cnt));
706 #endif
707         return (error);
708 }
709
710 /*
711  * This function represents the so-called 'hard case' for sx_xunlock
712  * operation.  All 'easy case' failures are redirected to this.  Note
713  * that ideally this would be a static function, but it needs to be
714  * accessible from at least sx.h.
715  */
716 void
717 _sx_xunlock_hard(struct sx *sx, uintptr_t tid, const char *file, int line)
718 {
719         uintptr_t x;
720         int queue, wakeup_swapper;
721
722         if (SCHEDULER_STOPPED())
723                 return;
724
725         MPASS(!(sx->sx_lock & SX_LOCK_SHARED));
726
727         /* If the lock is recursed, then unrecurse one level. */
728         if (sx_xlocked(sx) && sx_recursed(sx)) {
729                 if ((--sx->sx_recurse) == 0)
730                         atomic_clear_ptr(&sx->sx_lock, SX_LOCK_RECURSED);
731                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
732                         CTR2(KTR_LOCK, "%s: %p unrecursing", __func__, sx);
733                 return;
734         }
735         MPASS(sx->sx_lock & (SX_LOCK_SHARED_WAITERS |
736             SX_LOCK_EXCLUSIVE_WAITERS));
737         if (LOCK_LOG_TEST(&sx->lock_object, 0))
738                 CTR2(KTR_LOCK, "%s: %p contested", __func__, sx);
739
740         sleepq_lock(&sx->lock_object);
741         x = SX_LOCK_UNLOCKED;
742
743         /*
744          * The wake up algorithm here is quite simple and probably not
745          * ideal.  It gives precedence to shared waiters if they are
746          * present.  For this condition, we have to preserve the
747          * state of the exclusive waiters flag.
748          * If interruptible sleeps left the shared queue empty avoid a
749          * starvation for the threads sleeping on the exclusive queue by giving
750          * them precedence and cleaning up the shared waiters bit anyway.
751          */
752         if ((sx->sx_lock & SX_LOCK_SHARED_WAITERS) != 0 &&
753             sleepq_sleepcnt(&sx->lock_object, SQ_SHARED_QUEUE) != 0) {
754                 queue = SQ_SHARED_QUEUE;
755                 x |= (sx->sx_lock & SX_LOCK_EXCLUSIVE_WAITERS);
756         } else
757                 queue = SQ_EXCLUSIVE_QUEUE;
758
759         /* Wake up all the waiters for the specific queue. */
760         if (LOCK_LOG_TEST(&sx->lock_object, 0))
761                 CTR3(KTR_LOCK, "%s: %p waking up all threads on %s queue",
762                     __func__, sx, queue == SQ_SHARED_QUEUE ? "shared" :
763                     "exclusive");
764         atomic_store_rel_ptr(&sx->sx_lock, x);
765         wakeup_swapper = sleepq_broadcast(&sx->lock_object, SLEEPQ_SX, 0,
766             queue);
767         sleepq_release(&sx->lock_object);
768         if (wakeup_swapper)
769                 kick_proc0();
770 }
771
772 /*
773  * This function represents the so-called 'hard case' for sx_slock
774  * operation.  All 'easy case' failures are redirected to this.  Note
775  * that ideally this would be a static function, but it needs to be
776  * accessible from at least sx.h.
777  */
778 int
779 _sx_slock_hard(struct sx *sx, int opts, const char *file, int line)
780 {
781         GIANT_DECLARE;
782 #ifdef ADAPTIVE_SX
783         volatile struct thread *owner;
784 #endif
785 #ifdef LOCK_PROFILING
786         uint64_t waittime = 0;
787         int contested = 0;
788 #endif
789         uintptr_t x;
790         int error = 0;
791 #ifdef KDTRACE_HOOKS
792         uint64_t spin_cnt = 0;
793         uint64_t sleep_cnt = 0;
794         int64_t sleep_time = 0;
795 #endif
796
797         if (SCHEDULER_STOPPED())
798                 return (0);
799
800         /*
801          * As with rwlocks, we don't make any attempt to try to block
802          * shared locks once there is an exclusive waiter.
803          */
804         for (;;) {
805 #ifdef KDTRACE_HOOKS
806                 spin_cnt++;
807 #endif
808                 x = sx->sx_lock;
809
810                 /*
811                  * If no other thread has an exclusive lock then try to bump up
812                  * the count of sharers.  Since we have to preserve the state
813                  * of SX_LOCK_EXCLUSIVE_WAITERS, if we fail to acquire the
814                  * shared lock loop back and retry.
815                  */
816                 if (x & SX_LOCK_SHARED) {
817                         MPASS(!(x & SX_LOCK_SHARED_WAITERS));
818                         if (atomic_cmpset_acq_ptr(&sx->sx_lock, x,
819                             x + SX_ONE_SHARER)) {
820                                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
821                                         CTR4(KTR_LOCK,
822                                             "%s: %p succeed %p -> %p", __func__,
823                                             sx, (void *)x,
824                                             (void *)(x + SX_ONE_SHARER));
825                                 break;
826                         }
827                         continue;
828                 }
829 #ifdef HWPMC_HOOKS
830                 PMC_SOFT_CALL( , , lock, failed);
831 #endif
832                 lock_profile_obtain_lock_failed(&sx->lock_object, &contested,
833                     &waittime);
834
835 #ifdef ADAPTIVE_SX
836                 /*
837                  * If the owner is running on another CPU, spin until
838                  * the owner stops running or the state of the lock
839                  * changes.
840                  */
841                 if ((sx->lock_object.lo_flags & SX_NOADAPTIVE) == 0) {
842                         x = SX_OWNER(x);
843                         owner = (struct thread *)x;
844                         if (TD_IS_RUNNING(owner)) {
845                                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
846                                         CTR3(KTR_LOCK,
847                                             "%s: spinning on %p held by %p",
848                                             __func__, sx, owner);
849                                 GIANT_SAVE();
850                                 while (SX_OWNER(sx->sx_lock) == x &&
851                                     TD_IS_RUNNING(owner)) {
852 #ifdef KDTRACE_HOOKS
853                                         spin_cnt++;
854 #endif
855                                         cpu_spinwait();
856                                 }
857                                 continue;
858                         }
859                 }
860 #endif
861
862                 /*
863                  * Some other thread already has an exclusive lock, so
864                  * start the process of blocking.
865                  */
866                 sleepq_lock(&sx->lock_object);
867                 x = sx->sx_lock;
868
869                 /*
870                  * The lock could have been released while we spun.
871                  * In this case loop back and retry.
872                  */
873                 if (x & SX_LOCK_SHARED) {
874                         sleepq_release(&sx->lock_object);
875                         continue;
876                 }
877
878 #ifdef ADAPTIVE_SX
879                 /*
880                  * If the owner is running on another CPU, spin until
881                  * the owner stops running or the state of the lock
882                  * changes.
883                  */
884                 if (!(x & SX_LOCK_SHARED) &&
885                     (sx->lock_object.lo_flags & SX_NOADAPTIVE) == 0) {
886                         owner = (struct thread *)SX_OWNER(x);
887                         if (TD_IS_RUNNING(owner)) {
888                                 sleepq_release(&sx->lock_object);
889                                 continue;
890                         }
891                 }
892 #endif
893
894                 /*
895                  * Try to set the SX_LOCK_SHARED_WAITERS flag.  If we
896                  * fail to set it drop the sleep queue lock and loop
897                  * back.
898                  */
899                 if (!(x & SX_LOCK_SHARED_WAITERS)) {
900                         if (!atomic_cmpset_ptr(&sx->sx_lock, x,
901                             x | SX_LOCK_SHARED_WAITERS)) {
902                                 sleepq_release(&sx->lock_object);
903                                 continue;
904                         }
905                         if (LOCK_LOG_TEST(&sx->lock_object, 0))
906                                 CTR2(KTR_LOCK, "%s: %p set shared waiters flag",
907                                     __func__, sx);
908                 }
909
910                 /*
911                  * Since we have been unable to acquire the shared lock,
912                  * we have to sleep.
913                  */
914                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
915                         CTR2(KTR_LOCK, "%s: %p blocking on sleep queue",
916                             __func__, sx);
917
918 #ifdef KDTRACE_HOOKS
919                 sleep_time -= lockstat_nsecs();
920 #endif
921                 GIANT_SAVE();
922                 sleepq_add(&sx->lock_object, NULL, sx->lock_object.lo_name,
923                     SLEEPQ_SX | ((opts & SX_INTERRUPTIBLE) ?
924                     SLEEPQ_INTERRUPTIBLE : 0), SQ_SHARED_QUEUE);
925                 if (!(opts & SX_INTERRUPTIBLE))
926                         sleepq_wait(&sx->lock_object, 0);
927                 else
928                         error = sleepq_wait_sig(&sx->lock_object, 0);
929 #ifdef KDTRACE_HOOKS
930                 sleep_time += lockstat_nsecs();
931                 sleep_cnt++;
932 #endif
933                 if (error) {
934                         if (LOCK_LOG_TEST(&sx->lock_object, 0))
935                                 CTR2(KTR_LOCK,
936                         "%s: interruptible sleep by %p suspended by signal",
937                                     __func__, sx);
938                         break;
939                 }
940                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
941                         CTR2(KTR_LOCK, "%s: %p resuming from sleep queue",
942                             __func__, sx);
943         }
944         if (error == 0)
945                 LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_SX_SLOCK_ACQUIRE, sx,
946                     contested, waittime, file, line);
947 #ifdef KDTRACE_HOOKS
948         if (sleep_time)
949                 LOCKSTAT_RECORD1(LS_SX_XLOCK_BLOCK, sx, sleep_time);
950         if (spin_cnt > sleep_cnt)
951                 LOCKSTAT_RECORD1(LS_SX_XLOCK_SPIN, sx, (spin_cnt - sleep_cnt));
952 #endif
953         GIANT_RESTORE();
954         return (error);
955 }
956
957 /*
958  * This function represents the so-called 'hard case' for sx_sunlock
959  * operation.  All 'easy case' failures are redirected to this.  Note
960  * that ideally this would be a static function, but it needs to be
961  * accessible from at least sx.h.
962  */
963 void
964 _sx_sunlock_hard(struct sx *sx, const char *file, int line)
965 {
966         uintptr_t x;
967         int wakeup_swapper;
968
969         if (SCHEDULER_STOPPED())
970                 return;
971
972         for (;;) {
973                 x = sx->sx_lock;
974
975                 /*
976                  * We should never have sharers while at least one thread
977                  * holds a shared lock.
978                  */
979                 KASSERT(!(x & SX_LOCK_SHARED_WAITERS),
980                     ("%s: waiting sharers", __func__));
981
982                 /*
983                  * See if there is more than one shared lock held.  If
984                  * so, just drop one and return.
985                  */
986                 if (SX_SHARERS(x) > 1) {
987                         if (atomic_cmpset_rel_ptr(&sx->sx_lock, x,
988                             x - SX_ONE_SHARER)) {
989                                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
990                                         CTR4(KTR_LOCK,
991                                             "%s: %p succeeded %p -> %p",
992                                             __func__, sx, (void *)x,
993                                             (void *)(x - SX_ONE_SHARER));
994                                 break;
995                         }
996                         continue;
997                 }
998
999                 /*
1000                  * If there aren't any waiters for an exclusive lock,
1001                  * then try to drop it quickly.
1002                  */
1003                 if (!(x & SX_LOCK_EXCLUSIVE_WAITERS)) {
1004                         MPASS(x == SX_SHARERS_LOCK(1));
1005                         if (atomic_cmpset_rel_ptr(&sx->sx_lock,
1006                             SX_SHARERS_LOCK(1), SX_LOCK_UNLOCKED)) {
1007                                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
1008                                         CTR2(KTR_LOCK, "%s: %p last succeeded",
1009                                             __func__, sx);
1010                                 break;
1011                         }
1012                         continue;
1013                 }
1014
1015                 /*
1016                  * At this point, there should just be one sharer with
1017                  * exclusive waiters.
1018                  */
1019                 MPASS(x == (SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS));
1020
1021                 sleepq_lock(&sx->lock_object);
1022
1023                 /*
1024                  * Wake up semantic here is quite simple:
1025                  * Just wake up all the exclusive waiters.
1026                  * Note that the state of the lock could have changed,
1027                  * so if it fails loop back and retry.
1028                  */
1029                 if (!atomic_cmpset_rel_ptr(&sx->sx_lock,
1030                     SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS,
1031                     SX_LOCK_UNLOCKED)) {
1032                         sleepq_release(&sx->lock_object);
1033                         continue;
1034                 }
1035                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
1036                         CTR2(KTR_LOCK, "%s: %p waking up all thread on"
1037                             "exclusive queue", __func__, sx);
1038                 wakeup_swapper = sleepq_broadcast(&sx->lock_object, SLEEPQ_SX,
1039                     0, SQ_EXCLUSIVE_QUEUE);
1040                 sleepq_release(&sx->lock_object);
1041                 if (wakeup_swapper)
1042                         kick_proc0();
1043                 break;
1044         }
1045 }
1046
1047 #ifdef INVARIANT_SUPPORT
1048 #ifndef INVARIANTS
1049 #undef  _sx_assert
1050 #endif
1051
1052 /*
1053  * In the non-WITNESS case, sx_assert() can only detect that at least
1054  * *some* thread owns an slock, but it cannot guarantee that *this*
1055  * thread owns an slock.
1056  */
1057 void
1058 _sx_assert(struct sx *sx, int what, const char *file, int line)
1059 {
1060 #ifndef WITNESS
1061         int slocked = 0;
1062 #endif
1063
1064         if (panicstr != NULL)
1065                 return;
1066         switch (what) {
1067         case SA_SLOCKED:
1068         case SA_SLOCKED | SA_NOTRECURSED:
1069         case SA_SLOCKED | SA_RECURSED:
1070 #ifndef WITNESS
1071                 slocked = 1;
1072                 /* FALLTHROUGH */
1073 #endif
1074         case SA_LOCKED:
1075         case SA_LOCKED | SA_NOTRECURSED:
1076         case SA_LOCKED | SA_RECURSED:
1077 #ifdef WITNESS
1078                 witness_assert(&sx->lock_object, what, file, line);
1079 #else
1080                 /*
1081                  * If some other thread has an exclusive lock or we
1082                  * have one and are asserting a shared lock, fail.
1083                  * Also, if no one has a lock at all, fail.
1084                  */
1085                 if (sx->sx_lock == SX_LOCK_UNLOCKED ||
1086                     (!(sx->sx_lock & SX_LOCK_SHARED) && (slocked ||
1087                     sx_xholder(sx) != curthread)))
1088                         panic("Lock %s not %slocked @ %s:%d\n",
1089                             sx->lock_object.lo_name, slocked ? "share " : "",
1090                             file, line);
1091
1092                 if (!(sx->sx_lock & SX_LOCK_SHARED)) {
1093                         if (sx_recursed(sx)) {
1094                                 if (what & SA_NOTRECURSED)
1095                                         panic("Lock %s recursed @ %s:%d\n",
1096                                             sx->lock_object.lo_name, file,
1097                                             line);
1098                         } else if (what & SA_RECURSED)
1099                                 panic("Lock %s not recursed @ %s:%d\n",
1100                                     sx->lock_object.lo_name, file, line);
1101                 }
1102 #endif
1103                 break;
1104         case SA_XLOCKED:
1105         case SA_XLOCKED | SA_NOTRECURSED:
1106         case SA_XLOCKED | SA_RECURSED:
1107                 if (sx_xholder(sx) != curthread)
1108                         panic("Lock %s not exclusively locked @ %s:%d\n",
1109                             sx->lock_object.lo_name, file, line);
1110                 if (sx_recursed(sx)) {
1111                         if (what & SA_NOTRECURSED)
1112                                 panic("Lock %s recursed @ %s:%d\n",
1113                                     sx->lock_object.lo_name, file, line);
1114                 } else if (what & SA_RECURSED)
1115                         panic("Lock %s not recursed @ %s:%d\n",
1116                             sx->lock_object.lo_name, file, line);
1117                 break;
1118         case SA_UNLOCKED:
1119 #ifdef WITNESS
1120                 witness_assert(&sx->lock_object, what, file, line);
1121 #else
1122                 /*
1123                  * If we hold an exclusve lock fail.  We can't
1124                  * reliably check to see if we hold a shared lock or
1125                  * not.
1126                  */
1127                 if (sx_xholder(sx) == curthread)
1128                         panic("Lock %s exclusively locked @ %s:%d\n",
1129                             sx->lock_object.lo_name, file, line);
1130 #endif
1131                 break;
1132         default:
1133                 panic("Unknown sx lock assertion: %d @ %s:%d", what, file,
1134                     line);
1135         }
1136 }
1137 #endif  /* INVARIANT_SUPPORT */
1138
1139 #ifdef DDB
1140 static void
1141 db_show_sx(struct lock_object *lock)
1142 {
1143         struct thread *td;
1144         struct sx *sx;
1145
1146         sx = (struct sx *)lock;
1147
1148         db_printf(" state: ");
1149         if (sx->sx_lock == SX_LOCK_UNLOCKED)
1150                 db_printf("UNLOCKED\n");
1151         else if (sx->sx_lock == SX_LOCK_DESTROYED) {
1152                 db_printf("DESTROYED\n");
1153                 return;
1154         } else if (sx->sx_lock & SX_LOCK_SHARED)
1155                 db_printf("SLOCK: %ju\n", (uintmax_t)SX_SHARERS(sx->sx_lock));
1156         else {
1157                 td = sx_xholder(sx);
1158                 db_printf("XLOCK: %p (tid %d, pid %d, \"%s\")\n", td,
1159                     td->td_tid, td->td_proc->p_pid, td->td_name);
1160                 if (sx_recursed(sx))
1161                         db_printf(" recursed: %d\n", sx->sx_recurse);
1162         }
1163
1164         db_printf(" waiters: ");
1165         switch(sx->sx_lock &
1166             (SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS)) {
1167         case SX_LOCK_SHARED_WAITERS:
1168                 db_printf("shared\n");
1169                 break;
1170         case SX_LOCK_EXCLUSIVE_WAITERS:
1171                 db_printf("exclusive\n");
1172                 break;
1173         case SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS:
1174                 db_printf("exclusive and shared\n");
1175                 break;
1176         default:
1177                 db_printf("none\n");
1178         }
1179 }
1180
1181 /*
1182  * Check to see if a thread that is blocked on a sleep queue is actually
1183  * blocked on an sx lock.  If so, output some details and return true.
1184  * If the lock has an exclusive owner, return that in *ownerp.
1185  */
1186 int
1187 sx_chain(struct thread *td, struct thread **ownerp)
1188 {
1189         struct sx *sx;
1190
1191         /*
1192          * Check to see if this thread is blocked on an sx lock.
1193          * First, we check the lock class.  If that is ok, then we
1194          * compare the lock name against the wait message.
1195          */
1196         sx = td->td_wchan;
1197         if (LOCK_CLASS(&sx->lock_object) != &lock_class_sx ||
1198             sx->lock_object.lo_name != td->td_wmesg)
1199                 return (0);
1200
1201         /* We think we have an sx lock, so output some details. */
1202         db_printf("blocked on sx \"%s\" ", td->td_wmesg);
1203         *ownerp = sx_xholder(sx);
1204         if (sx->sx_lock & SX_LOCK_SHARED)
1205                 db_printf("SLOCK (count %ju)\n",
1206                     (uintmax_t)SX_SHARERS(sx->sx_lock));
1207         else
1208                 db_printf("XLOCK\n");
1209         return (1);
1210 }
1211 #endif