2

Let's say you're doing an asynchronous operation (like ReadDirectoryChangesW) using I/O completion ports. And for each call to the function, you allocate an OVERLAPPED structure (perhaps with some additional data) for use within the I/O completion callback. And then within the callback, after the OVERLAPPED structure has been used, you free the memory using the pointer provided as an argument.

Now let's say it's time to shut everything down and cancel any pending asynchronous calls. Is there a function you can call to retrieve a pointer to the OVERLAPPED structure used in any currently pending I/O operation, so that you can free the memory?

  • think this question faster more general. how do correct shutdown (ie destroy resources) if take in account that another threads can in parallel still use this resources. and exist general solution – RbMm Jul 21 '21 at 21:29
  • Well I create and allocate one OVERLAPPED structure for each call. –  Jul 21 '21 at 23:52
  • yes, this is correct (unique OVERLAPPED for every I/O call). but i mean that you need implement rundown protection for correct shutdown. count resources (in your case this is I/O call count) and do shutdown only when counter became 0 – RbMm Jul 22 '21 at 06:41
  • What about using WaitForThreadpoolIoCallbacks? (after calling CancelIoEx) –  Jul 22 '21 at 11:38
  • I mean use rundown protection and because it not implemented in user mode - implement it by self. This is very generic and universal solution. – RbMm Jul 22 '21 at 11:49
  • call like `ExAcquireRundownProtection` before begin I/O (or acquire any other resource which will be affected by shutdown). call `ExReleaseRundownProtection` after I/O completed (from callback) or after stop using resource. call `ExWaitForRundownProtectionRelease` when you want begin shutdown. despite in user mode not such api, easy implement it by self. possible (even more easy) implement asynchronous semantic here - not wait for rundown complete - butcall shutdown in arbitrary thread context, when it will be completed – RbMm Jul 22 '21 at 12:48

1 Answers1

4

Is there a function you can call to retrieve a pointer to the OVERLAPPED structure used in any currently pending I/O operation

No, there is not. It is your responsibility to keep track of your allocated OVERLAPPEDs.

However, when you cancel an asynchronous I/O operation, you will still receive a completion notification for it, indicating that the requested operation was aborted. So, if you are simply allocating your OVERLAPPEDs and passing them to the IOCP without keeping track of them, then you can continue freeing their memory in your notification handler, like you normally would. Simply don't fully shutdown until you have received a completion notification for every I/O operation that you have pending.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Do you know if it's still possible to do this if I'm using ATL's `CThreadPool`? Or does it sort of preempt this behavior? The relevant source is here: https://github.com/dblock/msiext/blob/master/externals/WinDDK/7600.16385.1/inc/atl71/atlutil.h#L1371 –  Jul 20 '21 at 23:50
  • 1
    The threading doesn't matter. If you start an I/O operation, and it returns pending, it is your responsibility to wait for that operation to fully finish before releasing any resources the operation is using, regardless of which thread is running the operation or reporting its completion. – Remy Lebeau Jul 21 '21 at 00:00
  • Sorry, to clarify my question: I'm trying to figure out if ATL's `CThreadPool` implementation lets that final completion notification through so that I can handle it in the client code. As you see from the source, `CThreadPool` manages the whole `GetQueuedCompletionStatus` loop for each thread. –  Jul 21 '21 at 00:13
  • 1
    `CThreadPool` has no concept of which I/Os are in flight. Each thread will stop running when it processes an internal `ATLS_POOL_SHUTDOWN` notification posted to the IOCP. If all of the active threads in the pool stop running while you still have pending I/Os in flight, they will get lost and will not process their completions. Worse, `CThreadPool` uses timeouts during shutdown and will brutefully kill threads if they take too long to shutdown. So, you should stop/cancel all of your pending I/Os first, AND wait for them to complete, before you then attempt to shutdown your thread pool. – Remy Lebeau Jul 21 '21 at 00:32
  • 1
    @user15284017 - for what you use self thread pool and `GetQueuedCompletionStatus`, when possible use `BindIoCompletionCallback` or `CreateThreadpoolIo` - in this case many part of work system create for you - manage thread pool and wait for completion events. you need only implement callback in this case – RbMm Jul 21 '21 at 08:01