0

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)?

Display Name
  • 2,323
  • 1
  • 26
  • 45

1 Answers1

3

It's not talking about if CancelIoEx is sync or async, it's saying if the I/O itself (e.g. ReadFile) is sync or async. It is describing the difference in behavior between sync and async ops.

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.

Sync ops -- ones without an OVERLAPPED structure, or ones which would complete immediately -- will return with an error ERROR_OPERATION_ABORTED.

Async ops -- ones with an OVERLAPPED structure that could not complete immediately -- will have a completion notice queued with ERROR_OPERATION_ABORTED.

Cory Nelson
  • 29,236
  • 5
  • 72
  • 110
  • Say ReadFile() is provided an overlapped structure but completes immediately. As I don't have FILE_SKIP_COMPLETION_PORT_ON_SUCCESS set, I expect a completion packet on success, and on error I manually store the GetLastError() and post a packet, in order to handle either case in the worker threads looping on GetQueuedCompletionStatusEx(). Is it OK then for me to assume I'll either get ERROR_OPERATION_ABORTED returned by the op, or at the completion queue, and there's nothing else to watch out for? Thanks – Display Name Aug 30 '14 at 00:33
  • It is indeed safe for you to assume that. – Cory Nelson Aug 30 '14 at 00:35