📄 overlap.cpp
字号:
// 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 + -