I/O completion ports and CancelIo

I’m seeing a situation that confounds me.

* App calls CreateFile
* App creates I/O completion port, binds file handle to IOCP
* App starts async requests using DeviceIoControl
* Driver queues IRPs, later completes some of them
* App spins in loop calling GetQueuedCompletionStatus,
issues new IRPs when old ones complete, etc.

The above works fine. At some point, the app decides to exit, calls
CancelIo, then app waits for all pending I/O to drain (calling
GetQueuedCompletionStatus and counting I/O). However, the app never sees
completion packets for those canceled IRPs. At this point, though, the app
never receives completion packets for the canceled IRPs.

I’m aware that CancelIo needs to run on the same thread that started the
I/O. The app uses a single thread. All I/O is issued on that one thread,
CancelIo runs on that thread, and completion packets are dequeued on that
thread.

I have set breakpoints in my driver, at the cancel routine for these IRPs.
When CancelIo runs, I see exactly what I expect in kernel-mode: my cancel
routine is called once for each IRP, and it successfully extracts the IRP
from the driver’s list, and completes the IRP with STATUS_CANCELLED.

Why, then, do I never receive completions for these requests? I’ve worked
with IOCPs many times before, and I always received completions for
cancelled requests, so I assume I’m doing something wrong in my driver. But
what? I see the call to my cancel routine, which definitely calls
IoCompleteRequest – what’s missing?

Any help is appreciated.

– arlie

Have you tried clearing the Cancel routine before completing it ?

I don’t understand why IOCP was used with just one thread.

I’m re-sending this to the list because I never saw it posted, nor any
replies, so I assume the list server never received or processed it.

Any help is greatly appreciated.

– arlie

-----Original Message-----
From: Arlie Davis [mailto:xxxxx@stonestreetone.com]
Sent: Monday, August 29, 2005 6:16 PM
To: ‘Windows System Software Devs Interest List’
Subject: I/O completion ports and CancelIo

I’m seeing a situation that confounds me.

* App calls CreateFile
* App creates I/O completion port, binds file handle to IOCP
* App starts async requests using DeviceIoControl
* Driver queues IRPs, later completes some of them
* App spins in loop calling GetQueuedCompletionStatus,
issues new IRPs when old ones complete, etc.

The above works fine. At some point, the app decides to exit, calls
CancelIo, then app waits for all pending I/O to drain (calling
GetQueuedCompletionStatus and counting I/O). However, the app never sees
completion packets for those canceled IRPs. At this point, though, the app
never receives completion packets for the canceled IRPs.

I’m aware that CancelIo needs to run on the same thread that started the
I/O. The app uses a single thread. All I/O is issued on that one thread,
CancelIo runs on that thread, and completion packets are dequeued on that
thread.

I have set breakpoints in my driver, at the cancel routine for these IRPs.
When CancelIo runs, I see exactly what I expect in kernel-mode: my cancel
routine is called once for each IRP, and it successfully extracts the IRP
from the driver’s list, and completes the IRP with STATUS_CANCELLED.

Why, then, do I never receive completions for these requests? I’ve worked
with IOCPs many times before, and I always received completions for
cancelled requests, so I assume I’m doing something wrong in my driver. But
what? I see the call to my cancel routine, which definitely calls
IoCompleteRequest – what’s missing?

Any help is appreciated.

– arlie