On Windows 10, I'm waiting for input from the console using
WaitForSingleObject
( GetStdHandle(STD_INPUT_HANDLE), ... )
and to cancel this waiting using CancelSynchronousIo()
.
But the cancellation does nothing (returns 0
and GetLastError()
is ERROR_NOT_FOUND
).
Any idea what I could be doing wrong?
Should I be able to cancel this waiting for new input on stdin?
(I actually want to do this with any HANDLE
whose GetFileType()
is FILE_TYPE_CHAR
, not only stdin, but stdin is certainly the most important use case and the simplest to test with).
Related discussions I've found:
- Synchronous ReadFile() on stdin cannot be unblocked by CancelSynchronousIo()
- win32: how stop ReadFile (stdin|pipe)
But unfortunately they only discuss ReadFile()
, not WaitForSingleObject()
. I've also tried WaitForMultipleObjects()
(with just a single object in the array), same problem.
(Background: I'm trying to improve input handling in the GHC Haskell compiler runtime.)
Console I/O is difficult to use asynchronously, it is simply not designed for it. See IO Completion Ports (IOCP) and Asynchronous I/O through STDIN, STDOUT and STDERR for some possible workarounds.
If that is not an option for you, then you will have to either:
use
WaitForSingleObject()
in a loop with a short timeout. Create a flag variable that your loop can look at on each iteration to break the loop if the flag is set.use
WaitForMutipleObjects()
, giving it 2HANDLE
s to wait on - one for the console (or whatever), and one for an event object fromCreateEvent()
. Then you can signal the event withSetEvent()
when you want to break the wait. The return value ofWaitForMutipleObjects()
will tell you whichHANDLE
was signaled.CancelSynchronousIo
cancel I/O operations that are issued by the specified thread. more concrete it cancelIRP
packets which associated with specified thread via callIoCancelIrp
. if use undocumentedNtCancelSynchronousIoFile
(CancelSynchronousIo
internally call it withIoRequestToCancel = 0
) we can be more selective - cancel only i/o request which used specifiedIoRequestToCancel
(system check thatIrp->UserIosb == IoRequestToCancel
and cancel only this requests)but
WaitForSingleObject
this is not I/O request. this call not create anyIRP
which can be canceled. so - no way do this.however if you use
WaitForSingleObjectEx
withbAlertable
set toTRUE
- you can break wait by queue apc to thread by usingQueueUserAPC
. also if useNtWaitForSingleObject
insteadWaitForSingleObjectEx
we can also alert thread by using undocumented callNtAlertThread
. in this caseNtWaitForSingleObject
will break withSTATUS_ALERTED
(note thatWaitForSingleObjectEx
which internally callNtWaitForSingleObject
do special check forSTATUS_ALERTED
and in case this status - again runNtWaitForSingleObject
- as result we can not breakWaitForSingleObjectEx
by callNtAlertThread
, butNtWaitForSingleObject
will be breaked.so if you need break waiting for std input - create additional thread, which must call not
CancelSynchronousIo
(this senseless) butQueueUserAPC
orNtAlertThread
(only if you useNtWaitForSingleObject
for wait). and input thread must wait in alertable state. so demo code can look like: