Читаем Windows® Internals, Sixth Edition, Part 1 полностью

If none of these shortcuts were effective, the wait block is inserted into the thread’s wait list, and the thread now attempts to commit its wait. (Meanwhile, the object lock or locks have been released, allowing other processors to modify the state of any of the objects that the thread is now supposed to attempt waiting on.) Assuming a noncontended scenario, where other processors are not interested in this thread or its wait objects, the wait switches into the committed state as long as there are no pending changes marked by the wait status register. The commit operation links the waiting thread in the PRCB list, activates an extra wait queue thread if needed, and inserts the timer associated with the wait timeout, if any. Because potentially quite a lot of cycles have elapsed by this point, it is again possible that the timeout has already elapsed. In this scenario, inserting the timer will cause immediate signaling of the thread, and thus a wait satisfaction on the timer, and the overall timeout of the wait. Otherwise, in the much more common scenario, the CPU now context switches away to the next thread that is ready for execution. (See Chapter 5 for more information on scheduling.)

In highly contended code paths on multiprocessor machines, it is possible and likely that the thread attempting to commit its wait has experienced a change while its wait was still in progress. One possible scenario is that one of the objects it was waiting on has just been signaled. As touched upon earlier, this causes the associated wait block to enter the WaitBlockBypassStart state, and the thread’s wait status register now shows the WaitAborted wait state. Another possible scenario is for an alert or APC to have been issued to the waiting thread, which does not set the WaitAborted state but enables one of the corresponding bits in the wait status register. Because APCs can break waits (depending on the type of APC, wait mode, and alertability), the APC is delivered and the wait is aborted. Other operations that will modify the wait status register without generating a full abort cycle include modifications to the thread’s priority or affinity, which will be processed when exiting the wait due to failure to commit, as with the previous cases mentioned.

Figure 3-27 shows the relationship of dispatcher objects to wait blocks to threads to PRCB. In this example, CPU 0 has two waiting (committed) threads: thread 1 is waiting for object B, and thread 2 is waiting for objects A and B. If object A is signaled, the kernel sees that because thread 2 is also waiting for another object, thread 2 can’t be readied for execution. On the other hand, if object B is signaled, the kernel can ready thread 1 for execution right away because it isn’t waiting for any other objects. (Alternatively, if thread 1 was also waiting for other objects but its wait type was a WaitAny, the kernel could still wake it up.)

Figure 3-27. Wait data structures

EXPERIMENT: Looking at Wait Queues

You can see the list of objects a thread is waiting for with the kernel debugger’s !thread command. For example, the following excerpt from the output of a !process command shows that the thread is waiting for an event object:kd> !process § THREAD fffffa8005292060 Cid 062c062c.0660 Teb: 000007fffffde000 Win32Thread: fffff900c01c68f0 WAIT: (WrUserRequest) UserMode Non-Alertable fffffa80047b8240 SynchronizationEvent

You can use the dt command to interpret the dispatcher header of the object like this:lkd> dt nt!_DISPATCHER_HEADER fffffa80047b8240 +0x000 Type : 0x1 '' +0x001 TimerControlFlags : 0 '' +0x001 Absolute : 0y0 +0x001Coalescable : 0y0 +0x001 KeepShifting : 0y0 +0x001 EncodedTolerableDelay : 0y00000 (0) +0x001 Abandoned : 0 '' +0x001 Signalling : 0 '' +0x002 ThreadControlFlags : 0x6 '' +0x002 CpuThrottled : 0y0 +0x002 CycleProfiling : 0y1 +0x002 CounterProfiling : 0y1 +0x002 Reserved : 0y00000 (0) +0x002 Hand : 0x6 '' +0x002 Size : 0x6 +0x003 TimerMiscFlags : 0 '' +0x003 Index : 0y000000 (0) +0x003 Inserted : 0y0 +0x003 Expired : 0y0 +0x003 DebugActive : 0 '' +0x003 ActiveDR7 : 0y0 +0x003 Instrumented : 0y0 +0x003 Reserved2 : 0y0000 +0x003 UmsScheduled : 0y0 +0x003 UmsPrimary : 0y0 +0x003 DpcActive : 0 '' +0x000 Lock : 393217 +0x004 SignalState : 0 +0x008 WaitListHead : _LIST_ENTRY [ 0xfffffa80'047b8248 - 0xfffffa80'047b8248 ]

Перейти на страницу:

Похожие книги