Valhalla Legends Forums Archive | General Programming | IO Completion Ports

AuthorMessageTime
Maddox
Once I've created my completion port and associated my device with it (a socket in this case), do I need to call WSARecv() to have it actually start detecting messages?

I need to use a completion port to detect if there is data to be read on multiple sockets and handle each one according (like select).
July 23, 2006, 2:56 PM
TheMinistered
STEP1 CREATE THE COMPLETION PORT:
[code]
HANDLE    hIocp;

hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
NULL,(ULONG_PTR)0, 0);

if (hIocp == NULL) {
    // Error
}
[/code]

STEP2 CREATE SOCKET(S) AND ASSOCIATE WITH IOCP:
[code]
SOCKET    s;

s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET) {
    // Error
}

if (CreateIoCompletionPort((HANDLE)s, hIocp, (ULONG_PTR)0, 0) == NULL) {
    // Error
}
[/code]


[QUOTE]
At this point, the socket s is associated with the completion port. Any overlapped operations performed on the socket will use the completion port for notification.  Note that the third parameter of CreateIoCompletionPort allows a completion key to be specified along with the socket handle to be associated.
[/QUOTE]

NOTE: The Completion Key!  It can be used to pass context information that is associated with the socket, like a struct for each connection containing extra information.


Now comes the fun part, polling!  You need to create some threads to poll GetQueuedCompletionStatus.  Typically one per processor works pretty good.

[QUOTE]
When an overlapped call is made, a pointer to an overlapped structure is passed as a parameter. GetQueuedCompletionStatus will return the same pointer when the operation completes. With this structure alone, however, an application can't tell which operation just completed. In order to keep track of the operations that have completed, it's useful to define your own OVERLAPPED structure that contains any extra information about each operation queued to the completion port (see Figure 1).
[/QUOTE]

So you need to define your own OVERLAPPED structure, I usually call mine OVERLAPPEDEX.  You specifically need to include a STATE variable, to know what kind of operation just occured (kinda like an enum?).

OVERLAPPEDEX STRUCT:
[code]
typedef struct OVERLAPPEDEX {
    OVERLAPPED        overlapped;
    SOCKET                s, c;
    int                        state;
    WSABUF                buffer;
    DWORD                dwBytes, dwFlags;
    // anything else useful can go here
};

#define ST_READ      0
#define ST_WRITE    1
#define ST_ACCEPT  2
[/code]

WORKER THREAD/POLLER:
[code]
DWORD WINAPI WorkerThread(LPVOID lpParam)
{   
    ULONG_PTR      *PerHandleKey;
    OVERLAPPED      *Overlapped;
    OVERLAPPEDEX    *OverlappedEx, *New*OverlappedEx;
    DWORD          dwBytesXfered;

    while (1)
    {
        ret = GetQueuedCompletionStatus(hIocp,&dwBytesXfered,(PULONG_PTR)&PerHandleKey, &Overlapped, INFINITE);
        if (ret == 0)
        {
            // Operation failed
            continue;
        }
        OverlappedEx = CONTAINING_RECORD(Overlapped, OVERLAPPEDEX, overlapped);
   
    switch (OverlappedEx->state)
    {
    case OP_ACCEPT:
        // Client socket is contained in OverlappedEx.c
        // Associate client socket with completion port
            CreateIoCompletionPort((HANDLE)OverlappedEx->c,hIocp,(ULONG_PTR)0,0);

        //  Need a new OVERLAPPEDEX structure
        //  for the newly accepted socket.
        NewOverlappedEx = AllocateOverlappedEx();
        if (!NewOverlappedEx )
        {
            // Error
        }
        NewOverlappedEx->s = OverlappedEx->c;
        NewOverlappedEx->state = OP_READ;

        // This function prepares the data to be sent
        PrepareSendBuffer(&NewOverlappedEx->buffer);
 
        ret = WSASend(NewOverlappedEx->s,&NewOverlappedEx->buffer,1,&NewOverlappedEx->dwBytes,0,&NewOverlappedEx.overlapped,NULL);
       
        if (ret == SOCKET_ERROR)
        {
            if (WSAGetLastError() != WSA_IO_PENDING)
            {
            // Error
            }
        }

        // Put structure in look aside list for later use
        FreeOverlappedPlus(OverlapPlus);

        // Signal accept thread to issue another AcceptEx
        SetEvent(hAcceptThread);
        break;

    case OP_READ:

        // ...
break;
    } // switch
    } // while
}  // WorkerThread
[/code]

enough for me, have fun ;P
July 27, 2006, 4:57 PM
Maddox
Wow, way to post meaningless, redundant code, that I've already seen, and then not answer my question.

July 27, 2006, 5:32 PM
inner.
[quote author=Maddox link=topic=15438.msg156174#msg156174 date=1154021521]
Wow, way to post meaningless, redundant code, that I've already seen, and then not answer my question.
[/quote]
I found that funny.
August 12, 2006, 7:06 AM
Excel
I didn't... I'm trying to figure out the same problem. :(
August 12, 2006, 8:49 AM
Arta
[quote author=Maddox link=topic=15438.msg155995#msg155995 date=1153666573]
Once I've created my completion port and associated my device with it (a socket in this case), do I need to call WSARecv() to have it actually start detecting messages?
[/quote]

Iirc, yes, and then again every time you receive data.
September 21, 2006, 8:55 AM

Search