Windows2003-3790/inetsrv/pop3/service/pop3svc/thdpool.cpp
2020-09-30 16:53:55 +02:00

276 lines
7.8 KiB
C++

/************************************************************************************************
Copyright (c) 2001 Microsoft Corporation
File Name: ThdPool.cpp
Abstract: Implementation of the thread pool (CThreadPool class)
Notes:
History: 08/01/2001 Created by Hao Yu (haoyu)
************************************************************************************************/
#include <stdafx.h>
#include <ThdPool.hxx>
#include <SockPool.hxx>
#include <GlobalDef.h>
// The common thread in the thread pool
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
ASSERT(NULL != lpParameter);
DWORD dwBytesRcvd=0;
DWORD Flags=0;
PIO_CONTEXT pIoContext=NULL;
LPOVERLAPPED pOverlapped=NULL;
HANDLE hCompPort=lpParameter;
HRESULT hr=CoInitializeEx(NULL, COINIT_MULTITHREADED);
if(FAILED(hr))
{
g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
EVENT_POP3_COM_INIT_FAIL);
ExitProcess(hr);
}
while(1)
{
GetQueuedCompletionStatus(hCompPort,
&dwBytesRcvd,
(PULONG_PTR)(&pIoContext),
&pOverlapped,
INFINITE);
//We don't care about return value
//since we use the failure case to clean up the IO Context
if(NULL == pIoContext || SERVICE_STOP_PENDING == g_dwServerStatus)
{
// This is a shutdown signal
break;
}
g_PerfCounters.DecPerfCntr(e_gcFreeThreadCnt);
pIoContext->m_pCallBack((PULONG_PTR)pIoContext, pOverlapped, dwBytesRcvd);
g_PerfCounters.IncPerfCntr(e_gcFreeThreadCnt);
}
g_PerfCounters.DecPerfCntr(e_gcFreeThreadCnt);
CoUninitialize();
return 0;
}
CThreadPool::CThreadPool()
{
InitializeCriticalSection(&m_csInitGuard);
m_hIOCompPort = NULL;
m_phTdArray = NULL;
m_dwTdCount = 0;
m_bInit = FALSE;
}
CThreadPool::~CThreadPool()
{
if(m_bInit)
{
Uninitialize();
}
DeleteCriticalSection(&m_csInitGuard);
}
// Job done in this function:
// 1) Calculate the number of threads need to be created,
// dwThreadPerProcessor * number of processors of the machine
// 2) Create the IO Completion port
// 3) Create threads
BOOL CThreadPool::Initialize(DWORD dwThreadPerProcessor)
{
int i;
BOOL bRtVal=TRUE;
SYSTEM_INFO SystemInfo;
EnterCriticalSection(&m_csInitGuard);
if(!m_bInit)
{
//Get the number of processors of the machine
GetSystemInfo(&SystemInfo);
if( dwThreadPerProcessor == 0 ||
dwThreadPerProcessor > MAX_THREAD_PER_PROCESSOR )
{
dwThreadPerProcessor = 1;
}
m_dwTdCount = SystemInfo.dwNumberOfProcessors * dwThreadPerProcessor;
// Create the IO Completion Port
m_hIOCompPort = CreateIoCompletionPort (
INVALID_HANDLE_VALUE,
NULL,
NULL,
m_dwTdCount);
if (NULL == m_hIOCompPort)
{
g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
POP3SVR_FAIL_TO_CREATE_IO_COMP_PORT,
GetLastError());
goto EXIT;
}
m_phTdArray=new HANDLE[m_dwTdCount];
if( NULL == m_phTdArray)
{
g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
POP3SVR_NOT_ENOUGH_MEMORY);
goto EXIT;
}
// Create the threads
for (i=0;i<m_dwTdCount; i++)
{
m_phTdArray[i] = CreateThread(
NULL,
0,
ThreadProc,
m_hIOCompPort,
0,
NULL);
if(NULL == m_phTdArray[i])
{
g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
POP3SVR_FAILED_TO_CREATE_THREAD,
GetLastError());
goto EXIT;
}
}
m_bInit=TRUE;
}
//Set the total free thread count
g_PerfCounters.SetPerfCntr(e_gcFreeThreadCnt, m_dwTdCount);
LeaveCriticalSection(&m_csInitGuard);
return TRUE;
EXIT:
//In case of error, cleanup and exit
if(NULL != m_phTdArray)
{
for(i=0; i<m_dwTdCount && m_phTdArray[i]; i++ )
{
if(m_phTdArray[i]!=NULL)
{
TerminateThread(m_phTdArray[i], -1);
CloseHandle(m_phTdArray[i]);
}
}
delete[](m_phTdArray);
m_phTdArray=NULL;
}
if(m_hIOCompPort)
{
CloseHandle(m_hIOCompPort);
m_hIOCompPort=NULL;
}
LeaveCriticalSection(&m_csInitGuard);
return FALSE;
}
// Terminate all threads and delete the completion port.
void CThreadPool::Uninitialize()
{
int i;
BOOL bFailedExit=FALSE;
DWORD dwRt;
DWORD dwStatus=0;
EnterCriticalSection(&m_csInitGuard);
if(m_bInit)
{
if(NULL != m_phTdArray)
{
for(i=0; i<m_dwTdCount; i++ )
{
PostQueuedCompletionStatus(m_hIOCompPort, 0, NULL, NULL);
}
dwRt=WaitForMultipleObjects(m_dwTdCount,
m_phTdArray,
TRUE,
SHUTDOWN_WAIT_TIME);
if( (WAIT_TIMEOUT == dwRt) ||
(WAIT_FAILED == dwRt) )
{
for(i=0; i<m_dwTdCount; i++ )
{
//In case some thread did not exit after the wait time
//terminate threads by force
if(NULL!= m_phTdArray[i])
{
if( !GetExitCodeThread(m_phTdArray[i], &dwStatus) ||
(STILL_ACTIVE==dwStatus))
{
// This is a bad case, however we can not wait
// forever, cleanup won't be complete in this case.
TerminateThread(m_phTdArray[i],0);
bFailedExit=TRUE;
}
CloseHandle(m_phTdArray[i]);
}
}
}
else
{
for(i=0; i<m_dwTdCount; i++ )
{
if(NULL!= m_phTdArray[i])
{
CloseHandle(m_phTdArray[i]);
}
}
}
delete[](m_phTdArray);
m_phTdArray=NULL;
}
if(m_hIOCompPort)
{
CloseHandle(m_hIOCompPort);
m_hIOCompPort=NULL;
}
m_bInit=FALSE;
}
LeaveCriticalSection(&m_csInitGuard);
if(bFailedExit)
{
g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
EVENT_POP3_SERVER_STOP_ERROR,
E_UNEXPECTED);
ExitProcess(E_UNEXPECTED);
}
}
// Associate an IO Context and the IO handle contained
// with the IO Completion port
BOOL CThreadPool::AssociateContext(PIO_CONTEXT pIoContext)
{
if(!m_bInit)
{
return FALSE;
}
return (NULL!=CreateIoCompletionPort(
(HANDLE)(pIoContext->m_hAsyncIO),
m_hIOCompPort,
(ULONG_PTR)pIoContext,
m_dwTdCount));
}