找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 12017|回复: 1

KeAcquireInStackQueuedSpinLock的实现

[复制链接]

1

主题

26

回帖

0

精华

铜牌会员

积分
219
发表于 2015-6-15 18:57:12 | 显示全部楼层 |阅读模式
最近在看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.

最后:微软程序员思想真扭曲。。。。

评分

参与人数 1水晶币 +20 收起 理由
Tesla.Angela + 20

查看全部评分

857

主题

2632

回帖

2

精华

管理员

此生无悔入华夏,  长居日耳曼尼亚。  

积分
36130
发表于 2015-6-15 21:16:18 | 显示全部楼层
写得很好,希望楼主多多在此发帖!
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

快速回复 返回顶部 返回列表