Clean up more #include files. Create an internal __boolean_t so two or
[dragonfly.git] / sys / sys / spinlock2.h
1 /*
2  * Copyright (c) 2005 Jeffrey M. Hsu.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Jeffrey M. Hsu.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of The DragonFly Project nor the names of its
16  *    contributors may be used to endorse or promote products derived
17  *    from this software without specific, prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $DragonFly: src/sys/sys/spinlock2.h,v 1.8 2006/05/21 03:43:47 dillon Exp $
33  */
34
35 #ifndef _SYS_SPINLOCK2_H_
36 #define _SYS_SPINLOCK2_H_
37
38 #ifndef _KERNEL
39
40 #error "This file should not be included by userland programs."
41
42 #else
43
44 #ifndef _SYS_THREAD2_H_
45 #include <sys/thread2.h>
46 #endif
47 #ifndef _MACHINE_ATOMIC_H_
48 #include <machine/atomic.h>
49 #endif
50 #ifndef _MACHINE_CPUFUNC_H_
51 #include <machine/cpufunc.h>
52 #endif
53
54 #ifdef SMP
55
56 #ifdef INVARIANTS
57
58 static __inline void
59 spin_lock_debug(thread_t td, int count)
60 {
61         td->td_spinlocks += count;
62 }
63
64 #endif
65
66 /*
67  * Attempt to obtain a spinlock on behalf of the specified thread.  Returns
68  * FALSE on failure, TRUE on success.
69  */
70 static __inline boolean_t
71 spin_trylock(thread_t td, struct spinlock *mtx)
72 {
73         if (atomic_swap_int(&mtx->lock, 1) == 0) {
74 #ifdef INVARIANTS
75                 spin_lock_debug(td, 1);
76 #endif
77                 return (TRUE);
78         }
79         return (FALSE);
80 }
81
82 /*
83  * Relase a spinlock obtained via spin_trylock() on behalf of the specified
84  * thread.  This function always succeeds.  It exists because the other
85  * standard release functions only operate on the current thread.
86  */
87 static __inline void
88 spin_tryunlock(thread_t td, struct spinlock *mtx)
89 {
90 #ifdef INVARIANTS
91         if (td->td_spinlocks <= 0)
92                 panic("spin_tryunlock: wasn't locked!");
93         spin_lock_debug(td, -1);
94 #endif
95         cpu_sfence();
96         mtx->lock = 0;          /* non-bus-locked lock release */
97 }
98
99 extern void spin_lock_contested(struct spinlock *mtx);
100
101 /*
102  * The quick versions should be used only if you are already
103  * in a critical section or you know the spinlock will never
104  * be used by an hard interrupt, IPI, or soft interrupt.
105  *
106  * Obtain a spinlock and return.
107  */
108 static __inline void
109 spin_lock_quick(struct spinlock *mtx)
110 {
111 #ifdef INVARIANTS
112         spin_lock_debug(curthread, 1);
113 #endif
114         if (atomic_swap_int(&mtx->lock, 1) != 0)
115                 spin_lock_contested(mtx);       /* slow path */
116 }
117
118 /*
119  * Release a spinlock previously obtained by the current thread.
120  */
121 static __inline void
122 spin_unlock_quick(struct spinlock *mtx)
123 {
124 #ifdef INVARIANTS
125         if (curthread->td_spinlocks <= 0)
126                 panic("spin_unlock_quick: wasn't locked!");
127         spin_lock_debug(curthread, -1);
128 #endif
129         cpu_sfence();
130         mtx->lock = 0;          /* non-bus-locked lock release */
131 }
132
133 /*
134  * Returns whether a spinlock is locked or not.  0 indicates not locked,
135  * non-zero indicates locked (by any thread, not necessarily the current
136  * thread).
137  */
138 static __inline boolean_t
139 spin_is_locked(struct spinlock *mtx)
140 {
141         return (mtx->lock);
142 }
143
144 static __inline void
145 spin_init(struct spinlock *mtx)
146 {
147         mtx->lock = 0;
148 }
149
150 static __inline void
151 spin_uninit(struct spinlock *mtx)
152 {
153         /* unused */
154 }
155
156 #else   /* SMP */
157
158 /*
159  * There is no spin_trylock(), spin_tryunlock(), or spin_is_locked()
160  * for UP builds.  These functions are used by the kernel only in
161  * situations where the spinlock actually has to work.
162  *
163  * We provide the rest of the calls for UP as degenerate inlines (note
164  * that the non-quick versions still obtain/release a critical section!).
165  * This way we don't have to have a billion #ifdef's floating around
166  * the rest of the kernel.
167  */
168
169 static __inline void    spin_lock_quick(struct spinlock *mtx) { }
170 static __inline void    spin_unlock_quick(struct spinlock *mtx) { }
171 static __inline void    spin_init(struct spinlock *mtx) { }
172
173 #endif  /* SMP */
174
175 /*
176  * The normal spin_lock() API automatically enters and exits a
177  * critical section, preventing deadlocks from interrupt preemption
178  * if the interrupt thread accesses the same spinlock.
179  */
180 static __inline void
181 spin_lock(struct spinlock *mtx)
182 {
183         crit_enter_id("spin");
184         spin_lock_quick(mtx);
185 }
186
187 static __inline void
188 spin_unlock(struct spinlock *mtx)
189 {
190         spin_unlock_quick(mtx);
191         crit_exit_id("spin");
192 }
193
194 #endif  /* _KERNEL */
195 #endif  /* _SYS_SPINLOCK2_H_ */
196