!deadlock

Die Erweiterung !deadlock zeigt Informationen über Deadlocks an, die von der Option Deadlock Detection des Driver Verifier gesammelt wurden.

!deadlock 
!deadlock 1

DLL

Kdexts.dll

Zusätzliche Informationen

Informationen über Driver Verifier finden Sie in der Dokumentation zum Windows Driver Kit (WDK).

Hinweise

Diese Erweiterung liefert nur dann nützliche Informationen, wenn die Option Deadlock Detection von Driver Verifier eine Verletzung der Sperrhierarchie festgestellt und Fehlerprüfung 0xC4 (DRIVER_VERIFIER_DETECTED_VIOLATION) ausgegeben hat.

Ohne Argumente bewirkt die Erweiterung !deadlock, dass die grundlegende Topologie der Sperrhierarchie angezeigt wird. Wenn es sich bei dem Problem nicht um eine einfache zyklische Blockade handelt, beschreibt dieser Befehl die aufgetretene Situation.

Die Erweiterung !deadlock 1 bewirkt, dass Stack Traces angezeigt werden. Die angezeigten Stack sind die, die zum Zeitpunkt der Erfassung der Sperren aktiv waren.

Hier ist ein Beispiel:

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'

Daran können Sie erkennen, welche Threads und welche Sperren beteiligt sind. Es handelt sich jedoch nur um eine Zusammenfassung, die möglicherweise nicht ausreicht, um die Situation angemessen zu beheben.

Verwenden Sie !deadlock 1, um den Inhalt der Aufrufstack zu dem Zeitpunkt auszudrucken, zu dem jede am Deadlock beteiligte Sperre erworben wurde. Da es sich hierbei um Laufzeit-Stacktraces handelt, sind sie vollständiger, wenn ein geprüfter Build verwendet wird. Geprüfte Builds waren auf älteren Windows-Versionen vor Windows 10, Version 1803, verfügbar. Bei einem freien Build können sie bereits nach einer Zeile abgeschnitten werden.

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 >>

Mit diesen Informationen haben Sie fast alles, was Sie brauchen, außer dem aktuellen 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

Daraus können Sie ersehen, um welche Schlösser es sich handelt und wo sie erworben wurden. Diese Informationen sollten ausreichen, um den Deadlock zu beheben. Wenn der Quellcode verfügbar ist, können Sie den Debugger verwenden, um genau zu sehen, wo das Problem aufgetreten ist:

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]

Jetzt kennen Sie den Namen der Quelldatei und die Zeilennummer, in der die Übernahme stattgefunden hat. In diesem Fall zeigen die Quelldateien, dass sich die Threads wie folgt verhalten haben:

  • Thema 1: DummyActivateVcComplete nahm die dummy miniport Sperre. Dann rief es dummyQueueRecvBuffers auf, das die globale Sperre dummy übernahm.

  • Thread 2: dummyRxInterruptOnCompletion hat die globale Sperre übernommen. Ein paar Zeilen später wurde die Miniport-Sperre aufgehoben.

An diesem Punkt wird die Sackgasse ganz deutlich.