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)
9 /* INCLUDES ******************************************************************/
18 /* PRIVATE FUNCTIONS *********************************************************/
22 // FIXME: The queued spinlock routines are broken.
27 KeAcquireQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle
)
30 PKSPIN_LOCK_QUEUE Prev
;
32 /* Set the new lock */
33 Prev
= (PKSPIN_LOCK_QUEUE
)
34 InterlockedExchange((PLONG
)LockHandle
->Next
,
38 /* There was nothing there before. We now own it */
39 *LockHandle
->Lock
|= LQ_OWN
;
43 /* Set the wait flag */
44 *LockHandle
->Lock
|= LQ_WAIT
;
47 Prev
->Next
= (PKSPIN_LOCK_QUEUE
)LockHandle
;
50 while (*LockHandle
->Lock
& LQ_WAIT
)
57 KeReleaseQueuedSpinLockFromDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle
)
61 PKSPIN_LOCK_QUEUE Waiter
;
63 /* Remove own and wait flags */
64 *LockHandle
->Lock
&= ~(LQ_OWN
| LQ_WAIT
);
65 LockVal
= *LockHandle
->Lock
;
67 /* Check if we already own it */
68 if (LockVal
== (KSPIN_LOCK
)LockHandle
)
71 LockVal
= (KSPIN_LOCK
)
72 InterlockedCompareExchangePointer(LockHandle
->Lock
,
76 if (LockVal
== (KSPIN_LOCK
)LockHandle
) return;
78 /* Need to wait for it */
79 Waiter
= LockHandle
->Next
;
83 Waiter
= LockHandle
->Next
;
87 *(ULONG_PTR
*)&Waiter
->Lock
^= (LQ_OWN
| LQ_WAIT
);
88 LockHandle
->Next
= NULL
;
94 // HACK: Hacked to work like normal spinlocks
99 KeAcquireQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle
)
102 /* Make sure we are at DPC or above! */
103 if (KeGetCurrentIrql() < DISPATCH_LEVEL
)
105 /* We aren't -- bugcheck */
106 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
107 (ULONG_PTR
)LockHandle
->Lock
,
113 /* Do the inlined function */
114 KxAcquireSpinLock(LockHandle
->Lock
);
120 KeReleaseQueuedSpinLockFromDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle
)
123 /* Make sure we are at DPC or above! */
124 if (KeGetCurrentIrql() < DISPATCH_LEVEL
)
126 /* We aren't -- bugcheck */
127 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
128 (ULONG_PTR
)LockHandle
->Lock
,
134 /* Do the inlined function */
135 KxReleaseSpinLock(LockHandle
->Lock
);
141 /* PUBLIC FUNCTIONS **********************************************************/
148 KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt
)
153 KeRaiseIrql(Interrupt
->SynchronizeIrql
, &OldIrql
);
155 /* Acquire spinlock on MP */
156 KeAcquireSpinLockAtDpcLevel(Interrupt
->ActualLock
);
165 KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt
,
168 /* Release lock on MP */
169 KeReleaseSpinLockFromDpcLevel(Interrupt
->ActualLock
);
172 KeLowerIrql(OldIrql
);
180 _KeInitializeSpinLock(IN PKSPIN_LOCK SpinLock
)
189 #undef KeAcquireSpinLockAtDpcLevel
192 KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock
)
194 /* Make sure we are at DPC or above! */
195 if (KeGetCurrentIrql() < DISPATCH_LEVEL
)
197 /* We aren't -- bugcheck */
198 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
205 /* Do the inlined function */
206 KxAcquireSpinLock(SpinLock
);
212 #undef KeReleaseSpinLockFromDpcLevel
215 KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock
)
217 /* Make sure we are at DPC or above! */
218 if (KeGetCurrentIrql() < DISPATCH_LEVEL
)
220 /* We aren't -- bugcheck */
221 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
228 /* Do the inlined function */
229 KxReleaseSpinLock(SpinLock
);
237 KefAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock
)
239 /* Make sure we are at DPC or above! */
240 if (KeGetCurrentIrql() < DISPATCH_LEVEL
)
242 /* We aren't -- bugcheck */
243 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
250 /* Do the inlined function */
251 KxAcquireSpinLock(SpinLock
);
259 KefReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock
)
261 /* Make sure we are at DPC or above! */
262 if (KeGetCurrentIrql() < DISPATCH_LEVEL
)
264 /* We aren't -- bugcheck */
265 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
272 /* Do the inlined function */
273 KxReleaseSpinLock(SpinLock
);
281 KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock
)
283 /* Do the inlined function */
284 KxAcquireSpinLock(SpinLock
);
292 KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock
)
294 /* Do the inlined function */
295 KxReleaseSpinLock(SpinLock
);
303 KeTryToAcquireSpinLockAtDpcLevel(IN OUT PKSPIN_LOCK SpinLock
)
306 /* Check if it's already acquired */
309 /* Try to acquire it */
310 if (InterlockedBitTestAndSet((PLONG
)SpinLock
, 0))
312 /* Someone else acquired it */
318 /* It was already acquired */
323 /* On debug builds, we OR in the KTHREAD */
324 *SpinLock
= (ULONG_PTR
)KeGetCurrentThread() | 1;
328 /* All is well, return TRUE */
337 KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock
,
338 IN PKLOCK_QUEUE_HANDLE LockHandle
)
341 /* Set it up properly */
342 LockHandle
->LockQueue
.Next
= NULL
;
343 LockHandle
->LockQueue
.Lock
= SpinLock
;
345 KeAcquireQueuedSpinLockAtDpcLevel(LockHandle
->LockQueue
.Next
);
347 /* Make sure we are at DPC or above! */
348 if (KeGetCurrentIrql() < DISPATCH_LEVEL
)
350 /* We aren't -- bugcheck */
351 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
352 (ULONG_PTR
)LockHandle
->LockQueue
.Lock
,
358 /* Acquire the lock */
359 KxAcquireSpinLock(LockHandle
->LockQueue
.Lock
); // HACK
369 KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle
)
373 /* Call the internal function */
374 KeReleaseQueuedSpinLockFromDpcLevel(LockHandle
->LockQueue
.Next
);
376 /* Make sure we are at DPC or above! */
377 if (KeGetCurrentIrql() < DISPATCH_LEVEL
)
379 /* We aren't -- bugcheck */
380 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
381 (ULONG_PTR
)LockHandle
->LockQueue
.Lock
,
387 /* Release the lock */
388 KxReleaseSpinLock(LockHandle
->LockQueue
.Lock
); // HACK
398 KeAcquireSpinLockForDpc(IN PKSPIN_LOCK SpinLock
)
409 KeReleaseSpinLockForDpc(IN PKSPIN_LOCK SpinLock
,
420 KeAcquireInStackQueuedSpinLockForDpc(IN PKSPIN_LOCK SpinLock
,
421 IN PKLOCK_QUEUE_HANDLE LockHandle
)
432 KeReleaseInStackQueuedSpinLockForDpc(IN PKLOCK_QUEUE_HANDLE LockHandle
)
442 KeTestSpinLock(IN PKSPIN_LOCK SpinLock
)
444 /* Test this spinlock */
447 /* Spinlock is busy, yield execution */
450 /* Return busy flag */
454 /* Spinlock appears to be free */
461 Kii386SpinOnSpinLock(PKSPIN_LOCK SpinLock
, ULONG Flags
)
463 // FIXME: Handle flags
464 UNREFERENCED_PARAMETER(Flags
);
466 /* Spin until it's unlocked */
467 while (*(volatile KSPIN_LOCK
*)SpinLock
& 1)
469 // FIXME: Check for timeout
471 /* Yield and keep looping */