我试图了解内核级别的死锁/活锁并探索不同的等待对象。使用notmyfault我创建了一个系统挂起并强制进行内存转储。显示notmyfault的进程我看到两个线程;一个试图获取快速互斥锁并正在等待SynchronizationEvent,另一个正在等待多个对象 - 所有同步时间。
THREAD fffffa800895f060 Cid 0f6c.0f5c Teb: 000007fffffde000 Win32Thread: fffff900c206bc20 WAIT: (WrFastMutex) KernelMode Non-Alertable
fffff88006ed0198 SynchronizationEvent
和
THREAD fffffa800895c060 Cid 0f6c.0f20 Teb: 000007fffffdc000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Alertable
fffffa80069d8ef0 SynchronizationTimer
fffffa80093d28c0 SynchronizationTimer
fffffa800948e060 SynchronizationTimer
我检查第一个同步事件的dispatch标头:
3: kd> dt nt!_DISPATCHER_HEADER fffff88006ed0198
*SNIP*
+0x008 WaitListHead : _LIST_ENTRY [ 0xfffffa80`0895f168 - 0xfffffa80`0895f168 ]
和等待列表标题上的kwait块。
3: kd> dt nt!_KWAIT_BLOCK 0xfffffa80`0895f168
+0x000 WaitListEntry : _LIST_ENTRY [ 0xfffff880`06ed01a0 - 0xfffff880`06ed01a0 ]
+0x010 Thread : 0xfffffa80`0895f060 _KTHREAD
+0x018 Object : 0xfffff880`06ed0198 Void
+0x020 NextWaitBlock : 0xfffffa80`0895f168 _KWAIT_BLOCK
*SNIP*
查看另一个线程的等待列表似乎对我有意义:死锁似乎是由每个在一个循环中引用彼此的kwait_block引起的(我猜这是死锁的实际定义)。
我遇到的问题是上面的调度程序头和kwait块。我的假设是第一个线程将等待使用同步定时器循环自身的线程。我假设我错过了一步或者只是误解,但为什么NextWaitBlock会引用自己呢?
修改:
此外,我注意到这些事件/计时器都没有表明它们已经发出信号,但fffffa800948e060包含一个插入的计时器。我的理解是,因果事件必须处于信号状态,这是不正确的还是我忽略了另一个等待对象?
答案 0 :(得分:4)
死锁似乎是由在某种循环中相互引用的每个kwait_block引起的(我猜这是死锁的实际定义)。
您误解了KWAIT_BLOCK结构中NextWaitBlock字段的用法。让我从一开始就开始(我知道你基于上面的输出理解)只是为了清楚起见:
当线程进入休眠状态等待Dispatcher对象发出信号时,线程会分配一个KWAIT_BLOCK结构并将结构排队到Object的DISPATCHER_HEADER。您可以通过与fffffa800895f060相关的结构化步骤来查看此链接。事件的DISPATCHER_HEADER将KWAIT_BLOCK排队等候,从那里你可以找到等待的线程。
Windows还支持线程一次在多个Dispatcher对象上等待的能力。发生这种情况时,线程为每个Dispatcher对象分配一个KWAIT_BLOCK结构,将每个结构排队到相应的DISPATCHER_HEADER,然后通过NextWaitBlock字段将KWAIT_BLOCK结构链接在一起。然后,线程选择是否要等待任何这些对象发出信号,或者让所有这些对象发出信号。因此,NextWaitBlock字段只是将此线程正在等待的所有内容链接在一起,而不是某种无限循环。
我遇到的问题是上面的调度程序头和kwait块。我的假设是第一个线程将等待使用同步定时器循环自身的线程。
线程正在等待事件发出信号。这就是你在这种情况下所得到的,鉴于Event无法确定系统中的哪个线程应该设置它。这使得解决这些问题比使用KMUTANT Dispatcher Object的死锁更困难。 KMUTANT记录哪个线程拥有它们,所以从那里你就知道下一步该在哪里。
我假设我错过了一步,或者只是误解,但为什么NextWaitBlock会引用自己呢?
这只是一个表示空列表的实现细节,该线程不会等待除事件之外的任何其他Dispatcher对象。