WriteFile函数是否通过lpOverlapped
参数传递了事件,如果它同步完成并成功的话?如果事件同步失败,它会发出信号吗?我已经打开了一个带有FILE_FLAG_OVERLAPPED
标志的文件的句柄。我无法从文档中弄清楚这一点,并且无法在代码中轻松地重现此案例。
答案 0 :(得分:2)
首先,这个问题不仅与WriteFile
相关,而且与任何异步I / O函数有关 - 几乎所有函数都获得指向OVERLAPPED
结构的指针。因为对于所有这些函数IRP
( I / O请求数据包)(在 wdm.h 中查看它的定义)被分配。来自OVERLAPPED
的hEvent
句柄已转换为对象指针并存储在PKEVENT UserEvent;
IRP
成员中。在IRP
例程中IopCompleteRequest
完成时,事件已设置(或未设置)。 IRP
完成函数对于所有I / O api都是通用的,因此规则(当完成触发时)与所有I / O api相关。不幸的是,这是非常糟糕的记录。 win32层(比较NT层)在这里添加了额外的,非常薄的问题。
基于wrk src code,我们可以看到异步io的I / O管理器触发完成(3种类型 - 事件,apc和iocp(互斥))
!NT_ERROR( irp->IoStatus.Status )
或irp->PendingReturned
。
如果我们使用原生api,直接返回NTSTATUS
- (ULONG)status < 0xc0000000
时。但是,如果不清楚,则设置范围0x80000000 <= status < 0xc0000000
或NT_WARNING(status)
非常有问题 - 完成(甚至设置,apc或数据包到iocp队列)。这是因为在分配IRP
之前,I / O管理器会执行一些基本检查,并且可以从此处返回错误。通常I / O管理器从NT_ERROR(status)
返回错误,这意味着没有完成(事件将不会被设置)),但是存在并且很少有例外。例如,对于ReadDirectoryChangesW
(或ZwNotifyChangeDirectoryFile
), lpBuffer 指针必须是DWORD对齐的(与FILE_NOTIFY_INFORMATION
完全对齐)否则I / O管理器返回{{1来自STATUS_DATATYPE_MISALIGNMENT
范围的(0x80000002)。但在这种情况下不会完成(事件集),因为函数在分配NT_WARNING
之前失败。从另一种情况来看,如果我们调用FSCTL_FILESYSTEM_GET_STATISTICS
缓冲区不够大 - 文件系统驱动程序(不是I / O管理器)返回IRP
(0x80000005)。但是因为此时STATUS_BUFFER_OVERFLOW
已经分配且代码不是来自IRP
范围 - 将是事件设置。
所以,如果来自I / O管理器的错误(在分配NT_ERROR
之前) - 将无法完成。否则,如果函数返回IRP
,则来自驱动程序(传递IRP
)完成的错误将是。结果如果我们得到:
!NT_ERROR(status)
(NT_SUCCESS(status)
(STATUS_PENDING
)是其中的一部分) - 将会
是
完成0x103
将无法完成NT_ERROR(status)
- 不清楚,从I / O管理器中依赖此错误
(不)或司机(是)但是使用win32层使情况更糟糕。因为不清楚它是如何解释NT_WARNING(status)
- 大多数win32 api将此解释为错误 - 返回 false 并设置最后一个错误(从状态转换)。但有些api - 例如ReadDirectoryChangesW
将此解释为成功代码 - 返回 true 并且未设置上一个错误。因此,如果我们使用错误的对齐缓冲区(但有效的其他参数)调用ReadDirectoryChangesW
- 它返回.. true 并且不设置任何错误。但api电话确实失败了。此处NT_WARNING(status)
内部返回ZwNotifyChangeDirectoryFile
。
从另一方面,如果STATUS_DATATYPE_MISALIGNMENT
的{{1}}失败(返回false),代码DeviceIoControl
(从FSCTL_FILESYSTEM_GET_STATISTICS
转换)事件(完成)将在此情况下设置
也是我们无法理解的win32错误代码 - 初始状态为ERROR_MORE_DATA
或STATUS_BUFFER_OVERFLOW
代码 - 转换(RtlNtStatusToDosError
)状态为win32错误丢失此信息
NT_ERROR
范围的问题,从vista开始,如果我们使用IOCP完成(而不是事件)并在文件上设置FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
,则可以解决问题 - 在这种情况下,I / O管理器将完成条目排入当且仅当本地api调用返回NT_WARNING
时,该端口。对于win32层,这通常意味着api返回false,最后一个错误是NT_WARNING(status)
。例外 - STATUS_PENDING
,ERROR_IO_PENDING
在此处返回true。但是,无论如何WriteFileEx
无效(我认为这是Windows bug)
还读取FILE_SKIP_SET_EVENT_ON_HANDLE
部分 - 这隐含地说明了在异步函数中设置显式事件(来自重叠)时 - 当请求返回成功代码时,或者返回的错误是{{ 1}}。但是这里有一个问题 - 什么是成功代码? win32 api返回true吗?并非始终如ReadFileEx
所示 - ReadDirectoryChangesW
(ERROR_IO_PENDING
)也是成功代码。或NtQueryDirectoryFile
返回的FSCTL_FILESYSTEM_GET_STATISTICS
也会设置成功代码 - 事件(apc或iocp完成)。但同样NtQueryDirectoryFile
可以返回ERROR_MORE_DATA
,当STATUS_BUFFER_OVERFLOW
错误对齐时 - 这是失败代码,因为在分配STATUS_NO_MORE_FILES
之前从I / O管理器返回
STATUS_DATATYPE_MISALIGNMENT
状态是成功代码(将完成),但在大多数情况下,win32层将其解释为失败代码(返回false)。
测试的代码示例:
FileInformation
并输出:
IRP