Sync to trunk head (r42241)
[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 #ifdef _X86_
90 /*
91 * @implemented
92 */
93 KIRQL
94 NTAPI
95 KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
96 {
97 KIRQL OldIrql;
98
99 /* Raise IRQL */
100 KeRaiseIrql(Interrupt->SynchronizeIrql, &OldIrql);
101
102 /* Acquire spinlock on MP */
103 KeAcquireSpinLockAtDpcLevel(Interrupt->ActualLock);
104 return OldIrql;
105 }
106
107 /*
108 * @implemented
109 */
110 VOID
111 NTAPI
112 KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt,
113 IN KIRQL OldIrql)
114 {
115 /* Release lock on MP */
116 KeReleaseSpinLockFromDpcLevel(Interrupt->ActualLock);
117
118 /* Lower IRQL */
119 KeLowerIrql(OldIrql);
120 }
121
122 /*
123 * @implemented
124 */
125 VOID
126 NTAPI
127 _KeInitializeSpinLock(IN PKSPIN_LOCK SpinLock)
128 {
129 /* Clear it */
130 *SpinLock = 0;
131 }
132 #endif
133
134 /*
135 * @implemented
136 */
137 #undef KeAcquireSpinLockAtDpcLevel
138 VOID
139 NTAPI
140 KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
141 {
142 /* Do the inlined function */
143 KxAcquireSpinLock(SpinLock);
144 }
145
146 /*
147 * @implemented
148 */
149 #undef KeReleaseSpinLockFromDpcLevel
150 VOID
151 NTAPI
152 KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
153 {
154 /* Do the lined function */
155 KxReleaseSpinLock(SpinLock);
156 }
157
158 /*
159 * @implemented
160 */
161 VOID
162 FASTCALL
163 KefAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
164 {
165 /* Do the inlined function */
166 KxAcquireSpinLock(SpinLock);
167 }
168
169 /*
170 * @implemented
171 */
172 VOID
173 FASTCALL
174 KefReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
175 {
176 /* Do the lined function */
177 KxReleaseSpinLock(SpinLock);
178 }
179
180 /*
181 * @implemented
182 */
183 VOID
184 FASTCALL
185 KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
186 {
187 /* Do the inlined function */
188 KxAcquireSpinLock(SpinLock);
189 }
190
191 /*
192 * @implemented
193 */
194 VOID
195 FASTCALL
196 KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
197 {
198 /* Do the lined function */
199 KxReleaseSpinLock(SpinLock);
200 }
201
202 /*
203 * @implemented
204 */
205 BOOLEAN
206 FASTCALL
207 KeTryToAcquireSpinLockAtDpcLevel(IN OUT PKSPIN_LOCK SpinLock)
208 {
209 #ifdef CONFIG_SMP
210 /* Check if it's already acquired */
211 if (!(*SpinLock))
212 {
213 /* Try to acquire it */
214 if (InterlockedBitTestAndSet((PLONG)SpinLock, 0))
215 {
216 /* Someone else acquired it */
217 return FALSE;
218 }
219 }
220 else
221 {
222 /* It was already acquired */
223 return FALSE;
224 }
225
226 #if DBG
227 /* On debug builds, we OR in the KTHREAD */
228 *SpinLock = (ULONG_PTR)KeGetCurrentThread() | 1;
229 #endif
230 #endif
231
232 /* All is well, return TRUE */
233 return TRUE;
234 }
235
236 /*
237 * @implemented
238 */
239 VOID
240 FASTCALL
241 KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock,
242 IN PKLOCK_QUEUE_HANDLE LockHandle)
243 {
244 #ifdef CONFIG_SMP
245 /* Set it up properly */
246 LockHandle->LockQueue.Next = NULL;
247 LockHandle->LockQueue.Lock = SpinLock;
248 KeAcquireQueuedSpinLockAtDpcLevel(LockHandle->LockQueue.Next);
249 #endif
250 }
251
252 /*
253 * @implemented
254 */
255 VOID
256 FASTCALL
257 KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle)
258 {
259 #ifdef CONFIG_SMP
260 /* Call the internal function */
261 KeReleaseQueuedSpinLockFromDpcLevel(LockHandle->LockQueue.Next);
262 #endif
263 }
264
265 /*
266 * @unimplemented
267 */
268 KIRQL
269 FASTCALL
270 KeAcquireSpinLockForDpc(IN PKSPIN_LOCK SpinLock)
271 {
272 UNIMPLEMENTED;
273 return 0;
274 }
275
276 /*
277 * @unimplemented
278 */
279 VOID
280 FASTCALL
281 KeReleaseSpinLockForDpc(IN PKSPIN_LOCK SpinLock,
282 IN KIRQL OldIrql)
283 {
284 UNIMPLEMENTED;
285 }
286
287 /*
288 * @unimplemented
289 */
290 KIRQL
291 FASTCALL
292 KeAcquireInStackQueuedSpinLockForDpc(IN PKSPIN_LOCK SpinLock,
293 IN PKLOCK_QUEUE_HANDLE LockHandle)
294 {
295 UNIMPLEMENTED;
296 return 0;
297 }
298
299 /*
300 * @unimplemented
301 */
302 VOID
303 FASTCALL
304 KeReleaseInStackQueuedSpinLockForDpc(IN PKLOCK_QUEUE_HANDLE LockHandle)
305 {
306 UNIMPLEMENTED;
307 }
308
309 /*
310 * @implemented
311 */
312 BOOLEAN
313 FASTCALL
314 KeTestSpinLock(IN PKSPIN_LOCK SpinLock)
315 {
316 /* Test this spinlock */
317 if (*SpinLock)
318 {
319 /* Spinlock is busy, yield execution */
320 YieldProcessor();
321
322 /* Return busy flag */
323 return FALSE;
324 }
325
326 /* Spinlock appears to be free */
327 return TRUE;
328 }
329
330 /* EOF */