/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- spinlock_init
- spinlock_cleanup
- spinlock_acquire
- spinlock_release
- 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 }