!Взаимоблокировки
Расширение !взаимоблокировки отображает сведения о взаимоблокировках, собранных параметром обнаружения взаимоблокировок средства проверки драйверов.
!deadlock
!deadlock 1
DLL-библиотеки
Kdexts.dll
Дополнительная информация
Сведения о средстве проверки драйверов см. в документации по комплекту драйверов Windows (WDK).
Замечания
Это расширение предоставляет только полезную информацию, если параметр обнаружения взаимоблокировки средства проверки драйверов обнаружил нарушение иерархии блокировки и выдал ошибку проверка 0xC4 (DRIVER_VERIFIER_DETECTED_VIOLATION).
Без каких-либо аргументов расширение !взаимоблокировки приводит к отображению базовой топологии иерархии блокировки. Если проблема не является простой циклической взаимоблокировкой, эта команда описывает ситуацию, которая произошла.
Расширение !взаимоблокировки 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'
Это указывает, какие потоки и какие блокировки участвуют. Однако она предназначена для сводки и может оказаться недостаточной информацией для адекватной отладки ситуации.
Используйте !взаимоблокировку 1 , чтобы распечатать содержимое стека вызовов во время получения каждой блокировки, участвующих в взаимоблокировке. Так как это трассировки стека во время выполнения, они будут более полными, если используется проверка сборка. Проверенные сборки были доступны в более ранних версиях Windows до Windows 10 версии 1803. В свободной сборке они могут быть усечены после одной строки.
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 взял глобальную блокировку. Затем, несколько строк позже, он взял минипорт блокировки.
На этом этапе взаимоблокировка становится совершенно ясной.