Leaked source code of windows server 2003
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.
 
 
 
 
 
 

273 lines
5.9 KiB

//+----------------------------------------------------------------------------
//
// Copyright (C) 1997, Microsoft Corporation
//
// File: thrdpool.cpp
//
// Contents: implementation of thrdpool library
//
// Description: See header file.
//
// Functions:
//
// History: 03/15/97 Rajeev Rajan (rajeevr) Created
//
//-----------------------------------------------------------------------------
#include <windows.h>
#include <thrdpool.h>
#include <dbgtrace.h>
LONG CWorkerThread::m_lInitCount = -1 ;
HANDLE CWorkerThread::m_hCompletionPort = NULL ;
BOOL
CWorkerThread::InitClass( DWORD dwConcurrency )
{
TraceFunctEnter("CWorkerThread::InitClass");
if( InterlockedIncrement( &m_lInitCount ) == 0 )
{
//
// called for the first time - go ahead with initialization
//
m_hCompletionPort = CreateIoCompletionPort(
INVALID_HANDLE_VALUE,
NULL,
0,
dwConcurrency
);
if( !m_hCompletionPort ) {
ErrorTrace(0, "Failed to create completion port: GetLastError is %d", GetLastError());
return FALSE ;
}
} else
{
//
// bogus Init or already called
//
InterlockedDecrement( &m_lInitCount );
return FALSE ;
}
DebugTrace(0,"Created completion port 0x%x", m_hCompletionPort);
TraceFunctLeave();
return TRUE ;
}
BOOL
CWorkerThread::TermClass()
{
TraceFunctEnter("CWorkerThread::TermClass");
if( InterlockedDecrement( &m_lInitCount ) < 0 )
{
//
// Init has been called so go ahead with termination
//
_ASSERT( m_hCompletionPort );
_VERIFY( CloseHandle( m_hCompletionPort ) );
return TRUE ;
}
return FALSE ;
}
CWorkerThread::CWorkerThread() : m_hThread(NULL), m_hShutdownEvent( NULL )
{
DWORD dwThreadId;
TraceFunctEnter("CWorkerThread::CWorkerThread");
//
// create shutdown event
//
if( !(m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL) ) ) {
ErrorTrace(0,"Failed to create shutdown event");
_ASSERT( FALSE );
return;
}
//
// create worker thread
//
if (!(m_hThread = ::CreateThread(
NULL,
0,
ThreadDispatcher,
this,
CREATE_SUSPENDED,
&dwThreadId))) {
ErrorTrace(0,"Failed to create thread: error: %d", GetLastError());
_ASSERT( FALSE );
}
else
{
_VERIFY( ResumeThread( m_hThread ) != 0xFFFFFFFF );
}
TraceFunctLeave();
return;
}
CWorkerThread::~CWorkerThread()
{
TraceFunctEnter("CWorkerThread::~CWorkerThread");
_ASSERT( m_hCompletionPort );
_ASSERT( m_hThread );
_ASSERT( m_hShutdownEvent );
//
// signal worker thread to shutdown
// this depends on derived class completion routines
// checking this event - if they dont, we will block
// till the thread finishes.
//
_VERIFY( SetEvent( m_hShutdownEvent ) );
//
// post a null termination packet
//
if( !PostWork( NULL ) ) {
ErrorTrace(0,"Error terminating worker thread");
_ASSERT( FALSE );
}
//
// wait for worker thread to terminate
//
DWORD dwWait = WaitForSingleObject(m_hThread, INFINITE);
if(WAIT_OBJECT_0 != dwWait) {
ErrorTrace(0,"WFSO: returned %d", dwWait);
_ASSERT( FALSE );
}
_VERIFY( CloseHandle(m_hThread) );
_VERIFY( CloseHandle(m_hShutdownEvent) );
m_hThread = NULL;
m_hShutdownEvent = NULL;
}
DWORD __stdcall CWorkerThread::ThreadDispatcher(PVOID pvWorkerThread)
{
//
// get pointer to this CWorkerThread object
//
CWorkerThread *pWorkerThread = (CWorkerThread *) pvWorkerThread;
//
// call GetQueuedCompletionStatus() to get work completion
//
pWorkerThread->GetWorkCompletion();
return 0;
}
VOID CWorkerThread::GetWorkCompletion(VOID)
{
DWORD dwBytesTransferred;
DWORD_PTR dwCompletionKey;
DWORD dwWait;
LPOVERLAPPED lpo;
LPWorkContextEnv lpWCE;
PVOID pvWorkContext;
TraceFunctEnter("CWorkerThread::GetWorkCompletion");
_ASSERT( m_hThread );
_ASSERT( m_hCompletionPort );
do
{
//
// wait for work items to be queued
//
if( !GetQueuedCompletionStatus(
m_hCompletionPort,
&dwBytesTransferred,
&dwCompletionKey,
&lpo,
INFINITE // wait timeout
) )
{
ErrorTrace(0,"GetQueuedCompletionStatus() failed: error: %d", GetLastError());
break ;
}
//
// get a hold of the work context envelope and work context
//
lpWCE = (LPWorkContextEnv) lpo;
pvWorkContext = lpWCE->pvWorkContext;
//
// check for termination packet
//
if( pvWorkContext == NULL ) {
DebugTrace(0,"Received termination packet - bailing");
delete lpWCE;
lpWCE = NULL;
break;
}
//
// check for termination signal
//
dwWait = WaitForSingleObject( m_hShutdownEvent, 0 );
//
// call derived class method to process work completion
//
if( WAIT_TIMEOUT == dwWait ) {
DebugTrace(0,"Calling WorkCompletion() routine");
WorkCompletion( pvWorkContext );
}
//
// destroy the WorkContextEnv object allocated before PostQueuedCompletionStatus()
//
delete lpWCE;
lpWCE = NULL;
} while( TRUE );
return;
}
BOOL CWorkerThread::PostWork(PVOID pvWorkerContext)
{
TraceFunctEnter("CWorkerThread::PostWork");
_ASSERT( m_hThread );
_ASSERT( m_hCompletionPort );
//
// allocate a WorkContextEnv blob - this is destroyed after GetQueuedCompletionStatus()
// completes ! We may want to have a pool of such blobs instead of hitting the heap !!
//
LPWorkContextEnv lpWCE = new WorkContextEnv;
if( !lpWCE ) {
ErrorTrace(0,"Failed to allocate memory");
return FALSE ;
}
ZeroMemory( lpWCE, sizeof(WorkContextEnv) );
lpWCE->pvWorkContext = pvWorkerContext;
if( !PostQueuedCompletionStatus(
m_hCompletionPort,
0,
0,
(LPOVERLAPPED)lpWCE
) )
{
ErrorTrace(0,"PostQCompletionStatus() failed: error: %d", GetLastError());
return FALSE ;
}
return TRUE;
}