如何正确等待 NtCreateFile/etc 完成?

how to properly wait for completion of NtCreateFile/etc?

我在我的应用程序中使用本机 NT API 来访问文件 (NtCreateFile/etc)。为了避免处理 STATUS_PENDING 我在打开相关文件时使用了 FILE_SYNCHRONOUS_IO_NONALERT 标志。因此,打开文件如下所示:

UNICODE_STRING fname = toNtUnicode(ntpath);

OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes(&oa, &fname, 0, at.handle(), NULL);

HANDLE h;
IO_STATUS_BLOCK io_status;
NTSTATUS r = NtOpenFile(&h, GENERIC_READ|SYNCHRONIZE, &oa, &io_status, 
    FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE);
if (r != STATUS_SUCCESS)
    ...; // error handling

不幸的是,它会导致内核序列化给定句柄上的所有操作。 IE。如果我尝试并行执行多个读取(使用多个线程)——在任何时间点只会处理一个请求。

我可以摆脱序列化:

HANDLE h;
IO_STATUS_BLOCK io_status;
NTSTATUS r = NtOpenFile(&h, GENERIC_READ|SYNCHRONIZE, &oa, &io_status, 
    FILE_SHARE_READ, FILE_DIRECTORY_FILE);
if (r == STATUS_PENDING)
    ...; // what to do here???

但是我究竟应该如何等待完成 -- WaitForSingleObject() 在文件句柄上?据我所知,由于多种原因它可以更改为信号状态——有什么方法可以告诉我打开的文件(或目录)操作已完成?

同样,如果我提交多个读取(来自多个线程)——我如何判断哪一个(如果有)已完成?

NtOpenFile 是同步的api。它永远不会 return STATUS_PENDING 给你。即使驱动程序 return STATUS_PENDING for IRP_MJ_CREATE i/o 子系统将等待 IRP 完成

https://github.com/Zer0Mem0ry/ntoskrnl/blob/master/Io/iomgr/parse.c#L1404

所以你永远不需要在 NtOpenFile 之后检查 STATUS_PENDING 并且永远不需要等待(原则上我们不能在这里等待 - 我们还没有文件句柄 - 所以不能等待它或者将其绑定为 IOCP。我们不会为 NtOpenFile)

传递任何事件或其他回调机制