使用 io 完成端口时,WriteFile post 是否立即完成完成数据包

does WriteFile post a completion packet on finishing immediately when using io completion ports

我知道当 WSARecv 与它一起使用时它可能会立即完成,在这种情况下仍会发布完成数据包并且可以使用 SetFileCompletionNotificationModes 更改此行为

但我想知道使用 WriteFile 的文件和管道的情况,如果我使用 iocp 进行异步读写并且操作立即完成,是否会发生相同的行为?或者我必须处理这个?

根据 Why does my asynchronous I/O request return TRUE instead of failing with ERROR_IO_PENDING?:

When you specify FILE_FLAG_OVERLAPPED, you’re promising that your program knows how to handle I/O which completes asynchronously, but it does not require the I/O stack to behave asynchronously. A driver can choose to perform your I/O synchronously anyway. For example, if the write operation can be performed by writing to cache without blocking, the driver will just copy the data to the cache and indicate synchronous completion. Don’t worry, be happy: Your I/O completed even faster than you expected!

Even though the I/O completed synchronously, all the asynchronous completion notification machinery is still active. It’s just that they all accomplished their job before the Write­File call returned. This means that the event handle will still be signaled, the completion routine will still run (once you wait alertably), and if the handle is bound to an I/O completion port, the I/O completion port will receive a completion notification.

You can use the Set­File­Completion­Notification­Modes function to change some aspects of this behavior, giving some control of the behavior of the I/O subsystem when a potentially-asynchronous I/O request completes synchronously.

存在所有异步 api 的共同行为,它隐含在 CancelThreadpoolIo 函数

中描述

请注意,根据设计我们需要调用 CancelThreadpoolIo 时且仅当不会通知 I/O 完成端口并且不会调用关联的 I/O 回调函数时。

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.

所以让 dwErrorCode 错误代码 return 由 api 编辑(NOERROR 如果 win32 api return TRUE)

下一个函数告诉你 - 是否会通知 IOCP

bool IsWillBeNotification(ULONG dwErrorCode, BOOL bSkipCompletionPortMode)
{
    switch (dwErrorCode)
    {
    case ERROR_IO_PENDING:
        return true;
    case NOERROR:
        return !bSkipCompletionPortMode;
    default:
        return false;
    }
}

以防我们使用本机 API 和 NTSTATUS

bool IsWillBeNotification(NTSTATUS status, BOOL bSkipCompletionPortMode)
{
    return (status == STATUS_PENDING) || (!NT_ERROR(status) && !bSkipCompletionPortMode);
}

所以:

  • if STATUS_PENDING - 将是 IOCP 数据包
  • if NT_ERROR(status) - 将没有数据包(状态在 [0xC0000000, 0xFFFFFFFF] 范围内)
  • 否则基于bSkipCompletionPortMode - 如果未设置

请注意,这是任何异步 io api 的一般规则。只有 NtLockFile/LockFileEx - 此规则的例外情况 - 即使 api 因 NtLockFile 实现

内部的错误而失败,也可以是 IOCP 通知