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/vm/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) 1991, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * This code is derived from software contributed to Berkeley by
    6  * The Mach Operating System project at Carnegie-Mellon University.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by the University of
   19  *      California, Berkeley and its contributors.
   20  * 4. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      from: @(#)kern_lock.c   8.1 (Berkeley) 6/11/93
   37  *
   38  *
   39  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
   40  * All rights reserved.
   41  *
   42  * Authors: Avadis Tevanian, Jr., Michael Wayne Young
   43  *
   44  * Permission to use, copy, modify and distribute this software and
   45  * its documentation is hereby granted, provided that both the copyright
   46  * notice and this permission notice appear in all copies of the
   47  * software, derivative works or modified versions, and any portions
   48  * thereof, and that both notices appear in supporting documentation.
   49  *
   50  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   51  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
   52  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   53  *
   54  * Carnegie Mellon requests users of this software to return to
   55  *
   56  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   57  *  School of Computer Science
   58  *  Carnegie Mellon University
   59  *  Pittsburgh PA 15213-3890
   60  *
   61  * any improvements or extensions that they make and grant Carnegie the
   62  * rights to redistribute these changes.
   63  *
   64  * $FreeBSD: src/sys/vm/kern_lock.c,v 1.10.4.1 1999/09/05 08:24:16 peter Exp $
   65  */
   66 
   67 /*
   68  *      Locking primitives implementation
   69  */
   70 
   71 #include <sys/param.h>
   72 #include <sys/systm.h>
   73 
   74 /* XXX */
   75 #include <sys/proc.h>
   76 
   77 #include <vm/vm.h>
   78 #include <vm/vm_param.h>
   79 #include <vm/vm_prot.h>
   80 #include <vm/lock.h>
   81 
   82 /*
   83  *      Routine:        lock_init
   84  *      Function:
   85  *              Initialize a lock; required before use.
   86  *              Note that clients declare the "struct lock"
   87  *              variables and then initialize them, rather
   88  *              than getting a new one from this module.
   89  */
   90 void
   91 lock_init(l, can_sleep)
   92         lock_t l;
   93         boolean_t can_sleep;
   94 {
   95         l->want_write = 0;
   96         l->want_upgrade = 0;
   97         l->waiting = 0;
   98         l->can_sleep = can_sleep;
   99         l->read_count = 0;
  100         l->proc = NULL;
  101         l->recursion_depth = 0;
  102 }
  103 
  104 void
  105 lock_sleepable(l, can_sleep)
  106         lock_t l;
  107         boolean_t can_sleep;
  108 {
  109         l->can_sleep = can_sleep;
  110 }
  111 
  112 
  113 /*
  114  *      Sleep locks.  These use the same data structure and algorithm
  115  *      as the spin locks, but the process sleeps while it is waiting
  116  *      for the lock.  These work on uniprocessor systems.
  117  */
  118 
  119 void
  120 lock_write(l)
  121         register lock_t l;
  122 {
  123         if (l->proc == curproc) {
  124                 /*
  125                  * Recursive lock.
  126                  */
  127                 l->recursion_depth++;
  128                 return;
  129         }
  130         /*
  131          * Try to acquire the want_write bit.
  132          */
  133         while (l->want_write) {
  134                 if (l->can_sleep && l->want_write) {
  135                         l->waiting = TRUE;
  136                         tsleep(l, PVM, "lckwt1", 0);
  137                 }
  138         }
  139         l->want_write = TRUE;
  140 
  141         /* Wait for readers (and upgrades) to finish */
  142 
  143         while ((l->read_count != 0) || l->want_upgrade) {
  144                 if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) {
  145                         l->waiting = TRUE;
  146                         tsleep(l, PVM, "lckwt2", 0);
  147                 }
  148         }
  149 }
  150 
  151 void
  152 lock_done(l)
  153         register lock_t l;
  154 {
  155         if (l->read_count != 0)
  156                 l->read_count--;
  157         else if (l->recursion_depth != 0)
  158                 l->recursion_depth--;
  159         else if (l->want_upgrade)
  160                 l->want_upgrade = FALSE;
  161         else
  162                 l->want_write = FALSE;
  163 
  164         if (l->waiting) {
  165                 l->waiting = FALSE;
  166                 wakeup(l);
  167         }
  168 }
  169 
  170 void
  171 lock_read(l)
  172         register lock_t l;
  173 {
  174         if (l->proc == curproc) {
  175                 /*
  176                  * Recursive lock.
  177                  */
  178                 l->read_count++;
  179                 return;
  180         }
  181         while (l->want_write || l->want_upgrade) {
  182                 if (l->can_sleep && (l->want_write || l->want_upgrade)) {
  183                         l->waiting = TRUE;
  184                         tsleep(l, PVM, "lockrd", 0);
  185                 }
  186         }
  187 
  188         l->read_count++;
  189 }
  190 
  191 /*
  192  *      Routine:        lock_read_to_write
  193  *      Function:
  194  *              Improves a read-only lock to one with
  195  *              write permission.  If another reader has
  196  *              already requested an upgrade to a write lock,
  197  *              no lock is held upon return.
  198  *
  199  *              Returns TRUE if the upgrade *failed*.
  200  */
  201 boolean_t
  202 lock_read_to_write(l)
  203         register lock_t l;
  204 {
  205         l->read_count--;
  206 
  207         if (l->proc == curproc) {
  208                 /*
  209                  * Recursive lock.
  210                  */
  211                 l->recursion_depth++;
  212                 return (FALSE);
  213         }
  214         if (l->want_upgrade) {
  215                 /*
  216                  * Someone else has requested upgrade. Since we've released a
  217                  * read lock, wake him up.
  218                  */
  219                 if (l->waiting) {
  220                         l->waiting = FALSE;
  221                         wakeup(l);
  222                 }
  223                 return (TRUE);
  224         }
  225         l->want_upgrade = TRUE;
  226 
  227         while (l->read_count != 0) {
  228                 if (l->can_sleep && l->read_count != 0) {
  229                         l->waiting = TRUE;
  230                         tsleep(l, PVM, "lckrw", 0);
  231                 }
  232         }
  233 
  234         return (FALSE);
  235 }
  236 
  237 void
  238 lock_write_to_read(l)
  239         register lock_t l;
  240 {
  241         l->read_count++;
  242         if (l->recursion_depth != 0)
  243                 l->recursion_depth--;
  244         else if (l->want_upgrade)
  245                 l->want_upgrade = FALSE;
  246         else
  247                 l->want_write = FALSE;
  248 
  249         if (l->waiting) {
  250                 l->waiting = FALSE;
  251                 wakeup(l);
  252         }
  253 }
  254 
  255 
  256 /*
  257  *      Routine:        lock_try_write
  258  *      Function:
  259  *              Tries to get a write lock.
  260  *
  261  *              Returns FALSE if the lock is not held on return.
  262  */
  263 
  264 boolean_t
  265 lock_try_write(l)
  266         register lock_t l;
  267 {
  268         if (l->proc == curproc) {
  269                 /*
  270                  * Recursive lock
  271                  */
  272                 l->recursion_depth++;
  273                 return (TRUE);
  274         }
  275         if (l->want_write || l->want_upgrade || l->read_count) {
  276                 /*
  277                  * Can't get lock.
  278                  */
  279                 return (FALSE);
  280         }
  281         /*
  282          * Have lock.
  283          */
  284 
  285         l->want_write = TRUE;
  286         return (TRUE);
  287 }
  288 
  289 /*
  290  *      Routine:        lock_try_read
  291  *      Function:
  292  *              Tries to get a read lock.
  293  *
  294  *              Returns FALSE if the lock is not held on return.
  295  */
  296 
  297 boolean_t
  298 lock_try_read(l)
  299         register lock_t l;
  300 {
  301         if (l->proc == curproc) {
  302                 /*
  303                  * Recursive lock
  304                  */
  305                 l->read_count++;
  306                 return (TRUE);
  307         }
  308         if (l->want_write || l->want_upgrade) {
  309                 return (FALSE);
  310         }
  311         l->read_count++;
  312         return (TRUE);
  313 }
  314 
  315 /*
  316  *      Routine:        lock_try_read_to_write
  317  *      Function:
  318  *              Improves a read-only lock to one with
  319  *              write permission.  If another reader has
  320  *              already requested an upgrade to a write lock,
  321  *              the read lock is still held upon return.
  322  *
  323  *              Returns FALSE if the upgrade *failed*.
  324  */
  325 boolean_t
  326 lock_try_read_to_write(l)
  327         register lock_t l;
  328 {
  329         if (l->proc == curproc) {
  330                 /*
  331                  * Recursive lock
  332                  */
  333                 l->read_count--;
  334                 l->recursion_depth++;
  335                 return (TRUE);
  336         }
  337         if (l->want_upgrade) {
  338                 return (FALSE);
  339         }
  340         l->want_upgrade = TRUE;
  341         l->read_count--;
  342 
  343         while (l->read_count != 0) {
  344                 l->waiting = TRUE;
  345                 tsleep(l, PVM, "lcktrw", 0);
  346         }
  347 
  348         return (TRUE);
  349 }
  350 
  351 /*
  352  *      Allow a process that has a lock for write to acquire it
  353  *      recursively (for read, write, or update).
  354  */
  355 void
  356 lock_set_recursive(l)
  357         lock_t l;
  358 {
  359         if (!l->want_write) {
  360                 panic("lock_set_recursive: don't have write lock");
  361         }
  362         l->proc = curproc;
  363 }
  364 
  365 /*
  366  *      Prevent a lock from being re-acquired.
  367  */
  368 void
  369 lock_clear_recursive(l)
  370         lock_t l;
  371 {
  372         if (l->proc != curproc) {
  373                 panic("lock_clear_recursive: wrong proc");
  374         }
  375         if (l->recursion_depth == 0)
  376                 l->proc = NULL;
  377 }

Cache object: a53259c2ddbfebcd7b53f3daa94a985f


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