• Welcome to Valhalla Legends Archive.
 

IO Completion Ports

Started by Maddox, July 23, 2006, 09:56 AM

Previous topic - Next topic

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).
asdf.

TheMinistered

STEP1 CREATE THE COMPLETION PORT:

HANDLE    hIocp;

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

if (hIocp == NULL) {
    // Error
}


STEP2 CREATE SOCKET(S) AND ASSOCIATE WITH IOCP:

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
}



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.

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).

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:

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


WORKER THREAD/POLLER:

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


enough for me, have fun ;P

Maddox

Wow, way to post meaningless, redundant code, that I've already seen, and then not answer my question.

asdf.

vuther.de

Quote from: Maddox on July 27, 2006, 12:32 PM
Wow, way to post meaningless, redundant code, that I've already seen, and then not answer my question.
I found that funny.

Excel

I didn't... I'm trying to figure out the same problem. :(

Arta

Quote from: Maddox on July 23, 2006, 09:56 AM
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?

Iirc, yes, and then again every time you receive data.