unfortunately apparently I poorly expressed my thought and my not the best English, if you not understand me.
“First, ignore whether the I/O Manager returns the error, or whether it’s from Fast I/O or IRP-based processing…but WHO returns the error isn’t relevant”
i try say absolute another( i only describe situation with this), ok let try else one
- i open for asynchronous I/O,
- bind IOCP to it (let be via CreateThreadpoolIo or BindIoCompletionCallback)
- i call some asynchronous API (Zw* or it win32 shell - no matter - anyway Zw* finally called)
(Tim Roberts ask - unclear when you’re talking from user mode and when you’re talking from kernel - here this no matter, Zw api called direct or indirect anyway. i say about both)
so now, i as developer need know - are will be IOCP entry as result of my I/O request or no ?
i not ask are api completed synchronous or not. this is elementary - based are STATUS_PENDING (ERROR_IO_PENDING) returned.
i ask - will be IOCP entry queued as result of I/O call or not ?
(really i even not ask this, i know this, but I’m trying to draw your attention to a very interesting (as it seems to me) question)
- if will be IOCP notification - my registered callback (with CreateThreadpoolIo or BindIoCompletionCallback) will be called by system (from thread pool which listen on IOCP)
- otherwise i need call callback manually by self.
this need for free resources allocated for API call - IO_STATUS_BLOCK (or OVERLAPPED), dereference object which encapsulate file handle. need call CancelThreadpoolIo, if i use TP_IO
look like CancelThreadpoolIo documentation give answer for this (really we must call CancelThreadpoolIo EXACTLY when will be no IOCP notification)
To prevent memory leaks, you must call the CancelThreadpoolIo function for either of the following scenarios:
- An overlapped (asynchronous) I/O operation fails (that is, the asynchronous I/O function call returns failure with an error code other than ERROR_IO_PENDING).
- An asynchronous I/O operation returns immediately with success and the file handle associated with the I/O completion object has the notification mode FILE_SKIP_COMPLETION_PORT_ON_SUCCESS. The file handle will not notify the I/O completion port and the associated I/O callback function will not be called.
but how i discover - this is incorrect.
really I/O request can synchronous return NT_ERROR status, but will be IOCP notification !!
and even more worse case
the asynchronous I/O request return STATUS_SUCCESS but will be no IOCP notification (despite we must wait for it in this case)
the last case I believe direct bug in windows - in NtUnlockFile api. look for win2003 src code (despite this already very old, in this points - nothing changed, how show tests in windows 10)
look - if diver implement FastIoUnlockSingle and it return TRUE (let be with STATUS_SUCCESS) - I/O manager just complete request, without IOCP
so what - asynchronous api call return STATUS_SUCCESS but will be no completion. and how detect this ?
compare with NtLockFile implementation:
here I/O manager post IOCP entry. even if I/O completed with error status !
the same situation with NtDeviceIoControlFile/IopXxxControlFile - if FastIoDeviceControl present and return TRUE - will be IoSetIoCompletion called, even if NT_ERROR status returned
(as opposite FastIoWrite and as FastIoRead called only for FO_SYNCHRONOUS_IO files)
ok, i agree that use Lock file on directory (which return sysnchronous STATUS_INVALID_PARAMETER) is wrong by design.
but - we can call LockFileEx with LOCKFILE_FAIL_IMMEDIATELY - in this case - we can just got STATUS_LOCK_NOT_GRANTED (C0000055) - by documentation - must not be IOCP completion in this case. so we can just release resources (IO_STATUS_BLOCK/OVERLAPPED) must call CancelThreadpoolIo etc. but will be and callback called, because entry queued to IOCP. as result will be double free of IO_STATUS_BLOCK and other. but i found way detect and correct handle this case.
but then, when we call UnlockFileEx (if we acquire lock) - it return synchronous STATUS_SUCCESS and we must except IOCP notification. can not release resources. but will be no notify and callback. and i not view any way detect this case at all (ok, lock/unlock file not very frequently used, but anyway. case with FastIoDeviceControl can be more frequently)
so i design special example, if somebody interest test it and view result yourself. here i try maximal describe case in code. i create 2 threads, which in concurrent try lock the first byte in same file.