You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
7.8 KiB
275 lines
7.8 KiB
/************************************************************************************************
|
|
|
|
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));
|
|
}
|
|
|
|
|