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_lock.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* 
    2  * Copyright (c) 1995
    3  *      The Regents of the University of California.  All rights reserved.
    4  * Copyright (C) 1997
    5  *      John S. Dyson.  All rights reserved.
    6  * Copyright (C) 2013
    7  *      Matthew Dillon, All rights reserved.
    8  *
    9  * This code contains ideas from software contributed to Berkeley by
   10  * Avadis Tevanian, Jr., Michael Wayne Young, and the Mach Operating
   11  * System project at Carnegie-Mellon University.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. Neither the name of the University nor the names of its contributors
   22  *    may be used to endorse or promote products derived from this software
   23  *    without specific prior written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  */
   37 
   38 #include "opt_lint.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/kernel.h>
   43 #include <sys/proc.h>
   44 #include <sys/lock.h>
   45 #include <sys/sysctl.h>
   46 #include <sys/spinlock.h>
   47 #include <sys/thread2.h>
   48 #include <sys/spinlock2.h>
   49 
   50 static void undo_upreq(struct lock *lkp);
   51 
   52 /*
   53  * Locking primitives implementation.
   54  * Locks provide shared/exclusive sychronization.
   55  */
   56 
   57 #ifdef DEBUG_LOCKS
   58 #define COUNT(td, x) (td)->td_locks += (x)
   59 #else
   60 #define COUNT(td, x)
   61 #endif
   62 
   63 #define LOCK_WAIT_TIME 100
   64 #define LOCK_SAMPLE_WAIT 7
   65 
   66 /*
   67  * Set, change, or release a lock.
   68  *
   69  */
   70 int
   71 #ifndef DEBUG_LOCKS
   72 lockmgr(struct lock *lkp, u_int flags)
   73 #else
   74 debuglockmgr(struct lock *lkp, u_int flags,
   75              const char *name, const char *file, int line)
   76 #endif
   77 {
   78         thread_t td;
   79         thread_t otd;
   80         int error;
   81         int extflags;
   82         int count;
   83         int pflags;
   84         int wflags;
   85         int timo;
   86 #ifdef DEBUG_LOCKS
   87         int i;
   88 #endif
   89 
   90         error = 0;
   91 
   92         if (mycpu->gd_intr_nesting_level &&
   93             (flags & LK_NOWAIT) == 0 &&
   94             (flags & LK_TYPE_MASK) != LK_RELEASE &&
   95             panic_cpu_gd != mycpu
   96         ) {
   97 
   98 #ifndef DEBUG_LOCKS
   99                 panic("lockmgr %s from %p: called from interrupt, ipi, "
  100                       "or hard code section",
  101                       lkp->lk_wmesg, ((int **)&lkp)[-1]);
  102 #else
  103                 panic("lockmgr %s from %s:%d: called from interrupt, ipi, "
  104                       "or hard code section",
  105                       lkp->lk_wmesg, file, line);
  106 #endif
  107         }
  108 
  109 #ifdef DEBUG_LOCKS
  110         if (mycpu->gd_spinlocks && ((flags & LK_NOWAIT) == 0)) {
  111                 panic("lockmgr %s from %s:%d: called with %d spinlocks held",
  112                       lkp->lk_wmesg, file, line, mycpu->gd_spinlocks);
  113         }
  114 #endif
  115 
  116         extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK;
  117         td = curthread;
  118 
  119 again:
  120         count = lkp->lk_count;
  121         cpu_ccfence();
  122 
  123         switch (flags & LK_TYPE_MASK) {
  124         case LK_SHARED:
  125                 /*
  126                  * Shared lock critical path case
  127                  */
  128                 if ((count & (LKC_EXREQ|LKC_UPREQ|LKC_EXCL)) == 0) {
  129                         if (atomic_cmpset_int(&lkp->lk_count,
  130                                               count, count + 1)) {
  131                                 COUNT(td, 1);
  132                                 break;
  133                         }
  134                         goto again;
  135                 }
  136 
  137                 /*
  138                  * If the caller already holds the lock exclusively then
  139                  * we silently obtain another count on the exclusive lock.
  140                  *
  141                  * WARNING!  The old FreeBSD behavior was to downgrade,
  142                  *           but this creates a problem when recursions
  143                  *           return to the caller and the caller expects
  144                  *           its original exclusive lock to remain exclusively
  145                  *           locked.
  146                  */
  147                 if (lkp->lk_lockholder == td) {
  148                         KKASSERT(count & LKC_EXCL);
  149                         if ((extflags & LK_CANRECURSE) == 0) {
  150                                 if (extflags & LK_NOWAIT) {
  151                                         error = EBUSY;
  152                                         break;
  153                                 }
  154                                 panic("lockmgr: locking against myself");
  155                         }
  156                         atomic_add_int(&lkp->lk_count, 1);
  157                         COUNT(td, 1);
  158                         break;
  159                 }
  160 
  161                 /*
  162                  * Slow path
  163                  */
  164                 pflags = (extflags & LK_PCATCH) ? PCATCH : 0;
  165                 timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0;
  166                 wflags = (td->td_flags & TDF_DEADLKTREAT) ?
  167                                 LKC_EXCL : (LKC_EXCL|LKC_EXREQ|LKC_UPREQ);
  168 
  169                 /*
  170                  * Block while the lock is held exclusively or, conditionally,
  171                  * if other threads are tring to obtain an exclusive lock or
  172                  * upgrade to one.
  173                  */
  174                 if (count & wflags) {
  175                         if (extflags & LK_NOWAIT) {
  176                                 error = EBUSY;
  177                                 break;
  178                         }
  179                         tsleep_interlock(lkp, pflags);
  180                         if (!atomic_cmpset_int(&lkp->lk_count, count,
  181                                               count | LKC_SHREQ)) {
  182                                 goto again;
  183                         }
  184 
  185                         mycpu->gd_cnt.v_lock_name[0] = 'S';
  186                         strncpy(mycpu->gd_cnt.v_lock_name + 1,
  187                                 lkp->lk_wmesg,
  188                                 sizeof(mycpu->gd_cnt.v_lock_name) - 2);
  189                         ++mycpu->gd_cnt.v_lock_colls;
  190 
  191                         error = tsleep(lkp, pflags | PINTERLOCKED,
  192                                        lkp->lk_wmesg, timo);
  193                         if (error)
  194                                 break;
  195                         if (extflags & LK_SLEEPFAIL) {
  196                                 error = ENOLCK;
  197                                 break;
  198                         }
  199                         goto again;
  200                 }
  201 
  202                 /*
  203                  * Otherwise we can bump the count
  204                  */
  205                 if (atomic_cmpset_int(&lkp->lk_count, count, count + 1)) {
  206                         COUNT(td, 1);
  207                         break;
  208                 }
  209                 goto again;
  210 
  211         case LK_EXCLUSIVE:
  212                 /*
  213                  * Exclusive lock critical path.
  214                  */
  215                 if (count == 0) {
  216                         if (atomic_cmpset_int(&lkp->lk_count, count,
  217                                               LKC_EXCL | (count + 1))) {
  218                                 lkp->lk_lockholder = td;
  219                                 COUNT(td, 1);
  220                                 break;
  221                         }
  222                         goto again;
  223                 }
  224 
  225                 /*
  226                  * Recursive lock if we already hold it exclusively.
  227                  */
  228                 if (lkp->lk_lockholder == td) {
  229                         KKASSERT(count & LKC_EXCL);
  230                         if ((extflags & LK_CANRECURSE) == 0) {
  231                                 if (extflags & LK_NOWAIT) {
  232                                         error = EBUSY;
  233                                         break;
  234                                 }
  235                                 panic("lockmgr: locking against myself");
  236                         }
  237                         atomic_add_int(&lkp->lk_count, 1);
  238                         COUNT(td, 1);
  239                         break;
  240                 }
  241 
  242                 /*
  243                  * We will block, handle LK_NOWAIT
  244                  */
  245                 if (extflags & LK_NOWAIT) {
  246                         error = EBUSY;
  247                         break;
  248                 }
  249 
  250                 /*
  251                  * Wait until we can obtain the exclusive lock.  EXREQ is
  252                  * automatically cleared when all current holders release
  253                  * so if we abort the operation we can safely leave it set.
  254                  * There might be other exclusive requesters.
  255                  */
  256                 pflags = (extflags & LK_PCATCH) ? PCATCH : 0;
  257                 timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0;
  258 
  259                 tsleep_interlock(lkp, pflags);
  260                 if (!atomic_cmpset_int(&lkp->lk_count, count,
  261                                        count | LKC_EXREQ)) {
  262                         goto again;
  263                 }
  264 
  265                 mycpu->gd_cnt.v_lock_name[0] = 'X';
  266                 strncpy(mycpu->gd_cnt.v_lock_name + 1,
  267                         lkp->lk_wmesg,
  268                         sizeof(mycpu->gd_cnt.v_lock_name) - 2);
  269                 ++mycpu->gd_cnt.v_lock_colls;
  270 
  271                 error = tsleep(lkp, pflags | PINTERLOCKED,
  272                                lkp->lk_wmesg, timo);
  273                 if (error)
  274                         break;
  275                 if (extflags & LK_SLEEPFAIL) {
  276                         error = ENOLCK;
  277                         break;
  278                 }
  279                 goto again;
  280 
  281         case LK_DOWNGRADE:
  282                 /*
  283                  * Downgrade an exclusive lock into a shared lock.  All
  284                  * counts on a recursive exclusive lock become shared.
  285                  *
  286                  * This function always succeeds.
  287                  */
  288                 if (lkp->lk_lockholder != td ||
  289                     (count & (LKC_EXCL|LKC_MASK)) != (LKC_EXCL|1)) {
  290                         panic("lockmgr: not holding exclusive lock");
  291                 }
  292 
  293 #ifdef DEBUG_LOCKS
  294                 for (i = 0; i < LOCKMGR_DEBUG_ARRAY_SIZE; i++) {
  295                         if (td->td_lockmgr_stack[i] == lkp &&
  296                             td->td_lockmgr_stack_id[i] > 0
  297                         ) {
  298                                 td->td_lockmgr_stack_id[i]--;
  299                                 break;
  300                         }
  301                 }
  302 #endif
  303                 /*
  304                  * NOTE! Must NULL-out lockholder before releasing LKC_EXCL.
  305                  */
  306                 otd = lkp->lk_lockholder;
  307                 lkp->lk_lockholder = NULL;
  308                 if (atomic_cmpset_int(&lkp->lk_count, count,
  309                                       count & ~(LKC_EXCL|LKC_SHREQ))) {
  310                         if (count & LKC_SHREQ)
  311                                 wakeup(lkp);
  312                         break;
  313                 }
  314                 lkp->lk_lockholder = otd;
  315                 goto again;
  316 
  317         case LK_EXCLUPGRADE:
  318                 /*
  319                  * Upgrade from a single shared lock to an exclusive lock.
  320                  *
  321                  * If another process is ahead of us to get an upgrade,
  322                  * then we want to fail rather than have an intervening
  323                  * exclusive access.  The shared lock is released on
  324                  * failure.
  325                  */
  326                 if (count & LKC_UPREQ) {
  327                         flags = LK_RELEASE;
  328                         error = EBUSY;
  329                         goto again;
  330                 }
  331                 /* fall through into normal upgrade */
  332 
  333         case LK_UPGRADE:
  334                 /*
  335                  * Upgrade a shared lock to an exclusive one.  This can cause
  336                  * the lock to be temporarily released and stolen by other
  337                  * threads.  LK_SLEEPFAIL or LK_NOWAIT may be used to detect
  338                  * this case, or use LK_EXCLUPGRADE.
  339                  *
  340                  * If the lock is already exclusively owned by us, this
  341                  * operation is a NOP.
  342                  *
  343                  * If we return an error (even NOWAIT), the current lock will
  344                  * be released.
  345                  *
  346                  * Start with the critical path.
  347                  */
  348                 if ((count & (LKC_UPREQ|LKC_EXCL|LKC_MASK)) == 1) {
  349                         if (atomic_cmpset_int(&lkp->lk_count, count,
  350                                               count | LKC_EXCL)) {
  351                                 lkp->lk_lockholder = td;
  352                                 break;
  353                         }
  354                         goto again;
  355                 }
  356 
  357                 /*
  358                  * If we already hold the lock exclusively this operation
  359                  * succeeds and is a NOP.
  360                  */
  361                 if (count & LKC_EXCL) {
  362                         if (lkp->lk_lockholder == td)
  363                                 break;
  364                         panic("lockmgr: upgrade unowned lock");
  365                 }
  366                 if ((count & LKC_MASK) == 0)
  367                         panic("lockmgr: upgrade unowned lock");
  368 
  369                 /*
  370                  * We cannot upgrade without blocking at this point.
  371                  */
  372                 if (extflags & LK_NOWAIT) {
  373                         flags = LK_RELEASE;
  374                         error = EBUSY;
  375                         goto again;
  376                 }
  377 
  378                 /*
  379                  * Release the shared lock and request the upgrade.
  380                  */
  381                 pflags = (extflags & LK_PCATCH) ? PCATCH : 0;
  382                 timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0;
  383                 tsleep_interlock(lkp, pflags);
  384                 wflags = (count & LKC_UPREQ) ? LKC_EXREQ : LKC_UPREQ;
  385 
  386                 /*
  387                  * If someone else owns UPREQ and this transition would
  388                  * allow it to be granted, we have to grant it.  Otherwise
  389                  * we release the shared lock.
  390                  */
  391                 if ((count & (LKC_UPREQ|LKC_MASK)) == (LKC_UPREQ | 1)) {
  392                         wflags |= LKC_EXCL | LKC_UPGRANT;
  393                         wflags |= count;
  394                         wflags &= ~LKC_UPREQ;
  395                 } else {
  396                         wflags |= (count - 1);
  397                 }
  398 
  399                 if (atomic_cmpset_int(&lkp->lk_count, count, wflags)) {
  400                         COUNT(td, -1);
  401 
  402                         /*
  403                          * Must wakeup the thread granted the upgrade.
  404                          */
  405                         if ((count & (LKC_UPREQ|LKC_MASK)) == (LKC_UPREQ | 1))
  406                                 wakeup(lkp);
  407 
  408                         mycpu->gd_cnt.v_lock_name[0] = 'U';
  409                         strncpy(mycpu->gd_cnt.v_lock_name + 1,
  410                                 lkp->lk_wmesg,
  411                                 sizeof(mycpu->gd_cnt.v_lock_name) - 2);
  412                         ++mycpu->gd_cnt.v_lock_colls;
  413 
  414                         error = tsleep(lkp, pflags | PINTERLOCKED,
  415                                        lkp->lk_wmesg, timo);
  416                         if (error)
  417                                 break;
  418                         if (extflags & LK_SLEEPFAIL) {
  419                                 error = ENOLCK;
  420                                 break;
  421                         }
  422 
  423                         /*
  424                          * Refactor to either LK_EXCLUSIVE or LK_WAITUPGRADE,
  425                          * depending on whether we were able to acquire the
  426                          * LKC_UPREQ bit.
  427                          */
  428                         if (count & LKC_UPREQ)
  429                                 flags = LK_EXCLUSIVE;   /* someone else */
  430                         else
  431                                 flags = LK_WAITUPGRADE; /* we own the bit */
  432                 }
  433                 goto again;
  434 
  435         case LK_WAITUPGRADE:
  436                 /*
  437                  * We own the LKC_UPREQ bit, wait until we are granted the
  438                  * exclusive lock (LKC_UPGRANT is set).
  439                  *
  440                  * IF THE OPERATION FAILS (tsleep error tsleep+LK_SLEEPFAIL),
  441                  * we have to undo the upgrade request and clean up any lock
  442                  * that might have been granted via a race.
  443                  */
  444                 if (count & LKC_UPGRANT) {
  445                         if (atomic_cmpset_int(&lkp->lk_count, count,
  446                                               count & ~LKC_UPGRANT)) {
  447                                 lkp->lk_lockholder = td;
  448                                 KKASSERT(count & LKC_EXCL);
  449                                 break;
  450                         }
  451                         /* retry */
  452                 } else {
  453                         pflags = (extflags & LK_PCATCH) ? PCATCH : 0;
  454                         timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0;
  455                         tsleep_interlock(lkp, pflags);
  456                         if (atomic_cmpset_int(&lkp->lk_count, count, count)) {
  457 
  458                                 mycpu->gd_cnt.v_lock_name[0] = 'U';
  459                                 strncpy(mycpu->gd_cnt.v_lock_name + 1,
  460                                         lkp->lk_wmesg,
  461                                         sizeof(mycpu->gd_cnt.v_lock_name) - 2);
  462                                 ++mycpu->gd_cnt.v_lock_colls;
  463 
  464                                 error = tsleep(lkp, pflags | PINTERLOCKED,
  465                                                lkp->lk_wmesg, timo);
  466                                 if (error) {
  467                                         undo_upreq(lkp);
  468                                         break;
  469                                 }
  470                                 if (extflags & LK_SLEEPFAIL) {
  471                                         error = ENOLCK;
  472                                         undo_upreq(lkp);
  473                                         break;
  474                                 }
  475                         }
  476                         /* retry */
  477                 }
  478                 goto again;
  479 
  480         case LK_RELEASE:
  481                 /*
  482                  * Release the currently held lock.  If releasing the current
  483                  * lock as part of an error return, error will ALREADY be
  484                  * non-zero.
  485                  *
  486                  * When releasing the last lock we automatically transition
  487                  * LKC_UPREQ to LKC_EXCL|1.
  488                  *
  489                  * WARNING! We cannot detect when there are multiple exclusive
  490                  *          requests pending.  We clear EXREQ unconditionally
  491                  *          on the 1->0 transition so it is possible for
  492                  *          shared requests to race the next exclusive
  493                  *          request.
  494                  *
  495                  * Always succeeds.
  496                  */
  497                 if ((count & LKC_MASK) == 0)
  498                         panic("lockmgr: LK_RELEASE: no lock held");
  499 
  500                 if (count & LKC_EXCL) {
  501                         if (lkp->lk_lockholder != LK_KERNTHREAD &&
  502                             lkp->lk_lockholder != td) {
  503                                 panic("lockmgr: pid %d, not exlusive "
  504                                       "lock holder thr %p/%p unlocking",
  505                                     (td->td_proc ? td->td_proc->p_pid : -1),
  506                                     td, lkp->lk_lockholder);
  507                         }
  508                         if ((count & (LKC_UPREQ|LKC_MASK)) == 1) {
  509                                 /*
  510                                  * Last exclusive count is being released
  511                                  */
  512                                 otd = lkp->lk_lockholder;
  513                                 lkp->lk_lockholder = NULL;
  514                                 if (!atomic_cmpset_int(&lkp->lk_count, count,
  515                                               (count - 1) &
  516                                            ~(LKC_EXCL|LKC_EXREQ|LKC_SHREQ))) {
  517                                         lkp->lk_lockholder = otd;
  518                                         goto again;
  519                                 }
  520                                 if (count & (LKC_EXREQ|LKC_SHREQ))
  521                                         wakeup(lkp);
  522                                 /* success */
  523                         } else if ((count & (LKC_UPREQ|LKC_MASK)) ==
  524                                    (LKC_UPREQ | 1)) {
  525                                 /*
  526                                  * Last exclusive count is being released but
  527                                  * an upgrade request is present, automatically
  528                                  * grant an exclusive state to the owner of
  529                                  * the upgrade request.
  530                                  */
  531                                 otd = lkp->lk_lockholder;
  532                                 lkp->lk_lockholder = NULL;
  533                                 if (!atomic_cmpset_int(&lkp->lk_count, count,
  534                                                 (count & ~LKC_UPREQ) |
  535                                                 LKC_UPGRANT)) {
  536                                         lkp->lk_lockholder = otd;
  537                                 }
  538                                 wakeup(lkp);
  539                                 /* success */
  540                         } else {
  541                                 otd = lkp->lk_lockholder;
  542                                 if (!atomic_cmpset_int(&lkp->lk_count, count,
  543                                                        count - 1)) {
  544                                         goto again;
  545                                 }
  546                                 /* success */
  547                         }
  548                         /* success */
  549                         if (otd != LK_KERNTHREAD)
  550                                 COUNT(td, -1);
  551                 } else {
  552                         if ((count & (LKC_UPREQ|LKC_MASK)) == 1) {
  553                                 /*
  554                                  * Last shared count is being released.
  555                                  */
  556                                 if (!atomic_cmpset_int(&lkp->lk_count, count,
  557                                               (count - 1) &
  558                                                ~(LKC_EXREQ|LKC_SHREQ))) {
  559                                         goto again;
  560                                 }
  561                                 if (count & (LKC_EXREQ|LKC_SHREQ))
  562                                         wakeup(lkp);
  563                                 /* success */
  564                         } else if ((count & (LKC_UPREQ|LKC_MASK)) ==
  565                                    (LKC_UPREQ | 1)) {
  566                                 /*
  567                                  * Last shared count is being released but
  568                                  * an upgrade request is present, automatically
  569                                  * grant an exclusive state to the owner of
  570                                  * the upgrade request.
  571                                  */
  572                                 if (!atomic_cmpset_int(&lkp->lk_count, count,
  573                                               (count & ~LKC_UPREQ) |
  574                                               LKC_EXCL | LKC_UPGRANT)) {
  575                                         goto again;
  576                                 }
  577                                 wakeup(lkp);
  578                         } else {
  579                                 if (!atomic_cmpset_int(&lkp->lk_count, count,
  580                                                        count - 1)) {
  581                                         goto again;
  582                                 }
  583                         }
  584                         /* success */
  585                         COUNT(td, -1);
  586                 }
  587                 break;
  588 
  589         default:
  590                 panic("lockmgr: unknown locktype request %d",
  591                     flags & LK_TYPE_MASK);
  592                 /* NOTREACHED */
  593         }
  594         return (error);
  595 }
  596 
  597 /*
  598  * Undo an upgrade request
  599  */
  600 static
  601 void
  602 undo_upreq(struct lock *lkp)
  603 {
  604         int count;
  605 
  606         for (;;) {
  607                 count = lkp->lk_count;
  608                 cpu_ccfence();
  609                 if (count & LKC_UPGRANT) {
  610                         /*
  611                          * UPREQ was shifted to UPGRANT.  We own UPGRANT now,
  612                          * another thread might own UPREQ.  Clear UPGRANT
  613                          * and release the granted lock.
  614                          */
  615                         if (atomic_cmpset_int(&lkp->lk_count, count,
  616                                               count & ~LKC_UPGRANT)) {
  617                                 lockmgr(lkp, LK_RELEASE);
  618                                 break;
  619                         }
  620                 } else if (count & LKC_EXCL) {
  621                         /*
  622                          * Clear the UPREQ we still own.  Nobody to wakeup
  623                          * here because there is an existing exclusive
  624                          * holder.
  625                          */
  626                         KKASSERT(count & LKC_UPREQ);
  627                         KKASSERT((count & LKC_MASK) > 0);
  628                         if (atomic_cmpset_int(&lkp->lk_count, count,
  629                                               count & ~LKC_UPREQ)) {
  630                                 wakeup(lkp);
  631                                 break;
  632                         }
  633                 } else if (count & LKC_EXREQ) {
  634                         /*
  635                          * Clear the UPREQ we still own.  We cannot wakeup any
  636                          * shared waiters because there is an exclusive
  637                          * request pending.
  638                          */
  639                         KKASSERT(count & LKC_UPREQ);
  640                         KKASSERT((count & LKC_MASK) > 0);
  641                         if (atomic_cmpset_int(&lkp->lk_count, count,
  642                                               count & ~LKC_UPREQ)) {
  643                                 break;
  644                         }
  645                 } else {
  646                         /*
  647                          * Clear the UPREQ we still own.  Wakeup any shared
  648                          * waiters.
  649                          */
  650                         KKASSERT(count & LKC_UPREQ);
  651                         KKASSERT((count & LKC_MASK) > 0);
  652                         if (atomic_cmpset_int(&lkp->lk_count, count,
  653                                               count &
  654                                               ~(LKC_UPREQ | LKC_SHREQ))) {
  655                                 if (count & LKC_SHREQ)
  656                                         wakeup(lkp);
  657                                 break;
  658                         }
  659                 }
  660                 /* retry */
  661         }
  662 }
  663 
  664 void
  665 lockmgr_kernproc(struct lock *lp)
  666 {
  667         struct thread *td __debugvar = curthread;
  668 
  669         if (lp->lk_lockholder != LK_KERNTHREAD) {
  670                 KASSERT(lp->lk_lockholder == td,
  671                     ("lockmgr_kernproc: lock not owned by curthread %p", td));
  672                 lp->lk_lockholder = LK_KERNTHREAD;
  673                 COUNT(td, -1);
  674         }
  675 }
  676 
  677 /*
  678  * Initialize a lock; required before use.
  679  */
  680 void
  681 lockinit(struct lock *lkp, const char *wmesg, int timo, int flags)
  682 {
  683         lkp->lk_flags = (flags & LK_EXTFLG_MASK);
  684         lkp->lk_count = 0;
  685         lkp->lk_wmesg = wmesg;
  686         lkp->lk_timo = timo;
  687         lkp->lk_lockholder = LK_NOTHREAD;
  688 }
  689 
  690 /*
  691  * Reinitialize a lock that is being reused for a different purpose, but
  692  * which may have pending (blocked) threads sitting on it.  The caller
  693  * must already hold the interlock.
  694  */
  695 void
  696 lockreinit(struct lock *lkp, const char *wmesg, int timo, int flags)
  697 {
  698         lkp->lk_wmesg = wmesg;
  699         lkp->lk_timo = timo;
  700 }
  701 
  702 /*
  703  * De-initialize a lock.  The structure must no longer be used by anyone.
  704  */
  705 void
  706 lockuninit(struct lock *lkp)
  707 {
  708         KKASSERT((lkp->lk_count & (LKC_EXREQ|LKC_SHREQ|LKC_UPREQ)) == 0);
  709 }
  710 
  711 /*
  712  * Determine the status of a lock.
  713  */
  714 int
  715 lockstatus(struct lock *lkp, struct thread *td)
  716 {
  717         int lock_type = 0;
  718         int count;
  719 
  720         count = lkp->lk_count;
  721         cpu_ccfence();
  722 
  723         if (count & LKC_EXCL) {
  724                 if (td == NULL || lkp->lk_lockholder == td)
  725                         lock_type = LK_EXCLUSIVE;
  726                 else
  727                         lock_type = LK_EXCLOTHER;
  728         } else if (count & LKC_MASK) {
  729                 lock_type = LK_SHARED;
  730         }
  731         return (lock_type);
  732 }
  733 
  734 /*
  735  * Return non-zero if the caller owns the lock shared or exclusive.
  736  * We can only guess re: shared locks.
  737  */
  738 int
  739 lockowned(struct lock *lkp)
  740 {
  741         thread_t td = curthread;
  742         int count;
  743 
  744         count = lkp->lk_count;
  745         cpu_ccfence();
  746 
  747         if (count & LKC_EXCL)
  748                 return(lkp->lk_lockholder == td);
  749         else
  750                 return((count & LKC_MASK) != 0);
  751 }
  752 
  753 /*
  754  * Determine the number of holders of a lock.
  755  *
  756  * The non-blocking version can usually be used for assertions.
  757  */
  758 int
  759 lockcount(struct lock *lkp)
  760 {
  761         return(lkp->lk_count & LKC_MASK);
  762 }
  763 
  764 int
  765 lockcountnb(struct lock *lkp)
  766 {
  767         return(lkp->lk_count & LKC_MASK);
  768 }
  769 
  770 /*
  771  * Print out information about state of a lock. Used by VOP_PRINT
  772  * routines to display status about contained locks.
  773  */
  774 void
  775 lockmgr_printinfo(struct lock *lkp)
  776 {
  777         struct thread *td = lkp->lk_lockholder;
  778         struct proc *p;
  779         int count;
  780 
  781         count = lkp->lk_count;
  782         cpu_ccfence();
  783 
  784         if (td && td != LK_KERNTHREAD && td != LK_NOTHREAD)
  785                 p = td->td_proc;
  786         else
  787                 p = NULL;
  788 
  789         if (count & LKC_EXCL) {
  790                 kprintf(" lock type %s: EXCLUS (count %08x) by td %p pid %d",
  791                     lkp->lk_wmesg, count, td,
  792                     p ? p->p_pid : -99);
  793         } else if (count & LKC_MASK) {
  794                 kprintf(" lock type %s: SHARED (count %08x)",
  795                     lkp->lk_wmesg, count);
  796         } else {
  797                 kprintf(" lock type %s: NOTHELD", lkp->lk_wmesg);
  798         }
  799         if (count & (LKC_EXREQ|LKC_SHREQ))
  800                 kprintf(" with waiters\n");
  801         else
  802                 kprintf("\n");
  803 }
  804 
  805 void
  806 lock_sysinit(struct lock_args *arg)
  807 {
  808         lockinit(arg->la_lock, arg->la_desc, 0, arg->la_flags);
  809 }

Cache object: c37026def061e4324865e9b9b739a1f9


[ 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.