如果事件同步完成,WriteFile是否会发出事件信号

时间:2018-04-21 19:36:05

标签: c windows winapi

WriteFile函数是否通过lpOverlapped参数传递了事件,如果它同步完成并成功的话?如果事件同步失败,它会发出信号吗?我已经打开了一个带有FILE_FLAG_OVERLAPPED标志的文件的句柄。我无法从文档中弄清楚这一点,并且无法在代码中轻松地重现此案例。

1 个答案:

答案 0 :(得分:2)

首先,这个问题不仅与WriteFile相关,而且与任何异步I / O函数有关 - 几乎所有函数都获得指向OVERLAPPED结构的指针。因为对于所有这些函数IRP I / O请求数据包)(在 wdm.h 中查看它的定义)被分配。来自OVERLAPPEDhEvent句柄已转换为对象指针并存储在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 < 0xc0000000NT_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_DATASTATUS_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_PENDINGERROR_IO_PENDING在此处返回true。但是,无论如何WriteFileEx无效(我认为这是Windows bug)

还读取FILE_SKIP_SET_EVENT_ON_HANDLE部分 - 这隐含地说明了在异步函数中设置显式事件(来自重叠)时 - 当请求返回成功代码时,或者返回的错误是{{ 1}}。但是这里有一个问题 - 什么是成功代码? win32 api返回true吗?并非始终如ReadFileEx所示 - ReadDirectoryChangesWERROR_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