视窗驱动程序,旋转锁采集和条件测试

Windows driver, spin lock acquisition and condition test

本文关键字:条件 测试 驱动程序 旋转      更新时间:2023-10-16

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

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,在这种情况下,旋转锁获取似乎非常繁重。

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

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

对于这个特殊的存在 破损保护

您需要在设备扩展中拥有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 中声明必须调用ExAcquireRundownProtectionExReleaseRundownProtectionIRQL <= APC_LEVEL这是错误的和错误的。ExAcquireRundownProtection简单地对内存执行一些联锁操作,RunRef到哪个点 - 所以如果它在非页面缓冲池中 - 我们可以随时调用此例程IRQL.设备扩展位于非页面缓冲池中。ExReleaseRundownProtection可以额外呼叫KeSetEvent等待设置为FALSE。因此,它可以在IRQL <= DISPATCH_LEVEL.ExReleaseRundownProtection我们通常从IoCompletion例程(以小于或等于DISPATCH_LEVELIRQL执行)调用,所以这里一切都好。

ExWaitForRundownProtectionRelease当然必须在<= APC_LEVEL调用,因为在这里我们可以等待,但是 PnP 经理在IRQLPASSIVE_LEVEL发送IRP_MN_REMOVE_DEVICE- 所以这里再次一切正常


当然,您在这里可以使用和删除锁,其功能几乎与破损保护完全相同。 简单的破损保护 - 更多新的 API,以及更好的设计/实现 比较删除锁。 但是,在IoReleaseRemoveLockIoReleaseRemoveLock的文档中正确地指出,IRQL <= DISPATCH_LEVEL必须是,并且必须在PASSIVE_LEVEL调用IoReleaseRemoveLockAndWait