⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 overlap.cpp

📁 < WINDOWS网络编程>>英文版,一本详细讲解WINDOWS平台下网络编程的国外经典书籍,适合英文水平高的牛人
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) 1999  Microsoft Corporation.  All Rights Reserved.
//
// Module Name: overlapped.cpp
//
// Description:
//
//    This module is responsible for handling the overlapped IO 
//    passed to us by the upper layer. If the LSP is on NT, then
//    an IO completion port (IOCP) is created and all overlapped
//    IO initiated by the upper layer passes through our IOCP.
//    If this is Win9x then we create a worker thread and execute
//    the overlapped IO via asynchronous procedure calls (APC).
//
#include "provider.h"

#include <stdio.h>
#include <stdlib.h>

#define DEFAULT_POOL_COUNT  100         // Default number of OVERLAPPED
#define MAX_PROC_COUNT      32          // Maximum number of worker threads

extern CRITICAL_SECTION    gOverlappedCS; // Protect access to the overlapped funcs
extern HANDLE              hLspHeap;

//
// For each overlapped operation given to us from the upper layer, we'll
// assign a WSAOVERLAPPEDPLUS structure so that we can make the overlapped
// call to the lower layer. The following variables are pointers to these
// structures.
//
LPWSAOVERLAPPEDPLUS FreePool  = NULL,           // List of unused structures
                    PendingStart = NULL,        // List of pending ops - start
                    PendingEnd  = NULL,         // List of pending ops - end
                    OverlappedPool = NULL;      // Entire list of structures

HANDLE              gWorkerThread[MAX_PROC_COUNT] = {NULL, NULL, NULL, NULL, NULL, NULL,
                                                     NULL, NULL, NULL, NULL, NULL, NULL,
                                                     NULL, NULL, NULL, NULL, NULL, NULL,
                                                     NULL, NULL, NULL, NULL, NULL, NULL,
                                                     NULL, NULL, NULL, NULL, NULL, NULL,
                                                     NULL, NULL},
                    ghWakeupSemaphore = NULL,   // Wakeup semaphore
                    ghIocp = NULL;              // Handle to the IOCP
DWORD               gdwThreadCount = -1;        // Number of worker threads

//
// Extenion function pointers declared in extension.cpp
//  These functions are loaded only when the caller calls them.
//
static TCHAR Msg[512]; 

//
// Function prototypes
//
int   ExecuteOverlappedOperation(WSAOVERLAPPEDPLUS *lpOverlapped, BOOL bSynchronous);
int   EnqueueOverlappedOperation(WSAOVERLAPPEDPLUS *op);
void  SetOverlappedInProgress(OVERLAPPED *ol);
void  PutbackOverlappedStructure(WSAOVERLAPPEDPLUS *olp);
DWORD WINAPI   OverlappedManagerThread(LPVOID lpParam);
VOID  CALLBACK CallUserApcProc(ULONG_PTR Context);
void  CheckForContextCleanup(WSAOVERLAPPEDPLUS *ol);


int AllocateFreePool()
{
    DWORD     i;

    //
    // Allocate our overlapped structures as well as zeroes it out
    //
    OverlappedPool = (LPWSAOVERLAPPEDPLUS)HeapAlloc(
                        hLspHeap, 
                        HEAP_ZERO_MEMORY,
                        sizeof(WSAOVERLAPPEDPLUS) * DEFAULT_POOL_COUNT);

    if (!OverlappedPool)
    {
        dbgprint("out of memory!");
        return WSAENOBUFS;
    }
    // Initialize our overlapped structures
    //
    for(i=0; i < DEFAULT_POOL_COUNT-1 ;i++)
    {
        OverlappedPool[i].next = &OverlappedPool[i+1];
    }
    FreePool  = &OverlappedPool[0];

    return NO_ERROR;
}

//
// Function: InitOverlappedManager
//
// Description:
//    This function is called once and determines whether we're running
//    on NT or Win9x. If on NT, create an IO completion port as the
//    intermediary between the upper and lower layer. All overlapped IO
//    will be posted using this IOCP. When IOCP are available we'll create
//    a number of threads (equal to the number of procs) to service the
//    completion of the IO. If on Win9x, we'll create a single thread which
//    will post overlapped IO operations using APCs.
//
int InitOverlappedManager()
{
    DWORD   dwId,
            i;

    EnterCriticalSection(&gOverlappedCS);

    if (gWorkerThread[0] != NULL)
    {
        LeaveCriticalSection(&gOverlappedCS);
        return 0;
    }

    if (AllocateFreePool() == WSAENOBUFS)
    {
        LeaveCriticalSection(&gOverlappedCS);
        return WSAENOBUFS;
    }

    //
    // See if we're on NT by trying to create the completion port. If it
    //  fails then we're on Win9x.
    //
    ghIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
                                    NULL,
                                    (ULONG_PTR)0,
                                    0);
    if (ghIocp)
    {
        SYSTEM_INFO     sinfo;

        // We're on NT so figure out how many processors we have
        //
        GetSystemInfo(&sinfo);
        gdwThreadCount = sinfo.dwNumberOfProcessors;

        dbgprint("Created IOCP: %d", ghIocp);
    }
    else
    {
        // We're on Win9x so create a semaphore instead. This is used to
        //  wake up the worker thread to service overlapped IO calls.
        //
        ghWakeupSemaphore = CreateSemaphore(NULL,
                                            0,
                                            MAXLONG,
                                            NULL);
        if (!ghWakeupSemaphore)
        {
            dbgprint("InitOverlappedManager: CreateSemaphore() failed: %d", GetLastError());
            LeaveCriticalSection(&gOverlappedCS);
            return WSAEPROVIDERFAILEDINIT;
        }
        // This is Win9x, no multiproc support
        //
        gdwThreadCount = 1;
    }

    dbgprint("Creating %d threads", gdwThreadCount);
    //
    // Create our worker threads
    //
    for(i=0; i < gdwThreadCount ;i++)
    {
        gWorkerThread[i] = CreateThread(NULL, 0, OverlappedManagerThread, (LPVOID)ghIocp, 0, &dwId);
        if (!gWorkerThread[i])
        {
            dbgprint("InitOverlappedManager: CreateThread() failed: %d", GetLastError());
            LeaveCriticalSection(&gOverlappedCS);
            return WSAEPROVIDERFAILEDINIT;
        }
    }
    LeaveCriticalSection(&gOverlappedCS);
    return 0;
}

//
// Function: StopOverlappedManager
//
// Description:
//    This function is called before the DLL gets unloaded. It tries to
//    shutdown the worker threads gracefully before exiting. It also
//    frees/closes allocated memory and handles.
//
int StopOverlappedManager()
{
    DWORD     i;
    int       ret;


    EnterCriticalSection(&gOverlappedCS);
    //
    // Post a completion packet to the IOCP (one for each thread)
    //
    if (ghIocp)
    {
        for(i=0; i < gdwThreadCount ;i++)
        {
            ret = PostQueuedCompletionStatus(ghIocp,
                                        -1,
                                         0,
                                         NULL);
            if (ret == 0)
            {
                dbgprint("PostQueuedCompletionStatus() failed: %d", GetLastError());
            }
        }
        ret = WaitForMultipleObjectsEx(gdwThreadCount, gWorkerThread, TRUE, 4000, TRUE);
    }

    for(i=0; i < gdwThreadCount ;i++)
    {
        CloseHandle(gWorkerThread[i]);
        gWorkerThread[i] = NULL;

        dbgprint("Closing thread");
    }

    if (ghIocp != NULL)
    {
        CloseHandle(ghIocp);
        ghIocp = NULL;
        dbgprint("Closing iocp");
    }
    if (ghWakeupSemaphore != NULL)
    {
        CloseHandle(ghWakeupSemaphore);
        ghWakeupSemaphore = NULL;
    }

    LeaveCriticalSection(&gOverlappedCS);

    return 0;
}

//
// Function: QueueOverlappedOperation
//
// Description:
//    Whenever one of the overlapped enabled Winsock SPI functions are
//    called (as an overlapped operation), it calls this function which
//    determines whether it can execute it immediate (in the case of NT
//    and IOCP) or post it to a queue to be executed by the woker thread
//    via an APC (on Win9x).
//
int QueueOverlappedOperation(WSAOVERLAPPEDPLUS *ol, SOCK_INFO *SocketContext)
{
    BOOL    bSynchronous=FALSE;
    int     err;

    // Set the fields of the overlapped to indicate IO is not complete yet
    //
    SetOverlappedInProgress(ol->lpCallerOverlapped);
    if (ghIocp)
    {
        // If we haven't already added the provider socket to the IOCP then
        //  do it now.
        //
        AcquireSocketLock(SocketContext);
        if (!SocketContext->hIocp)
        {
            SocketContext->hIocp = CreateIoCompletionPort((HANDLE)ol->ProviderSocket,
                                                          ghIocp,
                                                          ol->CallerSocket,
                                                          0);
            if (SocketContext->hIocp == NULL)
            {
                if ((err = GetLastError()) == ERROR_INVALID_PARAMETER)
                {
                    // Hack-o-rama. If the socket option SO_SYNCHRONOUS_(NON)ALERT 
                    // is set then no overlapped operation can be performed on that
                    // socket and tryiing to associate it with a completion port
                    // will fail. The other bad news is that an LSP cannot trap this
                    // setsockopt call. In reality we don't have to do anything. If
                    // an app sets this option and then makes overlapped calls anyway,
                    // then they shouldn't be expecting any overlapped notifications!
                    // This statement is put here in case you want to mark the socket
                    // info structure as synchronous.
                    //
                    bSynchronous = TRUE;
                }
                else
                {
                    dbgprint("QueueOverlappedOperation: CreateIoCompletionPort() "
                              "failed: %d (Prov %d Iocp %d Caller %d 0)", 
                            err, ol->ProviderSocket, 
                            ghIocp, ol->CallerSocket);
                }
            }

            dbgprint("Adding provider handle %X to IOCP", ol->ProviderSocket);
        }
        ReleaseSocketLock(SocketContext);
        //
        // Simply execute the operation
        //
        return ExecuteOverlappedOperation(ol, bSynchronous);
    }
    else
    {
        // Queue up the operation for the worker thread to initiate
        //
        return EnqueueOverlappedOperation(ol);
    }
}

//
// Function: EnqueueOverlappedOperation
//
// Description:
//    Enqueue an overlapped operation to be executed by the worker
//    thread via an APC.
//
int EnqueueOverlappedOperation(WSAOVERLAPPEDPLUS *op)
{
    EnterCriticalSection(&gOverlappedCS);

    if (op == NULL)
        dbgprint("EnqueueOverlappedOperation: op == NULL!");

    op->next = NULL;
    if (!PendingEnd)
    {
        PendingStart = op;
        PendingEnd   = op;
    }
    else
    {
        PendingEnd->next = op;
        PendingEnd       = op;
    }
    // Increment the semaphore count. This lets the worker thread
    // know that there are pending overlapped operations to execute.
    //
    ReleaseSemaphore(ghWakeupSemaphore, 1, NULL);

    LeaveCriticalSection(&gOverlappedCS);

    return WSA_IO_PENDING;
}

// 
// Function: DequeueOverlappedOperation
//
// Description:
//    Once the worker thread is notified that there are pending
//    operations, it calls this function to get the first operation
//    pending in order to execute it.
//
WSAOVERLAPPEDPLUS *DequeueOverlappedOperation()
{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -