I'm adding per-async-operation timeouts to my IOCP-based networking stuff, so I can have a similar interface in C++ as Java's NIO.2 uses. I've implemented this with a priority queue of timeouts that supports random-access removes (so that when an operation completes successfully, I can remove its associated timeout).
My question is how to handle the occurrence of a timeout. Right now I call CancelIoEx with the overlapped structure corresponding to the given timeout. However, I've just read this on MSDN:
If the file handle is associated with a completion port, an I/O completion packet is not queued to the port if a synchronous operation is successfully canceled. For asynchronous operations still pending, the cancel operation will queue an I/O completion packet.
I use overlapped structures extended with completion handlers (per operation user provided std::function taking error code and bytes written/read) which are executed whenever completion packets are dequeued (again, pretty much like Java's NIO.2 API). If the cancellation happens asynchronously, then the completion handler would be run as usual and would get the ERROR_OPERATION_ABORTED. But what if CancelIoEx succeeds cancelling the operation immediately? It sounds like, by the above quote, I would need to execute the handler at that point as I won't get a completion packet later. But how do I know which is the case, that is, whether the completion packet was queued or the operation was canceled immediately??? Unlike other async operations, CancelIoEx doesn't produce the ERROR_IO_PENDING that differentiates synchronous and asynchronous completion of the task (cancellation, in this case). Or, am I reading this wrong, and any overlapped operation is considered asynchronous (note: I have not set FILE_SKIP_COMPLETION_PORT_ON_SUCCESS, but then again that only applies to success, not errors and I assume doesn't affect cancellations)?