Ready… cancel… wait for it! (part 2)
A customer had a question about I/O cancellation. They have a pending
ReadFileEx call with a completion procedure. They then cancel the I/O with
CancelIoEx and wait for the completion by passing
TRUE as the
bWait parameter to
Assuming both return success, can I assume that my completion procedure will not be called after GetOverlappedResult returns? It appears that GetOverlappedResult waits non-alertably for the I/O to complete, so I’m assuming it just eats the APC if there was one. But if an APC had been posted just before I called CancelIoEx, will it also cancel that APC?
GetOverlappedResult does not magically revoke completion callbacks. Why should it?
Recall that completion is not the same as success. Completion means that the I/O subsystem has closed the books on the I/O operation. The underlying operation may have completed successfully or it may have failed (and cancellation is just one of the many possible reasons for failure). Either way, the completion procedure signed up to be notified when the I/O completes, and therefore it will be called to be informed of the completion due to cancellation.
Besides, as the customer noted, there is a race condition if the
CancelIoEx call is made just after the I/O completed, in which case it didn’t get cancelled after all.
This answers our question from last time, namely, how our fix for the cancellation code was incomplete. If the I/O had been issued with a completion routine (or equivalently, if it had been issued against an I/O completion port), then the code frees the
OVERLAPPED structure before the completion routine runs. The kernel doesn’t care that you did that (the kernel is finished with the
OVERLAPPED structure), but your completion routine is probably not going to be happy that it was given a pointer to freed memory as its
You have to delay freeing the
OVERLAPPED structure until the completion routine executes. Typically, this is done by allocating the
OVERLAPPED structure on the heap rather than the stack, and making it the completion routine’s responsibility to free the memory as its final act.