Windows驱动程序,自旋锁获取和条件测试

时间:2017-11-07 20:57:34

标签: c++ windows multithreading wdm

在一个调度例程中,我们有以下代码:

if (DeviceExtension->Flag)
{
    KeAcquireInStackQueuedSpinLockAtDpcLevel(&DeviceExtension->SpinLock, &LockHandle);

    //... when we will enter here, DeviceExtension->Flag can already be set to FALSE.

    KeReleaseInStackQueuedSpinLockFromDpcLevel(&LockHandle);
}

在另一个调度例程中,我们有以下代码:

KeAcquireInStackQueuedSpinLockAtDpcLevel(&DeviceExtension->SpinLock, &LockHandle);

//...

DeviceExtension->Flag = FALSE;
KeReleaseInStackQueuedSpinLockFromDpcLevel(&LockHandle);

因此,当我们在第一个调度例程中获得自旋锁定时,DeviceExtension->Flag已经可以通过第二个例程设置为FALSE。解决方案是获取自旋锁,然后检查DeviceExtension->Flag。但是DeviceExtension->Flag可能是FALSE,在这种情况下,自旋锁获取似乎非常重。

我不太熟悉多线程,特别是在内核模式下。我知道这个问题很愚蠢,但我迷路了。在这种情况下,什么是正确的解决方案?谢谢。

1 个答案:

答案 0 :(得分:1)

  

此标志表示要删除设备,因此它以单向工作

此特殊存在Run-Down Protection

您需要在设备扩展程序中使用EX_RUNDOWN_REF RunRef;成员bool Flag

初始化它
ExInitializeRundownProtection(&RunRef);

当您需要进行某些操作时,只有在尚未移除设备的情况下才需要执行操作:

if (ExAcquireRundownProtection(&DeviceExtension->RunRef))
{
    // do something
    ExReleaseRundownProtection(&DeviceExtension->RunRef)
}

并且在IRP_MN_REMOVE_DEVICE处理程序中需要调用

ExWaitForRundownProtectionRelease(&DeviceExtension->RunRef);

并且重要提示 - 尽管在msdn中声明必须在ExAcquireRundownProtection上调用ExReleaseRundownProtectionIRQL <= APC_LEVEL,但这是错误的。 ExAcquireRundownProtection只需对内存RunRef执行一些互锁操作 - 所以如果它在非分页池中 - 我们可以在任何IRQL调用此例程。设备扩展位于非分页池中。将{em>等待的ExReleaseRundownProtection附加电话KeSetEvent设置为FALSE。因此,它可以在IRQL <= DISPATCH_LEVEL运行。 ExReleaseRundownProtection我们通常从IoCompletion例程调用(在IRQL执行小于或等于DISPATCH_LEVEL),所以这里一切正常。

ExWaitForRundownProtectionRelease当然必须在<= APC_LEVEL调用,因为我们可以在这里等待,但是PnP经理会在IRP_MN_REMOVE_DEVICE IRQL发送PASSIVE_LEVEL - 所以好的,

当然你的这里可以使用和Remove Locks几乎完全相同的破坏保护。简单的破坏保护 - 更多的新api,更好的设计/实现比较删除锁。但是,在IoReleaseRemoveLockIoReleaseRemoveLock的文档中,正确声明IRQL <= DISPATCH_LEVEL必须且IoReleaseRemoveLockAndWait必须在PASSIVE_LEVEL

调用