495 lines
7.4 KiB
C
495 lines
7.4 KiB
C
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
spinlock.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the platform specific functions for acquiring
|
|
and releasing spin locks.
|
|
|
|
Author:
|
|
|
|
David N. Cutler (davec) 12-Jun-2000
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "ki.h"
|
|
|
|
__forceinline
|
|
VOID
|
|
KxAcquireSpinLock (
|
|
IN PKSPIN_LOCK SpinLock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function acquires a spin lock at the current IRQL.
|
|
|
|
Arguments:
|
|
|
|
SpinLock - Supplies a pointer to an spin lock.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PKTHREAD Thread;
|
|
|
|
//
|
|
// Acquire the specified spin lock at the current IRQL.
|
|
//
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
#if DBG
|
|
|
|
Thread = KeGetCurrentThread();
|
|
while (InterlockedCompareExchange64((PLONGLONG)SpinLock,
|
|
(LONGLONG)Thread,
|
|
0) != 0) {
|
|
|
|
#else
|
|
|
|
while (InterlockedExchange64((PLONGLONG)SpinLock,
|
|
(LONGLONG)SpinLock) != 0) {
|
|
|
|
#endif // DBG
|
|
|
|
do {
|
|
} while (*(volatile LONGLONG *)SpinLock != 0);
|
|
}
|
|
|
|
#endif // !defined(NT_UP)
|
|
|
|
return;
|
|
}
|
|
|
|
__forceinline
|
|
BOOLEAN
|
|
KxTryToAcquireSpinLock (
|
|
IN PKSPIN_LOCK SpinLock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function attempts acquires a spin lock at the current IRQL. If
|
|
the spinlock is already owned, then FALSE is returned. Otherwise,
|
|
TRUE is returned.
|
|
|
|
Arguments:
|
|
|
|
SpinLock - Supplies a pointer to a spin lock.
|
|
|
|
Return Value:
|
|
|
|
If the spin lock is acquired a value TRUE is returned. Otherwise, FALSE
|
|
is returned as the function value.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PKTHREAD Thread;
|
|
|
|
//
|
|
// Try to acquire the specified spin lock at the current IRQL.
|
|
//
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
if (*(volatile ULONGLONG *)SpinLock == 0) {
|
|
|
|
#if DBG
|
|
|
|
Thread = KeGetCurrentThread();
|
|
return InterlockedCompareExchange64((PLONGLONG)SpinLock,
|
|
(LONGLONG)Thread,
|
|
0) == 0;
|
|
|
|
#else
|
|
|
|
return InterlockedExchange64((PLONGLONG)SpinLock,
|
|
(LONGLONG)SpinLock) == 0;
|
|
|
|
#endif // DBG
|
|
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
|
|
#else
|
|
|
|
return TRUE;
|
|
|
|
#endif // !defined(NT_UP)
|
|
|
|
}
|
|
|
|
__forceinline
|
|
VOID
|
|
KxReleaseSpinLock (
|
|
IN PKSPIN_LOCK SpinLock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function releases the specified spin lock at the current IRQL.
|
|
|
|
Arguments:
|
|
|
|
SpinLock - Supplies a pointer to a spin lock.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
#if DBG
|
|
|
|
ASSERT(*(volatile ULONGLONG *)SpinLock == (ULONGLONG)KeGetCurrentThread());
|
|
|
|
#endif // DBG
|
|
|
|
*(volatile ULONGLONG *)SpinLock = 0;
|
|
|
|
#endif // !defined(NT_UP)
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
KeInitializeSpinLock (
|
|
IN PKSPIN_LOCK SpinLock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes a spin lock.
|
|
|
|
Arguments:
|
|
|
|
SpinLock - Supplies a pointer to a spin lock.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
*(volatile ULONGLONG *)SpinLock = 0;
|
|
return;
|
|
}
|
|
|
|
KIRQL
|
|
KeAcquireSpinLockRaiseToDpc (
|
|
IN PKSPIN_LOCK SpinLock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function raises IRQL to DISPATCH_LEVEL and acquires the specified
|
|
spin lock.
|
|
|
|
Arguments:
|
|
|
|
SpinLock - Supplies a pointer to a spin lock.
|
|
|
|
Return Value:
|
|
|
|
The previous IRQL is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
|
|
//
|
|
// Raise IRQL to DISPATCH_LEVEL and acquire the specified spin lock.
|
|
//
|
|
|
|
OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
|
|
KxAcquireSpinLock(SpinLock);
|
|
return OldIrql;
|
|
}
|
|
|
|
KIRQL
|
|
KeAcquireSpinLockRaiseToSynch (
|
|
IN PKSPIN_LOCK SpinLock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function raises IRQL to SYNCH_LEVEL and acquires the specified
|
|
spin lock.
|
|
|
|
Arguments:
|
|
|
|
SpinLock - Supplies a pointer to a spin lock.
|
|
|
|
Return Value:
|
|
|
|
The previous IRQL is returned as the function value.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
|
|
//
|
|
// Raise IRQL to SYNCH_LEVEL and acquire the specified spin lock.
|
|
//
|
|
|
|
OldIrql = KfRaiseIrql(SYNCH_LEVEL);
|
|
KxAcquireSpinLock(SpinLock);
|
|
return OldIrql;
|
|
}
|
|
|
|
VOID
|
|
KeAcquireSpinLockAtDpcLevel (
|
|
IN PKSPIN_LOCK SpinLock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function acquires a spin lock at the current IRQL.
|
|
|
|
Arguments:
|
|
|
|
SpinLock - Supplies a pointer to an spin lock.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Acquired the specified spin lock at the current IRQL.
|
|
//
|
|
|
|
KxAcquireSpinLock(SpinLock);
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
KeTryToAcquireSpinLock (
|
|
IN PKSPIN_LOCK SpinLock,
|
|
OUT PKIRQL OldIrql
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function raises IRQL to DISPATCH level and attempts to acquire a
|
|
spin lock. If the spin lock is already owned, then IRQL is restored to
|
|
its previous value and FALSE is returned. Otherwise, the spin lock is
|
|
acquired and TRUE is returned.
|
|
|
|
Arguments:
|
|
|
|
SpinLock - Supplies a pointer to a spin lock.
|
|
|
|
OldIrql - Supplies a pointer to a variable that receives the old IRQL.
|
|
|
|
Return Value:
|
|
|
|
If the spin lock is acquired a value TRUE is returned. Otherwise, FALSE
|
|
is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Raise IRQL to DISPATCH level and attempt to acquire the specified
|
|
// spin lock.
|
|
//
|
|
|
|
*OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
|
|
if (KxTryToAcquireSpinLock(SpinLock) == FALSE) {
|
|
KeLowerIrql(*OldIrql);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
KeTryToAcquireSpinLockAtDpcLevel (
|
|
IN PKSPIN_LOCK SpinLock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function attempts acquires a spin lock at the current IRQL. If
|
|
the spinlock is already owned, then FALSE is returned. Otherwise,
|
|
TRUE is returned.
|
|
|
|
Arguments:
|
|
|
|
SpinLock - Supplies a pointer to a spin lock.
|
|
|
|
Return Value:
|
|
|
|
If the spin lock is acquired a value TRUE is returned. Otherwise, FALSE
|
|
is returned as the function value.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Try to acquire the specified spin lock at the current IRQL.
|
|
//
|
|
|
|
return KxTryToAcquireSpinLock(SpinLock);
|
|
}
|
|
|
|
VOID
|
|
KeReleaseSpinLock (
|
|
IN PKSPIN_LOCK SpinLock,
|
|
IN KIRQL OldIrql
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function releases the specified spin lock and lowers IRQL to a
|
|
previous value.
|
|
|
|
Arguments:
|
|
|
|
SpinLock - Supplies a pointer to a spin lock.
|
|
|
|
OldIrql - Supplies the previous IRQL value.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Release the specified spin lock and lower IRQL.
|
|
//
|
|
|
|
KxReleaseSpinLock(SpinLock);
|
|
KeLowerIrql(OldIrql);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
KeReleaseSpinLockFromDpcLevel (
|
|
IN PKSPIN_LOCK SpinLock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function releases a spin lock at the current IRQL.
|
|
|
|
Arguments:
|
|
|
|
SpinLock - Supplies a pointer to a spin lock.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Release the specified spin lock.
|
|
//
|
|
|
|
KxReleaseSpinLock(SpinLock);
|
|
return;
|
|
}
|
|
|
|
#if defined(KeTestSpinLock)
|
|
#undef KeTestSpinLock
|
|
#endif
|
|
|
|
|
|
BOOLEAN
|
|
KeTestSpinLock (
|
|
IN PKSPIN_LOCK SpinLock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function tests a spin lock to determine if it is currently owned.
|
|
If the spinlock is already owned, then FALSE is returned. Otherwise,
|
|
TRUE is returned.
|
|
|
|
Arguments:
|
|
|
|
SpinLock - Supplies a pointer to a spin lock.
|
|
|
|
Return Value:
|
|
|
|
If the spin lock is currently owned, then a value of FALSE is returned.
|
|
Otherwise, a value of TRUE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
#if !defined(NT_UP)
|
|
return (*(volatile ULONGLONG *)SpinLock == 0);
|
|
#else
|
|
return TRUE;
|
|
#endif // !defined(NT_UP)
|
|
}
|
|
|