The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System, Second Edition

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_sx.c

Version: -  FREEBSD  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    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_adaptive_sx.h"
   40 #include "opt_ddb.h"
   41 
   42 #include <sys/cdefs.h>
   43 __FBSDID("$FreeBSD: src/sys/kern/kern_sx.c,v 1.25.2.10.2.1 2008/10/02 02:57:24 kensmith Exp $");
   44 
   45 #include <sys/param.h>
   46 #include <sys/ktr.h>
   47 #include <sys/lock.h>
   48 #include <sys/mutex.h>
   49 #include <sys/proc.h>
   50 #include <sys/sched.h>
   51 #include <sys/sleepqueue.h>
   52 #include <sys/sx.h>
   53 #include <sys/systm.h>
   54 
   55 #ifdef ADAPTIVE_SX
   56 #include <machine/cpu.h>
   57 #endif
   58 
   59 #ifdef DDB
   60 #include <ddb/ddb.h>
   61 #endif
   62 
   63 #if !defined(SMP) && defined(ADAPTIVE_SX)
   64 #error "You must have SMP to enable the ADAPTIVE_SX option"
   65 #endif
   66 
   67 CTASSERT(((SX_ADAPTIVESPIN | SX_RECURSE) & LO_CLASSFLAGS) ==
   68     (SX_ADAPTIVESPIN | SX_RECURSE));
   69 
   70 /* Handy macros for sleep queues. */
   71 #define SQ_EXCLUSIVE_QUEUE      0
   72 #define SQ_SHARED_QUEUE         1
   73 
   74 /*
   75  * Variations on DROP_GIANT()/PICKUP_GIANT() for use in this file.  We
   76  * drop Giant anytime we have to sleep or if we adaptively spin.
   77  */
   78 #define GIANT_DECLARE                                                   \
   79         int _giantcnt = 0;                                              \
   80         WITNESS_SAVE_DECL(Giant)                                        \
   81 
   82 #define GIANT_SAVE() do {                                               \
   83         if (mtx_owned(&Giant)) {                                        \
   84                 WITNESS_SAVE(&Giant.mtx_object, Giant);         \
   85                 while (mtx_owned(&Giant)) {                             \
   86                         _giantcnt++;                                    \
   87                         mtx_unlock(&Giant);                             \
   88                 }                                                       \
   89         }                                                               \
   90 } while (0)
   91 
   92 #define GIANT_RESTORE() do {                                            \
   93         if (_giantcnt > 0) {                                            \
   94                 mtx_assert(&Giant, MA_NOTOWNED);                        \
   95                 while (_giantcnt--)                                     \
   96                         mtx_lock(&Giant);                               \
   97                 WITNESS_RESTORE(&Giant.mtx_object, Giant);              \
   98         }                                                               \
   99 } while (0)
  100 
  101 /*
  102  * Returns true if an exclusive lock is recursed.  It assumes
  103  * curthread currently has an exclusive lock.
  104  */
  105 #define sx_recursed(sx)         ((sx)->sx_recurse != 0)
  106 
  107 #ifdef DDB
  108 static void     db_show_sx(struct lock_object *lock);
  109 #endif
  110 
  111 struct lock_class lock_class_sx = {
  112         .lc_name = "sx",
  113         .lc_flags = LC_SLEEPLOCK | LC_SLEEPABLE | LC_RECURSABLE | LC_UPGRADABLE,
  114 #ifdef DDB
  115         .lc_ddb_show = db_show_sx,
  116 #endif
  117 };
  118 
  119 #ifndef INVARIANTS
  120 #define _sx_assert(sx, what, file, line)
  121 #endif
  122 
  123 void
  124 sx_sysinit(void *arg)
  125 {
  126         struct sx_args *sargs = arg;
  127 
  128         sx_init(sargs->sa_sx, sargs->sa_desc);
  129 }
  130 
  131 void
  132 sx_init(struct sx *sx, const char *description)
  133 {
  134 
  135         sx_init_flags(sx, description, 0);
  136 }
  137 
  138 void
  139 sx_init_flags(struct sx *sx, const char *description, int opts)
  140 {
  141         int flags;
  142 
  143         MPASS((opts & ~(SX_QUIET | SX_RECURSE | SX_NOWITNESS | SX_DUPOK |
  144             SX_NOPROFILE | SX_ADAPTIVESPIN)) == 0);
  145 
  146         flags = LO_RECURSABLE | LO_SLEEPABLE | LO_UPGRADABLE;
  147         if (opts & SX_DUPOK)
  148                 flags |= LO_DUPOK;
  149         if (!(opts & SX_NOWITNESS))
  150                 flags |= LO_WITNESS;
  151         if (opts & SX_QUIET)
  152                 flags |= LO_QUIET;
  153 
  154         flags |= opts & (SX_ADAPTIVESPIN | SX_RECURSE);
  155         sx->sx_lock = SX_LOCK_UNLOCKED;
  156         sx->sx_recurse = 0;
  157         lock_init(&sx->lock_object, &lock_class_sx, description, NULL, flags);
  158 }
  159 
  160 void
  161 sx_destroy(struct sx *sx)
  162 {
  163 
  164         KASSERT(sx->sx_lock == SX_LOCK_UNLOCKED, ("sx lock still held"));
  165         KASSERT(sx->sx_recurse == 0, ("sx lock still recursed"));
  166         sx->sx_lock = SX_LOCK_DESTROYED;
  167         lock_destroy(&sx->lock_object);
  168 }
  169 
  170 int
  171 _sx_slock(struct sx *sx, int opts, const char *file, int line)
  172 {
  173         int error = 0;
  174 
  175         MPASS(curthread != NULL);
  176         KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
  177             ("sx_slock() of destroyed sx @ %s:%d", file, line));
  178         WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER, file, line);
  179         error = __sx_slock(sx, opts, file, line);
  180         if (!error) {
  181                 LOCK_LOG_LOCK("SLOCK", &sx->lock_object, 0, 0, file, line);
  182                 WITNESS_LOCK(&sx->lock_object, 0, file, line);
  183                 curthread->td_locks++;
  184         }
  185 
  186         return (error);
  187 }
  188 
  189 int
  190 _sx_try_slock(struct sx *sx, const char *file, int line)
  191 {
  192         uintptr_t x;
  193 
  194         x = sx->sx_lock;
  195         KASSERT(x != SX_LOCK_DESTROYED,
  196             ("sx_try_slock() of destroyed sx @ %s:%d", file, line));
  197         if ((x & SX_LOCK_SHARED) && atomic_cmpset_acq_ptr(&sx->sx_lock, x,
  198             x + SX_ONE_SHARER)) {
  199                 LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 1, file, line);
  200                 WITNESS_LOCK(&sx->lock_object, LOP_TRYLOCK, file, line);
  201                 curthread->td_locks++;
  202                 return (1);
  203         }
  204 
  205         LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 0, file, line);
  206         return (0);
  207 }
  208 
  209 int
  210 _sx_xlock(struct sx *sx, int opts, const char *file, int line)
  211 {
  212         int error = 0;
  213 
  214         MPASS(curthread != NULL);
  215         KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
  216             ("sx_xlock() of destroyed sx @ %s:%d", file, line));
  217         WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE, file,
  218             line);
  219         error = __sx_xlock(sx, curthread, opts, file, line);
  220         if (!error) {
  221                 LOCK_LOG_LOCK("XLOCK", &sx->lock_object, 0, sx->sx_recurse,
  222                     file, line);
  223                 WITNESS_LOCK(&sx->lock_object, LOP_EXCLUSIVE, file, line);
  224                 curthread->td_locks++;
  225         }
  226 
  227         return (error);
  228 }
  229 
  230 int
  231 _sx_try_xlock(struct sx *sx, const char *file, int line)
  232 {
  233         int rval;
  234 
  235         MPASS(curthread != NULL);
  236         KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
  237             ("sx_try_xlock() of destroyed sx @ %s:%d", file, line));
  238 
  239         if (sx_xlocked(sx) && (sx->lock_object.lo_flags & SX_RECURSE) != 0) {
  240                 sx->sx_recurse++;
  241                 atomic_set_ptr(&sx->sx_lock, SX_LOCK_RECURSED);
  242                 rval = 1;
  243         } else
  244                 rval = atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED,
  245                     (uintptr_t)curthread);
  246         LOCK_LOG_TRY("XLOCK", &sx->lock_object, 0, rval, file, line);
  247         if (rval) {
  248                 WITNESS_LOCK(&sx->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
  249                     file, line);
  250                 curthread->td_locks++;
  251         }
  252 
  253         return (rval);
  254 }
  255 
  256 void
  257 _sx_sunlock(struct sx *sx, const char *file, int line)
  258 {
  259 
  260         MPASS(curthread != NULL);
  261         KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
  262             ("sx_sunlock() of destroyed sx @ %s:%d", file, line));
  263         _sx_assert(sx, SA_SLOCKED, file, line);
  264         curthread->td_locks--;
  265         WITNESS_UNLOCK(&sx->lock_object, 0, file, line);
  266         LOCK_LOG_LOCK("SUNLOCK", &sx->lock_object, 0, 0, file, line);
  267 #ifdef LOCK_PROFILING_SHARED
  268         if (SX_SHARERS(sx->sx_lock) == 1)
  269                 lock_profile_release_lock(&sx->lock_object);
  270 #endif
  271         __sx_sunlock(sx, file, line);
  272 }
  273 
  274 void
  275 _sx_xunlock(struct sx *sx, const char *file, int line)
  276 {
  277 
  278         MPASS(curthread != NULL);
  279         KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
  280             ("sx_xunlock() of destroyed sx @ %s:%d", file, line));
  281         _sx_assert(sx, SA_XLOCKED, file, line);
  282         curthread->td_locks--;
  283         WITNESS_UNLOCK(&sx->lock_object, LOP_EXCLUSIVE, file, line);
  284         LOCK_LOG_LOCK("XUNLOCK", &sx->lock_object, 0, sx->sx_recurse, file,
  285             line);
  286         if (!sx_recursed(sx))
  287                 lock_profile_release_lock(&sx->lock_object);
  288         __sx_xunlock(sx, curthread, file, line);
  289 }
  290 
  291 /*
  292  * Try to do a non-blocking upgrade from a shared lock to an exclusive lock.
  293  * This will only succeed if this thread holds a single shared lock.
  294  * Return 1 if if the upgrade succeed, 0 otherwise.
  295  */
  296 int
  297 _sx_try_upgrade(struct sx *sx, const char *file, int line)
  298 {
  299         uintptr_t x;
  300         int success;
  301 
  302         KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
  303             ("sx_try_upgrade() of destroyed sx @ %s:%d", file, line));
  304         _sx_assert(sx, SA_SLOCKED, file, line);
  305 
  306         /*
  307          * Try to switch from one shared lock to an exclusive lock.  We need
  308          * to maintain the SX_LOCK_EXCLUSIVE_WAITERS flag if set so that
  309          * we will wake up the exclusive waiters when we drop the lock.
  310          */
  311         x = sx->sx_lock & SX_LOCK_EXCLUSIVE_WAITERS;
  312         success = atomic_cmpset_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) | x,
  313             (uintptr_t)curthread | x);
  314         LOCK_LOG_TRY("XUPGRADE", &sx->lock_object, 0, success, file, line);
  315         if (success)
  316                 WITNESS_UPGRADE(&sx->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
  317                     file, line);
  318         return (success);
  319 }
  320 
  321 /*
  322  * Downgrade an unrecursed exclusive lock into a single shared lock.
  323  */
  324 void
  325 _sx_downgrade(struct sx *sx, const char *file, int line)
  326 {
  327         uintptr_t x;
  328 
  329         KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
  330             ("sx_downgrade() of destroyed sx @ %s:%d", file, line));
  331         _sx_assert(sx, SA_XLOCKED | SA_NOTRECURSED, file, line);
  332 #ifndef INVARIANTS
  333         if (sx_recursed(sx))
  334                 panic("downgrade of a recursed lock");
  335 #endif
  336 
  337         WITNESS_DOWNGRADE(&sx->lock_object, 0, file, line);
  338 
  339         /*
  340          * Try to switch from an exclusive lock with no shared waiters
  341          * to one sharer with no shared waiters.  If there are
  342          * exclusive waiters, we don't need to lock the sleep queue so
  343          * long as we preserve the flag.  We do one quick try and if
  344          * that fails we grab the sleepq lock to keep the flags from
  345          * changing and do it the slow way.
  346          *
  347          * We have to lock the sleep queue if there are shared waiters
  348          * so we can wake them up.
  349          */
  350         x = sx->sx_lock;
  351         if (!(x & SX_LOCK_SHARED_WAITERS) &&
  352             atomic_cmpset_rel_ptr(&sx->sx_lock, x, SX_SHARERS_LOCK(1) |
  353             (x & SX_LOCK_EXCLUSIVE_WAITERS))) {
  354                 LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line);
  355                 return;
  356         }
  357 
  358         /*
  359          * Lock the sleep queue so we can read the waiters bits
  360          * without any races and wakeup any shared waiters.
  361          */
  362         sleepq_lock(&sx->lock_object);
  363 
  364         /*
  365          * Preserve SX_LOCK_EXCLUSIVE_WAITERS while downgraded to a single
  366          * shared lock.  If there are any shared waiters, wake them up.
  367          */
  368         x = sx->sx_lock;
  369         atomic_store_rel_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) |
  370             (x & SX_LOCK_EXCLUSIVE_WAITERS));
  371         if (x & SX_LOCK_SHARED_WAITERS)
  372                 sleepq_broadcast(&sx->lock_object, SLEEPQ_SX, -1,
  373                     SQ_SHARED_QUEUE);
  374         else
  375                 sleepq_release(&sx->lock_object);
  376 
  377         LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line);
  378 }
  379 
  380 /*
  381  * This function represents the so-called 'hard case' for sx_xlock
  382  * operation.  All 'easy case' failures are redirected to this.  Note
  383  * that ideally this would be a static function, but it needs to be
  384  * accessible from at least sx.h.
  385  */
  386 int
  387 _sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts, const char *file,
  388     int line)
  389 {
  390         GIANT_DECLARE;
  391 #ifdef ADAPTIVE_SX
  392         volatile struct thread *owner;
  393 #endif
  394         /* uint64_t waittime = 0; */
  395         uintptr_t x;
  396         int /* contested = 0, */error = 0;
  397 
  398         /* If we already hold an exclusive lock, then recurse. */
  399         if (sx_xlocked(sx)) {
  400                 KASSERT((sx->lock_object.lo_flags & SX_RECURSE) != 0,
  401             ("_sx_xlock_hard: recursed on non-recursive sx %s @ %s:%d\n",
  402                     sx->lock_object.lo_name, file, line));
  403                 sx->sx_recurse++;
  404                 atomic_set_ptr(&sx->sx_lock, SX_LOCK_RECURSED);
  405                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
  406                         CTR2(KTR_LOCK, "%s: %p recursing", __func__, sx);
  407                 return (0);
  408         }
  409 
  410         if (LOCK_LOG_TEST(&sx->lock_object, 0))
  411                 CTR5(KTR_LOCK, "%s: %s contested (lock=%p) at %s:%d", __func__,
  412                     sx->lock_object.lo_name, (void *)sx->sx_lock, file, line);
  413 
  414         while (!atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED, tid)) {
  415 #ifdef ADAPTIVE_SX
  416                 /*
  417                  * If the lock is write locked and the owner is
  418                  * running on another CPU, spin until the owner stops
  419                  * running or the state of the lock changes.
  420                  */
  421                 x = sx->sx_lock;
  422                 if (!(x & SX_LOCK_SHARED) &&
  423                     (sx->lock_object.lo_flags & SX_ADAPTIVESPIN)) {
  424                         x = SX_OWNER(x);
  425                         owner = (struct thread *)x;
  426                         if (TD_IS_RUNNING(owner)) {
  427                                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
  428                                         CTR3(KTR_LOCK,
  429                                             "%s: spinning on %p held by %p",
  430                                             __func__, sx, owner);
  431                                 GIANT_SAVE();
  432                                 lock_profile_obtain_lock_failed(
  433                                     &sx->lock_object, &contested, &waittime);
  434                                 while (SX_OWNER(sx->sx_lock) == x &&
  435                                     TD_IS_RUNNING(owner))
  436                                         cpu_spinwait();
  437                                 continue;
  438                         }
  439                 }
  440 #endif
  441 
  442                 sleepq_lock(&sx->lock_object);
  443                 x = sx->sx_lock;
  444 
  445                 /*
  446                  * If the lock was released while spinning on the
  447                  * sleep queue chain lock, try again.
  448                  */
  449                 if (x == SX_LOCK_UNLOCKED) {
  450                         sleepq_release(&sx->lock_object);
  451                         continue;
  452                 }
  453 
  454 #ifdef ADAPTIVE_SX
  455                 /*
  456                  * The current lock owner might have started executing
  457                  * on another CPU (or the lock could have changed
  458                  * owners) while we were waiting on the sleep queue
  459                  * chain lock.  If so, drop the sleep queue lock and try
  460                  * again.
  461                  */
  462                 if (!(x & SX_LOCK_SHARED) &&
  463                     (sx->lock_object.lo_flags & SX_ADAPTIVESPIN)) {
  464                         owner = (struct thread *)SX_OWNER(x);
  465                         if (TD_IS_RUNNING(owner)) {
  466                                 sleepq_release(&sx->lock_object);
  467                                 continue;
  468                         }
  469                 }
  470 #endif
  471 
  472                 /*
  473                  * If an exclusive lock was released with both shared
  474                  * and exclusive waiters and a shared waiter hasn't
  475                  * woken up and acquired the lock yet, sx_lock will be
  476                  * set to SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS.
  477                  * If we see that value, try to acquire it once.  Note
  478                  * that we have to preserve SX_LOCK_EXCLUSIVE_WAITERS
  479                  * as there are other exclusive waiters still.  If we
  480                  * fail, restart the loop.
  481                  */
  482                 if (x == (SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS)) {
  483                         if (atomic_cmpset_acq_ptr(&sx->sx_lock,
  484                             SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS,
  485                             tid | SX_LOCK_EXCLUSIVE_WAITERS)) {
  486                                 sleepq_release(&sx->lock_object);
  487                                 CTR2(KTR_LOCK, "%s: %p claimed by new writer",
  488                                     __func__, sx);
  489                                 break;
  490                         }
  491                         sleepq_release(&sx->lock_object);
  492                         continue;
  493                 }
  494 
  495                 /*
  496                  * Try to set the SX_LOCK_EXCLUSIVE_WAITERS.  If we fail,
  497                  * than loop back and retry.
  498                  */
  499                 if (!(x & SX_LOCK_EXCLUSIVE_WAITERS)) {
  500                         if (!atomic_cmpset_ptr(&sx->sx_lock, x,
  501                             x | SX_LOCK_EXCLUSIVE_WAITERS)) {
  502                                 sleepq_release(&sx->lock_object);
  503                                 continue;
  504                         }
  505                         if (LOCK_LOG_TEST(&sx->lock_object, 0))
  506                                 CTR2(KTR_LOCK, "%s: %p set excl waiters flag",
  507                                     __func__, sx);
  508                 }
  509 
  510                 /*
  511                  * Since we have been unable to acquire the exclusive
  512                  * lock and the exclusive waiters flag is set, we have
  513                  * to sleep.
  514                  */
  515                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
  516                         CTR2(KTR_LOCK, "%s: %p blocking on sleep queue",
  517                             __func__, sx);
  518 
  519                 GIANT_SAVE();
  520                 lock_profile_obtain_lock_failed(&sx->lock_object, &contested,
  521                     &waittime);
  522                 sleepq_add(&sx->lock_object, NULL, sx->lock_object.lo_name,
  523                     SLEEPQ_SX | ((opts & SX_INTERRUPTIBLE) ?
  524                     SLEEPQ_INTERRUPTIBLE : 0), SQ_EXCLUSIVE_QUEUE);
  525                 if (!(opts & SX_INTERRUPTIBLE))
  526                         sleepq_wait(&sx->lock_object);
  527                 else
  528                         error = sleepq_wait_sig(&sx->lock_object);
  529 
  530                 if (error) {
  531                         if (LOCK_LOG_TEST(&sx->lock_object, 0))
  532                                 CTR2(KTR_LOCK,
  533                         "%s: interruptible sleep by %p suspended by signal",
  534                                     __func__, sx);
  535                         break;
  536                 }
  537                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
  538                         CTR2(KTR_LOCK, "%s: %p resuming from sleep queue",
  539                             __func__, sx);
  540         }
  541 
  542         GIANT_RESTORE();
  543         if (!error)
  544                 lock_profile_obtain_lock_success(&sx->lock_object, contested,
  545                     waittime, file, line);
  546         return (error);
  547 }
  548 
  549 /*
  550  * This function represents the so-called 'hard case' for sx_xunlock
  551  * operation.  All 'easy case' failures are redirected to this.  Note
  552  * that ideally this would be a static function, but it needs to be
  553  * accessible from at least sx.h.
  554  */
  555 void
  556 _sx_xunlock_hard(struct sx *sx, uintptr_t tid, const char *file, int line)
  557 {
  558         uintptr_t x;
  559         int queue;
  560 
  561         MPASS(!(sx->sx_lock & SX_LOCK_SHARED));
  562 
  563         /* If the lock is recursed, then unrecurse one level. */
  564         if (sx_xlocked(sx) && sx_recursed(sx)) {
  565                 if ((--sx->sx_recurse) == 0)
  566                         atomic_clear_ptr(&sx->sx_lock, SX_LOCK_RECURSED);
  567                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
  568                         CTR2(KTR_LOCK, "%s: %p unrecursing", __func__, sx);
  569                 return;
  570         }
  571         MPASS(sx->sx_lock & (SX_LOCK_SHARED_WAITERS |
  572             SX_LOCK_EXCLUSIVE_WAITERS));
  573         if (LOCK_LOG_TEST(&sx->lock_object, 0))
  574                 CTR2(KTR_LOCK, "%s: %p contested", __func__, sx);
  575 
  576         sleepq_lock(&sx->lock_object);
  577         x = SX_LOCK_UNLOCKED;
  578 
  579         /*
  580          * The wake up algorithm here is quite simple and probably not
  581          * ideal.  It gives precedence to shared waiters if they are
  582          * present.  For this condition, we have to preserve the
  583          * state of the exclusive waiters flag.
  584          */
  585         if (sx->sx_lock & SX_LOCK_SHARED_WAITERS) {
  586                 queue = SQ_SHARED_QUEUE;
  587                 x |= (sx->sx_lock & SX_LOCK_EXCLUSIVE_WAITERS);
  588         } else
  589                 queue = SQ_EXCLUSIVE_QUEUE;
  590 
  591         /* Wake up all the waiters for the specific queue. */
  592         if (LOCK_LOG_TEST(&sx->lock_object, 0))
  593                 CTR3(KTR_LOCK, "%s: %p waking up all threads on %s queue",
  594                     __func__, sx, queue == SQ_SHARED_QUEUE ? "shared" :
  595                     "exclusive");
  596         atomic_store_rel_ptr(&sx->sx_lock, x);
  597         sleepq_broadcast(&sx->lock_object, SLEEPQ_SX, -1, queue);
  598 }
  599 
  600 /*
  601  * This function represents the so-called 'hard case' for sx_slock
  602  * operation.  All 'easy case' failures are redirected to this.  Note
  603  * that ideally this would be a static function, but it needs to be
  604  * accessible from at least sx.h.
  605  */
  606 int
  607 _sx_slock_hard(struct sx *sx, int opts, const char *file, int line)
  608 {
  609         GIANT_DECLARE;
  610 #ifdef ADAPTIVE_SX
  611         volatile struct thread *owner;
  612 #endif
  613 #ifdef LOCK_PROFILING_SHARED
  614         uint64_t waittime = 0;
  615         int contested = 0;
  616 #endif
  617         uintptr_t x;
  618         int error = 0;
  619 
  620         /*
  621          * As with rwlocks, we don't make any attempt to try to block
  622          * shared locks once there is an exclusive waiter.
  623          */
  624         for (;;) {
  625                 x = sx->sx_lock;
  626 
  627                 /*
  628                  * If no other thread has an exclusive lock then try to bump up
  629                  * the count of sharers.  Since we have to preserve the state
  630                  * of SX_LOCK_EXCLUSIVE_WAITERS, if we fail to acquire the
  631                  * shared lock loop back and retry.
  632                  */
  633                 if (x & SX_LOCK_SHARED) {
  634                         MPASS(!(x & SX_LOCK_SHARED_WAITERS));
  635                         if (atomic_cmpset_acq_ptr(&sx->sx_lock, x,
  636                             x + SX_ONE_SHARER)) {
  637 #ifdef LOCK_PROFILING_SHARED
  638                                 if (SX_SHARERS(x) == 0)
  639                                         lock_profile_obtain_lock_success(
  640                                             &sx->lock_object, contested,
  641                                             waittime, file, line);
  642 #endif
  643                                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
  644                                         CTR4(KTR_LOCK,
  645                                             "%s: %p succeed %p -> %p", __func__,
  646                                             sx, (void *)x,
  647                                             (void *)(x + SX_ONE_SHARER));
  648                                 break;
  649                         }
  650                         continue;
  651                 }
  652 
  653 #ifdef ADAPTIVE_SX
  654                 /*
  655                  * If the owner is running on another CPU, spin until
  656                  * the owner stops running or the state of the lock
  657                  * changes.
  658                  */
  659                 else if (sx->lock_object.lo_flags & SX_ADAPTIVESPIN) {
  660                         x = SX_OWNER(x);
  661                         owner = (struct thread *)x;
  662                         if (TD_IS_RUNNING(owner)) {
  663                                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
  664                                         CTR3(KTR_LOCK,
  665                                             "%s: spinning on %p held by %p",
  666                                             __func__, sx, owner);
  667                                 GIANT_SAVE();
  668 #ifdef LOCK_PROFILING_SHARED
  669                                 lock_profile_obtain_lock_failed(
  670                                     &sx->lock_object, &contested, &waittime);
  671 #endif
  672                                 while (SX_OWNER(sx->sx_lock) == x &&
  673                                     TD_IS_RUNNING(owner))
  674                                         cpu_spinwait();
  675                                 continue;
  676                         }
  677                 }
  678 #endif
  679 
  680                 /*
  681                  * Some other thread already has an exclusive lock, so
  682                  * start the process of blocking.
  683                  */
  684                 sleepq_lock(&sx->lock_object);
  685                 x = sx->sx_lock;
  686 
  687                 /*
  688                  * The lock could have been released while we spun.
  689                  * In this case loop back and retry.
  690                  */
  691                 if (x & SX_LOCK_SHARED) {
  692                         sleepq_release(&sx->lock_object);
  693                         continue;
  694                 }
  695 
  696 #ifdef ADAPTIVE_SX
  697                 /*
  698                  * If the owner is running on another CPU, spin until
  699                  * the owner stops running or the state of the lock
  700                  * changes.
  701                  */
  702                 if (!(x & SX_LOCK_SHARED) &&
  703                     (sx->lock_object.lo_flags & SX_ADAPTIVESPIN)) {
  704                         owner = (struct thread *)SX_OWNER(x);
  705                         if (TD_IS_RUNNING(owner)) {
  706                                 sleepq_release(&sx->lock_object);
  707                                 continue;
  708                         }
  709                 }
  710 #endif
  711 
  712                 /*
  713                  * Try to set the SX_LOCK_SHARED_WAITERS flag.  If we
  714                  * fail to set it drop the sleep queue lock and loop
  715                  * back.
  716                  */
  717                 if (!(x & SX_LOCK_SHARED_WAITERS)) {
  718                         if (!atomic_cmpset_ptr(&sx->sx_lock, x,
  719                             x | SX_LOCK_SHARED_WAITERS)) {
  720                                 sleepq_release(&sx->lock_object);
  721                                 continue;
  722                         }
  723                         if (LOCK_LOG_TEST(&sx->lock_object, 0))
  724                                 CTR2(KTR_LOCK, "%s: %p set shared waiters flag",
  725                                     __func__, sx);
  726                 }
  727 
  728                 /*
  729                  * Since we have been unable to acquire the shared lock,
  730                  * we have to sleep.
  731                  */
  732                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
  733                         CTR2(KTR_LOCK, "%s: %p blocking on sleep queue",
  734                             __func__, sx);
  735 
  736                 GIANT_SAVE();
  737 #ifdef LOCK_PROFILING_SHARED
  738                 lock_profile_obtain_lock_failed(&sx->lock_object, &contested,
  739                     &waittime);
  740 #endif
  741                 sleepq_add(&sx->lock_object, NULL, sx->lock_object.lo_name,
  742                     SLEEPQ_SX | ((opts & SX_INTERRUPTIBLE) ?
  743                     SLEEPQ_INTERRUPTIBLE : 0), SQ_SHARED_QUEUE);
  744                 if (!(opts & SX_INTERRUPTIBLE))
  745                         sleepq_wait(&sx->lock_object);
  746                 else
  747                         error = sleepq_wait_sig(&sx->lock_object);
  748 
  749                 if (error) {
  750                         if (LOCK_LOG_TEST(&sx->lock_object, 0))
  751                                 CTR2(KTR_LOCK,
  752                         "%s: interruptible sleep by %p suspended by signal",
  753                                     __func__, sx);
  754                         break;
  755                 }
  756                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
  757                         CTR2(KTR_LOCK, "%s: %p resuming from sleep queue",
  758                             __func__, sx);
  759         }
  760 
  761         GIANT_RESTORE();
  762         return (error);
  763 }
  764 
  765 /*
  766  * This function represents the so-called 'hard case' for sx_sunlock
  767  * operation.  All 'easy case' failures are redirected to this.  Note
  768  * that ideally this would be a static function, but it needs to be
  769  * accessible from at least sx.h.
  770  */
  771 void
  772 _sx_sunlock_hard(struct sx *sx, const char *file, int line)
  773 {
  774         uintptr_t x;
  775 
  776         for (;;) {
  777                 x = sx->sx_lock;
  778 
  779                 /*
  780                  * We should never have sharers while at least one thread
  781                  * holds a shared lock.
  782                  */
  783                 KASSERT(!(x & SX_LOCK_SHARED_WAITERS),
  784                     ("%s: waiting sharers", __func__));
  785 
  786                 /*
  787                  * See if there is more than one shared lock held.  If
  788                  * so, just drop one and return.
  789                  */
  790                 if (SX_SHARERS(x) > 1) {
  791                         if (atomic_cmpset_ptr(&sx->sx_lock, x,
  792                             x - SX_ONE_SHARER)) {
  793                                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
  794                                         CTR4(KTR_LOCK,
  795                                             "%s: %p succeeded %p -> %p",
  796                                             __func__, sx, (void *)x,
  797                                             (void *)(x - SX_ONE_SHARER));
  798                                 break;
  799                         }
  800                         continue;
  801                 }
  802 
  803                 /*
  804                  * If there aren't any waiters for an exclusive lock,
  805                  * then try to drop it quickly.
  806                  */
  807                 if (!(x & SX_LOCK_EXCLUSIVE_WAITERS)) {
  808                         MPASS(x == SX_SHARERS_LOCK(1));
  809                         if (atomic_cmpset_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1),
  810                             SX_LOCK_UNLOCKED)) {
  811                                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
  812                                         CTR2(KTR_LOCK, "%s: %p last succeeded",
  813                                             __func__, sx);
  814                                 break;
  815                         }
  816                         continue;
  817                 }
  818 
  819                 /*
  820                  * At this point, there should just be one sharer with
  821                  * exclusive waiters.
  822                  */
  823                 MPASS(x == (SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS));
  824 
  825                 sleepq_lock(&sx->lock_object);
  826 
  827                 /*
  828                  * Wake up semantic here is quite simple:
  829                  * Just wake up all the exclusive waiters.
  830                  * Note that the state of the lock could have changed,
  831                  * so if it fails loop back and retry.
  832                  */
  833                 if (!atomic_cmpset_ptr(&sx->sx_lock,
  834                     SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS,
  835                     SX_LOCK_UNLOCKED)) {
  836                         sleepq_release(&sx->lock_object);
  837                         continue;
  838                 }
  839                 if (LOCK_LOG_TEST(&sx->lock_object, 0))
  840                         CTR2(KTR_LOCK, "%s: %p waking up all thread on"
  841                             "exclusive queue", __func__, sx);
  842                 sleepq_broadcast(&sx->lock_object, SLEEPQ_SX, -1,
  843                     SQ_EXCLUSIVE_QUEUE);
  844                 break;
  845         }
  846 }
  847 
  848 /*
  849  * Atomically drop an sx lock while going to sleep.  This is just a hack
  850  * for 6.x.  In 7.0 and later this is done more cleanly.
  851  */
  852 int
  853 sx_sleep(void *ident, struct sx *sx, int priority, const char *wmesg, int timo)
  854 {
  855         struct thread *td;
  856         struct proc *p;
  857         int catch, rval, flags, xlocked;
  858         WITNESS_SAVE_DECL(sx_witness);
  859 
  860         td = curthread;
  861         p = td->td_proc;
  862 #ifdef KTRACE
  863         if (KTRPOINT(td, KTR_CSW))
  864                 ktrcsw(1, 0);
  865 #endif
  866         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
  867             "Sleeping on \"%s\"", wmesg);
  868         KASSERT(sx != NULL, ("sx_sleep w/o an sx lock"));
  869         KASSERT(ident != NULL && TD_IS_RUNNING(td), ("sx_sleep"));
  870 
  871         if (cold) {
  872                 /*
  873                  * During autoconfiguration, just return;
  874                  * don't run any other threads or panic below,
  875                  * in case this is the idle thread and already asleep.
  876                  * XXX: this used to do "s = splhigh(); splx(safepri);
  877                  * splx(s);" to give interrupts a chance, but there is
  878                  * no way to give interrupts a chance now.
  879                  */
  880                 if (priority & PDROP)
  881                         sx_unlock(sx);
  882                 return (0);
  883         }
  884         catch = priority & PCATCH;
  885         rval = 0;
  886 
  887         /*
  888          * If we are already on a sleep queue, then remove us from that
  889          * sleep queue first.  We have to do this to handle recursive
  890          * sleeps.
  891          */
  892         if (TD_ON_SLEEPQ(td))
  893                 sleepq_remove(td, td->td_wchan);
  894 
  895         flags = SLEEPQ_MSLEEP;
  896         if (catch)
  897                 flags |= SLEEPQ_INTERRUPTIBLE;
  898 
  899         sleepq_lock(ident);
  900         CTR5(KTR_PROC, "sx_sleep: thread %p (pid %ld, %s) on %s (%p)",
  901             (void *)td, (long)p->p_pid, p->p_comm, wmesg, ident);
  902 
  903         DROP_GIANT();
  904 
  905         /*
  906          * We put ourselves on the sleep queue and start our timeout
  907          * before calling thread_suspend_check, as we could stop there,
  908          * and a wakeup or a SIGCONT (or both) could occur while we were
  909          * stopped without resuming us.  Thus, we must be ready for sleep
  910          * when cursig() is called.  If the wakeup happens while we're
  911          * stopped, then td will no longer be on a sleep queue upon
  912          * return from cursig().
  913          */
  914         sleepq_add(ident, &sx->lock_object, wmesg, flags, 0);
  915         if (timo)
  916                 sleepq_set_timeout(ident, timo);
  917 
  918         /*
  919          * Now that we are on the queue, drop the sleepq lock so we
  920          * can safely unlock the sx lock.
  921          */
  922         sleepq_release(ident);
  923         WITNESS_SAVE(&sx->lock_object, sx_witness);
  924         xlocked = sx_xlocked(sx);
  925         if (xlocked)
  926                 sx_xunlock(sx);
  927         else
  928                 sx_sunlock(sx);
  929         sleepq_lock(ident);
  930 
  931         /*
  932          * Adjust this thread's priority.
  933          */
  934         if ((priority & PRIMASK) != 0) {
  935                 mtx_lock_spin(&sched_lock);
  936                 sched_prio(td, priority & PRIMASK);
  937                 mtx_unlock_spin(&sched_lock);
  938         }
  939 
  940         if (timo && catch)
  941                 rval = sleepq_timedwait_sig(ident);
  942         else if (timo)
  943                 rval = sleepq_timedwait(ident);
  944         else if (catch)
  945                 rval = sleepq_wait_sig(ident);
  946         else {
  947                 sleepq_wait(ident);
  948                 rval = 0;
  949         }
  950 #ifdef KTRACE
  951         if (KTRPOINT(td, KTR_CSW))
  952                 ktrcsw(0, 0);
  953 #endif
  954         PICKUP_GIANT();
  955         if (!(priority & PDROP)) {
  956                 if (xlocked)
  957                         sx_xlock(sx);
  958                 else
  959                         sx_slock(sx);
  960                 WITNESS_RESTORE(&sx->lock_object, sx_witness);
  961         }
  962         return (rval);
  963 }
  964 
  965 #ifdef INVARIANT_SUPPORT
  966 #ifndef INVARIANTS
  967 #undef  _sx_assert
  968 #endif
  969 
  970 /*
  971  * In the non-WITNESS case, sx_assert() can only detect that at least
  972  * *some* thread owns an slock, but it cannot guarantee that *this*
  973  * thread owns an slock.
  974  */
  975 void
  976 _sx_assert(struct sx *sx, int what, const char *file, int line)
  977 {
  978 #ifndef WITNESS
  979         int slocked = 0;
  980 #endif
  981 
  982         if (panicstr != NULL)
  983                 return;
  984         switch (what) {
  985         case SA_SLOCKED:
  986         case SA_SLOCKED | SA_NOTRECURSED:
  987         case SA_SLOCKED | SA_RECURSED:
  988 #ifndef WITNESS
  989                 slocked = 1;
  990                 /* FALLTHROUGH */
  991 #endif
  992         case SA_LOCKED:
  993         case SA_LOCKED | SA_NOTRECURSED:
  994         case SA_LOCKED | SA_RECURSED:
  995 #ifdef WITNESS
  996                 witness_assert(&sx->lock_object, what, file, line);
  997 #else
  998                 /*
  999                  * If some other thread has an exclusive lock or we
 1000                  * have one and are asserting a shared lock, fail.
 1001                  * Also, if no one has a lock at all, fail.
 1002                  */
 1003                 if (sx->sx_lock == SX_LOCK_UNLOCKED ||
 1004                     (!(sx->sx_lock & SX_LOCK_SHARED) && (slocked ||
 1005                     sx_xholder(sx) != curthread)))
 1006                         panic("Lock %s not %slocked @ %s:%d\n",
 1007                             sx->lock_object.lo_name, slocked ? "share " : "",
 1008                             file, line);
 1009 
 1010                 if (!(sx->sx_lock & SX_LOCK_SHARED)) {
 1011                         if (sx_recursed(sx)) {
 1012                                 if (what & SA_NOTRECURSED)
 1013                                         panic("Lock %s recursed @ %s:%d\n",
 1014                                             sx->lock_object.lo_name, file,
 1015                                             line);
 1016                         } else if (what & SA_RECURSED)
 1017                                 panic("Lock %s not recursed @ %s:%d\n",
 1018                                     sx->lock_object.lo_name, file, line);
 1019                 }
 1020 #endif
 1021                 break;
 1022         case SA_XLOCKED:
 1023         case SA_XLOCKED | SA_NOTRECURSED:
 1024         case SA_XLOCKED | SA_RECURSED:
 1025                 if (sx_xholder(sx) != curthread)
 1026                         panic("Lock %s not exclusively locked @ %s:%d\n",
 1027                             sx->lock_object.lo_name, file, line);
 1028                 if (sx_recursed(sx)) {
 1029                         if (what & SA_NOTRECURSED)
 1030                                 panic("Lock %s recursed @ %s:%d\n",
 1031                                     sx->lock_object.lo_name, file, line);
 1032                 } else if (what & SA_RECURSED)
 1033                         panic("Lock %s not recursed @ %s:%d\n",
 1034                             sx->lock_object.lo_name, file, line);
 1035                 break;
 1036         case SA_UNLOCKED:
 1037 #ifdef WITNESS
 1038                 witness_assert(&sx->lock_object, what, file, line);
 1039 #else
 1040                 /*
 1041                  * If we hold an exclusve lock fail.  We can't
 1042                  * reliably check to see if we hold a shared lock or
 1043                  * not.
 1044                  */
 1045                 if (sx_xholder(sx) == curthread)
 1046                         panic("Lock %s exclusively locked @ %s:%d\n",
 1047                             sx->lock_object.lo_name, file, line);
 1048 #endif
 1049                 break;
 1050         default:
 1051                 panic("Unknown sx lock assertion: %d @ %s:%d", what, file,
 1052                     line);
 1053         }
 1054 }
 1055 #endif  /* INVARIANT_SUPPORT */
 1056 
 1057 #ifdef DDB
 1058 static void
 1059 db_show_sx(struct lock_object *lock)
 1060 {
 1061         struct thread *td;
 1062         struct sx *sx;
 1063 
 1064         sx = (struct sx *)lock;
 1065 
 1066         db_printf(" state: ");
 1067         if (sx->sx_lock == SX_LOCK_UNLOCKED)
 1068                 db_printf("UNLOCKED\n");
 1069         else if (sx->sx_lock == SX_LOCK_DESTROYED) {
 1070                 db_printf("DESTROYED\n");
 1071                 return;
 1072         } else if (sx->sx_lock & SX_LOCK_SHARED)
 1073                 db_printf("SLOCK: %ju\n", (uintmax_t)SX_SHARERS(sx->sx_lock));
 1074         else {
 1075                 td = sx_xholder(sx);
 1076                 db_printf("XLOCK: %p (tid %d, pid %d, \"%s\")\n", td,
 1077                     td->td_tid, td->td_proc->p_pid, td->td_proc->p_comm);
 1078                 if (sx_recursed(sx))
 1079                         db_printf(" recursed: %d\n", sx->sx_recurse);
 1080         }
 1081 
 1082         db_printf(" waiters: ");
 1083         switch(sx->sx_lock &
 1084             (SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS)) {
 1085         case SX_LOCK_SHARED_WAITERS:
 1086                 db_printf("shared\n");
 1087                 break;
 1088         case SX_LOCK_EXCLUSIVE_WAITERS:
 1089                 db_printf("exclusive\n");
 1090                 break;
 1091         case SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS:
 1092                 db_printf("exclusive and shared\n");
 1093                 break;
 1094         default:
 1095                 db_printf("none\n");
 1096         }
 1097 }
 1098 
 1099 /*
 1100  * Check to see if a thread that is blocked on a sleep queue is actually
 1101  * blocked on an sx lock.  If so, output some details and return true.
 1102  * If the lock has an exclusive owner, return that in *ownerp.
 1103  */
 1104 int
 1105 sx_chain(struct thread *td, struct thread **ownerp)
 1106 {
 1107         struct sx *sx;
 1108 
 1109         /*
 1110          * Check to see if this thread is blocked on an sx lock.
 1111          * First, we check the lock class.  If that is ok, then we
 1112          * compare the lock name against the wait message.
 1113          */
 1114         sx = td->td_wchan;
 1115         if (LOCK_CLASS(&sx->lock_object) != &lock_class_sx ||
 1116             sx->lock_object.lo_name != td->td_wmesg)
 1117                 return (0);
 1118 
 1119         /* We think we have an sx lock, so output some details. */
 1120         db_printf("blocked on sx \"%s\" ", td->td_wmesg);
 1121         *ownerp = sx_xholder(sx);
 1122         if (sx->sx_lock & SX_LOCK_SHARED)
 1123                 db_printf("SLOCK (count %ju)\n",
 1124                     (uintmax_t)SX_SHARERS(sx->sx_lock));
 1125         else
 1126                 db_printf("XLOCK\n");
 1127         return (1);
 1128 }
 1129 #endif

Cache object: 1b96bcc30d7cb37f75f3741ac288de22


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.