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 **********************************************************/
94 KeInitializeSpinLock(IN PKSPIN_LOCK SpinLock
)
103 #undef KeAcquireSpinLockAtDpcLevel
106 KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock
)
108 /* Do the inlined function */
109 KxAcquireSpinLock(SpinLock
);
115 #undef KeReleaseSpinLockFromDpcLevel
118 KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock
)
120 /* Do the lined function */
121 KxReleaseSpinLock(SpinLock
);
129 KefAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock
)
131 /* Do the inlined function */
132 KxAcquireSpinLock(SpinLock
);
140 KefReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock
)
142 /* Do the lined function */
143 KxReleaseSpinLock(SpinLock
);
151 KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock
)
153 /* Do the inlined function */
154 KxAcquireSpinLock(SpinLock
);
162 KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock
)
164 /* Do the lined function */
165 KxReleaseSpinLock(SpinLock
);
173 KeTryToAcquireSpinLockAtDpcLevel(IN OUT PKSPIN_LOCK SpinLock
)
176 /* Check if it's already acquired */
179 /* Try to acquire it */
180 if (InterlockedBitTestAndSet((PLONG
)SpinLock
, 0))
182 /* Someone else acquired it */
188 /* It was already acquired */
193 /* On debug builds, we OR in the KTHREAD */
194 *SpinLock
= (ULONG_PTR
)KeGetCurrentThread() | 1;
198 /* All is well, return TRUE */
207 KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock
,
208 IN PKLOCK_QUEUE_HANDLE LockHandle
)
211 /* Set it up properly */
212 LockHandle
->LockQueue
.Next
= NULL
;
213 LockHandle
->LockQueue
.Lock
= SpinLock
;
214 KeAcquireQueuedSpinLockAtDpcLevel(LockHandle
->LockQueue
.Next
);
223 KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle
)
226 /* Call the internal function */
227 KeReleaseQueuedSpinLockFromDpcLevel(LockHandle
->LockQueue
.Next
);
236 KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt
)
241 KeRaiseIrql(Interrupt
->SynchronizeIrql
, &OldIrql
);
243 /* Acquire spinlock on MP */
244 KefAcquireSpinLockAtDpcLevel(Interrupt
->ActualLock
);
253 KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt
,
256 /* Release lock on MP */
257 KefReleaseSpinLockFromDpcLevel(Interrupt
->ActualLock
);
260 KeLowerIrql(OldIrql
);
268 KeAcquireSpinLockForDpc(IN PKSPIN_LOCK SpinLock
)
279 KeReleaseSpinLockForDpc(IN PKSPIN_LOCK SpinLock
,
290 KeAcquireInStackQueuedSpinLockForDpc(IN PKSPIN_LOCK SpinLock
,
291 IN PKLOCK_QUEUE_HANDLE LockHandle
)
302 KeReleaseInStackQueuedSpinLockForDpc(IN PKLOCK_QUEUE_HANDLE LockHandle
)
312 KeTestSpinLock(IN PKSPIN_LOCK SpinLock
)
314 /* Test this spinlock */
317 /* Spinlock is busy, yield execution */
320 /* Return busy flag */
324 /* Spinlock appears to be free */