IO completion port key confusion

I'm writing an IO completion port based server (source code here) using the Windows DLL API in Python using the ctypes module. But this is a pretty direct usage of the API and this question is directed at those who have a knowledge of IOCP, not Python.

As I understand the documentation for CreateIoCompletionPort, you specify your "user defined" completion key when you call this function with a file handle (in my case a socket) you are associating with the created IOCP. When you get around to calling GetQueuedCompletionStatus, you get a completion key value along with a pointer to an overlapped object. The completion key should identify what overlapped object and request has completed.

However, let's say I pass in 100 as the completion key in my CreateIoCompletionPort call with an overlapped object. When the same overlapped object has its IO completed and it arrives back through GetQueuedCompletionStatus, the completion key that accompanies it is much larger and bares no resemblance to the original value of 100.

Am I misunderstanding how the completion key works, or must I be doing it wrong in the source code I linked above?


Asked by: Catherine854 | Posted: 06-12-2021






Answer 1

What I've found in everyday practice is that it is best to simply focus on the OVERLAPPED result, as that will be unchanged. One way that you can use it effectively is to have something like the following:

struct CompletionHandler
{
    OVERLAPPED dummy_ovl;
    /* Stuff that actually means something to you here */
};

When you post something to the IOCP (whether via I/O call or just a post via Win32 API), you first create a CompletionHandler object that you will use to track the call, and cast the address of that object to OVERLAPPED*.

CompletionHander my_handler;
// Fill in whatever you need to in my_handler
// Don't forget to keep the original my_handler!

// I/O call goes here, and for OVERLAPPED* give: (OVERLAPPED*)&my_handler

This way, when you get the OVERLAPPED result all you have to do is cast it back to CompletionHandler and voila! You have the original context of your call.

OVERLAPPED* from_queued_completion_status;
// Actually get a value into from_queued_completion_status

CompletionHandler* handler_for_this_completion = (CompletionHandler*)from_queued_completion_status;
// Have fun!

For more details in a real-world setting, check out Boost's implementation of ASIO for Windows (ver 1.42 header here). There are some details like validation the OVERLAPPED pointer you get from GetQueuedCompletionStatus, but again, see the link for a good way to implement.

Answered by: Rubie300 | Posted: 07-01-2022



Answer 2

You should think about the completion key as 'per connection' data and the (extended) overlapped structure as 'per i/o' operation.

Some people use an extended overlapped structure for BOTH and store all the information that they need in the extended overlapped structure. I have always stored a reference counted object that wraps my socket in the completion key and a reference counted data buffer as an extended overlapped structure. If you're interested you can see some example IOCP code in C++ here.

The completion key is, effectively, just an opaque handle to data that the I/O completion system will give back to you when a completion occurs on the socket.

Answered by: Rubie987 | Posted: 07-01-2022



Answer 3

GetQueuedCompletionStatus returns two things, an OVERLAPPED structure and a completion key. The completion key represents per-device information, and the OVERLAPPED structure represents per-call information. The completion key should match what was given in the call to CreateIoCompletionPort. Typically, you would use a pointer to a structure containing information about the connection as the completion key.

It looks like you're not doing anything with completionKey as returned by GetQueuedCompletionStatus.

I'm guessing you want:

if completionKey != acceptKey:
    Cleanup()
    ...

edit:

Does Python somehow know that the OVERLAPPED structure created in CreateAcceptSocket is being used asynchronously by the Win32 API and prevent it from being GC'd?

Answered by: Catherine924 | Posted: 07-01-2022



Answer 4

The problem is in how I am passing the completion keys. The completion key argument is a pointer, yet it passes back the pointer not the value pointed to - a little confusing to me at least.

Also the completion key passed for the accepted connection overlapped packet is that of the listening socket - not the accepted socket.

Answered by: Rebecca716 | Posted: 07-01-2022



Answer 5

Completion key is not a pointer - it is a number of type ULONG_PTR, which just means "an integer the size of a pointer" so it is 32-bits on x86 and 64-bits on x64. The typename is confusing, but when win32 typenames refer to a pointer they do it by having a P at the front of the name, not the end.

Answered by: Adrian477 | Posted: 07-01-2022



Answer 6

If your application is multithreading, make sure that the CompletionKey you're passing is either constant or a pointer value to object on heap rather than on stack. In your example where 100 is passed as constant, you must be wrong to say any change. But as to the problem it could be that you pass a socket handle in CreateIoCompletionPort but not a reference to handle in GetQueuedCompletionStatus in order to retrive it. You can do

HANDLE socket;
CreateIoCompletionPort((HANDLE)socket, existed_io_completion_port, (ULONG_PTR)socket, 0);
/*some I/Os*/
...

and

HANDLE socket;
GetQueuedCompletionStatus(existed_io_completion_port, &io_bytes_done, (PULONG_PTR)&socket, &overlapped);

and pay attention to the type in bracket.

Answered by: Ada134 | Posted: 07-01-2022



Similar questions

Has anyone found a good set of python plugins for vim -- specifically module completion?

I'm looking for a suite of plugins that can help me finally switch over to vim full-time. Right now I'm using Komodo with some good success, but their vim bindings have enough little errors that I'm tired of it. What I do love in Komodo, though, is the code completion. So, here's what I'm looking for (ordered by importance). Code completion, meaning: the ability to code complete modules/functi...


How do I add tab completion to the Python shell?

When starting a django application using python manage.py shell, I get an InteractiveConsole shell - I can use tab completion, etc. Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26) [GCC 4.0.1 (Apple Inc. build 5465)] on darwin Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) When just starting a python interpreter using python


Python tell when an ftp transfer sits on completion

I have to download some files from an FTP server. Seems prosaic enough. However, the way this server behaves is if the file is very large, the connection will just hang when the download ostensibly completes. How can I handle this gracefully using ftplib in python? Sample python code: from ftplib import FTP ... ftp = FTP(host) ftp.login(login, passwd) files=ftp.nlst() ftp.set_debuglevel(2)...


python tab completion in windows

I'm writing a cross-platform shell like program in python and I'd like to add custom tab-completion actions. On Unix systems I can use the built-in readline module and use code like the following to specify a list of possible completions when I hit the TAB key: import readline readline.parse_and_bind( 'tab: complete' ) readline.set_completer( ... ) How can I do this on Windows? I'd like to...


Getting proper code completion for Python on Vim?

I've gotten omnicompletion with Pysmell to work before, but I can't seem to do it again. I tried following some steps online, but most, if not all, of them are to vague and assume too much that you know what you are doing to some extent. Can someone post a full, step-by-step tutorial on how to get code completion working properly, for complete Vim newbies (for dummies?)?


python - Trick code completion with PyDev like with PDT?

Is there a way to help PyDev code completion by telling it the type of a variable? With PDT, you can use PHPDoc-like syntax for such purpose: /* @var $my_var MyClass */ $my_var = myFunction(); // PDT is able to figure out that $my_var is a MyClass object. But till now, I cannot figure out how to do the same in python.


mercurial - Tab Completion in Python Command Line Interface - how to catch Tab events

I'm writing a little CLI in Python (as an extension to Mercurial) and would like to support tab-completion. Specifically, I would like catch tabs in the prompt and show a list of matching options (just like bash). Example: Enter section name: ext*TAB* extensions extras The problem is I'm not sure how to catch the Tab events. I'm using the ui.prompt() API of Merc...


Code completion in NetBeans' python plugin does not work properly

I am asking on StackOverflow because surely I am doing something completely silly and I hope S.O. might provide me with a quick answer. I've installed the latest stable Python-plugin for NetBeans. It works great, and I tested code completion with various packages such as sys, os and so on. It works beautifully. However, it does not seem to pick up the code completion for the code in my ow...


python - Weird behaviour with optparse and bash tab completion

I am building a script for users new to Linux, so please understand why I am asking this :) My script runs like this: python script.py -f filename.txt I am using the optparse module for this. However, I noticed the following when doing tab completion. The tab completion works when I do: python script.py <tab completion> # Tab completion wo...


python - which inotify event signals the completion of a large file operation?

for large files or slow connections, copying files may take some time. using pyinotify, i have been watching for the IN_CREATE event code. but this seems to occur at the start of a file transfer. i need to know when a file is completely copied - it aint much use if it's only half there. when a file transfer is finished and completed, what inotify event is fired?






Still can't find your answer? Check out these communities...



PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python



top