!deadlock

!deadlock 扩展显示驱动程序验证程序的死锁检测选项收集的死锁相关信息。

!deadlock 
!deadlock 1

DLL

Kdexts.dll

其他信息

有关驱动程序验证程序的信息,请参阅 Windows 驱动程序工具包 (WDK) 文档。

注解

仅当驱动程序验证程序的死锁检测选项检测到锁层次结构冲突并发出 Bug 检查 0xC4 (DRIVER_VERIFIER_DETECTED_VIOLATION) 时,此扩展才会提供有用的信息。

在没有任何参数的情况下,!deadlock 扩展会导致显示基本锁层次结构拓扑。 如果问题不是简单的循环死锁,此命令将描述发生的情况。

!deadlock 1 扩展会显示堆栈跟踪。 显示的堆栈将是获取锁时处于活动状态的堆栈。

以下是示例:

0:kd> !deadlock

Deadlock detected (2 resources in 2 threads):

Thread 0: A B
Thread 1: B A

Where:
Thread 0 = 8d3ba030
Thread 1 = 8d15c030
Lock A =   bba2af30 Type 'Spinlock'
Lock B =   dummy!GlobalLock Type 'Spinlock'

这会告诉您涉及到哪些线程和哪些锁。 但是,这只是一个摘要,可能没有足够的信息来充分调试情况。

使用 !deadlock 1 输出在获取参与死锁的每个锁时调用堆栈的内容。 由于这些是运行时堆栈跟踪,因此在使用已检查的版本时,它们将更加完整。 Windows 10 版本 1803 之前的旧版 Windows 上提供已检查的版本。 在免费版本中,它们可能会在一行之后被截断。

0:kd> !deadlock 1

Deadlock detected (2 resources in 2 threads):

Thread 0 (8D14F750) took locks in the following order:

    Lock A -- b7906f30 (Spinlock)
    Stack:   dummy!DummyActivateVcComplete+0x63
             dummy!dummyOpenVcChannels+0x2E1
             dummy!DummyAllocateRecvBufferComplete+0x436
             dummy!DummyAllocateComplete+0x55
             NDIS!ndisMQueuedAllocateSharedHandler+0xC9
             NDIS!ndisWorkerThread+0xEE

    Lock B -- dummy!GlobalLock (Spinlock)
    Stack:   dummy!dummyQueueRecvBuffers+0x2D
             dummy!DummyActivateVcComplete+0x90
             dummy!dummyOpenVcChannels+0x2E1
             dummy!DummyAllocateRecvBufferComplete+0x436
             dummy!DummyAllocateComplete+0x55

Thread 1 (8D903030) took locks in the following order:

    Lock B -- dummy!GlobalLock (Spinlock)
    Stack:   dummy!dummyRxInterruptOnCompletion+0x25D
             dummy!DummyHandleInterrupt+0x32F
             NDIS!ndisMDpcX+0x3C
             ntkrnlpa!KiRetireDpcList+0x5D

    Lock A -- b7906f30 (Spinlock)
    Stack:   << Current stack >>

利用此信息,除了当前堆栈之外,您几乎拥有了所需的一切:

0: kd> k
ChildEBP RetAddr
f78aae6c 80664c58 ntkrnlpa!DbgBreakPoint
f78aae74 8066523f ntkrnlpa!ViDeadlockReportIssue+0x2f
f78aae9c 806665df ntkrnlpa!ViDeadlockAnalyze+0x253
f78aaee8 8065d944 ntkrnlpa!VfDeadlockAcquireResource+0x20b
f78aaf08 bfd6df46 ntkrnlpa!VerifierKeAcquireSpinLockAtDpcLevel+0x44
f78aafa4 b1bf2d2d dummy!dummyRxInterruptOnCompletion+0x2b5
f78aafc4 bfde9d8c dummy!DummyHandleInterrupt+0x32f
f78aafd8 804b393b NDIS!ndisMDpcX+0x3c
f78aaff4 804b922b ntkrnlpa!KiRetireDpcList+0x5d

从中可以看出涉及哪些锁及其获取位置。 这些信息应该足以让您调试死锁。 如果有源代码,可以使用调试器查看问题发生的具体位置:

0: kd> .lines
Line number information will be loaded

0: kd> u dummy!DummyActivateVcComplete+0x63 l1
dummy!DummyActivateVcComplete+63 [d:\nt\drivers\dummy\vc.c @ 2711]:
b1bfe6c9 837d0c00         cmp     dword ptr [ebp+0xc],0x0

0: kd> u dummy!dummyQueueRecvBuffers+0x2D l1
dummy!dummyQueueRecvBuffers+2d [d:\nt\drivers\dummy\receive.c @ 2894]:
b1bf4e39 807d0c01         cmp     byte ptr [ebp+0xc],0x1

0: kd> u dummy!dummyRxInterruptOnCompletion+0x25D l1
dummy!dummyRxInterruptOnCompletion+25d [d:\nt\drivers\dummy\receive.c @ 1424]:
b1bf5d05 85f6             test    esi,esi

0: kd> u dummy!dummyRxInterruptOnCompletion+0x2b5 l1
dummy!dummyRxInterruptOnCompletion+2b5 [d:\nt\drivers\dummy\receive.c @ 1441]:
b1bf5d5d 8b4648           mov     eax,[esi+0x48]

现在,您知道了源文件的名称和获取位置的行号。 在这种情况下,源文件将如下显示线程的行为:

  • 线程 1:DummyActivateVcComplete 获取了虚拟微型端口锁。 然后,它调用 dummyQueueRecvBuffers,获取了虚拟全局锁。

  • 线程 2:dummyRxInterruptOnCompletion 获取了全局锁。 然后,几行后,它获取了微型端口锁。

此时,死锁变得完全清晰。