Why does SynchronizationEvent point to itself?

I am trying to understand kernel-level deadlocks / livelocks and researching different wait objects. Using notmyfault I created a hang system and forced a memory dump. By showing the process notmyfault, I see two threads; the one trying to get a fast mutex and waiting for a SynchronizationEvent, and the other one waiting for multiple objects - all SynchronizationTimers.

THREAD fffffa800895f060  Cid 0f6c.0f5c  Teb: 000007fffffde000 Win32Thread: fffff900c206bc20 WAIT: (WrFastMutex) KernelMode Non-Alertable
    fffff88006ed0198  SynchronizationEvent

      

and

THREAD fffffa800895c060  Cid 0f6c.0f20  Teb: 000007fffffdc000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Alertable
    fffffa80069d8ef0  SynchronizationTimer
    fffffa80093d28c0  SynchronizationTimer
    fffffa800948e060  SynchronizationTimer

      

I check the send header on the first sync event:

3: kd> dt nt!_DISPATCHER_HEADER fffff88006ed0198
   *SNIP*
   +0x008 WaitListHead     : _LIST_ENTRY [ 0xfffffa80`0895f168 - 0xfffffa80`0895f168 ]

      

and a kwait block in the header of the waitlist.

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*

      

It seems to me that it makes sense to look at another thread's waitlist: a deadlock appears to be caused by each of the kwait_blocks referencing each other as a loop (which I think is the actual definition of a deadlock).

The problem I am facing is with the dispatcher header and the kwait block above. My guess would be that the first thread will wait on a thread that loops on itself with the sync timers. I'm guessing I missed a step or just a misunderstanding, but why is NextWaitBlock referenced instead?

EDIT

Also, I noticed that none of these events / timers indicate that they were signaled, but fffffa800948e060 contains an inserted timer. I understand that the causal event must be in a signaled state, is this wrong or is there another wait object that I missed?

+3


source to share


1 answer


The deadlock appears to be caused by each of the kwait_ blocks referencing each other in a loop (which I think is the actual definition of a deadlock).

You misunderstand the use of the NextWaitBlock field in the KWAIT_BLOCK structure. Let me start from the beginning (which I know you understand based on the above output) just for clarity:

When a thread goes to sleep, waiting for the Dispatcher to be signaled, the thread allocates the KWAIT_BLOCK structure and queues up the DISPATCHER_HEADER object structure. This link can be seen by your walking structured linking to the fffffa800895f060 stream. The DISPATCHER_HEADER event has KWAIT_BLOCK to it and from there you can find the waiting thread.

Windows also supports the ability for a thread to wait for multiple Manager objects at the same time. When this happens, the thread allocates a KWAIT_BLOCK structure for each Dispatcher, puts each structure in its corresponding DISPATCHER_HEADER, and then ties the KWAIT_BLOCK structures together through the NextWaitBlock field. The thread then chooses whether it wants to expect ANY of these objects to become a signal, or for ALL of these objects to become signals. So the NextWaitBlock field just binds whatever that thread is waiting for, not some kind of endless loop.



The problem I am facing is with the dispatcher header and the kwait block above. My guess would be that the first thread will wait on a thread that loops on itself with the sync timers.

The thread waits for an event to be signaled. That's all you get in this case, given the Event, there is no way to determine which thread on the system should install it. This makes solving these more difficult than, say, a dead end with the KMUTANT dispatcher object. KMUTANTs record which stream they own, so from there you know where to look next.

I'm guessing I skipped a step or just didn't get it, but why is NextWaitBlock referenced instead?

It is just an implementation detail indicating an empty list, this thread is not waiting for any other Dispatcher object other than an event.

+4


source







All Articles