mirror of
https://github.com/reactos/reactos.git
synced 2024-11-09 08:08:38 +00:00
c501d8112c
svn path=/branches/aicom-network-fixes/; revision=34994
263 lines
5.1 KiB
C
263 lines
5.1 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: ntoskrnl/ke/spinlock.c
|
|
* PURPOSE: Spinlock and Queued Spinlock Support
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <internal/debug.h>
|
|
|
|
#define LQ_WAIT 1
|
|
#define LQ_OWN 2
|
|
|
|
/* PRIVATE FUNCTIONS *********************************************************/
|
|
|
|
VOID
|
|
FASTCALL
|
|
KeAcquireQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle)
|
|
{
|
|
#ifdef CONFIG_SMP
|
|
PKSPIN_LOCK_QUEUE Prev;
|
|
|
|
/* Set the new lock */
|
|
Prev = (PKSPIN_LOCK_QUEUE)
|
|
InterlockedExchange((PLONG)LockHandle->Next,
|
|
(LONG)LockHandle);
|
|
if (!Prev)
|
|
{
|
|
/* There was nothing there before. We now own it */
|
|
*LockHandle->Lock |= LQ_OWN;
|
|
return;
|
|
}
|
|
|
|
/* Set the wait flag */
|
|
*LockHandle->Lock |= LQ_WAIT;
|
|
|
|
/* Link us */
|
|
Prev->Next = (PKSPIN_LOCK_QUEUE)LockHandle;
|
|
|
|
/* Loop and wait */
|
|
while (*LockHandle->Lock & LQ_WAIT)
|
|
YieldProcessor();
|
|
#endif
|
|
}
|
|
|
|
VOID
|
|
FASTCALL
|
|
KeReleaseQueuedSpinLockFromDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle)
|
|
{
|
|
#ifdef CONFIG_SMP
|
|
KSPIN_LOCK LockVal;
|
|
PKSPIN_LOCK_QUEUE Waiter;
|
|
|
|
/* Remove own and wait flags */
|
|
*LockHandle->Lock &= ~(LQ_OWN | LQ_WAIT);
|
|
LockVal = *LockHandle->Lock;
|
|
|
|
/* Check if we already own it */
|
|
if (LockVal == (KSPIN_LOCK)LockHandle)
|
|
{
|
|
/* Disown it */
|
|
LockVal = (KSPIN_LOCK)
|
|
InterlockedCompareExchangePointer(LockHandle->Lock,
|
|
NULL,
|
|
LockHandle);
|
|
}
|
|
if (LockVal == (KSPIN_LOCK)LockHandle) return;
|
|
|
|
/* Need to wait for it */
|
|
Waiter = LockHandle->Next;
|
|
while (!Waiter)
|
|
{
|
|
YieldProcessor();
|
|
Waiter = LockHandle->Next;
|
|
}
|
|
|
|
/* It's gone */
|
|
*(ULONG_PTR*)&Waiter->Lock ^= (LQ_OWN | LQ_WAIT);
|
|
LockHandle->Next = NULL;
|
|
#endif
|
|
}
|
|
|
|
/* PUBLIC FUNCTIONS **********************************************************/
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
KeInitializeSpinLock(IN PKSPIN_LOCK SpinLock)
|
|
{
|
|
/* Clear it */
|
|
*SpinLock = 0;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
#undef KeAcquireSpinLockAtDpcLevel
|
|
VOID
|
|
NTAPI
|
|
KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
|
|
{
|
|
/* Do the inlined function */
|
|
KxAcquireSpinLock(SpinLock);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
#undef KeReleaseSpinLockFromDpcLevel
|
|
VOID
|
|
NTAPI
|
|
KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
|
|
{
|
|
/* Do the lined function */
|
|
KxReleaseSpinLock(SpinLock);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
FASTCALL
|
|
KefAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
|
|
{
|
|
/* Do the inlined function */
|
|
KxAcquireSpinLock(SpinLock);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
FASTCALL
|
|
KefReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
|
|
{
|
|
/* Do the lined function */
|
|
KxReleaseSpinLock(SpinLock);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
FASTCALL
|
|
KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
|
|
{
|
|
/* Do the inlined function */
|
|
KxAcquireSpinLock(SpinLock);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
FASTCALL
|
|
KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
|
|
{
|
|
/* Do the lined function */
|
|
KxReleaseSpinLock(SpinLock);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOLEAN
|
|
FASTCALL
|
|
KeTryToAcquireSpinLockAtDpcLevel(IN OUT PKSPIN_LOCK SpinLock)
|
|
{
|
|
#ifdef CONFIG_SMP
|
|
/* Check if it's already acquired */
|
|
if (!(*SpinLock))
|
|
{
|
|
/* Try to acquire it */
|
|
if (InterlockedBitTestAndSet((PLONG)SpinLock, 0))
|
|
{
|
|
/* Someone else acquired it */
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* It was already acquired */
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef DBG
|
|
/* On debug builds, we OR in the KTHREAD */
|
|
*SpinLock = (ULONG_PTR)KeGetCurrentThread() | 1;
|
|
#endif
|
|
#endif
|
|
|
|
/* All is well, return TRUE */
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
FASTCALL
|
|
KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock,
|
|
IN PKLOCK_QUEUE_HANDLE LockHandle)
|
|
{
|
|
#ifdef CONFIG_SMP
|
|
/* Set it up properly */
|
|
LockHandle->LockQueue.Next = NULL;
|
|
LockHandle->LockQueue.Lock = SpinLock;
|
|
KeAcquireQueuedSpinLockAtDpcLevel(LockHandle->LockQueue.Next);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
FASTCALL
|
|
KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle)
|
|
{
|
|
#ifdef CONFIG_SMP
|
|
/* Call the internal function */
|
|
KeReleaseQueuedSpinLockFromDpcLevel(LockHandle->LockQueue.Next);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
KIRQL
|
|
NTAPI
|
|
KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
/* Raise IRQL */
|
|
KeRaiseIrql(Interrupt->SynchronizeIrql, &OldIrql);
|
|
|
|
/* Acquire spinlock on MP */
|
|
KefAcquireSpinLockAtDpcLevel(Interrupt->ActualLock);
|
|
return OldIrql;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt,
|
|
IN KIRQL OldIrql)
|
|
{
|
|
/* Release lock on MP */
|
|
KefReleaseSpinLockFromDpcLevel(Interrupt->ActualLock);
|
|
|
|
/* Lower IRQL */
|
|
KeLowerIrql(OldIrql);
|
|
}
|
|
|
|
/* EOF */
|