/************************************************************************************************ 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)); }