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