6

I'm using the GetQueuedCompletionStatusEx() api, and I've just realized that it can indeed read N OVERLAPPEDs packets in just 1 syscall, instead of only 1 OVERLAPPED, like GetQueuedCompletionStatus(), but my concern is that I cannot know anything about per-OVERLAPPED error code.

While GetQueuedCompletionStatus() returns only 1 OVERLAPPED per call, it gives to me the ability to check, calling GetLastError(), the last error for the current OVERLAPPED packet.

How I could do this with GetQueuedCompletionStatusEx() which in fact returns N OVERLAPPEDs packets, but not N error codes?

I have read around that by calling GetOverlappedResult() you can achieve that, but my point is: if I call GetQueuedCompletionStatusEx() to get N OVERLAPPEDs packets, and then I have to call another syscall for EACH of them, the benefit of calling 1 syscall to get N OVERLAPPEDs is pointless, since you'll call 1+N syscalls. At this point I could stay simply with GetQueuedCompletionStatus() and call only N syscalls (for N OVERLAPPEDs) instead of 1+N.

Do anyone know more about this?

Marco Pagliaricci
  • 1,366
  • 17
  • 31
  • Yeah I have noticed that, but: that is a NTSTATUS error, and not a GetLastError() code, I guess I should use HRESULT_FROM_NT(overlapped->Internal) to get the correct GetLastError() code, right? And will that macro be reliable? I mean, I don't want to get some errors in some versions of Windows and some other errors in some other versions. I say that because I read somewhere that "Internal" parameter of OVERLAPPEDs shouldn't be used because its not documented so it may change in the future. I was expecting something more documented by `GetQueuedCompletionStatusEx()` :) – Marco Pagliaricci Mar 22 '14 at 10:01
  • Are you sure that `GetOverlappedResult` requires a syscall? – Harry Johnston Mar 23 '14 at 22:15
  • 1
    I guess so. Its an API to whom (optionally) you can pass an HANDLE, so I guess it calls some syscall, internally. I have solved that just by calling `RtlNtStatusToDosError()` from ntdll.dll and passing it the ovrlapped->Internal parameter, which will be converted to a GetLastError()-like code in ntdll.dll, which is *not* a syscall for sure :) It works just pretty fine, with some #ifdefs I choose if using the former or the latter. – Marco Pagliaricci Mar 23 '14 at 22:38
  • I would only expect `GetOverlappedResult` to call into the kernel if it has to wait for the operation to complete. It can do everything else in user mode. Win32 functions don't call into kernel mode just for fun! But if you want a supported mechanism that avoids extra API calls, consider using APCs. – Harry Johnston Mar 23 '14 at 22:44
  • Maybe you're right about that API calling kernel stuff only if it has to wait. I have noticed that its counterpart, `WSAGetOverlappedResult()` works only if you pass it a *valid* SOCKET, otherwise it returns error 10038 (not a sock), maybe that calls the kernel anyway? Btw, I don't think APCs are a solution, because they do not scale so well as I/O completion ports. I will get less syscall calling maybe, but worst performance in general! – Marco Pagliaricci Mar 23 '14 at 23:09
  • 1
    At any rate, the overhead of one extra kernel transition per completed I/O operation seems very unlikely to be significant. You may be right about APCs, because they are always queued to the thread that initiated the I/O - though of course you could always implement your own re-queuing mechanism. – Harry Johnston Mar 24 '14 at 00:02

1 Answers1

4

The completion status is stored in the OVERLAPPED.Internal field. But as you noted, that's the native api status code, not a winapi error code. An easy way to translate it is to call GetOverlappedResult(). It doesn't matter what you pass for the bWait argument, it will always return immediately. Use WSAGetOverlappedResult() for sockets.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Even if `GetOverlappedResult()` returns immediately, it is always a syscall the process has to do, in my opinion reducing the benefits for grabbing N OVERLAPPEDs with only 1 syscall. Another point of concern is that I don't know if an OVERLAPPED belongs to a socket or a file or a pipe, so how I can know what to call, if `GetOverlappedResult()` or `WSAGetOverlappedResult()` ? Do I need a flag inside a my own "derived" structure from the OVERLAPPED for that? – Marco Pagliaricci Mar 22 '14 at 10:27
  • 1
    Avoid relying on opinion, just switch the debugger to disassembly and step into the function. It won't take long. And sure, having to keep track of the context of the I/O operation is always necessary. Something specific needs to happen after it completes, you should already have this in place. If not then you'll add it soon. – Hans Passant Mar 22 '14 at 10:43