使用删除锁
删除锁例程提供了一种方法来跟踪设备上的未完成 I/O 操作数,并确定何时可以安全地分离和删除驱动程序的设备对象。 系统将这些例程提供给驱动程序编写器,作为实现其自己的跟踪机制的替代方法。
驱动程序可以使用此机制来实现两个目的:
为了确保驱动程序的 DispatchPnP 例程在锁定时不会完成IRP_MN_REMOVE_DEVICE请求(例如,另一个驱动程序例程正在访问设备)。
若要计算驱动程序不应删除其设备对象的原因数,并在该计数变为零时设置事件。
若要初始化删除锁,驱动程序应在其设备扩展中分配IO_REMOVE_LOCK结构,然后调用 IoInitializeRemoveLock。 当驱动程序初始化设备对象的其余设备扩展时,驱动程序通常会在其 AddDevice 例程中调用 IoInitializeRemoveLock。
每次启动 I/O 操作时,驱动程序都必须调用 IoAcquireRemoveLock。 驱动程序每次完成 I/O 操作时都必须调用 IoReleaseRemoveLock。 驱动程序可以多次获取锁。 删除锁例程维护锁的未完成购置计数。 每次调用 IoAcquireRemoveLock 都会递增计数,IoReleaseRemoveLock 会递减计数。
驱动程序在传出对代码的引用时,还应调用 IoAcquireRemoveLock (对于计时器、DPC、回调等)。 然后,驱动程序必须在返回事件时调用 IoReleaseRemoveLock 。
在IRP_MN_REMOVE_DEVICE的调度代码中,驱动程序必须再次获取锁,然后调用 IoReleaseRemoveLockAndWait。 在释放锁的所有未完成收购之前,此例程不会返回。 若要允许排队的 I/O 操作完成,每个驱动程序应先调用 IoReleaseRemoveLockAndWait,然后再将IRP_MN_REMOVE_DEVICE请求传递给下一个较低的驱动程序,然后再释放内存、调用 IoDetachDevice 或调用 IoDeleteDevice。 为特定的删除锁调用 IoReleaseRemoveLockAndWait 后,对同一删除锁的 IoAcquireRemoveLock 的所有后续调用都将失败。
IoReleaseRemoveLockAndWait 返回后,驱动程序应将设备视为已准备好删除且无法执行 I/O 操作的状态。 因此,驱动程序不得调用 IoInitializeRemoveLock 以重新初始化删除锁。 驱动程序验证程序正在验证驱动程序时违反此规则将导致 bug 检查。
由于驱动程序将IO_REMOVE_LOCK结构存储在设备对象的设备扩展中,因此当驱动程序在处理IRP_MN_REMOVE_DEVICE请求时删除设备扩展时,删除删除锁。