0

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

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

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

4

1 回答 1

1

此标志表示要删除设备,因此它以一种方式工作

对于这种特殊存在的停机保护

您需要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。设备扩展在非分页池中。可以将带有WaitExReleaseRundownProtection附加调用设置为。结果它可以在. 我们通常从例程调用(在小于或等于 的情况下执行)所以这里一切正常。KeSetEventFALSEIRQL <= DISPATCH_LEVELExReleaseRundownProtectionIoCompletionIRQLDISPATCH_LEVEL

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


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

于 2017-11-07T23:30:25.880 回答