2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ke/spinlock.c
5 * PURPOSE: Implements spinlocks
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * David Welch (welch@cwcom.net)
10 /* INCLUDES ****************************************************************/
14 #include <internal/debug.h>
16 #undef KefAcquireSpinLockAtDpcLevel
17 #undef KeAcquireSpinLockAtDpcLevel
18 #undef KefReleaseSpinLockFromDpcLevel
19 #undef KeReleaseSpinLockFromDpcLevel
24 /* FUNCTIONS ***************************************************************/
29 * FUNCTION: Synchronizes the execution of a given routine with the ISR
30 * of a given interrupt object
32 * Interrupt = Interrupt object to synchronize with
33 * SynchronizeRoutine = Routine to call whose execution is
34 * synchronized with the ISR
35 * SynchronizeContext = Parameter to pass to the synchronized routine
36 * RETURNS: TRUE if the operation succeeded
40 KeSynchronizeExecution(PKINTERRUPT Interrupt
,
41 PKSYNCHRONIZE_ROUTINE SynchronizeRoutine
,
42 PVOID SynchronizeContext
)
47 /* Raise IRQL and acquire lock on MP */
48 OldIrql
= KeAcquireInterruptSpinLock(Interrupt
);
50 /* Call the routine */
51 Status
= SynchronizeRoutine(SynchronizeContext
);
53 /* Release lock and lower IRQL */
54 KeReleaseInterruptSpinLock(Interrupt
, OldIrql
);
56 /* Return routine status */
65 KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt
)
70 KeRaiseIrql(Interrupt
->SynchronizeIrql
, &OldIrql
);
72 /* Acquire spinlock on MP */
73 KiAcquireSpinLock(Interrupt
->ActualLock
);
80 * FUNCTION: Initalizes a spinlock
82 * SpinLock = Caller supplied storage for the spinlock
86 KeInitializeSpinLock(PKSPIN_LOCK SpinLock
)
96 KefAcquireSpinLockAtDpcLevel(PKSPIN_LOCK SpinLock
)
98 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
99 KiAcquireSpinLock(SpinLock
);
105 * FUNCTION: Acquires a spinlock when the caller is already running at
108 * SpinLock = Spinlock to acquire
112 KeAcquireSpinLockAtDpcLevel (PKSPIN_LOCK SpinLock
)
114 KefAcquireSpinLockAtDpcLevel(SpinLock
);
122 KefReleaseSpinLockFromDpcLevel(PKSPIN_LOCK SpinLock
)
124 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
125 KiReleaseSpinLock(SpinLock
);
131 * FUNCTION: Releases a spinlock when the caller was running at dispatch
132 * level before acquiring it
134 * SpinLock = Spinlock to release
138 KeReleaseSpinLockFromDpcLevel (PKSPIN_LOCK SpinLock
)
140 KefReleaseSpinLockFromDpcLevel(SpinLock
);
148 KiAcquireSpinLock(PKSPIN_LOCK SpinLock
)
153 /* Try to acquire it */
154 if (InterlockedBitTestAndSet((PLONG
)SpinLock
, 0))
156 /* Value changed... wait until it's locked */
157 while (*(volatile KSPIN_LOCK
*)SpinLock
== 1) YieldProcessor();
161 /* All is well, break out */
165 #endif /* CONFIG_SMP */
173 KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt
,
176 /* Release lock on MP */
177 KiReleaseSpinLock(Interrupt
->ActualLock
);
180 KeLowerIrql(OldIrql
);
188 KiReleaseSpinLock(PKSPIN_LOCK SpinLock
)
191 /* Simply clear it */
198 KeAcquireQueuedSpinLockAtDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle
)
201 PKSPIN_LOCK_QUEUE Prev
;
203 /* Set the new lock */
204 Prev
= (PKSPIN_LOCK_QUEUE
)
205 InterlockedExchange((PLONG
)LockHandle
->LockQueue
.Lock
,
209 /* There was nothing there before. We now own it */
210 *(ULONG_PTR
*)&LockHandle
->LockQueue
.Lock
|= LQ_OWN
;
214 /* Set the wait flag */
215 *(ULONG_PTR
*)&LockHandle
->LockQueue
.Lock
|= LQ_WAIT
;
218 Prev
->Next
= (PKSPIN_LOCK_QUEUE
)LockHandle
;
221 while ( *(ULONG_PTR
*)&LockHandle
->LockQueue
.Lock
& LQ_WAIT
) YieldProcessor();
228 KeReleaseQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle
)
232 PKSPIN_LOCK_QUEUE Waiter
;
234 /* Remove own and wait flags */
235 *(ULONG_PTR
*)&LockHandle
->LockQueue
.Lock
&= ~(LQ_OWN
| LQ_WAIT
);
236 LockVal
= *LockHandle
->LockQueue
.Lock
;
238 /* Check if we already own it */
239 if (LockVal
== (KSPIN_LOCK
)LockHandle
)
242 LockVal
= (KSPIN_LOCK
)
243 InterlockedCompareExchangePointer(LockHandle
->LockQueue
.Lock
,
247 if (LockVal
== (KSPIN_LOCK
)LockHandle
) return;
249 /* Need to wait for it */
250 Waiter
= LockHandle
->LockQueue
.Next
;
254 Waiter
= LockHandle
->LockQueue
.Next
;
258 *(ULONG_PTR
*)&Waiter
->Lock
^= (LQ_OWN
| LQ_WAIT
);
259 LockHandle
->LockQueue
.Next
= NULL
;
268 KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock
,
269 IN PKLOCK_QUEUE_HANDLE LockHandle
)
271 /* Set it up properly */
272 LockHandle
->LockQueue
.Next
= NULL
;
273 LockHandle
->LockQueue
.Lock
= SpinLock
;
274 KeAcquireQueuedSpinLockAtDpcLevel((PKLOCK_QUEUE_HANDLE
)
275 &LockHandle
->LockQueue
.Next
);
283 KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle
)
285 /* Call the internal function */
286 KeReleaseQueuedSpinLockFromDpcLevel((PKLOCK_QUEUE_HANDLE
)
287 &LockHandle
->LockQueue
.Next
);