It does not. The async is set to `signaled` right away, so that Status can be set to STATUS_PENDING and subsequently checked via `GetOverlappedResult()`. But I see the point. I'll look for some way to do it without "unsignaling" the async.
If that's the case this is also a problem for sync IO which can in theory run away from wait before IOSB status is set? Maybe it is hard to get in practice (or even impossible before ntsync) because system APC with IO completion is delivered to waiting thread. But I think we want the same for sync IO wait as well, async should only be signaled once IOSB is delivered. There is no reason this thing should work different for cancellation wait, right?
The other thing to be careful about is to not "satisfy" the wait for the final IOSB Status (i.e. we want the application to still be able to wait on the file handle or the OVERLAPPED event after `NtCancelIoFile()` returns).
Do we care when the wait completion for the IO caller happens WRT to the waits in NtCancelIO? If this is async IO the caller should never meet async's wait object. I suppose it is not detectable whether NtCancelIO exited before wait on overlapped event or for IO completion or after, so do we care if IO completion is performed from async_wait been satisfied for NtCancelIO wait or before that when server processed cancellation?