root/kern/thread/spinlock.c

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

DEFINITIONS

This source file includes following definitions.
  1. spinlock_init
  2. spinlock_cleanup
  3. spinlock_acquire
  4. spinlock_release
  5. spinlock_do_i_hold

   1 /*
   2  * Copyright (c) 2009
   3  *      The President and Fellows of Harvard College.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the University nor the names of its contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 /* Make sure to build out-of-line versions of spinlock inline functions */
  31 #define SPINLOCK_INLINE   /* empty */
  32 
  33 #include <types.h>
  34 #include <lib.h>
  35 #include <cpu.h>
  36 #include <spl.h>
  37 #include <spinlock.h>
  38 #include <current.h>    /* for curcpu */
  39 
  40 /*
  41  * Spinlocks.
  42  */
  43 
  44 
  45 /*
  46  * Initialize spinlock.
  47  */
  48 void
  49 spinlock_init(struct spinlock *lk)
  50 {
  51         spinlock_data_set(&lk->lk_lock, 0);
  52         lk->lk_holder = NULL;
  53 }
  54 
  55 /*
  56  * Clean up spinlock.
  57  */
  58 void
  59 spinlock_cleanup(struct spinlock *lk)
  60 {
  61         KASSERT(lk->lk_holder == NULL);
  62         KASSERT(spinlock_data_get(&lk->lk_lock) == 0);
  63 }
  64 
  65 /*
  66  * Get the lock.
  67  *
  68  * First disable interrupts (otherwise, if we get a timer interrupt we
  69  * might come back to this lock and deadlock), then use a machine-level
  70  * atomic operation to wait for the lock to be free.
  71  */
  72 void
  73 spinlock_acquire(struct spinlock *lk)
  74 {
  75         struct cpu *mycpu;
  76 
  77         splraise(IPL_NONE, IPL_HIGH);
  78 
  79         /* this must work before curcpu initialization */
  80         if (CURCPU_EXISTS()) {
  81                 mycpu = curcpu->c_self;
  82                 if (lk->lk_holder == mycpu) {
  83                         panic("Deadlock on spinlock %p\n", lk);
  84                 }
  85         }
  86         else {
  87                 mycpu = NULL;
  88         }
  89 
  90         while (1) {
  91                 /*
  92                  * Do test-test-and-set, that is, read first before
  93                  * doing test-and-set, to reduce bus contention.
  94                  *
  95                  * Test-and-set is a machine-level atomic operation
  96                  * that writes 1 into the lock word and returns the
  97                  * previous value. If that value was 0, the lock was
  98                  * previously unheld and we now own it. If it was 1,
  99                  * we don't.
 100                  */
 101                 if (spinlock_data_get(&lk->lk_lock) != 0) {
 102                         continue;
 103                 }
 104                 if (spinlock_data_testandset(&lk->lk_lock) != 0) {
 105                         continue;
 106                 }
 107                 break;
 108         }
 109 
 110         lk->lk_holder = mycpu;
 111 }
 112 
 113 /*
 114  * Release the lock.
 115  */
 116 void
 117 spinlock_release(struct spinlock *lk)
 118 {
 119         /* this must work before curcpu initialization */
 120         if (CURCPU_EXISTS()) {
 121                 KASSERT(lk->lk_holder == curcpu->c_self);
 122         }
 123 
 124         lk->lk_holder = NULL;
 125         spinlock_data_set(&lk->lk_lock, 0);
 126         spllower(IPL_HIGH, IPL_NONE);
 127 }
 128 
 129 /*
 130  * Check if the current cpu holds the lock.
 131  */ 
 132 bool
 133 spinlock_do_i_hold(struct spinlock *lk)
 134 {
 135         if (!CURCPU_EXISTS()) {
 136                 return true;
 137         }
 138 
 139         /* Assume we can read lk_holder atomically enough for this to work */
 140         return (lk->lk_holder == curcpu->c_self);
 141 }

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