- In Win32 DBG is defined to 0 for a non-debug build and to 1 for a debug build....
[reactos.git] / reactos / ntoskrnl / ke / spinlock.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/spinlock.c
5 * PURPOSE: Spinlock and Queued Spinlock Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #define LQ_WAIT 1
16 #define LQ_OWN 2
17
18 /* PRIVATE FUNCTIONS *********************************************************/
19
20 VOID
21 FASTCALL
22 KeAcquireQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle)
23 {
24 #ifdef CONFIG_SMP
25 PKSPIN_LOCK_QUEUE Prev;
26
27 /* Set the new lock */
28 Prev = (PKSPIN_LOCK_QUEUE)
29 InterlockedExchange((PLONG)LockHandle->Next,
30 (LONG)LockHandle);
31 if (!Prev)
32 {
33 /* There was nothing there before. We now own it */
34 *LockHandle->Lock |= LQ_OWN;
35 return;
36 }
37
38 /* Set the wait flag */
39 *LockHandle->Lock |= LQ_WAIT;
40
41 /* Link us */
42 Prev->Next = (PKSPIN_LOCK_QUEUE)LockHandle;
43
44 /* Loop and wait */
45 while (*LockHandle->Lock & LQ_WAIT)
46 YieldProcessor();
47 #endif
48 }
49
50 VOID
51 FASTCALL
52 KeReleaseQueuedSpinLockFromDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle)
53 {
54 #ifdef CONFIG_SMP
55 KSPIN_LOCK LockVal;
56 PKSPIN_LOCK_QUEUE Waiter;
57
58 /* Remove own and wait flags */
59 *LockHandle->Lock &= ~(LQ_OWN | LQ_WAIT);
60 LockVal = *LockHandle->Lock;
61
62 /* Check if we already own it */
63 if (LockVal == (KSPIN_LOCK)LockHandle)
64 {
65 /* Disown it */
66 LockVal = (KSPIN_LOCK)
67 InterlockedCompareExchangePointer(LockHandle->Lock,
68 NULL,
69 LockHandle);
70 }
71 if (LockVal == (KSPIN_LOCK)LockHandle) return;
72
73 /* Need to wait for it */
74 Waiter = LockHandle->Next;
75 while (!Waiter)
76 {
77 YieldProcessor();
78 Waiter = LockHandle->Next;
79 }
80
81 /* It's gone */
82 *(ULONG_PTR*)&Waiter->Lock ^= (LQ_OWN | LQ_WAIT);
83 LockHandle->Next = NULL;
84 #endif
85 }
86
87 /* PUBLIC FUNCTIONS **********************************************************/
88
89 /*
90 * @implemented
91 */
92 VOID
93 NTAPI
94 KeInitializeSpinLock(IN PKSPIN_LOCK SpinLock)
95 {
96 /* Clear it */
97 *SpinLock = 0;
98 }
99
100 /*
101 * @implemented
102 */
103 #undef KeAcquireSpinLockAtDpcLevel
104 VOID
105 NTAPI
106 KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
107 {
108 /* Do the inlined function */
109 KxAcquireSpinLock(SpinLock);
110 }
111
112 /*
113 * @implemented
114 */
115 #undef KeReleaseSpinLockFromDpcLevel
116 VOID
117 NTAPI
118 KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
119 {
120 /* Do the lined function */
121 KxReleaseSpinLock(SpinLock);
122 }
123
124 /*
125 * @implemented
126 */
127 VOID
128 FASTCALL
129 KefAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
130 {
131 /* Do the inlined function */
132 KxAcquireSpinLock(SpinLock);
133 }
134
135 /*
136 * @implemented
137 */
138 VOID
139 FASTCALL
140 KefReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
141 {
142 /* Do the lined function */
143 KxReleaseSpinLock(SpinLock);
144 }
145
146 /*
147 * @implemented
148 */
149 VOID
150 FASTCALL
151 KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
152 {
153 /* Do the inlined function */
154 KxAcquireSpinLock(SpinLock);
155 }
156
157 /*
158 * @implemented
159 */
160 VOID
161 FASTCALL
162 KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
163 {
164 /* Do the lined function */
165 KxReleaseSpinLock(SpinLock);
166 }
167
168 /*
169 * @implemented
170 */
171 BOOLEAN
172 FASTCALL
173 KeTryToAcquireSpinLockAtDpcLevel(IN OUT PKSPIN_LOCK SpinLock)
174 {
175 #ifdef CONFIG_SMP
176 /* Check if it's already acquired */
177 if (!(*SpinLock))
178 {
179 /* Try to acquire it */
180 if (InterlockedBitTestAndSet((PLONG)SpinLock, 0))
181 {
182 /* Someone else acquired it */
183 return FALSE;
184 }
185 }
186 else
187 {
188 /* It was already acquired */
189 return FALSE;
190 }
191
192 #if DBG
193 /* On debug builds, we OR in the KTHREAD */
194 *SpinLock = (ULONG_PTR)KeGetCurrentThread() | 1;
195 #endif
196 #endif
197
198 /* All is well, return TRUE */
199 return TRUE;
200 }
201
202 /*
203 * @implemented
204 */
205 VOID
206 FASTCALL
207 KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock,
208 IN PKLOCK_QUEUE_HANDLE LockHandle)
209 {
210 #ifdef CONFIG_SMP
211 /* Set it up properly */
212 LockHandle->LockQueue.Next = NULL;
213 LockHandle->LockQueue.Lock = SpinLock;
214 KeAcquireQueuedSpinLockAtDpcLevel(LockHandle->LockQueue.Next);
215 #endif
216 }
217
218 /*
219 * @implemented
220 */
221 VOID
222 FASTCALL
223 KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle)
224 {
225 #ifdef CONFIG_SMP
226 /* Call the internal function */
227 KeReleaseQueuedSpinLockFromDpcLevel(LockHandle->LockQueue.Next);
228 #endif
229 }
230
231 /*
232 * @implemented
233 */
234 KIRQL
235 NTAPI
236 KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
237 {
238 KIRQL OldIrql;
239
240 /* Raise IRQL */
241 KeRaiseIrql(Interrupt->SynchronizeIrql, &OldIrql);
242
243 /* Acquire spinlock on MP */
244 KefAcquireSpinLockAtDpcLevel(Interrupt->ActualLock);
245 return OldIrql;
246 }
247
248 /*
249 * @implemented
250 */
251 VOID
252 NTAPI
253 KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt,
254 IN KIRQL OldIrql)
255 {
256 /* Release lock on MP */
257 KefReleaseSpinLockFromDpcLevel(Interrupt->ActualLock);
258
259 /* Lower IRQL */
260 KeLowerIrql(OldIrql);
261 }
262
263 /*
264 * @unimplemented
265 */
266 KIRQL
267 FASTCALL
268 KeAcquireSpinLockForDpc(IN PKSPIN_LOCK SpinLock)
269 {
270 UNIMPLEMENTED;
271 return 0;
272 }
273
274 /*
275 * @unimplemented
276 */
277 VOID
278 FASTCALL
279 KeReleaseSpinLockForDpc(IN PKSPIN_LOCK SpinLock,
280 IN KIRQL OldIrql)
281 {
282 UNIMPLEMENTED;
283 }
284
285 /*
286 * @unimplemented
287 */
288 KIRQL
289 FASTCALL
290 KeAcquireInStackQueuedSpinLockForDpc(IN PKSPIN_LOCK SpinLock,
291 IN PKLOCK_QUEUE_HANDLE LockHandle)
292 {
293 UNIMPLEMENTED;
294 return 0;
295 }
296
297 /*
298 * @unimplemented
299 */
300 VOID
301 FASTCALL
302 KeReleaseInStackQueuedSpinLockForDpc(IN PKLOCK_QUEUE_HANDLE LockHandle)
303 {
304 UNIMPLEMENTED;
305 }
306
307 /*
308 * @implemented
309 */
310 BOOLEAN
311 FASTCALL
312 KeTestSpinLock(IN PKSPIN_LOCK SpinLock)
313 {
314 /* Test this spinlock */
315 if (*SpinLock)
316 {
317 /* Spinlock is busy, yield execution */
318 YieldProcessor();
319
320 /* Return busy flag */
321 return FALSE;
322 }
323
324 /* Spinlock appears to be free */
325 return TRUE;
326 }
327
328 /* EOF */