GetQueuedCompletionStatusEx() 不返回 per-OVERLAPPED 错误代码
Posted
技术标签:
【中文标题】GetQueuedCompletionStatusEx() 不返回 per-OVERLAPPED 错误代码【英文标题】:GetQueuedCompletionStatusEx() doesn't return a per-OVERLAPPED error code 【发布时间】:2014-03-22 09:34:59 【问题描述】:我正在使用GetQueuedCompletionStatusEx()
api,我刚刚意识到它
确实可以在 1 个系统调用中读取 N OVERLAPPEDs 个数据包,而不是像 GetQueuedCompletionStatus()
那样只读取 1 个 OVERLAPPED,但我担心的是我对 per-OVERLAPPED 错误代码一无所知。
虽然GetQueuedCompletionStatus()
每次调用只返回 1 个 OVERLAPPED,但它让我能够检查,调用 GetLastError()
,当前 OVERLAPPED 数据包的最后一个错误。
我如何使用GetQueuedCompletionStatusEx()
做到这一点,它实际上返回 N OVERLAPPEDs 个数据包,但不返回 N 个错误代码?
我已经通过调用 GetOverlappedResult()
了解了这一点,您可以实现这一点,但我的意思是:如果我调用 GetQueuedCompletionStatusEx()
来获取 N OVERLAPPEDs 个数据包,然后我必须为 EACH 调用另一个系统调用 em> 其中,调用 1 个系统调用来获得 N OVERLAPPED 的好处是没有意义的,因为您将调用 1+N 个系统调用。在这一点上,我可以简单地使用GetQueuedCompletionStatus()
,并且只调用 N 个系统调用(对于 N OVERLAPPEDs)而不是 1+N。
有人知道更多吗?
【问题讨论】:
是的,我注意到了,但是:这是一个 NTSTATUS 错误,而不是 GetLastError() 代码,我想我应该使用 HRESULT_FROM_NT(overlapped->Internal) 来获得正确的 GetLastError() 代码, 对?该宏是否可靠?我的意思是,我不想在某些版本的 Windows 中出现一些错误,而在某些其他版本中出现一些其他错误。我之所以这么说是因为我在某处读到不应使用 OVERLAPPED 的“内部”参数,因为它没有记录在案,因此将来可能会发生变化。我期待GetQueuedCompletionStatusEx()
记录的更多内容:)
您确定GetOverlappedResult
需要系统调用吗?
我想是的。它是一个 API,您可以(可选地)向其传递一个 HANDLE,所以我猜它在内部调用了一些系统调用。我已经解决了这个问题,只需从 ntdll.dll 调用 RtlNtStatusToDosError()
并将 ovrlapped->Internal 参数传递给它,该参数将转换为 ntdll.dll 中类似 GetLastError() 的代码,即 not 肯定是系统调用 :) 它工作得很好,我选择使用前者还是后者。
我只希望GetOverlappedResult
在必须等待操作完成时调用内核。它可以在用户模式下做所有其他事情。 Win32 函数不会仅仅为了好玩而调用内核模式!但如果您想要一种避免额外 API 调用的受支持机制,请考虑使用 APC。
无论如何,每次完成的 I/O 操作一个额外的内核转换的开销似乎不太可能是显着的。关于 APC,您可能是对的,因为它们总是排队到启动 I/O 的线程——当然,您总是可以实现自己的重新排队机制。
【参考方案1】:
完成状态存储在OVERLAPPED.Internal
字段中。但正如您所指出的,这是本机 api 状态代码,而不是 winapi 错误代码。翻译它的一种简单方法是致电GetOverlappedResult()。你为 bWait 参数传递什么并不重要,它总是会立即返回。对套接字使用 WSAGetOverlappedResult()。
【讨论】:
即使GetOverlappedResult()
立即返回,它始终是进程必须执行的系统调用,在我看来减少了仅用 1 个系统调用获取 N OVERLAPPED 的好处。另一个值得关注的问题是,我不知道 OVERLAPPED 是属于套接字还是文件还是管道,所以我怎么知道要调用什么,如果 GetOverlappedResult()
或 WSAGetOverlappedResult()
?为此,我是否需要在我自己的“派生”结构中使用 OVERLAPPED 的标志?
避免依赖意见,只需将调试器切换到反汇编并单步执行功能即可。不会花很长时间。当然,必须始终跟踪 I/O 操作的上下文。完成后需要发生一些特定的事情,您应该已经准备好。如果没有,那么您很快就会添加它。以上是关于GetQueuedCompletionStatusEx() 不返回 per-OVERLAPPED 错误代码的主要内容,如果未能解决你的问题,请参考以下文章
如何强制 GetQueuedCompletionStatus() 立即返回?
一些使用 WSASend 的 OVERLAPS 没有使用 GetQueuedCompletionStatus 及时返回?
当 GetQueuedCompletionStatus() 返回 FALSE 时,这些参数的值是多少?
GetQueuedCompletionStatus 返回后发生错误,错误号为 ERROR_INVALID_NETNAME
GetQueuedCompletionStatus 继续选择关闭套接字上的事件
io 完成端口问题,每个 GetQueuedCompletionStatus 调用多个 wsarecv 或 wsasend