The purpose of PendingReturned is really to communicate the state of the latest SL_PENDING_RETURNED stack location to the completion routine or to IopsCompleteRequest tail.
The completion routine will use PendingReturned to propagate SL_PENDING_RETURNED to its current stack location, and also can use it for deciding whether it need to call KeSetEvent for a little bit of optimization.
At any completion routine level, PendingReturned needs to correspond to the most recent SL_PENDING_RETURNED, not to some accumulated SL_PENDING_RETURNED value.
There is a rule for CRs to do “if( Irp->PendingReturned ) IoMarkIrpPending(Irp);”.
Imagine some IoMarkIrpPending was executed. Then the next IoCompleteRequest will (according to 1) set Irp->PendingReturned to TRUE. Then it will pop 1 stack location off the IRP and call the CR. The CR will, accoding to 2), call IoMarkIrpPending() on the previous SP.
So the whole IRP is inwound, and the final state of Irp->PendingReturned is “TRUE if at least any IoMarkIrpPending was ever made on the IRP, FALSE otherwise”.
This is what I was speaking about.
To make this statement wrong, on what you insist, at least some CR must forget to do “if( Irp->PendingReturned ) IoMarkIrpPending(Irp);”.
This does exactly what I said it did. Irp->PendingReturned is non-zero if SL_PENDING_RETURNED is set in the next lower stack location, and is zero otherwise. So, the statement that Irp->PendingReturned “once it is set, it is not cleared” is not correct.
Silly argument.
C’mon… you know how this works, and I know how this works. We’ve both known how this works for 20 years, I suspect. Why are we wasting our time and everyone else’s time with this discussion?
Suppose:
DISPATCH ROUTINE:
a) Clears an event.
b) Sets a completion routine, passing the event as context
c) IoCallDriver’s the IRP to the next driver
d) Waits on the (cleared/unsignaled) event
COMPLETION ROUTINE:
e) Gets the completion callback
f) Sets the event
g) returns STATUS_MORE_PROCESSING_REQUIRED from the completion routine
DISPATCH ROUTINE AGAIN:
f) Wakes up in the dispatch routine
g) Complete the IRP with STATUS_SUCCESS
h) returns STATUS_SUCCESS
We all know this is a super-common design pattern. It’s the IoForwardIrpSynchronously pattern.
Irp->PendingReturned is NOT set in this case. And you do NOT propagate the pending bit in this case. If you WERE to propagate the pending bit in this case, your code would be wrong.
Somebody stated this previously, but it’s worth restating: The rule is simply that if you return STATUS_PENDING from your Dispatch Routine, you MUST in all cases set SL_PENDING_RETURNED in your I/O Stack Location *before* the I/O Manager process that stack location.
Again… I don’t see how this thread is gaining anyone who reads the archives a better understanding of this complex topic. We have a group of people who are each trying to demonstrate their understanding by posting three sentences on a complex topic… sometimes as a barrage of out of order replies, in some cases without the necessary context to those sentences, and in some cases I suspect without bothering to carefully read the previous posts.
Given that we’re getting exactly nowhere, can we just let it be at this point?