26.08.2013 Views

366.7 KB - Evernote

366.7 KB - Evernote

366.7 KB - Evernote

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Effect of User Mode APCs on Kernel Wait Functions<br />

The previous section brings us to an interesting detail about the documented DDK wait functions.<br />

Consider, for instance, the DDK help about KeWaitForSingleObject: among the possible return<br />

values, STATUS_USER_APC is listed with the following description:<br />

“The wait was interrupted to deliver a user asynchronous procedure call (APC) to the calling thread.”<br />

The point is, the user APC has not yet been delivered: it will be, when the thread will re-enter user<br />

mode.<br />

Thus, when KeWaitForSingleObject returns, the APC has merely aborted the wait, but it is still to be<br />

delivered. The wait has been aborted so that the thread can return to user mode and, thanks to<br />

UserApcPending being set, deliver the APC.<br />

If the thread were to stay in kernel mode, for instance by entering another wait, the APC would remain<br />

pending.<br />

User Mode APC Delivery Test in The Sample Driver<br />

The sample driver accompanying this article shows this behaviour, by testing different wait cases. The<br />

driver dispatch function for this test is called ApcUserModeTest.<br />

This function creates a separate thread which will queue the APC to the one executing it, then enters<br />

an alertable user-mode wait. The APC-requesting thread executes a function named ApcRequester.<br />

When ApcRequester queue the APC to the original thread, the latter returns from<br />

KeWaitForSingleObject with STATUS_USER_APC. However, the APC has not yet been delivered<br />

and we can confirm this, because the APC kernel routine, when called, writes “Hello from the USER<br />

APC kernel routine” on the debugger console. We will see that this happens only after<br />

ApcUserModeTest has returned to user mode.<br />

Before returning, ApcUserModeTest shows a few more interesting cases. First, it tries again to enter<br />

an alertable user-mode wait with KeWaitForSingleObject. However, the function immediately returns<br />

with STATUS_USER_APC. Thus, once a thread has user APCs pending, it simply can’t enter such a<br />

wait.<br />

It then tries a non-alertable user mode wait and, interestingly, the result is the same. This means<br />

alertability matters only when APCs are requested for a thread which is already waiting: the thread is<br />

only awakened if the wait is alertable. On the other hand, alertable or not, a thread can’t enter a user<br />

mode wait if it already has pending user APCs.<br />

Finally, ApcUserModeTest tries a non-alertable kernel mode wait and this time the thread is put to<br />

sleep, regardless of the pending APCs.<br />

After all these tests, ApcUserModeTest terminates, the thread returns to user mode and only then the<br />

APC is dispatched and we see the debug message from its KernelMode routine.<br />

Earlier, when examining nt!KiInsertQueueApc for user APCs, we reasoned that the wait functions<br />

would have had to account for the fact that a thread could call them after APCs have been queued for<br />

it. This follows from the fact that, for not-waiting threads, nt!KiInsertQueueApc does nothing more than<br />

chaining the APCs to its list; the target thread is thus free to attempt to enter an alertable user mode<br />

wait after this.<br />

26

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!