使用自旋锁时防止错误和死锁

虽然驱动程序例程具有旋转锁,但它不能在不关闭系统的情况下导致硬件异常或引发软件异常。 换句话说,驱动程序的 ISR 和驱动程序在调用 KeSynchronizeExecution 时提供的任何 SynchCritSection 例程不得导致错误或陷阱,例如页面错误或算术异常,也不能引发软件异常。 调用 KeAcquireSpinLockKeAcquireInStackQueuedSpinLock 的例程也不能导致硬件异常或引发软件异常,直到它释放其执行旋转锁并且不再在 IRQL = DISPATCH_LEVEL 下运行。

可分页数据和支持例程

在持有旋转锁时,驱动程序不得调用访问可分页数据的例程。 请记住,驱动程序可以调用某些支持例程,这些例程访问可分页数据的情况是且仅当其调用是在严格小于 DISPATCH_LEVEL 的 IRQL 上执行时发生的。 此 IRQL 限制阻止在持有旋转锁时调用这些支持例程。 有关任何特定支持例程的 IRQL 要求,请参阅例程的参考页。

递归

尝试以递归方式获取旋转锁一定会导致死锁:保留递归例程的实例化无法释放旋转锁,而第二次实例化旋转(尝试获取同一个旋转锁)。

以下指南介绍了如何将旋转锁与递归例程配合使用:

  • 递归例程在持有旋转锁时不得调用自身,或不得尝试在后续调用中获取相同的旋转锁。

  • 虽然递归例程持有一个旋转锁,但如果递归可能导致死锁或可能导致调用方保留旋转锁超过 25 微秒,则另一个驱动程序例程不得调用递归例程。

有关递归驱动程序例程的详细信息,请参阅 使用内核堆栈

嵌套旋转锁获取

尝试获取第二个旋转锁而持有另一个旋转锁也可能导致死锁或驱动程序性能不佳。

以下指南介绍了驱动程序应如何保留旋转锁:

  • 除非无法发生死锁,否则驱动程序不得调用使用旋转锁的支持例程。

  • 即使无法发生死锁,驱动程序也不应调用使用旋转锁的支持例程,除非备用编码技术无法提供类似的驱动程序性能和功能。

  • 如果驱动程序进行嵌套调用来获取旋转锁,则每次获取旋转锁时,它必须始终以相同的顺序获取旋转锁。 此顺序有助于避免死锁。

通常,避免使用嵌套的旋转锁来保护重叠的子集或离散的共享数据和资源集。 考虑一下,如果驱动程序使用两个执行旋转锁来保护离散资源,例如一对计时器对象,这些对象可能由各种驱动程序例程单独和集体设置。 每当两个例程之一(每个都持有一个旋转锁)尝试获取另一个旋转锁时,驱动程序都会在 SMP 计算机中间歇性地死锁。

有关获取嵌套旋转锁的详细信息,请参阅 锁、死锁和同步