366.7 KB - Evernote
366.7 KB - Evernote
366.7 KB - Evernote
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
Special Vs. Regular Kernel APCs<br />
On the subject of how regular APCs are limited, nt!KiDeliverApc has the final say: it is this function<br />
which decides when such an APC will be delivered.<br />
The function enforces the following rules:<br />
• When the NormalRoutine of a regular APC is in progress, (ApcState.KernelApcInProgress !=<br />
0), other regular APCs are not delivered to the same thread. Even if the thread catches an<br />
APC interrupt and enters nt!KiDeliverApc.<br />
• When ApcState.KernelApcDisable !=0, regular APCs are not delivered.<br />
If nt!KiDeliverApc is called with ApcState.KernelApcDisable != 0, KernelApcPending is left<br />
zeroed, which prevents further calls to the function on context switches. nt!KiDeliverApc will<br />
be called again when KernelApcPending is set, perhaps by queuing another APC.<br />
• Regular APCs have both a KernelRoutine and a NormalRoutine. The first is called at APC<br />
IRQL, the second at PASSIVE.<br />
The KernelRoutine is called first and can change the address of the NormalRoutine that will<br />
be invoked or avoid the call altogether, by zeroing the NormalRoutine pointer.<br />
Furthermore, the logic of nt!KiInsertQueueApc implies that:<br />
• When a regular APC is queued to a wating thread, the thread is not awakened if:<br />
o The NormalRoutine of another regular APC is in progress on the thread<br />
(ApcState.KernelApcInProgress != 0)<br />
This implies that the NormalRoutine can enter a wating state and know for sure that<br />
the thread will not service other regular APCs during the wait.<br />
o KernelApcDisable has a non-zero value.<br />
It is interesting to note how the DDK states that the conditions under which a waiting thread receives<br />
regular APCs are:<br />
“thread not already in an APC, thread not in a critical section”<br />
Thus, “in a critical section” KernelApcDisable is set to a non-zero value.<br />
User Mode APCs<br />
This section analyzes the scheduling and delivery of user mode APCs.<br />
The main difference between these APCs and kernel mode ones is that their NormalRoutine is<br />
executed in user mode, so the APC implementation has to switch to ring 3 before calling<br />
NormalRoutine.<br />
Scheduling<br />
As for kernel mode APCs, the scheduling performed by nt!KiInsertQueueApc can be split into two<br />
main steps: linking the _KAPC to a list of pending APCs and updating control variables for the target<br />
thread so that it will process the waiting APC, when the right conditions apply.<br />
23