原创:IRQL高于DPC伪级别使用自旋锁 By 旖旎(于2009-2-1发表)

//微软为开发者提供了IRQL低于DPC级别(严格来说是伪级别,因为并非处理器级别,而是微软模拟的虚假//级别,其目的不详,也许是为了麻痹开发者吧。)下使用自旋锁的方法。但是很多时候往往要在IRQL高于//该伪级别下使用自旋锁,那应该怎么办呢?翻开WRK阅之。

//微软的KeBugCheck2函数,运行级别是HIGH_LEVEL,但是为防止重入应该使用了自旋锁,确实如此吗?记//事本打开看之。

//=====================================================================
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
    KiAcquireSpinLock(&KeBugCheckCallbackLock);

    //
    // If the specified callback record is currently not registered, then
    // register the callback record.
    //{

    BOOLEAN Deregister;
    KIRQL OldIrql;
    //
    // Raise IRQL to HIGH_LEVEL and acquire the bugcheck callback list
    // spinlock.
    //
    //提升IRQL到HIGH_LEVEL级别并且请求故障检测(所谓:蓝屏)回调列表自旋锁

    KeRaiseIrql(HIGH_LEVEL, &OldIrql);            //提升IRQL
    KiAcquireSpinLock(&KeBugCheckCallbackLock);        //获得自旋锁

    //
    // If the specified callback record is currently registered, then
    // deregister the callback record.
    //

    Deregister = FALSE;
    if (CallbackRecord->State == BufferInserted) {
        CallbackRecord->State = BufferEmpty;
        RemoveEntryList(&CallbackRecord->Entry);
        Deregister = TRUE;
    }

    //
    // Release the bugcheck callback spinlock, lower IRQL to its previous
    // value, and return whether the callback record was successfully
    // deregistered.
    //

    KiReleaseSpinLock(&KeBugCheckCallbackLock);        //释放自旋锁
    KeLowerIrql(OldIrql);                //降低IRQL
    return Deregister;
}

//=====================================================================


//得到以下两个函数:
FASTCALL VOID 
KiAcquireSpinLock(
    IN PKSPIN_LOCK  SpinLock,
    );

FASTCALL VOID 
KiReleaseSpinLock(
    IN PKSPIN_LOCK  SpinLock,
    );

//注意是FASTCALL函数,也就是:ECX存放第一个参数 EDX存放第2个参数,其余参数从右到左依次压栈,由//被调用着清除堆栈。
//注意:该函数既不提高IRQL也不降低IRQL,我们可以仿照KeBugCheck那样 调用前提高优先级到HIGH_LEVLL

//=====================================================================
//其实自旋锁只是一个循环,无非是使用了PAUSE指令,可以节省处理器使用率。并且使用了原子测试指令//lock bts来测试而已。IDA打开NTOS,找到以下的代码

//=====================================================================
.text:004699D0                 public KiAcquireSpinLock            //注意:是导出函数
.text:004699D0 KiAcquireSpinLock proc near             ; CODE XREF: sub_4172CC+2Dp
.text:004699D0                                         ; sub_4209A8+5j ...
.text:004699D0                 lock bts dword ptr [ecx], 0
.text:004699D5                 jb      short loc_4699D8
.text:004699D7                 retn
.text:004699D8 ; ---------------------------------------------------------------------------
.text:004699D8
.text:004699D8 loc_4699D8:                             ; CODE XREF: KiAcquireSpinLock+5j
.text:004699D8                                         ; KiAcquireSpinLock+12j
.text:004699D8                 test    dword ptr [ecx], 1
.text:004699DE                 jz      short KiAcquireSpinLock
.text:004699E0                 pause
.text:004699E2                 jmp     short loc_4699D8
.text:004699E2 KiAcquireSpinLock endp


//=====================================================================

.text:004699F0                 public KiReleaseSpinLock
.text:004699F0 KiReleaseSpinLock proc near             ; CODE XREF: sub_41730C+Ep
.text:004699F0                                         ; sub_4209B8+5j ...
.text:004699F0                 mov     byte ptr [ecx], 0
.text:004699F3                 retn
.text:004699F3 KiReleaseSpinLock endp
//所谓的自旋锁也不过如此而已。
//关闭记事本,写以下日志,以供参考。
//旖旎 2008.05.23

并不是所有的贴子都是原创,此时作者均指发表的人而不是文章的作者,作者会说明是否是转贴