在一个调度例程中,我们有以下代码:
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,在这种情况下,自旋锁获取似乎非常重。
我不太熟悉多线程,特别是在内核模式下。我知道这个问题很愚蠢,但我迷路了。在这种情况下,什么是正确的解决方案?谢谢。
答案 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
上调用ExReleaseRundownProtection
和IRQL <= 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,更好的设计/实现比较删除锁。但是,在IoReleaseRemoveLock
和IoReleaseRemoveLock
的文档中,正确声明IRQL
<= DISPATCH_LEVEL
必须且IoReleaseRemoveLockAndWait
必须在PASSIVE_LEVEL