home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / vm / kern_lock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-21  |  11.7 KB  |  534 lines

  1. /* 
  2.  * Copyright (c) 1991 Regents of the University of California.
  3.  * 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.  *    @(#)kern_lock.c    7.4 (Berkeley) 4/21/91
  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.  
  65. /*
  66.  *    Locking primitives implementation
  67.  */
  68.  
  69. #include "param.h"
  70. #include "vm_param.h"
  71. #include "lock.h"
  72.  
  73. /* XXX */
  74. #include "proc.h"
  75. typedef    int *thread_t;
  76. #define    current_thread()    ((thread_t)&curproc->p_thread)
  77. /* XXX */
  78.  
  79. #if    NCPUS > 1
  80.  
  81. /*
  82.  *    Module:        lock
  83.  *    Function:
  84.  *        Provide reader/writer sychronization.
  85.  *    Implementation:
  86.  *        Simple interlock on a bit.  Readers first interlock
  87.  *        increment the reader count, then let go.  Writers hold
  88.  *        the interlock (thus preventing further readers), and
  89.  *        wait for already-accepted readers to go away.
  90.  */
  91.  
  92. /*
  93.  *    The simple-lock routines are the primitives out of which
  94.  *    the lock package is built.  The implementation is left
  95.  *    to the machine-dependent code.
  96.  */
  97.  
  98. #ifdef    notdef
  99. /*
  100.  *    A sample implementation of simple locks.
  101.  *    assumes:
  102.  *        boolean_t test_and_set(boolean_t *)
  103.  *            indivisibly sets the boolean to TRUE
  104.  *            and returns its old value
  105.  *        and that setting a boolean to FALSE is indivisible.
  106.  */
  107. /*
  108.  *    simple_lock_init initializes a simple lock.  A simple lock
  109.  *    may only be used for exclusive locks.
  110.  */
  111.  
  112. void simple_lock_init(l)
  113.     simple_lock_t    l;
  114. {
  115.     *(boolean_t *)l = FALSE;
  116. }
  117.  
  118. void simple_lock(l)
  119.     simple_lock_t    l;
  120. {
  121.     while (test_and_set((boolean_t *)l))
  122.         continue;
  123. }
  124.  
  125. void simple_unlock(l)
  126.     simple_lock_t    l;
  127. {
  128.     *(boolean_t *)l = FALSE;
  129. }
  130.  
  131. boolean_t simple_lock_try(l)
  132.     simple_lock_t    l;
  133. {
  134.         return (!test_and_set((boolean_t *)l));
  135. }
  136. #endif    notdef
  137. #endif    NCPUS > 1
  138.  
  139. #if    NCPUS > 1
  140. int lock_wait_time = 100;
  141. #else    NCPUS > 1
  142.  
  143.     /*
  144.      *     It is silly to spin on a uni-processor as if we
  145.      *    thought something magical would happen to the
  146.      *    want_write bit while we are executing.
  147.      */
  148. int lock_wait_time = 0;
  149. #endif    NCPUS > 1
  150.  
  151.  
  152. /*
  153.  *    Routine:    lock_init
  154.  *    Function:
  155.  *        Initialize a lock; required before use.
  156.  *        Note that clients declare the "struct lock"
  157.  *        variables and then initialize them, rather
  158.  *        than getting a new one from this module.
  159.  */
  160. void lock_init(l, can_sleep)
  161.     lock_t        l;
  162.     boolean_t    can_sleep;
  163. {
  164.     bzero(l, sizeof(lock_data_t));
  165.     simple_lock_init(&l->interlock);
  166.     l->want_write = FALSE;
  167.     l->want_upgrade = FALSE;
  168.     l->read_count = 0;
  169.     l->can_sleep = can_sleep;
  170.     l->thread = (char *)-1;        /* XXX */
  171.     l->recursion_depth = 0;
  172. }
  173.  
  174. void lock_sleepable(l, can_sleep)
  175.     lock_t        l;
  176.     boolean_t    can_sleep;
  177. {
  178.     simple_lock(&l->interlock);
  179.     l->can_sleep = can_sleep;
  180.     simple_unlock(&l->interlock);
  181. }
  182.  
  183.  
  184. /*
  185.  *    Sleep locks.  These use the same data structure and algorithm
  186.  *    as the spin locks, but the process sleeps while it is waiting
  187.  *    for the lock.  These work on uniprocessor systems.
  188.  */
  189.  
  190. void lock_write(l)
  191.     register lock_t    l;
  192. {
  193.     register int    i;
  194.  
  195.     simple_lock(&l->interlock);
  196.  
  197.     if (((thread_t)l->thread) == current_thread()) {
  198.         /*
  199.          *    Recursive lock.
  200.          */
  201.         l->recursion_depth++;
  202.         simple_unlock(&l->interlock);
  203.         return;
  204.     }
  205.  
  206.     /*
  207.      *    Try to acquire the want_write bit.
  208.      */
  209.     while (l->want_write) {
  210.         if ((i = lock_wait_time) > 0) {
  211.             simple_unlock(&l->interlock);
  212.             while (--i > 0 && l->want_write)
  213.                 continue;
  214.             simple_lock(&l->interlock);
  215.         }
  216.  
  217.         if (l->can_sleep && l->want_write) {
  218.             l->waiting = TRUE;
  219.             thread_sleep((int) l, &l->interlock, FALSE);
  220.             simple_lock(&l->interlock);
  221.         }
  222.     }
  223.     l->want_write = TRUE;
  224.  
  225.     /* Wait for readers (and upgrades) to finish */
  226.  
  227.     while ((l->read_count != 0) || l->want_upgrade) {
  228.         if ((i = lock_wait_time) > 0) {
  229.             simple_unlock(&l->interlock);
  230.             while (--i > 0 && (l->read_count != 0 ||
  231.                     l->want_upgrade))
  232.                 continue;
  233.             simple_lock(&l->interlock);
  234.         }
  235.  
  236.         if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) {
  237.             l->waiting = TRUE;
  238.             thread_sleep((int) l, &l->interlock, FALSE);
  239.             simple_lock(&l->interlock);
  240.         }
  241.     }
  242.     simple_unlock(&l->interlock);
  243. }
  244.  
  245. void lock_done(l)
  246.     register lock_t    l;
  247. {
  248.     simple_lock(&l->interlock);
  249.  
  250.     if (l->read_count != 0)
  251.         l->read_count--;
  252.     else
  253.     if (l->recursion_depth != 0)
  254.         l->recursion_depth--;
  255.     else
  256.     if (l->want_upgrade)
  257.          l->want_upgrade = FALSE;
  258.     else
  259.          l->want_write = FALSE;
  260.  
  261.     if (l->waiting) {
  262.         l->waiting = FALSE;
  263.         thread_wakeup((int) l);
  264.     }
  265.     simple_unlock(&l->interlock);
  266. }
  267.  
  268. void lock_read(l)
  269.     register lock_t    l;
  270. {
  271.     register int    i;
  272.  
  273.     simple_lock(&l->interlock);
  274.  
  275.     if (((thread_t)l->thread) == current_thread()) {
  276.         /*
  277.          *    Recursive lock.
  278.          */
  279.         l->read_count++;
  280.         simple_unlock(&l->interlock);
  281.         return;
  282.     }
  283.  
  284.     while (l->want_write || l->want_upgrade) {
  285.         if ((i = lock_wait_time) > 0) {
  286.             simple_unlock(&l->interlock);
  287.             while (--i > 0 && (l->want_write || l->want_upgrade))
  288.                 continue;
  289.             simple_lock(&l->interlock);
  290.         }
  291.  
  292.         if (l->can_sleep && (l->want_write || l->want_upgrade)) {
  293.             l->waiting = TRUE;
  294.             thread_sleep((int) l, &l->interlock, FALSE);
  295.             simple_lock(&l->interlock);
  296.         }
  297.     }
  298.  
  299.     l->read_count++;
  300.     simple_unlock(&l->interlock);
  301. }
  302.  
  303. /*
  304.  *    Routine:    lock_read_to_write
  305.  *    Function:
  306.  *        Improves a read-only lock to one with
  307.  *        write permission.  If another reader has
  308.  *        already requested an upgrade to a write lock,
  309.  *        no lock is held upon return.
  310.  *
  311.  *        Returns TRUE if the upgrade *failed*.
  312.  */
  313. boolean_t lock_read_to_write(l)
  314.     register lock_t    l;
  315. {
  316.     register int    i;
  317.  
  318.     simple_lock(&l->interlock);
  319.  
  320.     l->read_count--;
  321.  
  322.     if (((thread_t)l->thread) == current_thread()) {
  323.         /*
  324.          *    Recursive lock.
  325.          */
  326.         l->recursion_depth++;
  327.         simple_unlock(&l->interlock);
  328.         return(FALSE);
  329.     }
  330.  
  331.     if (l->want_upgrade) {
  332.         /*
  333.          *    Someone else has requested upgrade.
  334.          *    Since we've released a read lock, wake
  335.          *    him up.
  336.          */
  337.         if (l->waiting) {
  338.             l->waiting = FALSE;
  339.             thread_wakeup((int) l);
  340.         }
  341.  
  342.         simple_unlock(&l->interlock);
  343.         return (TRUE);
  344.     }
  345.  
  346.     l->want_upgrade = TRUE;
  347.  
  348.     while (l->read_count != 0) {
  349.         if ((i = lock_wait_time) > 0) {
  350.             simple_unlock(&l->interlock);
  351.             while (--i > 0 && l->read_count != 0)
  352.                 continue;
  353.             simple_lock(&l->interlock);
  354.         }
  355.  
  356.         if (l->can_sleep && l->read_count != 0) {
  357.             l->waiting = TRUE;
  358.             thread_sleep((int) l, &l->interlock, FALSE);
  359.             simple_lock(&l->interlock);
  360.         }
  361.     }
  362.  
  363.     simple_unlock(&l->interlock);
  364.     return (FALSE);
  365. }
  366.  
  367. void lock_write_to_read(l)
  368.     register lock_t    l;
  369. {
  370.     simple_lock(&l->interlock);
  371.  
  372.     l->read_count++;
  373.     if (l->recursion_depth != 0)
  374.         l->recursion_depth--;
  375.     else
  376.     if (l->want_upgrade)
  377.         l->want_upgrade = FALSE;
  378.     else
  379.          l->want_write = FALSE;
  380.  
  381.     if (l->waiting) {
  382.         l->waiting = FALSE;
  383.         thread_wakeup((int) l);
  384.     }
  385.  
  386.     simple_unlock(&l->interlock);
  387. }
  388.  
  389.  
  390. /*
  391.  *    Routine:    lock_try_write
  392.  *    Function:
  393.  *        Tries to get a write lock.
  394.  *
  395.  *        Returns FALSE if the lock is not held on return.
  396.  */
  397.  
  398. boolean_t lock_try_write(l)
  399.     register lock_t    l;
  400. {
  401.  
  402.     simple_lock(&l->interlock);
  403.  
  404.     if (((thread_t)l->thread) == current_thread()) {
  405.         /*
  406.          *    Recursive lock
  407.          */
  408.         l->recursion_depth++;
  409.         simple_unlock(&l->interlock);
  410.         return(TRUE);
  411.     }
  412.  
  413.     if (l->want_write || l->want_upgrade || l->read_count) {
  414.         /*
  415.          *    Can't get lock.
  416.          */
  417.         simple_unlock(&l->interlock);
  418.         return(FALSE);
  419.     }
  420.  
  421.     /*
  422.      *    Have lock.
  423.      */
  424.  
  425.     l->want_write = TRUE;
  426.     simple_unlock(&l->interlock);
  427.     return(TRUE);
  428. }
  429.  
  430. /*
  431.  *    Routine:    lock_try_read
  432.  *    Function:
  433.  *        Tries to get a read lock.
  434.  *
  435.  *        Returns FALSE if the lock is not held on return.
  436.  */
  437.  
  438. boolean_t lock_try_read(l)
  439.     register lock_t    l;
  440. {
  441.     simple_lock(&l->interlock);
  442.  
  443.     if (((thread_t)l->thread) == current_thread()) {
  444.         /*
  445.          *    Recursive lock
  446.          */
  447.         l->read_count++;
  448.         simple_unlock(&l->interlock);
  449.         return(TRUE);
  450.     }
  451.  
  452.     if (l->want_write || l->want_upgrade) {
  453.         simple_unlock(&l->interlock);
  454.         return(FALSE);
  455.     }
  456.  
  457.     l->read_count++;
  458.     simple_unlock(&l->interlock);
  459.     return(TRUE);
  460. }
  461.  
  462. /*
  463.  *    Routine:    lock_try_read_to_write
  464.  *    Function:
  465.  *        Improves a read-only lock to one with
  466.  *        write permission.  If another reader has
  467.  *        already requested an upgrade to a write lock,
  468.  *        the read lock is still held upon return.
  469.  *
  470.  *        Returns FALSE if the upgrade *failed*.
  471.  */
  472. boolean_t lock_try_read_to_write(l)
  473.     register lock_t    l;
  474. {
  475.  
  476.     simple_lock(&l->interlock);
  477.  
  478.     if (((thread_t)l->thread) == current_thread()) {
  479.         /*
  480.          *    Recursive lock
  481.          */
  482.         l->read_count--;
  483.         l->recursion_depth++;
  484.         simple_unlock(&l->interlock);
  485.         return(TRUE);
  486.     }
  487.  
  488.     if (l->want_upgrade) {
  489.         simple_unlock(&l->interlock);
  490.         return(FALSE);
  491.     }
  492.     l->want_upgrade = TRUE;
  493.     l->read_count--;
  494.  
  495.     while (l->read_count != 0) {
  496.         l->waiting = TRUE;
  497.         thread_sleep((int) l, &l->interlock, FALSE);
  498.         simple_lock(&l->interlock);
  499.     }
  500.  
  501.     simple_unlock(&l->interlock);
  502.     return(TRUE);
  503. }
  504.  
  505. /*
  506.  *    Allow a process that has a lock for write to acquire it
  507.  *    recursively (for read, write, or update).
  508.  */
  509. void lock_set_recursive(l)
  510.     lock_t        l;
  511. {
  512.     simple_lock(&l->interlock);
  513.     if (!l->want_write) {
  514.         panic("lock_set_recursive: don't have write lock");
  515.     }
  516.     l->thread = (char *) current_thread();
  517.     simple_unlock(&l->interlock);
  518. }
  519.  
  520. /*
  521.  *    Prevent a lock from being re-acquired.
  522.  */
  523. void lock_clear_recursive(l)
  524.     lock_t        l;
  525. {
  526.     simple_lock(&l->interlock);
  527.     if (((thread_t) l->thread) != current_thread()) {
  528.         panic("lock_clear_recursive: wrong thread");
  529.     }
  530.     if (l->recursion_depth == 0)
  531.         l->thread = (char *)-1;        /* XXX */
  532.     simple_unlock(&l->interlock);
  533. }
  534.