- Fix InterlockedBitTestAndReset and InterlockedBitTestAndSet

- Implement YieldProcessor
- Fix formatting in spinlock.c
- KiAcquireSpinlock and KiReleaseSpinLock should be no-op functions on uniprocessor machines.
- KiReleaseSpinLock does not need interlocked access to release the lock.
- Use portable code for KiAcquireSpinLock. Also use interlocked bit operations since they are faster.

svn path=/trunk/; revision=20436
This commit is contained in:
Alex Ionescu 2005-12-29 19:54:42 +00:00
parent ea4fcb6188
commit 3785fc8f82
2 changed files with 108 additions and 123 deletions

View file

@ -1,16 +1,10 @@
/* $Id$
*
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PROJECT: ReactOS Kernel
* FILE: ntoskrnl/ke/spinlock.c
* PURPOSE: Implements spinlocks
*
* PROGRAMMERS: David Welch (welch@cwcom.net)
*/
/*
* NOTE: On a uniprocessor machine spinlocks are implemented by raising
* the irq level
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
* David Welch (welch@cwcom.net)
*/
/* INCLUDES ****************************************************************/
@ -19,16 +13,16 @@
#define NDEBUG
#include <internal/debug.h>
#undef KefAcquireSpinLockAtDpcLevel
#undef KeAcquireSpinLockAtDpcLevel
#undef KefReleaseSpinLockFromDpcLevel
#undef KeReleaseSpinLockFromDpcLevel
/* FUNCTIONS ***************************************************************/
/*
* @implemented
*/
BOOLEAN STDCALL
KeSynchronizeExecution (PKINTERRUPT Interrupt,
PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
PVOID SynchronizeContext)
/*
*
* FUNCTION: Synchronizes the execution of a given routine with the ISR
* of a given interrupt object
* ARGUMENTS:
@ -38,17 +32,26 @@ KeSynchronizeExecution (PKINTERRUPT Interrupt,
* SynchronizeContext = Parameter to pass to the synchronized routine
* RETURNS: TRUE if the operation succeeded
*/
BOOLEAN
STDCALL
KeSynchronizeExecution(PKINTERRUPT Interrupt,
PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
PVOID SynchronizeContext)
{
KIRQL oldlvl;
BOOLEAN ret;
KIRQL OldIrql;
BOOLEAN Status;
oldlvl = KeAcquireInterruptSpinLock(Interrupt);
/* Raise IRQL and acquire lock on MP */
OldIrql = KeAcquireInterruptSpinLock(Interrupt);
ret = SynchronizeRoutine(SynchronizeContext);
/* Call the routine */
Status = SynchronizeRoutine(SynchronizeContext);
KeReleaseInterruptSpinLock(Interrupt, oldlvl);
/* Release lock and lower IRQL */
KeReleaseInterruptSpinLock(Interrupt, OldIrql);
return(ret);
/* Return routine status */
return Status;
}
/*
@ -56,148 +59,107 @@ KeSynchronizeExecution (PKINTERRUPT Interrupt,
*/
KIRQL
STDCALL
KeAcquireInterruptSpinLock(
IN PKINTERRUPT Interrupt
)
KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
{
KIRQL oldIrql;
KIRQL OldIrql;
KeRaiseIrql(Interrupt->SynchronizeIrql, &oldIrql);
KiAcquireSpinLock(Interrupt->ActualLock);
return oldIrql;
/* Raise IRQL */
KeRaiseIrql(Interrupt->SynchronizeIrql, &OldIrql);
/* Acquire spinlock on MP */
KiAcquireSpinLock(Interrupt->ActualLock);
return OldIrql;
}
/*
* @implemented
*/
VOID STDCALL
KeInitializeSpinLock (PKSPIN_LOCK SpinLock)
/*
*
* FUNCTION: Initalizes a spinlock
* ARGUMENTS:
* SpinLock = Caller supplied storage for the spinlock
*/
VOID
STDCALL
KeInitializeSpinLock(PKSPIN_LOCK SpinLock)
{
*SpinLock = 0;
*SpinLock = 0;
}
#undef KefAcquireSpinLockAtDpcLevel
/*
* @implemented
*/
VOID FASTCALL
VOID
FASTCALL
KefAcquireSpinLockAtDpcLevel(PKSPIN_LOCK SpinLock)
{
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
KiAcquireSpinLock(SpinLock);
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
KiAcquireSpinLock(SpinLock);
}
#undef KeAcquireSpinLockAtDpcLevel
/*
* @implemented
*/
VOID STDCALL
KeAcquireSpinLockAtDpcLevel (PKSPIN_LOCK SpinLock)
/*
*
* FUNCTION: Acquires a spinlock when the caller is already running at
* dispatch level
* ARGUMENTS:
* SpinLock = Spinlock to acquire
*/
VOID
STDCALL
KeAcquireSpinLockAtDpcLevel (PKSPIN_LOCK SpinLock)
{
KefAcquireSpinLockAtDpcLevel(SpinLock);
KefAcquireSpinLockAtDpcLevel(SpinLock);
}
/*
* @unimplemented
* @implemented
*/
VOID
FASTCALL
KeAcquireInStackQueuedSpinLockAtDpcLevel(
IN PKSPIN_LOCK SpinLock,
IN PKLOCK_QUEUE_HANDLE LockHandle
)
{
UNIMPLEMENTED;
}
#undef KefReleaseSpinLockFromDpcLevel
/*
* @implemented
*/
VOID FASTCALL
KefReleaseSpinLockFromDpcLevel(PKSPIN_LOCK SpinLock)
{
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
KiReleaseSpinLock(SpinLock);
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
KiReleaseSpinLock(SpinLock);
}
#undef KeReleaseSpinLockFromDpcLevel
/*
* @implemented
*/
VOID STDCALL
KeReleaseSpinLockFromDpcLevel (PKSPIN_LOCK SpinLock)
/*
*
* FUNCTION: Releases a spinlock when the caller was running at dispatch
* level before acquiring it
* ARGUMENTS:
* SpinLock = Spinlock to release
*/
{
KefReleaseSpinLockFromDpcLevel(SpinLock);
}
/*
* @unimplemented
*/
VOID
FASTCALL
KeReleaseInStackQueuedSpinLockFromDpcLevel(
IN PKLOCK_QUEUE_HANDLE LockHandle
)
STDCALL
KeReleaseSpinLockFromDpcLevel (PKSPIN_LOCK SpinLock)
{
UNIMPLEMENTED;
KefReleaseSpinLockFromDpcLevel(SpinLock);
}
/*
* @implemented
*/
VOID FASTCALL
VOID
FASTCALL
KiAcquireSpinLock(PKSPIN_LOCK SpinLock)
{
ULONG i;
/*
* FIXME: This depends on gcc assembling this test to a single load from
* the spinlock's value.
*/
ASSERT(*SpinLock < 2);
while ((i = InterlockedExchangeUL(SpinLock, 1)) == 1)
{
#ifdef CONFIG_SMP
/* Avoid reading the value again too fast */
#if 1
__asm__ __volatile__ ("1:\n\t"
"cmpl $0,(%0)\n\t"
"jne 1b\n\t"
:
: "r" (SpinLock));
#else
while (0 != *(volatile KSPIN_LOCK*)SpinLock);
#endif
#else
DbgPrint("Spinning on spinlock %x current value %x\n", SpinLock, i);
KEBUGCHECKEX(SPIN_LOCK_ALREADY_OWNED, (ULONG)SpinLock, 0, 0, 0);
for (;;)
{
/* Try to acquire it */
if (InterlockedBitTestAndSet((PLONG)SpinLock, 0))
{
/* Value changed... wait until it's locked */
while (*SpinLock == 1) YieldProcessor();
}
else
{
/* All is well, break out */
break;
}
}
#endif /* CONFIG_SMP */
}
}
/*
@ -205,27 +167,48 @@ KiAcquireSpinLock(PKSPIN_LOCK SpinLock)
*/
VOID
STDCALL
KeReleaseInterruptSpinLock(
IN PKINTERRUPT Interrupt,
IN KIRQL OldIrql
)
KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt,
IN KIRQL OldIrql)
{
KiReleaseSpinLock(Interrupt->ActualLock);
KeLowerIrql(OldIrql);
/* Release lock on MP */
KiReleaseSpinLock(Interrupt->ActualLock);
/* Lower IRQL */
KeLowerIrql(OldIrql);
}
/*
* @implemented
*/
VOID FASTCALL
VOID
FASTCALL
KiReleaseSpinLock(PKSPIN_LOCK SpinLock)
{
if (*SpinLock != 1)
{
DbgPrint("Releasing unacquired spinlock %x\n", SpinLock);
KEBUGCHECKEX(SPIN_LOCK_NOT_OWNED, (ULONG)SpinLock, 0, 0, 0);
}
(void)InterlockedExchangeUL(SpinLock, 0);
#ifdef CONFIG_SMP
/* Simply clear it */
*SpinLock = 0;
#endif
}
/*
* @unimplemented
*/
VOID
FASTCALL
KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock,
IN PKLOCK_QUEUE_HANDLE LockHandle)
{
UNIMPLEMENTED;
}
/*
* @unimplemented
*/
VOID
FASTCALL
KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle)
{
UNIMPLEMENTED;
}
/* EOF */

View file

@ -3700,7 +3700,7 @@ InterlockedBitTestAndSet(IN LONG *Base,
{
LONG OldBit;
__asm__ __volatile__("lock"
__asm__ __volatile__("lock "
"btsl %2,%1\n\t"
"sbbl %0,%0\n\t"
:"=r" (OldBit),"=m" (*Base)
@ -3715,7 +3715,7 @@ InterlockedBitTestAndReset(IN LONG *Base,
{
LONG OldBit;
__asm__ __volatile__("lock"
__asm__ __volatile__("lock "
"btrl %2,%1\n\t"
"sbbl %0,%0\n\t"
:"=r" (OldBit),"=m" (*Base)
@ -3726,6 +3726,8 @@ InterlockedBitTestAndReset(IN LONG *Base,
#endif
#define YieldProcessor() __asm__ __volatile__("pause");
#if defined(_AMD64_)
#if defined(_M_AMD64)