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 KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt
)
99 KeRaiseIrql(Interrupt
->SynchronizeIrql
, &OldIrql
);
101 /* Acquire spinlock on MP */
102 KeAcquireSpinLockAtDpcLevel(Interrupt
->ActualLock
);
111 KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt
,
114 /* Release lock on MP */
115 KeReleaseSpinLockFromDpcLevel(Interrupt
->ActualLock
);
118 KeLowerIrql(OldIrql
);
126 KeInitializeSpinLock(IN PKSPIN_LOCK SpinLock
)
135 #undef KeAcquireSpinLockAtDpcLevel
138 KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock
)
140 /* Do the inlined function */
141 KxAcquireSpinLock(SpinLock
);
147 #undef KeReleaseSpinLockFromDpcLevel
150 KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock
)
152 /* Do the lined function */
153 KxReleaseSpinLock(SpinLock
);
161 KefAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock
)
163 /* Do the inlined function */
164 KxAcquireSpinLock(SpinLock
);
172 KefReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock
)
174 /* Do the lined function */
175 KxReleaseSpinLock(SpinLock
);
183 KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock
)
185 /* Do the inlined function */
186 KxAcquireSpinLock(SpinLock
);
194 KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock
)
196 /* Do the lined function */
197 KxReleaseSpinLock(SpinLock
);
205 KeTryToAcquireSpinLockAtDpcLevel(IN OUT PKSPIN_LOCK SpinLock
)
208 /* Check if it's already acquired */
211 /* Try to acquire it */
212 if (InterlockedBitTestAndSet((PLONG
)SpinLock
, 0))
214 /* Someone else acquired it */
220 /* It was already acquired */
225 /* On debug builds, we OR in the KTHREAD */
226 *SpinLock
= (ULONG_PTR
)KeGetCurrentThread() | 1;
230 /* All is well, return TRUE */
239 KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock
,
240 IN PKLOCK_QUEUE_HANDLE LockHandle
)
243 /* Set it up properly */
244 LockHandle
->LockQueue
.Next
= NULL
;
245 LockHandle
->LockQueue
.Lock
= SpinLock
;
246 KeAcquireQueuedSpinLockAtDpcLevel(LockHandle
->LockQueue
.Next
);
255 KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle
)
258 /* Call the internal function */
259 KeReleaseQueuedSpinLockFromDpcLevel(LockHandle
->LockQueue
.Next
);
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 */