2017-09-13 106 views
0

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

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 

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

我能摆脱系列化:

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()对文件处理?据我所知,由于许多原因它可以改变为信号状态 - 是否有任何方法可以告诉我打开的文件(或dir)操作已完成?同样,如果我提交多个读取(来自多个线程) - 我怎么知道哪一个(如果有的话)完成了?

回答

0

NtOpenFile是同步api。它永远不会返回STATUS_PENDING给你。即使IRP_MJ_CREATE I/O子系统驱动器返回STATUS_PENDING将等待IRP完整

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

,所以你永远不需要NtOpenFile后检查STATUS_PENDING永不需要等待(在原则上我们不能在这里等着 - 。我们还没有文件句柄 - 所以不能在它等待或结合说IOCP我们不传递任何事件或NtOpenFile另一个回调机制)

+0

奇怪......我发誓,我观察到STATUS_UPDATE时打开目录。我会再试一次。同时,关于其他操作 - 我是否应该等待该事件传递给NtReadFile?如果是,那么我并不需要SYNCHRONIZE标志,对吧? –

+0

NtClose()怎么样 - 它保证是同步的吗?另外,我是否可以假定所有关于NtXXX函数的说法都同样适用于相应的ZwXXX函数(如果在用户模式下调用)? –

+0

@ C.M。 'ZwOpenFile'和'ZwClose'是**同步** api的设计。它**从不**返回'STATUS_PENDING'。 * Nt *和* Zw *函数 - 在用户模式下是别名。这是相同的功能(两个名称指向相同的地址) – RbMm