[NTOS]
[reactos.git] / reactos / hal / halx86 / generic / spinlock.c
1 /*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/up/spinlock.c
5 * PURPOSE: Spinlock and Queued Spinlock Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 /* Enable this (and the define in irq.S) to make UP HAL work for MP Kernel */
12 /* #define CONFIG_SMP */
13
14 #include <hal.h>
15 #define NDEBUG
16 #include <debug.h>
17
18 #undef KeAcquireSpinLock
19 #undef KeReleaseSpinLock
20
21 //
22 // This is duplicated from ke_x.h
23 //
24 #ifdef CONFIG_SMP
25 //
26 // Spinlock Acquisition at IRQL >= DISPATCH_LEVEL
27 //
28 FORCEINLINE
29 VOID
30 KxAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
31 {
32 /* Make sure that we don't own the lock already */
33 if (((KSPIN_LOCK)KeGetCurrentThread() | 1) == *SpinLock)
34 {
35 /* We do, bugcheck! */
36 KeBugCheckEx(SPIN_LOCK_ALREADY_OWNED, (ULONG_PTR)SpinLock, 0, 0, 0);
37 }
38
39 for (;;)
40 {
41 /* Try to acquire it */
42 if (InterlockedBitTestAndSet((PLONG)SpinLock, 0))
43 {
44 /* Value changed... wait until it's locked */
45 while (*(volatile KSPIN_LOCK *)SpinLock == 1)
46 {
47 #ifdef DBG
48 /* On debug builds, we use a much slower but useful routine */
49 //Kii386SpinOnSpinLock(SpinLock, 5);
50
51 /* FIXME: Do normal yield for now */
52 YieldProcessor();
53 #else
54 /* Otherwise, just yield and keep looping */
55 YieldProcessor();
56 #endif
57 }
58 }
59 else
60 {
61 #ifdef DBG
62 /* On debug builds, we OR in the KTHREAD */
63 *SpinLock = (KSPIN_LOCK)KeGetCurrentThread() | 1;
64 #endif
65 /* All is well, break out */
66 break;
67 }
68 }
69 }
70
71 //
72 // Spinlock Release at IRQL >= DISPATCH_LEVEL
73 //
74 FORCEINLINE
75 VOID
76 KxReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
77 {
78 #ifdef DBG
79 /* Make sure that the threads match */
80 if (((KSPIN_LOCK)KeGetCurrentThread() | 1) != *SpinLock)
81 {
82 /* They don't, bugcheck */
83 KeBugCheckEx(SPIN_LOCK_NOT_OWNED, (ULONG_PTR)SpinLock, 0, 0, 0);
84 }
85 #endif
86 /* Clear the lock */
87 InterlockedAnd((PLONG)SpinLock, 0);
88 }
89
90 #else
91
92 //
93 // Spinlock Acquire at IRQL >= DISPATCH_LEVEL
94 //
95 FORCEINLINE
96 VOID
97 KxAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
98 {
99 /* On UP builds, spinlocks don't exist at IRQL >= DISPATCH */
100 UNREFERENCED_PARAMETER(SpinLock);
101 }
102
103 //
104 // Spinlock Release at IRQL >= DISPATCH_LEVEL
105 //
106 FORCEINLINE
107 VOID
108 KxReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
109 {
110 /* On UP builds, spinlocks don't exist at IRQL >= DISPATCH */
111 UNREFERENCED_PARAMETER(SpinLock);
112 }
113
114 #endif
115
116 /* FUNCTIONS *****************************************************************/
117
118 /*
119 * @implemented
120 */
121 VOID
122 NTAPI
123 KeAcquireSpinLock(PKSPIN_LOCK SpinLock,
124 PKIRQL OldIrql)
125 {
126 /* Call the fastcall function */
127 *OldIrql = KfAcquireSpinLock(SpinLock);
128 }
129
130 /*
131 * @implemented
132 */
133 KIRQL
134 FASTCALL
135 KeAcquireSpinLockRaiseToSynch(PKSPIN_LOCK SpinLock)
136 {
137 KIRQL OldIrql;
138
139 /* Raise to sync */
140 KeRaiseIrql(SYNCH_LEVEL, &OldIrql);
141
142 /* Acquire the lock and return */
143 KxAcquireSpinLock(SpinLock);
144 return OldIrql;
145 }
146
147 /*
148 * @implemented
149 */
150 VOID
151 NTAPI
152 KeReleaseSpinLock(PKSPIN_LOCK SpinLock,
153 KIRQL NewIrql)
154 {
155 /* Call the fastcall function */
156 KfReleaseSpinLock(SpinLock, NewIrql);
157 }
158
159 /*
160 * @implemented
161 */
162 KIRQL
163 FASTCALL
164 KfAcquireSpinLock(PKSPIN_LOCK SpinLock)
165 {
166 KIRQL OldIrql;
167
168 /* Raise to dispatch and acquire the lock */
169 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
170 KxAcquireSpinLock(SpinLock);
171 return OldIrql;
172 }
173
174 /*
175 * @implemented
176 */
177 VOID
178 FASTCALL
179 KfReleaseSpinLock(PKSPIN_LOCK SpinLock,
180 KIRQL OldIrql)
181 {
182 /* Release the lock and lower IRQL back */
183 KxReleaseSpinLock(SpinLock);
184 KeLowerIrql(OldIrql);
185 }
186
187 /*
188 * @implemented
189 */
190 KIRQL
191 FASTCALL
192 KeAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber)
193 {
194 KIRQL OldIrql;
195
196 /* Raise to dispatch */
197 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
198
199 /* Acquire the lock */
200 KxAcquireSpinLock(KeGetCurrentPrcb()->LockQueue[LockNumber].Lock); // HACK
201 return OldIrql;
202 }
203
204 /*
205 * @implemented
206 */
207 KIRQL
208 FASTCALL
209 KeAcquireQueuedSpinLockRaiseToSynch(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber)
210 {
211 KIRQL OldIrql;
212
213 /* Raise to synch */
214 KeRaiseIrql(SYNCH_LEVEL, &OldIrql);
215
216 /* Acquire the lock */
217 KxAcquireSpinLock(KeGetCurrentPrcb()->LockQueue[LockNumber].Lock); // HACK
218 return OldIrql;
219 }
220
221 /*
222 * @implemented
223 */
224 VOID
225 FASTCALL
226 KeAcquireInStackQueuedSpinLock(IN PKSPIN_LOCK SpinLock,
227 IN PKLOCK_QUEUE_HANDLE LockHandle)
228 {
229 /* Set up the lock */
230 LockHandle->LockQueue.Next = NULL;
231 LockHandle->LockQueue.Lock = SpinLock;
232
233 /* Raise to dispatch */
234 KeRaiseIrql(DISPATCH_LEVEL, &LockHandle->OldIrql);
235
236 /* Acquire the lock */
237 KxAcquireSpinLock(LockHandle->LockQueue.Lock); // HACK
238 }
239
240 /*
241 * @implemented
242 */
243 VOID
244 FASTCALL
245 KeAcquireInStackQueuedSpinLockRaiseToSynch(IN PKSPIN_LOCK SpinLock,
246 IN PKLOCK_QUEUE_HANDLE LockHandle)
247 {
248 /* Set up the lock */
249 LockHandle->LockQueue.Next = NULL;
250 LockHandle->LockQueue.Lock = SpinLock;
251
252 /* Raise to synch */
253 KeRaiseIrql(SYNCH_LEVEL, &LockHandle->OldIrql);
254
255 /* Acquire the lock */
256 KxAcquireSpinLock(LockHandle->LockQueue.Lock); // HACK
257 }
258
259 /*
260 * @implemented
261 */
262 VOID
263 FASTCALL
264 KeReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber,
265 IN KIRQL OldIrql)
266 {
267 /* Release the lock */
268 KxReleaseSpinLock(KeGetCurrentPrcb()->LockQueue[LockNumber].Lock); // HACK
269
270 /* Lower IRQL back */
271 KeLowerIrql(OldIrql);
272 }
273
274 /*
275 * @implemented
276 */
277 VOID
278 FASTCALL
279 KeReleaseInStackQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockHandle)
280 {
281 /* Simply lower IRQL back */
282 KxReleaseSpinLock(LockHandle->LockQueue.Lock); // HACK
283 KeLowerIrql(LockHandle->OldIrql);
284 }
285
286 /*
287 * @implemented
288 */
289 BOOLEAN
290 FASTCALL
291 KeTryToAcquireQueuedSpinLockRaiseToSynch(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber,
292 IN PKIRQL OldIrql)
293 {
294 #ifdef CONFIG_SMP
295 ASSERT(FALSE); // FIXME: Unused
296 while (TRUE);
297 #endif
298
299 /* Simply raise to synch */
300 KeRaiseIrql(SYNCH_LEVEL, OldIrql);
301
302 /* Always return true on UP Machines */
303 return TRUE;
304 }
305
306 /*
307 * @implemented
308 */
309 LOGICAL
310 FASTCALL
311 KeTryToAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber,
312 OUT PKIRQL OldIrql)
313 {
314 #ifdef CONFIG_SMP
315 ASSERT(FALSE); // FIXME: Unused
316 while (TRUE);
317 #endif
318
319 /* Simply raise to dispatch */
320 KeRaiseIrql(DISPATCH_LEVEL, OldIrql);
321
322 /* Always return true on UP Machines */
323 return TRUE;
324 }
325
326 #undef KeRaiseIrql
327 /*
328 * @implemented
329 */
330 VOID
331 NTAPI
332 KeRaiseIrql(KIRQL NewIrql,
333 PKIRQL OldIrql)
334 {
335 /* Call the fastcall function */
336 *OldIrql = KfRaiseIrql(NewIrql);
337 }
338
339 #undef KeLowerIrql
340 /*
341 * @implemented
342 */
343 VOID
344 NTAPI
345 KeLowerIrql(KIRQL NewIrql)
346 {
347 /* Call the fastcall function */
348 KfLowerIrql(NewIrql);
349 }