Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

181 lines
4.4 KiB

//
// Copyright (c) 2001 Microsoft Corporation. All rights reserved.
//
// Declaration of CWorkerThread.
//
#include "stdinc.h"
#include <process.h>
#include "workthread.h"
unsigned int __stdcall WorkerThread(LPVOID lpThreadParameter)
{
reinterpret_cast<CWorkerThread*>(lpThreadParameter)->Main();
return 0;
}
HRESULT
CWorkerThread::Create()
{
if (m_hThread)
return S_FALSE;
if (!m_hEvent)
return E_FAIL; // The constructor was unable to create the event we'll need to run the thread so we can't create it.
m_hrCOM = E_FAIL;
m_fEnd = false;
m_hThread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, WorkerThread, this, 0, &m_uiThreadId));
return m_hThread ? S_OK : E_FAIL;
}
void
CWorkerThread::Terminate(bool fWaitForThreadToExit)
{
if (!m_hThread)
return;
EnterCriticalSection(&m_CriticalSection);
m_fEnd = true;
SetEvent(m_hEvent);
LeaveCriticalSection(&m_CriticalSection);
if (fWaitForThreadToExit)
{
// Wait until the other thread stops processing.
WaitForSingleObject(m_hThread, INFINITE);
}
CloseHandle(m_hThread);
m_hThread = NULL;
}
CWorkerThread::CWorkerThread(bool fUsesCOM, bool fDeferCreation)
: m_hThread(NULL),
m_uiThreadId(0),
m_fUsesCOM(fUsesCOM)
{
InitializeCriticalSection(&m_CriticalSection);
// Note: on pre-Blackcomb OS's, this call can raise an exception; if it
// ever pops in stress, we can add an exception handler and retry loop.
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!m_hEvent)
return;
if (!fDeferCreation)
Create();
}
CWorkerThread::~CWorkerThread()
{
Terminate(false);
CloseHandle(m_hEvent);
DeleteCriticalSection(&m_CriticalSection);
}
HRESULT CWorkerThread::Call(FunctionPointer pfn, void *pvParams, UINT cbParams, bool fBlock)
{
if (!m_hThread)
return E_FAIL;
if (fBlock && GetCurrentThreadId() == m_uiThreadId)
{
// The call is already on this thread so just do it.
pfn(pvParams);
return S_OK;
}
TListItem<CallInfo> *pItem = new TListItem<CallInfo>;
if (!pItem)
return E_OUTOFMEMORY;
CallInfo &rinfo = pItem->GetItemValue();
rinfo.pfn = pfn;
rinfo.hEventOut = fBlock ? CreateEvent(NULL, FALSE, FALSE, NULL) : 0;
if (rinfo.hEventOut)
{
// Synchronous call -- OK to reference via pointer to params
rinfo.pvParams = pvParams;
}
else
{
// Asynchronous call -- need to copy params
rinfo.pvParams = new char[cbParams];
if (!rinfo.pvParams)
{
delete pItem;
return E_OUTOFMEMORY;
}
CopyMemory(rinfo.pvParams, pvParams, cbParams);
}
EnterCriticalSection(&m_CriticalSection);
m_Calls.AddHead(pItem);
HANDLE hEventCall = rinfo.hEventOut; // Can't refer to rinfo after we set the event because the worker will delete the event.
SetEvent(m_hEvent);
LeaveCriticalSection(&m_CriticalSection);
if (hEventCall)
{
WaitForSingleObject(hEventCall, INFINITE);
if (FAILED(m_hrCOM))
return m_hrCOM;
CloseHandle(hEventCall);
}
return S_OK;
}
void CWorkerThread::Main()
{
if (m_fUsesCOM)
{
m_hrCOM = CoInitialize(NULL);
if (FAILED(m_hrCOM))
{
Trace(1, "Error: CoInitialize failed: 0x%08x.\n", m_hrCOM);
}
}
for (;;)
{
// block until there's something to do
WaitForSingleObject(m_hEvent, INFINITE);
EnterCriticalSection(&m_CriticalSection);
// check for end
if (m_fEnd)
{
LeaveCriticalSection(&m_CriticalSection);
if (m_fUsesCOM && SUCCEEDED(m_hrCOM))
CoUninitialize();
_endthreadex(0);
}
// take all the list items
TListItem<CallInfo> *m_pCallHead = m_Calls.GetHead();
m_Calls.RemoveAll();
LeaveCriticalSection(&m_CriticalSection);
// call each function
TListItem<CallInfo> *m_pCall = m_pCallHead;
while (m_pCall)
{
CallInfo &rinfo = m_pCall->GetItemValue();
if (SUCCEEDED(m_hrCOM))
rinfo.pfn(rinfo.pvParams);
if (rinfo.hEventOut)
SetEvent(rinfo.hEventOut);
else
delete[] rinfo.pvParams;
TListItem<CallInfo> *m_pNext = m_pCall->GetNext();
delete m_pCall;
m_pCall = m_pNext;
}
}
}