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 KeAcquireQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle
)
25 PKSPIN_LOCK_QUEUE Prev
;
27 /* Set the new lock */
28 Prev
= (PKSPIN_LOCK_QUEUE
)
29 InterlockedExchange((PLONG
)LockHandle
->Next
,
33 /* There was nothing there before. We now own it */
34 *LockHandle
->Lock
|= LQ_OWN
;
38 /* Set the wait flag */
39 *LockHandle
->Lock
|= LQ_WAIT
;
42 Prev
->Next
= (PKSPIN_LOCK_QUEUE
)LockHandle
;
45 while (*LockHandle
->Lock
& LQ_WAIT
)
52 KeReleaseQueuedSpinLockFromDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle
)
56 PKSPIN_LOCK_QUEUE Waiter
;
58 /* Remove own and wait flags */
59 *LockHandle
->Lock
&= ~(LQ_OWN
| LQ_WAIT
);
60 LockVal
= *LockHandle
->Lock
;
62 /* Check if we already own it */
63 if (LockVal
== (KSPIN_LOCK
)LockHandle
)
66 LockVal
= (KSPIN_LOCK
)
67 InterlockedCompareExchangePointer(LockHandle
->Lock
,
71 if (LockVal
== (KSPIN_LOCK
)LockHandle
) return;
73 /* Need to wait for it */
74 Waiter
= LockHandle
->Next
;
78 Waiter
= LockHandle
->Next
;
82 *(ULONG_PTR
*)&Waiter
->Lock
^= (LQ_OWN
| LQ_WAIT
);
83 LockHandle
->Next
= NULL
;
87 /* PUBLIC FUNCTIONS **********************************************************/
95 KeInitializeSpinLock(IN PKSPIN_LOCK SpinLock
)
105 #undef KeAcquireSpinLockAtDpcLevel
108 KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock
)
110 /* Do the inlined function */
111 KxAcquireSpinLock(SpinLock
);
117 #undef KeReleaseSpinLockFromDpcLevel
120 KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock
)
122 /* Do the lined function */
123 KxReleaseSpinLock(SpinLock
);
131 KefAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock
)
133 /* Do the inlined function */
134 KxAcquireSpinLock(SpinLock
);
142 KefReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock
)
144 /* Do the lined function */
145 KxReleaseSpinLock(SpinLock
);
153 KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock
)
155 /* Do the inlined function */
156 KxAcquireSpinLock(SpinLock
);
164 KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock
)
166 /* Do the lined function */
167 KxReleaseSpinLock(SpinLock
);
175 KeTryToAcquireSpinLockAtDpcLevel(IN OUT PKSPIN_LOCK SpinLock
)
178 /* Check if it's already acquired */
181 /* Try to acquire it */
182 if (InterlockedBitTestAndSet((PLONG
)SpinLock
, 0))
184 /* Someone else acquired it */
190 /* It was already acquired */
195 /* On debug builds, we OR in the KTHREAD */
196 *SpinLock
= (ULONG_PTR
)KeGetCurrentThread() | 1;
200 /* All is well, return TRUE */
209 KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock
,
210 IN PKLOCK_QUEUE_HANDLE LockHandle
)
213 /* Set it up properly */
214 LockHandle
->LockQueue
.Next
= NULL
;
215 LockHandle
->LockQueue
.Lock
= SpinLock
;
216 KeAcquireQueuedSpinLockAtDpcLevel(LockHandle
->LockQueue
.Next
);
225 KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle
)
228 /* Call the internal function */
229 KeReleaseQueuedSpinLockFromDpcLevel(LockHandle
->LockQueue
.Next
);
238 KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt
)
243 KeRaiseIrql(Interrupt
->SynchronizeIrql
, &OldIrql
);
245 /* Acquire spinlock on MP */
246 KefAcquireSpinLockAtDpcLevel(Interrupt
->ActualLock
);
255 KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt
,
258 /* Release lock on MP */
259 KefReleaseSpinLockFromDpcLevel(Interrupt
->ActualLock
);
262 KeLowerIrql(OldIrql
);
270 KeAcquireSpinLockForDpc(IN PKSPIN_LOCK SpinLock
)
281 KeReleaseSpinLockForDpc(IN PKSPIN_LOCK SpinLock
,
292 KeAcquireInStackQueuedSpinLockForDpc(IN PKSPIN_LOCK SpinLock
,
293 IN PKLOCK_QUEUE_HANDLE LockHandle
)
304 KeReleaseInStackQueuedSpinLockForDpc(IN PKLOCK_QUEUE_HANDLE LockHandle
)
314 KeTestSpinLock(IN PKSPIN_LOCK SpinLock
)