|
最近在看WRK源码时,总是碰到这个函数。今天研究了的时候一时还没反应过来。
1.先说下整体设计思想。首先,要有一个全局的PSPIN_LOCK。其次是一个关键的结构
typedef struct _KSPIN_LOCK_QUEUE
{
struct _KSPIN_LOCK_QUEUE * volatile Next;
PKSPIN_LOCK volatile Lock;
}
typedef struct _KLOCK_QUEUE_HANDLE
{
KSPIN_LOCK_QUEUE LockQueue;
KIRQL OldIrql;
}
神奇就神奇在这里了。在获取锁的过程中,它会修改PSPIN_LOCK的指向,使其指向我们栈中的一个类型为LOCK_QUEUE_HANDLE的局部变量。而我们局部变量中LockQueue->Next将指向全局的PSPIN_LOCK。若其他线程继续执行如此操作,它会把上一个栈中的局部变量获得,并将自己的变量插入到上一个局部变量之后。
参考代码:
VOID
KeAcquireInStackQueuedSpinLock (
__inout PKSPIN_LOCK SpinLock ,
__out PKLOCK_QUEUE_HANDLE LockHandle
)
/*++
Routine Description:
This function raises IRQL to DISPATCH_LEVEL and acquires the specified
in stack queued spin lock.
Arguments:
SpinLock - Supplies the home address of the queued spin lock.
LockHandle - Supplies the address of a lock queue handle.
Return Value:
None.
--*/
{
//
// Raise IRQL to DISPATCH_LEVEL and acquire the specified in stack
// queued spin lock.
//
#if ! defined (NT_UP )
LockHandle -> LockQueue . Lock = SpinLock ;
LockHandle -> LockQueue . Next = NULL ;
#else
UNREFERENCED_PARAMETER(SpinLock);
#endif
LockHandle -> OldIrql = KfRaiseIrql (DISPATCH_LEVEL );
KxAcquireQueuedSpinLock (& LockHandle -> LockQueue , SpinLock );
return ;
}
VOID
KxAcquireQueuedSpinLock (
__inout PKSPIN_LOCK_QUEUE LockQueue ,
__inout PKSPIN_LOCK SpinLock
)
/*++
Routine Description:
This function acquires a queued spin lock at the current IRQL.
Arguments:
LockQueue - Supplies a pointer to a spin lock queue.
SpinLock - Supplies a pointer to the spin lock associated with the lock
queue.
Return Value:
None.
--*/
{
//
// Insert the specified lock queue entry at the end of the lock queue
// list. If the list was previously empty, then lock ownership is
// immediately granted. Otherwise, wait for ownership of the lock to
// be granted.
//
#if ! defined (NT_UP )
PKSPIN_LOCK_QUEUE TailQueue ;
TailQueue = InterlockedExchangePointer ((PVOID *) SpinLock , LockQueue );
if ( TailQueue != NULL )
{
KxWaitForLockOwnerShip ( LockQueue , TailQueue );
}
#else
UNREFERENCED_PARAMETER(LockQueue);
UNREFERENCED_PARAMETER(SpinLock);
#endif
return ;
}
ULONG64
KxWaitForLockOwnerShip (
__inout PKSPIN_LOCK_QUEUE LockQueue ,
__inout PKSPIN_LOCK_QUEUE TailQueue
)
/*++
Routine Description:
Arguments:
LockQueue - Supplies the address of the lock queue entry that is now
the last entry in the lock queue.
TailQueue - Supplies the address of the previous last entry in the lock
queue.
Return Value:
The number of wait loops that were executed.
--*/
{
ULONG64 SpinCount ;
//
// Set the wait bit in the acquiring lock queue entry and set the next
// lock queue entry in the last lock queue entry.
//
*(( ULONG64 volatile *)& LockQueue -> Lock) |= LOCK_QUEUE_WAIT ;
TailQueue -> Next = LockQueue ;
//
// Wait for lock ownership to be passed.
//
SpinCount = 0;
do {
KeYieldProcessor ();
} while ((*(( ULONG64 volatile *)& LockQueue -> Lock) & LOCK_QUEUE_WAIT ) != 0);
KeMemoryBarrier ();
return SpinCount ;
}
总结:
1.初始化局部变量的值.
2.提升中断请求级。
3.执行关键函数 TailQueue = InterlockedExchangePointer ((PVOID *) SpinLock , LockQueue );
若TailQueue未空(第一次)则直接获得资源返回。若不为空(非第一次),则设置LockQueue->Lock标志LOCK_QUEUE_WAIT,插链表
TailQueue->Next = LockQueue.
最后:微软程序员思想真扭曲。。。。
|
评分
-
查看全部评分
|