8d5c72c641f65bc34f7f16bf378544067ffd2017
[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 KIRQL
93 NTAPI
94 KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
95 {
96 KIRQL OldIrql;
97
98 /* Raise IRQL */
99 KeRaiseIrql(Interrupt->SynchronizeIrql, &OldIrql);
100
101 /* Acquire spinlock on MP */
102 KeAcquireSpinLockAtDpcLevel(Interrupt->ActualLock);
103 return OldIrql;
104 }
105
106 /*
107 * @implemented
108 */
109 VOID
110 NTAPI
111 KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt,
112 IN KIRQL OldIrql)
113 {
114 /* Release lock on MP */
115 KeReleaseSpinLockFromDpcLevel(Interrupt->ActualLock);
116
117 /* Lower IRQL */
118 KeLowerIrql(OldIrql);
119 }
120
121 /*
122 * @implemented
123 */
124 VOID
125 NTAPI
126 _KeInitializeSpinLock(IN PKSPIN_LOCK SpinLock)
127 {
128 /* Clear it */
129 *SpinLock = 0;
130 }
131
132 /*
133 * @implemented
134 */
135 #undef KeAcquireSpinLockAtDpcLevel
136 VOID
137 NTAPI
138 KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
139 {
140 /* Do the inlined function */
141 KxAcquireSpinLock(SpinLock);
142 }
143
144 /*
145 * @implemented
146 */
147 #undef KeReleaseSpinLockFromDpcLevel
148 VOID
149 NTAPI
150 KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
151 {
152 /* Do the lined function */
153 KxReleaseSpinLock(SpinLock);
154 }
155
156 /*
157 * @implemented
158 */
159 VOID
160 FASTCALL
161 KefAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
162 {
163 /* Do the inlined function */
164 KxAcquireSpinLock(SpinLock);
165 }
166
167 /*
168 * @implemented
169 */
170 VOID
171 FASTCALL
172 KefReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
173 {
174 /* Do the lined function */
175 KxReleaseSpinLock(SpinLock);
176 }
177
178 /*
179 * @implemented
180 */
181 VOID
182 FASTCALL
183 KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
184 {
185 /* Do the inlined function */
186 KxAcquireSpinLock(SpinLock);
187 }
188
189 /*
190 * @implemented
191 */
192 VOID
193 FASTCALL
194 KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
195 {
196 /* Do the lined function */
197 KxReleaseSpinLock(SpinLock);
198 }
199
200 /*
201 * @implemented
202 */
203 BOOLEAN
204 FASTCALL
205 KeTryToAcquireSpinLockAtDpcLevel(IN OUT PKSPIN_LOCK SpinLock)
206 {
207 #ifdef CONFIG_SMP
208 /* Check if it's already acquired */
209 if (!(*SpinLock))
210 {
211 /* Try to acquire it */
212 if (InterlockedBitTestAndSet((PLONG)SpinLock, 0))
213 {
214 /* Someone else acquired it */
215 return FALSE;
216 }
217 }
218 else
219 {
220 /* It was already acquired */
221 return FALSE;
222 }
223
224 #if DBG
225 /* On debug builds, we OR in the KTHREAD */
226 *SpinLock = (ULONG_PTR)KeGetCurrentThread() | 1;
227 #endif
228 #endif
229
230 /* All is well, return TRUE */
231 return TRUE;
232 }
233
234 /*
235 * @implemented
236 */
237 VOID
238 FASTCALL
239 KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock,
240 IN PKLOCK_QUEUE_HANDLE LockHandle)
241 {
242 #ifdef CONFIG_SMP
243 /* Set it up properly */
244 LockHandle->LockQueue.Next = NULL;
245 LockHandle->LockQueue.Lock = SpinLock;
246 KeAcquireQueuedSpinLockAtDpcLevel(LockHandle->LockQueue.Next);
247 #endif
248 }
249
250 /*
251 * @implemented
252 */
253 VOID
254 FASTCALL
255 KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle)
256 {
257 #ifdef CONFIG_SMP
258 /* Call the internal function */
259 KeReleaseQueuedSpinLockFromDpcLevel(LockHandle->LockQueue.Next);
260 #endif
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 */