root/kern/kern_lock.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lock_printf
  2. lockinit
  3. lockstatus
  4. lockmgr
  5. lockmgr_printinfo
  6. simple_lock_init
  7. _simple_lock
  8. _simple_lock_held
  9. _simple_lock_try
  10. _simple_unlock
  11. simple_lock_dump
  12. simple_lock_freecheck
  13. simple_lock_switchcheck
  14. simple_lock_only_held
  15. _kernel_lock_init
  16. _kernel_lock
  17. _kernel_unlock
  18. _kernel_proc_lock
  19. _kernel_proc_unlock

    1 /*      $OpenBSD: kern_lock.c,v 1.30 2007/05/31 22:07:53 thib Exp $     */
    2 
    3 /* 
    4  * Copyright (c) 1995
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code contains ideas from software contributed to Berkeley by
    8  * Avadis Tevanian, Jr., Michael Wayne Young, and the Mach Operating
    9  * System project at Carnegie-Mellon University.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. Neither the name of the University nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  *
   35  *      @(#)kern_lock.c 8.18 (Berkeley) 5/21/95
   36  */
   37 
   38 #include <sys/param.h>
   39 #include <sys/proc.h>
   40 #include <sys/lock.h>
   41 #include <sys/systm.h>
   42 #include <sys/sched.h>
   43 
   44 #include <machine/cpu.h>
   45 
   46 #ifndef spllock
   47 #define spllock() splhigh()
   48 #endif
   49 
   50 #ifdef MULTIPROCESSOR
   51 #define CPU_NUMBER() cpu_number()
   52 #else
   53 #define CPU_NUMBER() 0
   54 #endif
   55 
   56 void record_stacktrace(int *, int);
   57 void playback_stacktrace(int *, int);
   58 
   59 /*
   60  * Locking primitives implementation.
   61  * Locks provide shared/exclusive synchronization.
   62  */
   63 
   64 #ifdef DDB /* { */
   65 #ifdef MULTIPROCESSOR
   66 int simple_lock_debugger = 1;   /* more serious on MP */
   67 #else
   68 int simple_lock_debugger = 0;
   69 #endif
   70 #define SLOCK_DEBUGGER()        if (simple_lock_debugger) Debugger()
   71 #define SLOCK_TRACE()                                                   \
   72         db_stack_trace_print((db_expr_t)__builtin_frame_address(0),     \
   73             TRUE, 65535, "", lock_printf);
   74 #else
   75 #define SLOCK_DEBUGGER()        /* nothing */
   76 #define SLOCK_TRACE()           /* nothing */
   77 #endif /* } */
   78 
   79 /*
   80  * Acquire a resource.
   81  */
   82 #define ACQUIRE(lkp, error, extflags, drain, wanted)                    \
   83 do {                                                                    \
   84         for (error = 0; wanted; ) {                                     \
   85                 if ((drain))                                            \
   86                         (lkp)->lk_flags |= LK_WAITDRAIN;                \
   87                 else                                                    \
   88                         (lkp)->lk_waitcount++;                          \
   89                 /* XXX Cast away volatile. */                           \
   90                 error = tsleep((drain) ?                                \
   91                     (void *)&(lkp)->lk_flags : (void *)(lkp),           \
   92                     (lkp)->lk_prio, (lkp)->lk_wmesg, (lkp)->lk_timo);   \
   93                 if ((drain) == 0)                                       \
   94                         (lkp)->lk_waitcount--;                          \
   95                 if (error)                                              \
   96                         break;                                          \
   97                 if ((extflags) & LK_SLEEPFAIL) {                        \
   98                         error = ENOLCK;                                 \
   99                         break;                                          \
  100                 }                                                       \
  101         }                                                               \
  102 } while (0)
  103 
  104 #define SETHOLDER(lkp, pid, cpu_id)                                     \
  105         (lkp)->lk_lockholder = (pid)
  106 
  107 #define WEHOLDIT(lkp, pid, cpu_id)                                      \
  108         (lkp)->lk_lockholder == (pid)
  109 
  110 #define WAKEUP_WAITER(lkp)                                              \
  111 do {                                                                    \
  112         if ((lkp)->lk_waitcount)                                {       \
  113                 /* XXX Cast away volatile. */                           \
  114                 wakeup((void *)(lkp));                                  \
  115         }                                                               \
  116 } while (/*CONSTCOND*/0)
  117 
  118 #if defined(LOCKDEBUG) /* { */
  119 #if defined(MULTIPROCESSOR) /* { */
  120 struct simplelock spinlock_list_slock = SIMPLELOCK_INITIALIZER;
  121 
  122 #define SPINLOCK_LIST_LOCK()                                            \
  123         __cpu_simple_lock(&spinlock_list_slock.lock_data)
  124 
  125 #define SPINLOCK_LIST_UNLOCK()                                          \
  126         __cpu_simple_unlock(&spinlock_list_slock.lock_data)
  127 #else
  128 #define SPINLOCK_LIST_LOCK()    /* nothing */
  129 
  130 #define SPINLOCK_LIST_UNLOCK()  /* nothing */
  131 #endif /* MULTIPROCESSOR */ /* } */
  132 
  133 TAILQ_HEAD(, lock) spinlock_list =
  134     TAILQ_HEAD_INITIALIZER(spinlock_list);
  135 #endif /* LOCKDEBUG */ /* } */
  136 
  137 #define HAVEIT(lkp)                                                     \
  138 do {                                                                    \
  139 } while (/*CONSTCOND*/0)
  140 
  141 #define DONTHAVEIT(lkp)                                                 \
  142 do {                                                                    \
  143 } while (/*CONSTCOND*/0)
  144 
  145 #if defined(LOCKDEBUG)
  146 /*
  147  * Lock debug printing routine; can be configured to print to console
  148  * or log to syslog.
  149  */
  150 void
  151 lock_printf(const char *fmt, ...)
  152 {
  153         char b[150];
  154         va_list ap;
  155 
  156         va_start(ap, fmt);
  157         if (lock_debug_syslog)
  158                 vlog(LOG_DEBUG, fmt, ap);
  159         else {
  160                 vsnprintf(b, sizeof(b), fmt, ap);
  161                 printf_nolog("%s", b);
  162         }
  163         va_end(ap);
  164 }
  165 #endif /* LOCKDEBUG */
  166 
  167 /*
  168  * Initialize a lock; required before use.
  169  */
  170 void
  171 lockinit(struct lock *lkp, int prio, char *wmesg, int timo, int flags)
  172 {
  173 
  174         bzero(lkp, sizeof(struct lock));
  175         lkp->lk_flags = flags & LK_EXTFLG_MASK;
  176         lkp->lk_lockholder = LK_NOPROC;
  177         lkp->lk_prio = prio;
  178         lkp->lk_timo = timo;
  179         lkp->lk_wmesg = wmesg;  /* just a name for spin locks */
  180 #if defined(LOCKDEBUG)
  181         lkp->lk_lock_file = NULL;
  182         lkp->lk_unlock_file = NULL;
  183 #endif
  184 }
  185 
  186 /*
  187  * Determine the status of a lock.
  188  */
  189 int
  190 lockstatus(struct lock *lkp)
  191 {
  192         int lock_type = 0;
  193 
  194         if (lkp->lk_exclusivecount != 0)
  195                 lock_type = LK_EXCLUSIVE;
  196         else if (lkp->lk_sharecount != 0)
  197                 lock_type = LK_SHARED;
  198         return (lock_type);
  199 }
  200 
  201 /*
  202  * Set, change, or release a lock.
  203  *
  204  * Shared requests increment the shared count. Exclusive requests set the
  205  * LK_WANT_EXCL flag (preventing further shared locks), and wait for already
  206  * accepted shared locks and shared-to-exclusive upgrades to go away.
  207  */
  208 int
  209 lockmgr(__volatile struct lock *lkp, u_int flags, struct simplelock *interlkp)
  210 {
  211         int error;
  212         pid_t pid;
  213         int extflags;
  214         cpuid_t cpu_id;
  215         struct proc *p = curproc;
  216 
  217         error = 0;
  218         extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK;
  219 
  220 #ifdef DIAGNOSTIC
  221         if (p == NULL)
  222                 panic("lockmgr: process context required");
  223 #endif          
  224         /* Process context required. */
  225         pid = p->p_pid;
  226         cpu_id = CPU_NUMBER();
  227 
  228         /*
  229          * Once a lock has drained, the LK_DRAINING flag is set and an
  230          * exclusive lock is returned. The only valid operation thereafter
  231          * is a single release of that exclusive lock. This final release
  232          * clears the LK_DRAINING flag and sets the LK_DRAINED flag. Any
  233          * further requests of any sort will result in a panic. The bits
  234          * selected for these two flags are chosen so that they will be set
  235          * in memory that is freed (freed memory is filled with 0xdeadbeef).
  236          */
  237         if (lkp->lk_flags & (LK_DRAINING|LK_DRAINED)) {
  238 #ifdef DIAGNOSTIC
  239                 if (lkp->lk_flags & LK_DRAINED)
  240                         panic("lockmgr: using decommissioned lock");
  241                 if ((flags & LK_TYPE_MASK) != LK_RELEASE ||
  242                     WEHOLDIT(lkp, pid, cpu_id) == 0)
  243                         panic("lockmgr: non-release on draining lock: %d",
  244                             flags & LK_TYPE_MASK);
  245 #endif /* DIAGNOSTIC */
  246                 lkp->lk_flags &= ~LK_DRAINING;
  247                 lkp->lk_flags |= LK_DRAINED;
  248         }
  249 
  250         /*
  251          * Check if the caller is asking us to be schizophrenic.
  252          */
  253         if ((lkp->lk_flags & (LK_CANRECURSE|LK_RECURSEFAIL)) ==
  254             (LK_CANRECURSE|LK_RECURSEFAIL))
  255                 panic("lockmgr: make up your mind");
  256 
  257         switch (flags & LK_TYPE_MASK) {
  258 
  259         case LK_SHARED:
  260                 if (WEHOLDIT(lkp, pid, cpu_id) == 0) {
  261                         /*
  262                          * If just polling, check to see if we will block.
  263                          */
  264                         if ((extflags & LK_NOWAIT) && (lkp->lk_flags &
  265                             (LK_HAVE_EXCL | LK_WANT_EXCL))) {
  266                                 error = EBUSY;
  267                                 break;
  268                         }
  269                         /*
  270                          * Wait for exclusive locks and upgrades to clear.
  271                          */
  272                         ACQUIRE(lkp, error, extflags, 0, lkp->lk_flags &
  273                             (LK_HAVE_EXCL | LK_WANT_EXCL));
  274                         if (error)
  275                                 break;
  276                         lkp->lk_sharecount++;
  277                         break;
  278                 }
  279                 /*
  280                  * We hold an exclusive lock, so downgrade it to shared.
  281                  * An alternative would be to fail with EDEADLK.
  282                  */
  283                 lkp->lk_sharecount++;
  284 
  285                 if (WEHOLDIT(lkp, pid, cpu_id) == 0 ||
  286                     lkp->lk_exclusivecount == 0)
  287                         panic("lockmgr: not holding exclusive lock");
  288                 lkp->lk_sharecount += lkp->lk_exclusivecount;
  289                 lkp->lk_exclusivecount = 0;
  290                 lkp->lk_flags &= ~LK_HAVE_EXCL;
  291                 SETHOLDER(lkp, LK_NOPROC, LK_NOCPU);
  292 #if defined(LOCKDEBUG)
  293                 lkp->lk_unlock_file = file;
  294                 lkp->lk_unlock_line = line;
  295 #endif
  296                 DONTHAVEIT(lkp);
  297                 WAKEUP_WAITER(lkp);
  298                 break;
  299 
  300         case LK_EXCLUSIVE:
  301                 if (WEHOLDIT(lkp, pid, cpu_id)) {
  302                         /*
  303                          * Recursive lock.
  304                          */
  305                         if ((extflags & LK_CANRECURSE) == 0) {
  306                                 if (extflags & LK_RECURSEFAIL) {
  307                                         error = EDEADLK;
  308                                         break;
  309                                 } else
  310                                         panic("lockmgr: locking against myself");
  311                         }
  312                         lkp->lk_exclusivecount++;
  313                         break;
  314                 }
  315                 /*
  316                  * If we are just polling, check to see if we will sleep.
  317                  */
  318                 if ((extflags & LK_NOWAIT) && ((lkp->lk_flags &
  319                      (LK_HAVE_EXCL | LK_WANT_EXCL)) ||
  320                      lkp->lk_sharecount != 0)) {
  321                         error = EBUSY;
  322                         break;
  323                 }
  324                 /*
  325                  * Try to acquire the want_exclusive flag.
  326                  */
  327                 ACQUIRE(lkp, error, extflags, 0, lkp->lk_flags &
  328                     (LK_HAVE_EXCL | LK_WANT_EXCL));
  329                 if (error)
  330                         break;
  331                 lkp->lk_flags |= LK_WANT_EXCL;
  332                 /*
  333                  * Wait for shared locks and upgrades to finish.
  334                  */
  335                 ACQUIRE(lkp, error, extflags, 0, lkp->lk_sharecount != 0);
  336                 lkp->lk_flags &= ~LK_WANT_EXCL;
  337                 if (error)
  338                         break;
  339                 lkp->lk_flags |= LK_HAVE_EXCL;
  340                 SETHOLDER(lkp, pid, cpu_id);
  341 #if defined(LOCKDEBUG)
  342                 lkp->lk_lock_file = file;
  343                 lkp->lk_lock_line = line;
  344 #endif
  345                 HAVEIT(lkp);
  346                 if (lkp->lk_exclusivecount != 0)
  347                         panic("lockmgr: non-zero exclusive count");
  348                 lkp->lk_exclusivecount = 1;
  349                 break;
  350 
  351         case LK_RELEASE:
  352                 if (lkp->lk_exclusivecount != 0) {
  353                         if (WEHOLDIT(lkp, pid, cpu_id) == 0) {
  354                                 panic("lockmgr: pid %d, not exclusive lock "
  355                                     "holder %d unlocking",
  356                                     pid, lkp->lk_lockholder);
  357                         }
  358                         lkp->lk_exclusivecount--;
  359                         if (lkp->lk_exclusivecount == 0) {
  360                                 lkp->lk_flags &= ~LK_HAVE_EXCL;
  361                                 SETHOLDER(lkp, LK_NOPROC, LK_NOCPU);
  362 #if defined(LOCKDEBUG)
  363                                 lkp->lk_unlock_file = file;
  364                                 lkp->lk_unlock_line = line;
  365 #endif
  366                                 DONTHAVEIT(lkp);
  367                         }
  368                 } else if (lkp->lk_sharecount != 0) {
  369                         lkp->lk_sharecount--;
  370                 }
  371 #ifdef DIAGNOSTIC
  372                 else
  373                         panic("lockmgr: release of unlocked lock!");
  374 #endif
  375                 WAKEUP_WAITER(lkp);
  376                 break;
  377 
  378         case LK_DRAIN:
  379                 /*
  380                  * Check that we do not already hold the lock, as it can 
  381                  * never drain if we do. Unfortunately, we have no way to
  382                  * check for holding a shared lock, but at least we can
  383                  * check for an exclusive one.
  384                  */
  385                 if (WEHOLDIT(lkp, pid, cpu_id))
  386                         panic("lockmgr: draining against myself");
  387                 /*
  388                  * If we are just polling, check to see if we will sleep.
  389                  */
  390                 if ((extflags & LK_NOWAIT) && ((lkp->lk_flags &
  391                      (LK_HAVE_EXCL | LK_WANT_EXCL)) ||
  392                      lkp->lk_sharecount != 0 || lkp->lk_waitcount != 0)) {
  393                         error = EBUSY;
  394                         break;
  395                 }
  396                 ACQUIRE(lkp, error, extflags, 1,
  397                     ((lkp->lk_flags &
  398                      (LK_HAVE_EXCL | LK_WANT_EXCL)) ||
  399                      lkp->lk_sharecount != 0 ||
  400                      lkp->lk_waitcount != 0));
  401                 if (error)
  402                         break;
  403                 lkp->lk_flags |= LK_DRAINING | LK_HAVE_EXCL;
  404                 SETHOLDER(lkp, pid, cpu_id);
  405 #if defined(LOCKDEBUG)
  406                 lkp->lk_lock_file = file;
  407                 lkp->lk_lock_line = line;
  408 #endif
  409                 HAVEIT(lkp);
  410                 lkp->lk_exclusivecount = 1;
  411                 break;
  412 
  413         default:
  414                 panic("lockmgr: unknown locktype request %d",
  415                     flags & LK_TYPE_MASK);
  416                 /* NOTREACHED */
  417         }
  418         if ((lkp->lk_flags & LK_WAITDRAIN) != 0 &&
  419             ((lkp->lk_flags &
  420             (LK_HAVE_EXCL | LK_WANT_EXCL)) == 0 &&
  421             lkp->lk_sharecount == 0 && lkp->lk_waitcount == 0)) {
  422                 lkp->lk_flags &= ~LK_WAITDRAIN;
  423                 wakeup((void *)&lkp->lk_flags);
  424         }
  425         return (error);
  426 }
  427 
  428 #ifdef DIAGNOSTIC
  429 /*
  430  * Print out information about state of a lock. Used by VOP_PRINT
  431  * routines to display ststus about contained locks.
  432  */
  433 void
  434 lockmgr_printinfo(__volatile struct lock *lkp)
  435 {
  436 
  437         if (lkp->lk_sharecount)
  438                 printf(" lock type %s: SHARED (count %d)", lkp->lk_wmesg,
  439                     lkp->lk_sharecount);
  440         else if (lkp->lk_flags & LK_HAVE_EXCL) {
  441                 printf(" lock type %s: EXCL (count %d) by ",
  442                     lkp->lk_wmesg, lkp->lk_exclusivecount);
  443                 printf("pid %d", lkp->lk_lockholder);
  444         } else
  445                 printf(" not locked");
  446         if (lkp->lk_waitcount > 0)
  447                 printf(" with %d pending", lkp->lk_waitcount);
  448 }
  449 #endif /* DIAGNOSTIC */
  450 
  451 #if defined(LOCKDEBUG)
  452 TAILQ_HEAD(, simplelock) simplelock_list =
  453     TAILQ_HEAD_INITIALIZER(simplelock_list);
  454 
  455 #if defined(MULTIPROCESSOR) /* { */
  456 struct simplelock simplelock_list_slock = SIMPLELOCK_INITIALIZER;
  457 
  458 #define SLOCK_LIST_LOCK()                                               \
  459         __cpu_simple_lock(&simplelock_list_slock.lock_data)
  460 
  461 #define SLOCK_LIST_UNLOCK()                                             \
  462         __cpu_simple_unlock(&simplelock_list_slock.lock_data)
  463 
  464 #define SLOCK_COUNT(x)                                                  \
  465         curcpu()->ci_simple_locks += (x)
  466 #else
  467 u_long simple_locks;
  468 
  469 #define SLOCK_LIST_LOCK()       /* nothing */
  470 
  471 #define SLOCK_LIST_UNLOCK()     /* nothing */
  472 
  473 #define SLOCK_COUNT(x)          simple_locks += (x)
  474 #endif /* MULTIPROCESSOR */ /* } */
  475 
  476 #ifdef MULTIPROCESSOR
  477 #define SLOCK_MP()              lock_printf("on cpu %ld\n",             \
  478                                     (u_long) cpu_number())
  479 #else
  480 #define SLOCK_MP()              /* nothing */
  481 #endif
  482 
  483 #define SLOCK_WHERE(str, alp, id, l)                                    \
  484 do {                                                                    \
  485         lock_printf("\n");                                              \
  486         lock_printf(str);                                               \
  487         lock_printf("lock: %p, currently at: %s:%d\n", (alp), (id), (l)); \
  488         SLOCK_MP();                                                     \
  489         if ((alp)->lock_file != NULL)                                   \
  490                 lock_printf("last locked: %s:%d\n", (alp)->lock_file,   \
  491                     (alp)->lock_line);                                  \
  492         if ((alp)->unlock_file != NULL)                                 \
  493                 lock_printf("last unlocked: %s:%d\n", (alp)->unlock_file, \
  494                     (alp)->unlock_line);                                \
  495         SLOCK_TRACE()                                                   \
  496         SLOCK_DEBUGGER();                                               \
  497 } while (/*CONSTCOND*/0)
  498 
  499 /*
  500  * Simple lock functions so that the debugger can see from whence
  501  * they are being called.
  502  */
  503 void
  504 simple_lock_init(struct simplelock *lkp)
  505 {
  506 
  507 #if defined(MULTIPROCESSOR) /* { */
  508         __cpu_simple_lock_init(&alp->lock_data);
  509 #else
  510         alp->lock_data = __SIMPLELOCK_UNLOCKED;
  511 #endif /* } */
  512         alp->lock_file = NULL;
  513         alp->lock_line = 0;
  514         alp->unlock_file = NULL;
  515         alp->unlock_line = 0;
  516         alp->lock_holder = LK_NOCPU;
  517 }
  518 
  519 void
  520 _simple_lock(__volatile struct simplelock *lkp, const char *id, int l)
  521 {
  522         cpuid_t cpu_id = CPU_NUMBER();
  523         int s;
  524 
  525         s = spllock();
  526 
  527         /*
  528          * MULTIPROCESSOR case: This is `safe' since if it's not us, we
  529          * don't take any action, and just fall into the normal spin case.
  530          */
  531         if (alp->lock_data == __SIMPLELOCK_LOCKED) {
  532 #if defined(MULTIPROCESSOR) /* { */
  533                 if (alp->lock_holder == cpu_id) {
  534                         SLOCK_WHERE("simple_lock: locking against myself\n",
  535                             alp, id, l);
  536                         goto out;
  537                 }
  538 #else
  539                 SLOCK_WHERE("simple_lock: lock held\n", alp, id, l);
  540                 goto out;
  541 #endif /* MULTIPROCESSOR */ /* } */
  542         }
  543 
  544 #if defined(MULTIPROCESSOR) /* { */
  545         /* Acquire the lock before modifying any fields. */
  546         splx(s);
  547         __cpu_simple_lock(&alp->lock_data);
  548         s = spllock();
  549 #else
  550         alp->lock_data = __SIMPLELOCK_LOCKED;
  551 #endif /* } */
  552 
  553         if (alp->lock_holder != LK_NOCPU) {
  554                 SLOCK_WHERE("simple_lock: uninitialized lock\n",
  555                     alp, id, l);
  556         }
  557         alp->lock_file = id;
  558         alp->lock_line = l;
  559         alp->lock_holder = cpu_id;
  560 
  561         SLOCK_LIST_LOCK();
  562         /* XXX Cast away volatile */
  563         TAILQ_INSERT_TAIL(&simplelock_list, (struct simplelock *)alp, list);
  564         SLOCK_LIST_UNLOCK();
  565 
  566         SLOCK_COUNT(1);
  567 
  568  out:
  569         splx(s);
  570 }
  571 
  572 int
  573 _simple_lock_held(__volatile struct simplelock *alp)
  574 {
  575         cpuid_t cpu_id = CPU_NUMBER();
  576         int s, locked = 0;
  577 
  578         s = spllock();
  579 
  580 #if defined(MULTIPROCESSOR)
  581         if (__cpu_simple_lock_try(&alp->lock_data) == 0)
  582                 locked = (alp->lock_holder == cpu_id);
  583         else
  584                 __cpu_simple_unlock(&alp->lock_data);
  585 #else
  586         if (alp->lock_data == __SIMPLELOCK_LOCKED) {
  587                 locked = 1;
  588                 KASSERT(alp->lock_holder == cpu_id);
  589         }
  590 #endif
  591 
  592         splx(s);
  593 
  594         return (locked);
  595 }
  596 
  597 int
  598 _simple_lock_try(__volatile struct simplelock *lkp, const char *id, int l)
  599 {
  600         cpuid_t cpu_id = CPU_NUMBER();
  601         int s, rv = 0;
  602 
  603         s = spllock();
  604 
  605         /*
  606          * MULTIPROCESSOR case: This is `safe' since if it's not us, we
  607          * don't take any action.
  608          */
  609 #if defined(MULTIPROCESSOR) /* { */
  610         if ((rv = __cpu_simple_lock_try(&alp->lock_data)) == 0) {
  611                 if (alp->lock_holder == cpu_id)
  612                         SLOCK_WHERE("simple_lock_try: locking against myself\n",
  613                             alp, id, l);
  614                 goto out;
  615         }
  616 #else
  617         if (alp->lock_data == __SIMPLELOCK_LOCKED) {
  618                 SLOCK_WHERE("simple_lock_try: lock held\n", alp, id, l);
  619                 goto out;
  620         }
  621         alp->lock_data = __SIMPLELOCK_LOCKED;
  622 #endif /* MULTIPROCESSOR */ /* } */
  623 
  624         /*
  625          * At this point, we have acquired the lock.
  626          */
  627 
  628         rv = 1;
  629 
  630         alp->lock_file = id;
  631         alp->lock_line = l;
  632         alp->lock_holder = cpu_id;
  633 
  634         SLOCK_LIST_LOCK();
  635         /* XXX Cast away volatile. */
  636         TAILQ_INSERT_TAIL(&simplelock_list, (struct simplelock *)alp, list);
  637         SLOCK_LIST_UNLOCK();
  638 
  639         SLOCK_COUNT(1);
  640 
  641  out:
  642         splx(s);
  643         return (rv);
  644 }
  645 
  646 void
  647 _simple_unlock(__volatile struct simplelock *lkp, const char *id, int l)
  648 {
  649         int s;
  650 
  651         s = spllock();
  652 
  653         /*
  654          * MULTIPROCESSOR case: This is `safe' because we think we hold
  655          * the lock, and if we don't, we don't take any action.
  656          */
  657         if (alp->lock_data == __SIMPLELOCK_UNLOCKED) {
  658                 SLOCK_WHERE("simple_unlock: lock not held\n",
  659                     alp, id, l);
  660                 goto out;
  661         }
  662 
  663         SLOCK_LIST_LOCK();
  664         TAILQ_REMOVE(&simplelock_list, alp, list);
  665         SLOCK_LIST_UNLOCK();
  666 
  667         SLOCK_COUNT(-1);
  668 
  669         alp->list.tqe_next = NULL;      /* sanity */
  670         alp->list.tqe_prev = NULL;      /* sanity */
  671 
  672         alp->unlock_file = id;
  673         alp->unlock_line = l;
  674 
  675 #if defined(MULTIPROCESSOR) /* { */
  676         alp->lock_holder = LK_NOCPU;
  677         /* Now that we've modified all fields, release the lock. */
  678         __cpu_simple_unlock(&alp->lock_data);
  679 #else
  680         alp->lock_data = __SIMPLELOCK_UNLOCKED;
  681         KASSERT(alp->lock_holder == CPU_NUMBER());
  682         alp->lock_holder = LK_NOCPU;
  683 #endif /* } */
  684 
  685  out:
  686         splx(s);
  687 }
  688 
  689 void
  690 simple_lock_dump(void)
  691 {
  692         struct simplelock *alp;
  693         int s;
  694 
  695         s = spllock();
  696         SLOCK_LIST_LOCK();
  697         lock_printf("all simple locks:\n");
  698         TAILQ_FOREACH(alp, &simplelock_list, list) {
  699                 lock_printf("%p CPU %lu %s:%d\n", alp, alp->lock_holder,
  700                     alp->lock_file, alp->lock_line);
  701         }
  702         SLOCK_LIST_UNLOCK();
  703         splx(s);
  704 }
  705 
  706 void
  707 simple_lock_freecheck(void *start, void *end)
  708 {
  709         struct simplelock *alp;
  710         int s;
  711 
  712         s = spllock();
  713         SLOCK_LIST_LOCK();
  714         TAILQ_FOREACH(alp, &simplelock_list, list) {
  715                 if ((void *)alp >= start && (void *)alp < end) {
  716                         lock_printf("freeing simple_lock %p CPU %lu %s:%d\n",
  717                             alp, alp->lock_holder, alp->lock_file,
  718                             alp->lock_line);
  719                         SLOCK_DEBUGGER();
  720                 }
  721         }
  722         SLOCK_LIST_UNLOCK();
  723         splx(s);
  724  }
  725 
  726 /*
  727  * We must be holding exactly one lock: the sched_lock.
  728  */
  729 
  730 #ifdef notyet
  731 void
  732 simple_lock_switchcheck(void)
  733 {
  734 
  735         simple_lock_only_held(&sched_lock, "switching");
  736 }
  737 #endif
  738 
  739 void
  740 simple_lock_only_held(volatile struct simplelock *lp, const char *where)
  741 {
  742         struct simplelock *alp;
  743         cpuid_t cpu_id = CPU_NUMBER();
  744         int s;
  745 
  746         if (lp) {
  747                 LOCK_ASSERT(simple_lock_held(lp));
  748         }
  749         s = spllock();
  750         SLOCK_LIST_LOCK();
  751         TAILQ_FOREACH(alp, &simplelock_list, list) {
  752                 if (alp == lp)
  753                         continue;
  754                 if (alp->lock_holder == cpu_id)
  755                         break;
  756         }
  757         SLOCK_LIST_UNLOCK();
  758         splx(s);
  759 
  760         if (alp != NULL) {
  761                 lock_printf("\n%s with held simple_lock %p "
  762                     "CPU %lu %s:%d\n",
  763                     where, alp, alp->lock_holder, alp->lock_file,
  764                     alp->lock_line);
  765                 SLOCK_TRACE();
  766                 SLOCK_DEBUGGER();
  767         }
  768 }
  769 #endif /* LOCKDEBUG */
  770 
  771 #if defined(MULTIPROCESSOR)
  772 /*
  773  * Functions for manipulating the kernel_lock.  We put them here
  774  * so that they show up in profiles.
  775  */
  776 
  777 struct __mp_lock kernel_lock; 
  778 
  779 void
  780 _kernel_lock_init(void)
  781 {
  782         __mp_lock_init(&kernel_lock);
  783 }
  784 
  785 /*
  786  * Acquire/release the kernel lock.  Intended for use in the scheduler
  787  * and the lower half of the kernel.
  788  */
  789 
  790 void
  791 _kernel_lock(void)
  792 {
  793         SCHED_ASSERT_UNLOCKED();
  794         __mp_lock(&kernel_lock);
  795 }
  796 
  797 void
  798 _kernel_unlock(void)
  799 {
  800         __mp_unlock(&kernel_lock);
  801 }
  802 
  803 /*
  804  * Acquire/release the kernel_lock on behalf of a process.  Intended for
  805  * use in the top half of the kernel.
  806  */
  807 void
  808 _kernel_proc_lock(struct proc *p)
  809 {
  810         SCHED_ASSERT_UNLOCKED();
  811         __mp_lock(&kernel_lock);
  812         atomic_setbits_int(&p->p_flag, P_BIGLOCK);
  813 }
  814 
  815 void
  816 _kernel_proc_unlock(struct proc *p)
  817 {
  818         atomic_clearbits_int(&p->p_flag, P_BIGLOCK);
  819         __mp_unlock(&kernel_lock);
  820 }
  821 
  822 #ifdef MP_LOCKDEBUG
  823 /* CPU-dependent timing, needs this to be settable from ddb. */
  824 int __mp_lock_spinout = 200000000;
  825 #endif
  826 
  827 #endif /* MULTIPROCESSOR */

/* [<][>][^][v][top][bottom][index][help] */