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.
 
 
 
 
 
 

1179 lines
31 KiB

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
EXECQ.CPP
Abstract:
Implements classes related to abstract execution queues.
Classes implemeted:
CExecRequest An abstract request.
CExecQueue A queue of requests with an associated thread
History:
23-Jul-96 raymcc Created.
3/10/97 levn Fully documented (heh, heh)
14-Aug-99 raymcc Changed timeouts
30-Oct-99 raymcc Critsec changes for NT Wksta Stress Oct 30 1999
--*/
#include "precomp.h"
#include <stdio.h>
#include <wbemcomn.h>
#include <execq.h>
#include <cominit.h>
#include <sync.h>
#include "genutils.h"
#define IDLE_THREAD_TIMEOUT 12000
#define OVERLFLOW_TIMEOUT 5000
//***************************************************************************
long CExecQueue::mstatic_lNumInits = -1;
POLARITY DWORD mstatic_dwTlsIndex = 0xFFFFFFFF;
class CTlsStaticCleanUp
{
public:
CTlsStaticCleanUp() {}
~CTlsStaticCleanUp() { if (mstatic_dwTlsIndex != 0xFFFFFFFF) TlsFree(mstatic_dwTlsIndex); }
};
CTlsStaticCleanUp g_tlsStaticCleanup;
#ifdef WINMGMT_THREAD_DEBUG
CCritSec CExecRequest::mstatic_cs;
CPointerArray<CExecRequest> CExecRequest::mstatic_apOut;
#define THREADDEBUGTRACE DEBUGTRACE
#else
#define THREADDEBUGTRACE(X)
#endif
CExecRequest::CExecRequest() : m_hWhenDone(NULL), m_pNext(NULL), m_lPriority(0), m_fOk( true )
{
#ifdef WINMGMT_THREAD_DEBUG
CInCritSec ics(&mstatic_cs);
mstatic_apOut.Add(this);
#endif
}
CExecRequest::~CExecRequest()
{
#ifdef WINMGMT_THREAD_DEBUG
CInCritSec ics(&mstatic_cs);
for(int i = 0; i < mstatic_apOut.GetSize(); i++)
{
if(mstatic_apOut[i] == this)
{
mstatic_apOut.RemoveAt(i);
break;
}
}
#endif
}
DWORD CExecQueue::GetTlsIndex()
{
return mstatic_dwTlsIndex;
}
CExecQueue::CThreadRecord::CThreadRecord(CExecQueue* pQueue)
: m_pQueue(pQueue), m_pCurrentRequest(NULL), m_bReady(FALSE),
m_bExitNow(FALSE),m_hThread(NULL)
{
m_hAttention = CreateEvent(NULL, FALSE, FALSE, NULL);
if (NULL == m_hAttention) throw CX_MemoryException();
}
CExecQueue::CThreadRecord::~CThreadRecord()
{
CloseHandle(m_hAttention);
if (m_hThread) CloseHandle(m_hThread);
}
void CExecQueue::CThreadRecord::Signal()
{
SetEvent(m_hAttention);
}
//******************************************************************************
//
// See execq.h for documentation
//
//******************************************************************************
CExecQueue::CExecQueue() :
m_lNumThreads(0),
m_lMaxThreads(1),
m_lNumIdle(0),
m_lNumRequests(0),
m_pHead(NULL),
m_pTail(NULL),
m_dwTimeout(IDLE_THREAD_TIMEOUT),
m_dwOverflowTimeout(OVERLFLOW_TIMEOUT),
m_lHiPriBound(-1),
m_lHiPriMaxThreads(1),
m_lRef(0),
m_bShutDonwCalled(FALSE)
{
InitTls();
SetRequestLimits(4000);
}
//******************************************************************************
//
// See execq.h for documentation
//
//******************************************************************************
CExecQueue::~CExecQueue()
{
Shutdown();
}
void CExecQueue::Shutdown()
{
CCritSecWrapper cs(&m_cs);
// Get all member thread handles
// =============================
if (m_bShutDonwCalled) return;
cs.Enter();
if (m_bShutDonwCalled) return;
m_bShutDonwCalled = TRUE;
int nNumHandles = m_aThreads.Size();
int i, j=0;
HANDLE* ah = NULL;
if (nNumHandles)
{
ah = new HANDLE[nNumHandles];
DEBUGTRACE((LOG_WBEMCORE, "Queue is shutting down!\n"));
for(i = 0; i < nNumHandles; i++)
{
CThreadRecord* pRecord = (CThreadRecord*)m_aThreads[i];
if ( pRecord->m_hThread && ah)
{
ah[j++] = pRecord->m_hThread;
}
// Inform the thread it should go away when ready
// ==============================================
pRecord->m_bExitNow = TRUE;
// Wake it up if necessary
// =======================
pRecord->Signal();
}
}
cs.Leave();
// Make sure all our threads are gone
// ==================================
for( i=0; i < j && ah; i++ )
{
DWORD dwRet = WaitForSingleObject( ah[i], INFINITE );
_DBG_ASSERT( dwRet != WAIT_FAILED );
CloseHandle(ah[i]);
}
delete [] ah;
// Remove all outstanding requests
// ===============================
while(m_pHead)
{
CExecRequest* pReq = m_pHead;
m_pHead = m_pHead->GetNext();
delete pReq;
}
}
//******************************************************************************
//
// See execq.h for documentation
//
//******************************************************************************
// static
void CExecQueue::InitTls()
{
if(InterlockedIncrement(&mstatic_lNumInits) == 0)
{
mstatic_dwTlsIndex = TlsAlloc();
}
}
void CExecQueue::Enter()
{
m_cs.Enter();
}
void CExecQueue::Leave()
{
m_cs.Leave();
}
//******************************************************************************
//
// See dbgalloc.h for documentation
//
//******************************************************************************
void CExecQueue::Register(CThreadRecord* pRecord)
{
TlsSetValue(mstatic_dwTlsIndex, (void*)pRecord);
}
BOOL CExecQueue::IsSuitableThread(CThreadRecord* pRecord, CExecRequest* pReq)
{
if(pRecord->m_pCurrentRequest == NULL)
return TRUE;
// This thread is in the middle of something. By default, ignore it
// ================================================================
return FALSE;
}
//******************************************************************************
//
// See dbgalloc.h for documentation
//
//******************************************************************************
HRESULT CExecQueue::Enqueue(CExecRequest* pRequest, HANDLE* phWhenDone)
{
if (m_bShutDonwCalled) return WBEM_E_FAILED;
CCritSecWrapper cs(&m_cs);
if (m_bShutDonwCalled) return WBEM_E_FAILED;
// Check if the request has a problem with it. If so, return the
// appropriate error code.
if ( !pRequest->IsOk() )
{
return WBEM_E_OUT_OF_MEMORY;
}
// Create an event handle to signal when request is finished, if required
// ======================================================================
if(phWhenDone)
{
*phWhenDone = CreateEvent(NULL, FALSE, FALSE, NULL);
if (NULL == *phWhenDone) return WBEM_E_OUT_OF_MEMORY;
pRequest->SetWhenDoneHandle(*phWhenDone);
}
cs.Enter();
// Search for a suitable thread
// ============================
for(int i = 0; i < m_aThreads.Size(); i++)
{
CThreadRecord* pRecord = (CThreadRecord*)m_aThreads[i];
if(pRecord->m_bReady)
{
// Free. Check if suitable
// =======================
if(IsSuitableThread(pRecord, pRequest))
{
pRecord->m_pCurrentRequest = pRequest;
pRecord->m_bReady = FALSE;
pRecord->Signal();
m_lNumIdle--;
// Done!
// =====
cs.Leave();
return WBEM_S_NO_ERROR;
}
}
}
// No suitable thread found. Add to the queue
// ==========================================
if(m_lNumRequests >= m_lAbsoluteLimitCount)
{
cs.Leave();
return WBEM_E_FAILED;
}
// Search for insert position based on priority
// ============================================
AdjustInitialPriority(pRequest);
CExecRequest* pCurrent = m_pHead;
CExecRequest* pLast = NULL;
while(pCurrent && pCurrent->GetPriority() <= pRequest->GetPriority())
{
pLast = pCurrent;
pCurrent = pCurrent->GetNext();
}
// Insert
// ======
if(pCurrent)
{
pRequest->SetNext(pCurrent);
}
else
{
m_pTail = pRequest;
}
if(pLast)
{
pLast->SetNext(pRequest);
}
else
{
m_pHead= pRequest;
}
m_lNumRequests++;
// Adjust priorities of the loosers
// ================================
while(pCurrent)
{
AdjustPriorityForPassing(pCurrent);
pCurrent = pCurrent->GetNext();
}
// Create a new thread, if required
// ================================
if(DoesNeedNewThread(pRequest))
CreateNewThread();
long lIndex = m_lNumRequests;
cs.Leave();
// Sit out whatever penalty is imposed
// ===================================
SitOutPenalty(lIndex);
return WBEM_S_NO_ERROR;
}
//******************************************************************************
//
// See dbgalloc.h for documentation
//
//******************************************************************************
HRESULT CExecQueue::EnqueueWithoutSleep(CExecRequest* pRequest, HANDLE* phWhenDone)
{
if (m_bShutDonwCalled) return WBEM_E_FAILED;
CCritSecWrapper cs(&m_cs);
if (m_bShutDonwCalled) return WBEM_E_FAILED;
// Check if the request has a problem with it. If so, return the
// appropriate error code.
if ( !pRequest->IsOk() )
{
return WBEM_E_OUT_OF_MEMORY;
}
// Create an event handle to signal when request is finished, if required
// ======================================================================
if(phWhenDone)
{
*phWhenDone = CreateEvent(NULL, FALSE, FALSE, NULL);
if (NULL == *phWhenDone) return WBEM_E_OUT_OF_MEMORY;
pRequest->SetWhenDoneHandle(*phWhenDone);
}
cs.Enter();
// Search for a suitable thread
// ============================
for(int i = 0; i < m_aThreads.Size(); i++)
{
CThreadRecord* pRecord = (CThreadRecord*)m_aThreads[i];
if(pRecord->m_bReady)
{
// Free. Check if suitable
// =======================
if(IsSuitableThread(pRecord, pRequest))
{
pRecord->m_pCurrentRequest = pRequest;
pRecord->m_bReady = FALSE;
pRecord->Signal();
m_lNumIdle--;
// Done!
// =====
cs.Leave();
return WBEM_S_NO_ERROR;
}
}
}
// No suitable thread found. Add to the queue
// ==========================================
if(m_lNumRequests >= m_lAbsoluteLimitCount)
{
cs.Leave();
return WBEM_E_FAILED;
}
// Search for insert position based on priority
// ============================================
AdjustInitialPriority(pRequest);
CExecRequest* pCurrent = m_pHead;
CExecRequest* pLast = NULL;
while(pCurrent && pCurrent->GetPriority() <= pRequest->GetPriority())
{
pLast = pCurrent;
pCurrent = pCurrent->GetNext();
}
// Insert
// ======
if(pCurrent)
{
pRequest->SetNext(pCurrent);
}
else
{
m_pTail = pRequest;
}
if(pLast)
{
pLast->SetNext(pRequest);
}
else
{
m_pHead= pRequest;
}
m_lNumRequests++;
// Adjust priorities of the loosers
// ================================
while(pCurrent)
{
AdjustPriorityForPassing(pCurrent);
pCurrent = pCurrent->GetNext();
}
// Create a new thread, if required
// ================================
if(DoesNeedNewThread(pRequest))
CreateNewThread();
long lIndex = m_lNumRequests;
cs.Leave();
return WBEM_S_NO_ERROR;
}
DWORD CExecQueue::CalcSitOutPenalty(long lRequestIndex)
{
if(lRequestIndex <= m_lStartSlowdownCount)
return 0; // no penalty
if(lRequestIndex > m_lAbsoluteLimitCount)
lRequestIndex = ( m_lAbsoluteLimitCount -1 );
// Calculate the timeout
// =====================
double dblTimeout =
m_dblAlpha / (m_lAbsoluteLimitCount - lRequestIndex) +
m_dblBeta;
// Return penalty
// ===========
return ((DWORD) dblTimeout);
}
void CExecQueue::SitOutPenalty(long lRequestIndex)
{
DWORD dwSitOutPenalty = CalcSitOutPenalty( lRequestIndex );
// Sleep on it
// ===========
if ( 0 != dwSitOutPenalty )
{
Sleep( dwSitOutPenalty );
}
}
HRESULT CExecQueue::EnqueueAndWait(CExecRequest* pRequest)
{
if(IsAppropriateThread())
{
pRequest->Execute();
delete pRequest;
return WBEM_S_NO_ERROR;
}
HANDLE hWhenDone;
HRESULT hr = Enqueue(pRequest, &hWhenDone);
CCloseMe cmWhenDone( hWhenDone );
if ( FAILED(hr) ) return hr;
DWORD dwRes = WbemWaitForSingleObject(hWhenDone, INFINITE);
return ( dwRes == WAIT_OBJECT_0 ? WBEM_S_NO_ERROR : WBEM_E_FAILED );
}
BOOL CExecQueue::DoesNeedNewThread(CExecRequest* pRequest)
{
if(m_lNumIdle > 0 || m_lNumRequests == 0)
return FALSE;
if(m_lNumThreads < m_lMaxThreads)
return TRUE;
else if(pRequest->GetPriority() <= m_lHiPriBound &&
m_lNumThreads < m_lHiPriMaxThreads)
return TRUE;
else
return FALSE;
}
//******************************************************************************
//
// See dbgalloc.h for documentation
//
//******************************************************************************
BOOL CExecQueue::Execute(CThreadRecord* pRecord)
{
CExecRequest* pReq = pRecord->m_pCurrentRequest;
HRESULT hres = pReq->Execute();
if(hres == RPC_E_RETRY)
{
// The request has been postponed
// ==============================
DEBUGTRACE((LOG_WBEMCORE, "Thread %p postponed request %p\n",
pRecord, pReq));
}
else
{
if(hres != WBEM_NO_ERROR)
{
LogError(pReq, hres);
}
HANDLE hWhenDone = pReq->GetWhenDoneHandle();
if(hWhenDone != NULL)
{
SetEvent(hWhenDone);
}
THREADDEBUGTRACE((LOG_WBEMCORE, "Thread %p done with request %p\n",
pRecord, pReq));
delete pReq;
}
pRecord->m_pCurrentRequest = NULL;
return TRUE;
}
//******************************************************************************
//
// See dbgalloc.h for documentation
//
//******************************************************************************
void CExecQueue::LogError(CExecRequest* pRequest, int nRes)
{
DEBUGTRACE((LOG_WBEMCORE,
"Error %X occured executing queued request\n", nRes));
pRequest->DumpError();
}
HRESULT CExecQueue::InitializeThread()
{
return CoInitializeEx(0,COINIT_MULTITHREADED|COINIT_DISABLE_OLE1DDE);
}
void CExecQueue::UninitializeThread()
{
CoUninitialize();
}
CExecRequest* CExecQueue::SearchForSuitableRequest(CThreadRecord* pRecord)
{
// Assumes in critical section
// ===========================
CExecRequest* pCurrent = m_pHead;
CExecRequest* pPrev = NULL;
while(pCurrent)
{
if(IsSuitableThread(pRecord, pCurrent))
{
// Found one --- take it
// =====================
if(pPrev)
pPrev->SetNext(pCurrent->GetNext());
else
m_pHead = pCurrent->GetNext();
if(pCurrent == m_pTail)
m_pTail = pPrev;
m_lNumRequests--;
break;
}
pPrev = pCurrent;
pCurrent = pCurrent->GetNext();
}
return pCurrent;
}
//******************************************************************************
//
// See dbgalloc.h for documentation
//
//******************************************************************************
void CExecQueue::ThreadMain(CThreadRecord* pRecord)
{
CCritSecWrapper cs(&m_cs);
if (FAILED(InitializeThread())) return;
// Register this queue with this thread, so any further wait would be
// interruptable
// ==================================================================
Register(pRecord);
while (1)
{
// Returning from work. At this point, our event is not signaled,
// our m_pCurrentRequest is NULL and our m_bReady is FALSE
// ====================================================================
// Search for work in the queue
// ============================
cs.Enter();
CExecRequest* pCurrent = SearchForSuitableRequest(pRecord);
if(pCurrent)
{
// Found some. Take it
// ===================
pRecord->m_pCurrentRequest = pCurrent;
}
else
{
// No work in the queue. Wait
// ==========================
pRecord->m_bReady = TRUE;
m_lNumIdle++;
DWORD dwTimeout = GetIdleTimeout(pRecord);
cs.Leave();
DWORD dwRes = WbemWaitForSingleObject(pRecord->m_hAttention,
dwTimeout);
cs.Enter();
if(dwRes != WAIT_OBJECT_0)
{
// Check if someone managed to place a request in our record
// after the timeout.
// =========================================================
if(WbemWaitForSingleObject(pRecord->m_hAttention, 0) ==
WAIT_OBJECT_0)
{
DEBUGTRACE((LOG_WBEMCORE, "AMAZING: Thread %p received "
"request %p after timing out. Returning to the "
"queue\n", pRecord, pRecord->m_pCurrentRequest));
if(pRecord->m_bExitNow || pRecord->m_pCurrentRequest == NULL)
{
ShutdownThread(pRecord);
cs.Leave();
return;
}
pRecord->m_pQueue->Enqueue(pRecord->m_pCurrentRequest);
pRecord->m_pCurrentRequest = NULL;
}
// Timeout. See if it is time to quit
// ==================================
pRecord->m_bReady = FALSE;
if(IsIdleTooLong(pRecord, dwTimeout))
{
ShutdownThread(pRecord);
cs.Leave();
return;
}
// Go and wait a little more
// =========================
m_lNumIdle--;
cs.Leave();
continue;
}
else
{
// Check why we were awaken
// ========================
if(pRecord->m_bExitNow || pRecord->m_pCurrentRequest == NULL)
{
ShutdownThread(pRecord);
cs.Leave();
return;
}
// We have a request. Enqueue already adjusted lNumIdle and
// our m_bReady;
}
}
// Execute the request
// ===================
cs.Leave();
Execute(pRecord);
}
}
DWORD CExecQueue::GetIdleTimeout(CThreadRecord* pRecord)
{
if(m_lNumThreads > m_lMaxThreads)
return m_dwOverflowTimeout;
else
return m_dwTimeout;
}
BOOL CExecQueue::IsIdleTooLong(CThreadRecord* pRecord, DWORD dwTimeout)
{
if(m_lNumThreads > m_lMaxThreads)
return TRUE;
else if(dwTimeout < m_dwTimeout)
return FALSE;
else
return TRUE;
}
void CExecQueue::ShutdownThread(CThreadRecord* pRecord)
{
CCritSecWrapper cs(&m_cs);
cs.Enter();
TlsSetValue(mstatic_dwTlsIndex, NULL);
for(int i = 0; i < m_aThreads.Size(); i++)
{
if(m_aThreads[i] == pRecord)
{
m_aThreads.RemoveAt(i);
// Make sure we don't close the handle if the queue's Shutdown is
// waiting on it
// ==============================================================
if(pRecord->m_bExitNow)
pRecord->m_hThread = NULL;
delete pRecord;
m_lNumIdle--;
m_lNumThreads--;
break;
}
}
UninitializeThread();
cs.Leave();
}
//******************************************************************************
//
// See dbgalloc.h for documentation
//
//******************************************************************************
// static
DWORD WINAPI CExecQueue::_ThreadEntry(LPVOID pObj)
{
CThreadRecord* pRecord = (CThreadRecord*)pObj;
pRecord->m_pQueue->ThreadMain(pRecord);
return 0;
}
//******************************************************************************
//
// See dbgalloc.h for documentation
//
//******************************************************************************
BOOL CExecQueue::CreateNewThread()
{
BOOL bRet = FALSE;
try
{
CInCritSec ics(&m_cs);
// Create new thread record
// ========================
wmilib::auto_ptr<CThreadRecord> pNewRecord( new CThreadRecord(this));
if (NULL == pNewRecord.get()) return FALSE;
if (CFlexArray::no_error != m_aThreads.Add(pNewRecord.get())) return FALSE;
DWORD dwId;
pNewRecord->m_hThread = CreateThread(0, 0, _ThreadEntry, pNewRecord.get(), 0,&dwId);
if( NULL == pNewRecord->m_hThread )
{
m_aThreads.RemoveAt(m_aThreads.Size()-1);
return FALSE;
}
pNewRecord.release(); // array took ownership
m_lNumThreads++;
bRet = TRUE;
}
catch (CX_Exception &)
{
bRet = FALSE;
}
return bRet;
}
DWORD CompensateForBug(DWORD dwOriginal, DWORD dwElapsed)
{
if(dwOriginal == 0xFFFFFFFF)
return 0xFFFFFFFF;
DWORD dwLeft = dwOriginal - dwElapsed;
if(dwLeft > 0x7FFFFFFF)
dwLeft = 0x7FFFFFFF;
return dwLeft;
}
DWORD CExecQueue::WaitForSingleObjectWhileBusy(HANDLE hHandle, DWORD dwWait,
CThreadRecord* pRecord)
{
CCritSecWrapper cs(&m_cs);
CExecRequest* pOld = pRecord->m_pCurrentRequest;
DWORD dwStart = GetTickCount();
while (dwWait > GetTickCount() - dwStart)
{
// Search for work in the queue
// ============================
cs.Enter();
CExecRequest* pCurrent = SearchForSuitableRequest(pRecord);
if(pCurrent != NULL)
{
pRecord->m_pCurrentRequest = pCurrent;
if(pRecord->m_pCurrentRequest == pOld)
{
// Something is very wrong
// =======================
}
}
else
{
// No work in the queue. Wait
// ==========================
pRecord->m_bReady = TRUE;
// Block until a request comes through.
// ====================================
HANDLE ahSems[2];
ahSems[0] = hHandle;
ahSems[1] = pRecord->m_hAttention;
cs.Leave();
DWORD dwLeft = CompensateForBug(dwWait, (GetTickCount() - dwStart));
DWORD dwRes = WbemWaitForMultipleObjects(2, ahSems, dwLeft);
cs.Enter();
pRecord->m_bReady = FALSE;
if(dwRes != WAIT_OBJECT_0 + 1)
{
// Either our target handle is ready or we timed out
// =================================================
// Check if anyone placed a request in our record
// ==============================================
if(pRecord->m_pCurrentRequest != pOld)
{
// Re-issue it to the queue
// ========================
pRecord->m_pQueue->Enqueue(pRecord->m_pCurrentRequest);
pRecord->m_pCurrentRequest = pOld;
// Decrement our semaphore
// =======================
dwRes = WaitForSingleObject(pRecord->m_hAttention, 0);
if(dwRes != WAIT_OBJECT_0)
{
// Internal error --- whoever placed the request had
// to have upped the semaphore
// =================================================
ERRORTRACE((LOG_WBEMCORE, "Internal error: queue "
"semaphore is too low\n"));
}
}
cs.Leave();
return dwRes;
}
else
{
// Check why we were awaken
// ========================
if(pRecord->m_bExitNow || pRecord->m_pCurrentRequest == NULL)
{
// Can't exit in the middle of a request. Leave it for later
// =========================================================
pRecord->Signal();
cs.Leave();
DWORD dwLeft2 = CompensateForBug(dwWait,
(GetTickCount() - dwStart));
return WbemWaitForSingleObject(hHandle, dwLeft2);
}
// We've got work to do
// ====================
if(pRecord->m_pCurrentRequest == pOld)
{
// Something is very wrong
// =======================
}
}
}
// Execute the request
// ===================
cs.Leave();
Execute(pRecord);
pRecord->m_pCurrentRequest = pOld;
}
return WAIT_TIMEOUT;
}
DWORD CExecQueue::UnblockedWaitForSingleObject(HANDLE hHandle, DWORD dwWait,
CThreadRecord* pRecord)
{
CCritSecWrapper cs(&m_cs);
// Silently bump the max threads count. We will not allow the queue to reuse
// this thread, so we need to account for this missing thread while we
// are blocked. Essentially, we are hijacking the code that was hijacking
// the thread
cs.Enter();
m_lMaxThreads++;
m_lHiPriMaxThreads++;
cs.Leave();
DWORD dwRet = WbemWaitForSingleObject( hHandle, dwWait );
// The thread is back, so bump down the max threads number. If extra threads were in
// fact created, they should eventually peter out and go away.
cs.Enter();
m_lMaxThreads--;
m_lHiPriMaxThreads--;
cs.Leave();
return dwRet;
}
//******************************************************************************
//
// See dbgalloc.h for documentation
//
//******************************************************************************
// static
DWORD CExecQueue::QueueWaitForSingleObject(HANDLE hHandle, DWORD dwWait)
{
InitTls();
// Get the queue that is registered for this thread, if any
// ========================================================
CThreadRecord* pRecord = (CThreadRecord*)TlsGetValue(mstatic_dwTlsIndex);
if(pRecord == NULL)
{
// No queue is registered with this thread. Just wait
// ==================================================
return WbemWaitForSingleObject(hHandle, dwWait);
}
CExecQueue* pQueue = pRecord->m_pQueue;
return pQueue->WaitForSingleObjectWhileBusy(hHandle, dwWait, pRecord);
}
// static
DWORD CExecQueue::QueueUnblockedWaitForSingleObject(HANDLE hHandle, DWORD dwWait)
{
InitTls();
// Get the queue that is registered for this thread, if any
// ========================================================
CThreadRecord* pRecord = (CThreadRecord*)TlsGetValue(mstatic_dwTlsIndex);
if(pRecord == NULL)
{
// No queue is registered with this thread. Just wait
// ==================================================
return WbemWaitForSingleObject(hHandle, dwWait);
}
CExecQueue* pQueue = pRecord->m_pQueue;
return pQueue->UnblockedWaitForSingleObject(hHandle, dwWait, pRecord);
}
void CExecQueue::SetThreadLimits(long lMaxThreads, long lHiPriMaxThreads,
long lHiPriBound)
{
m_lMaxThreads = lMaxThreads;
if(lHiPriMaxThreads == -1)
m_lHiPriMaxThreads = lMaxThreads * 1.1;
else
m_lHiPriMaxThreads = lHiPriMaxThreads;
m_lHiPriBound = lHiPriBound;
while(DoesNeedNewThread(NULL))
CreateNewThread();
}
BOOL CExecQueue::IsAppropriateThread()
{
// Get the queue that is registered for this thread, if any
// ========================================================
CThreadRecord* pRecord = (CThreadRecord*)TlsGetValue(mstatic_dwTlsIndex);
if(pRecord == NULL)
return FALSE;
CExecQueue* pQueue = pRecord->m_pQueue;
if(pQueue != this)
return FALSE;
return TRUE;
}
BOOL CExecQueue::IsSTAThread()
{
// Get the queue that is registered for this thread, if any
// ========================================================
CThreadRecord* pRecord = (CThreadRecord*)TlsGetValue(mstatic_dwTlsIndex);
if(pRecord == NULL) return FALSE;
return pRecord->m_pQueue->IsSTA();
}
void CExecQueue::SetRequestLimits(long lAbsoluteLimitCount,
long lStartSlowdownCount,
long lOneSecondDelayCount)
{
CCritSecWrapper cs(&m_cs);
cs.Enter();
m_lAbsoluteLimitCount = lAbsoluteLimitCount;
m_lStartSlowdownCount = lStartSlowdownCount;
if(m_lStartSlowdownCount < 0)
{
m_lStartSlowdownCount = m_lAbsoluteLimitCount / 2;
}
m_lOneSecondDelayCount = lOneSecondDelayCount;
if(m_lOneSecondDelayCount < 0)
{
m_lOneSecondDelayCount =
m_lAbsoluteLimitCount * 0.2 + m_lStartSlowdownCount * 0.8;
}
// Calculate coefficients
// ======================
m_dblBeta =
1000 *
((double)m_lAbsoluteLimitCount - (double)m_lOneSecondDelayCount) /
((double)m_lStartSlowdownCount - (double)m_lOneSecondDelayCount);
m_dblAlpha = m_dblBeta *
((double)m_lStartSlowdownCount - (double)m_lAbsoluteLimitCount);
cs.Leave();
}