!deadlock

La extensión !deadlock muestra información sobre los interbloqueos recogidos por la opción de detección de interbloqueos del comprobador de controladores.

!deadlock 
!deadlock 1

Archivo DLL

Kdexts.dll

Información adicional

Para obtener información sobre el comprobador de controladores, consulte la documentación del Kit de controladores de Windows (WDK).

Comentarios

Esta extensión solo proporcionará información útil si la opción de detección de interbloqueo del comprobador de controladores ha detectado una infracción de la jerarquía de bloqueo y ha emitido la comprobación de errores 0xC4 (DRIVER_VERIFIER_DETECTED_VIOLATION).

Sin ningún argumento, la extensión !deadlock hace que se muestre la topología básica de la jerarquía de bloqueos. Si el problema no es un simple interbloqueo cíclico, este comando describirá la situación que se ha producido.

La extensión !deadlock 1 hace que se muestren los seguimientos de pila. Las pilas mostradas serán las que estaban activas en el momento en que se adquirieron los bloqueos.

Este es un ejemplo:

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'

Esto le indica qué subprocesos y qué bloqueos están implicados. Sin embargo, pretende ser un resumen y puede no ser suficiente información para depurar adecuadamente la situación.

Utilice !deadlock 1 para imprimir el contenido de las pilas de llamada en el momento en que se adquirió cada bloqueo participante en el bloqueo. Dado que se trata de seguimientos de pila en tiempo de ejecución, serán más completas si se utiliza una compilación comprobada. Las compilaciones comprobadas estaban disponibles en versiones anteriores de Windows antes de Windows 10, versión 1803. En una compilación libre, pueden truncarse después de tan solo una línea.

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

Con esta información, tiene casi todo lo que necesita, excepto la pila actual:

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

A partir de ahí puede ver qué bloqueos estaban implicados y dónde se adquirieron. Esto debería ser suficiente información para que pueda depurar el interbloqueo. Si el código fuente está disponible, puede utilizar el depurador para ver exactamente dónde se ha producido el problema:

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]

Ahora ya conoce el nombre del archivo fuente y el número de línea donde se produjo la adquisición. En este caso, los archivos fuente mostrarán que los subprocesos se comportaron de la siguiente manera:

  • Subproceso 1: DummyActivateVcComplete tomó el bloqueo de minipuerto dummy. A continuación, llamó a dummyQueueRecvBuffers, que tomó el bloqueo global de dummy.

  • Subproceso 2: dummyRxInterruptOnCompletion tomó el bloqueo global. Luego, unas líneas más tarde, tomó el bloqueo de minipuerto.

En este punto, el interbloqueo se resuelve por completo.