Implement in-stack queued spinlock
This commit is contained in:
@@ -40,6 +40,10 @@
|
|||||||
#define IPI_FROZEN_STATE_FREEZE 0x05
|
#define IPI_FROZEN_STATE_FREEZE 0x05
|
||||||
#define IPI_FROZEN_STATE_ACTIVE 0x20
|
#define IPI_FROZEN_STATE_ACTIVE 0x20
|
||||||
|
|
||||||
|
/* Lock queue states */
|
||||||
|
#define LOCK_QUEUE_WAIT 1
|
||||||
|
#define LOCK_QUEUE_OWNER 2
|
||||||
|
|
||||||
/* APC pending state length */
|
/* APC pending state length */
|
||||||
#define KAPC_STATE_LENGTH (FIELD_OFFSET(KAPC_STATE, UserApcPending) + sizeof(BOOLEAN))
|
#define KAPC_STATE_LENGTH (FIELD_OFFSET(KAPC_STATE, UserApcPending) + sizeof(BOOLEAN))
|
||||||
|
|
||||||
|
|||||||
@@ -36,13 +36,20 @@ namespace KE
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
STATIC XTFASTCALL VOID AcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_LEVEL LockLevel);
|
STATIC XTFASTCALL VOID AcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_LEVEL LockLevel);
|
||||||
|
STATIC XTFASTCALL VOID AcquireQueuedSpinLock(IN PKSPIN_LOCK SpinLock,
|
||||||
|
IN PKLOCK_QUEUE_HANDLE LockQueueHandle);
|
||||||
STATIC XTFASTCALL VOID AcquireSpinLock(IN OUT PKSPIN_LOCK SpinLock);
|
STATIC XTFASTCALL VOID AcquireSpinLock(IN OUT PKSPIN_LOCK SpinLock);
|
||||||
STATIC XTAPI VOID InitializeAllLocks();
|
STATIC XTAPI VOID InitializeAllLocks();
|
||||||
STATIC XTAPI VOID InitializeLockQueues();
|
STATIC XTAPI VOID InitializeLockQueues();
|
||||||
STATIC XTAPI VOID InitializeSpinLock(IN PKSPIN_LOCK SpinLock);
|
STATIC XTAPI VOID InitializeSpinLock(IN PKSPIN_LOCK SpinLock);
|
||||||
STATIC XTFASTCALL VOID ReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_LEVEL LockLevel);
|
STATIC XTFASTCALL VOID ReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_LEVEL LockLevel);
|
||||||
|
STATIC XTFASTCALL VOID ReleaseQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockQueueHandle);
|
||||||
STATIC XTFASTCALL VOID ReleaseSpinLock(IN OUT PKSPIN_LOCK SpinLock);
|
STATIC XTFASTCALL VOID ReleaseSpinLock(IN OUT PKSPIN_LOCK SpinLock);
|
||||||
STATIC XTFASTCALL BOOLEAN TestSpinLock(IN PKSPIN_LOCK SpinLock);
|
STATIC XTFASTCALL BOOLEAN TestSpinLock(IN PKSPIN_LOCK SpinLock);
|
||||||
|
|
||||||
|
private:
|
||||||
|
STATIC XTFASTCALL VOID AcquireQueuedSpinLock(IN PKSPIN_LOCK_QUEUE LockQueue);
|
||||||
|
STATIC XTFASTCALL VOID ReleaseQueuedSpinLock(IN PKSPIN_LOCK_QUEUE LockQueue);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Acquires a specified queued spinlock.
|
* Acquires a pre-allocated system queued spinlock.
|
||||||
*
|
*
|
||||||
* @param LockLevel
|
* @param LockLevel
|
||||||
* Supplies the queued spinlock level.
|
* Supplies the queued spinlock level.
|
||||||
@@ -25,7 +25,66 @@ VOID
|
|||||||
KE::SpinLock::AcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_LEVEL LockLevel)
|
KE::SpinLock::AcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_LEVEL LockLevel)
|
||||||
{
|
{
|
||||||
/* Acquire the queued spinlock */
|
/* Acquire the queued spinlock */
|
||||||
AcquireSpinLock(KE::Processor::GetCurrentProcessorControlBlock()->LockQueue[LockLevel].Lock);
|
AcquireQueuedSpinLock(&KE::Processor::GetCurrentProcessorControlBlock()->LockQueue[LockLevel]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a lock queue handle and acquires an in-stack queued spin lock.
|
||||||
|
*
|
||||||
|
* @param SpinLock
|
||||||
|
* Supplies a pointer to the global queued spin lock to be acquired.
|
||||||
|
*
|
||||||
|
* @param LockQueueHandle
|
||||||
|
* Supplies a pointer to a caller-allocated lock queue handle.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTFASTCALL
|
||||||
|
VOID
|
||||||
|
KE::SpinLock::AcquireQueuedSpinLock(IN PKSPIN_LOCK SpinLock,
|
||||||
|
IN PKLOCK_QUEUE_HANDLE LockQueueHandle)
|
||||||
|
{
|
||||||
|
/* Initialize the queue node */
|
||||||
|
LockQueueHandle->LockQueue.Lock = SpinLock;
|
||||||
|
LockQueueHandle->LockQueue.Next = NULLPTR;
|
||||||
|
|
||||||
|
/* Acquire queued spin lock */
|
||||||
|
AcquireQueuedSpinLock(&LockQueueHandle->LockQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquires an in-stack queued spin lock.
|
||||||
|
*
|
||||||
|
* @param LockQueue
|
||||||
|
* Supplies a pointer to the local, stack-allocated lock queue entry.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTFASTCALL
|
||||||
|
VOID
|
||||||
|
KE::SpinLock::AcquireQueuedSpinLock(IN PKSPIN_LOCK_QUEUE LockQueue)
|
||||||
|
{
|
||||||
|
PKSPIN_LOCK_QUEUE LockQueueTail;
|
||||||
|
|
||||||
|
/* Swap the global lock pointer */
|
||||||
|
LockQueueTail = (PKSPIN_LOCK_QUEUE)RTL::Atomic::ExchangePointer((PVOID*)LockQueue->Lock, LockQueue);
|
||||||
|
if(LockQueueTail)
|
||||||
|
{
|
||||||
|
/* Mark the lock state as waiting and link local node to the previous queue tail */
|
||||||
|
LockQueue->Lock = (PKSPIN_LOCK)((ULONG_PTR)LockQueue->Lock | LOCK_QUEUE_WAIT);
|
||||||
|
LockQueueTail->Next = LockQueue;
|
||||||
|
|
||||||
|
/* Spin until the previous owner clears the wait flag */
|
||||||
|
while((*(VOLATILE PULONG_PTR)&LockQueue->Lock) & LOCK_QUEUE_WAIT)
|
||||||
|
{
|
||||||
|
/* Yield the processor*/
|
||||||
|
AR::CpuFunctions::YieldProcessor();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -148,7 +207,7 @@ KE::SpinLock::InitializeSpinLock(IN PKSPIN_LOCK SpinLock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases a queued spinlock.
|
* Releases a pre-allocated system queued spinlock.
|
||||||
*
|
*
|
||||||
* @param LockLevel
|
* @param LockLevel
|
||||||
* Supplies the queued spinlock level.
|
* Supplies the queued spinlock level.
|
||||||
@@ -162,7 +221,65 @@ VOID
|
|||||||
KE::SpinLock::ReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_LEVEL LockLevel)
|
KE::SpinLock::ReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_LEVEL LockLevel)
|
||||||
{
|
{
|
||||||
/* Clear the lock */
|
/* Clear the lock */
|
||||||
ReleaseSpinLock(KE::Processor::GetCurrentProcessorControlBlock()->LockQueue[LockLevel].Lock);
|
ReleaseQueuedSpinLock(&KE::Processor::GetCurrentProcessorControlBlock()->LockQueue[LockLevel]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases an in-stack queued spin lock using the provided lock queue handle.
|
||||||
|
*
|
||||||
|
* @param LockQueueHandle
|
||||||
|
* Supplies a pointer to the lock queue handle that currently holds the lock.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTFASTCALL
|
||||||
|
VOID
|
||||||
|
KE::SpinLock::ReleaseQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockQueueHandle)
|
||||||
|
{
|
||||||
|
/* Release queued spin lock */
|
||||||
|
ReleaseQueuedSpinLock(&LockQueueHandle->LockQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases an in-stack queued spin lock.
|
||||||
|
*
|
||||||
|
* @param LockQueue
|
||||||
|
* Supplies a pointer to the local, stack-allocated lock queue entry that currently holds the lock.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTFASTCALL
|
||||||
|
VOID
|
||||||
|
KE::SpinLock::ReleaseQueuedSpinLock(IN PKSPIN_LOCK_QUEUE LockQueue)
|
||||||
|
{
|
||||||
|
PKSPIN_LOCK_QUEUE NextLockQueue;
|
||||||
|
|
||||||
|
/* Get the pointer to the next waiting processor in the queue */
|
||||||
|
NextLockQueue = LockQueue->Next;
|
||||||
|
if(!NextLockQueue)
|
||||||
|
{
|
||||||
|
/* Remove the lock */
|
||||||
|
if(RTL::Atomic::CompareExchangePointer((PVOID *)LockQueue->Lock, NULLPTR, LockQueue) == LockQueue)
|
||||||
|
{
|
||||||
|
/* Lock removed, exit */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait until next pointer is updated */
|
||||||
|
while(!(NextLockQueue = *(VOLATILE PKSPIN_LOCK_QUEUE *)&LockQueue->Next))
|
||||||
|
{
|
||||||
|
/* Yield the processor*/
|
||||||
|
AR::CpuFunctions::YieldProcessor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up local node and clear wait flag */
|
||||||
|
LockQueue->Next = NULLPTR;
|
||||||
|
NextLockQueue->Lock = (PKSPIN_LOCK)((ULONG_PTR)NextLockQueue->Lock ^ LOCK_QUEUE_WAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user