//****************************************************************************** // // EVTOOLS.CPP // // Copyright (C) 1996-1999 Microsoft Corporation // //****************************************************************************** #include "precomp.h" #include #include #include #include //***************************************************************************** // // Implementation: // // This class contains a queue of event handles. The top() one is always // signalled --- it corresponds to the turn that is currently allowed to // execute. Handles are added to the queue in GetInLine. Handles are removed // from the queue in EndTurn, at which time the next handle in line is // signalled. // // m_pCurrentTurn contains the pointer to the turn that has returned from from // WaitForTurn, but not from EndTurn. Note, that m_pCurrentTurn may be empty // even if a turn is scheduled to execute --- there is a gap between the time // when a turn's handle is signalled, and its WaitForTurn succeeds. // // However, it is guranteed that by the time a legitimate call to EndTurn is // made, m_pCurrentTurn contains the pointer to the turn in question, at which // time it is reset to NULL. // // An additional optimization is that if the same thread calls GetInLine // multiple times concurrently, we simply // //***************************************************************************** CExecLine::CExecLine() : m_pCurrentTurn(NULL), m_pLastIssuedTurn(NULL), m_dwLastIssuedTurnThreadId(0) { } CExecLine::~CExecLine() { // No need to do anything --- handles are closed by tokens // ======================================================= } CExecLine::CTurn* CExecLine::GetInLine() { CInCritSec ics(&m_cs); // // First, check if this thread was the guy who got the last turn // if(m_pLastIssuedTurn && m_dwLastIssuedTurnThreadId == GetCurrentThreadId()) { // // It is us --- just reuse that turn and be done with it // m_pLastIssuedTurn->AddRef(); return m_pLastIssuedTurn; } // // Allocate a new turn // CTurn* pTurn = new CTurn; if(pTurn == NULL) return NULL; if(!pTurn->Init()) { ERRORTRACE((LOG_ESS, "Unable to initialize turn: %d\n", GetLastError())); delete pTurn; return NULL; } // // Add its event to the queue // try { m_qTurns.push_back(pTurn); } catch( CX_MemoryException ) { return NULL; } // // Check if we are currently executing // if(m_qTurns.size() == 1) { // // Release first in line // if(!ReleaseFirst()) { // // Something went horribly wrong // ERRORTRACE((LOG_ESS, "Unable to release first turn: %d\n", GetLastError())); m_qTurns.pop_front(); delete pTurn; return NULL; } } // // Mark ourselves as the last issued turn // m_pLastIssuedTurn = pTurn; m_dwLastIssuedTurnThreadId = GetCurrentThreadId(); return pTurn; } // assumes in m_cs and m_qTurns is not empty BOOL CExecLine::ReleaseFirst() { return SetEvent(m_qTurns.front()->GetEvent()); } DWORD CExecLine::WaitForTurn(CTurn* pTurn, DWORD dwTimeout) { // Wait for the turn event to be signaled // ====================================== DWORD dwRes = WbemWaitForSingleObject(pTurn->GetEvent(), dwTimeout); { CInCritSec ics(&m_cs); if(dwRes == WAIT_OBJECT_0) { // Got it --- record this turn as executing // ======================================== m_pCurrentTurn = pTurn; } } return dwRes; } BOOL CExecLine::EndTurn(CTurn* pTurn) { CInCritSec ics(&m_cs); // Check that this is the running turn // =================================== if(pTurn != m_pCurrentTurn) return FALSE; m_pCurrentTurn = NULL; // Delete the turn object // ====================== if(pTurn->Release() > 0) { // // This is not the last incarnation of this turn. No further action is // required, as the same thread will call Wait and End again // return TRUE; } // // Remove the last issued turn if this is it // if(m_pLastIssuedTurn == pTurn) { m_pLastIssuedTurn = NULL; m_dwLastIssuedTurnThreadId = 0; } // // Pop its handle off the queue // m_qTurns.pop_front(); // // Signal the next one // if(!m_qTurns.empty()) return ReleaseFirst(); else return TRUE; } BOOL CExecLine::DiscardTurn(ACQUIRE CTurn* pTurn) { CInCritSec ics(&m_cs); if(pTurn->Release() > 0) { // // This is not the last incarnation of this turn. No further action is // required // return TRUE; } else { // if pTurn is going away, we'd better make sure that we don't try to reuse it... // HMH 4/12/99, RAID 48420 if (pTurn == m_pLastIssuedTurn) m_pLastIssuedTurn = NULL; } // // Search for it in the queue // BOOL bFound = FALSE; for(TTurnIterator it = m_qTurns.begin(); it != m_qTurns.end();) { if((*it) == pTurn) { // // erase it and continue // it = m_qTurns.erase(it); bFound = TRUE; break; } else it++; } if(!bFound) return FALSE; if(it == m_qTurns.begin() && it != m_qTurns.end()) { // // Discarded turn was actually active --- signal the next one // ReleaseFirst(); } return TRUE; } CExecLine::CTurn::CTurn() : m_hEvent(NULL), m_lRef(1) { } BOOL CExecLine::CTurn::Init() { m_dwOwningThreadId = GetCurrentThreadId(); m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); return (m_hEvent != NULL); } long CExecLine::CTurn::AddRef() { return InterlockedIncrement(&m_lRef); } long CExecLine::CTurn::Release() { long l = InterlockedDecrement(&m_lRef); if(l == 0) delete this; return l; } CExecLine::CTurn::~CTurn() { if(m_hEvent) CloseHandle(m_hEvent); } void* CExecLine::CTurn::operator new(size_t nSize) { return CTemporaryHeap::Alloc(nSize); } void CExecLine::CTurn::operator delete(void* p) { CTemporaryHeap::Free(p, sizeof(CExecLine::CTurn)); } INTERNAL const SECURITY_DESCRIPTOR* GetSD( IWbemEvent* pEvent,ULONG* pcEvent ) { static long mstatic_lSdHandle = -1; HRESULT hres; // // Get the SD from the event // _IWmiObject* pEventEx = NULL; pEvent->QueryInterface(IID__IWmiObject, (void**)&pEventEx); CReleaseMe rm1(pEventEx); if(mstatic_lSdHandle == -1) { pEventEx->GetPropertyHandleEx(SECURITY_DESCRIPTOR_PROPNAME, 0, NULL, &mstatic_lSdHandle); } const SECURITY_DESCRIPTOR* pSD = NULL; hres = pEventEx->GetArrayPropAddrByHandle(mstatic_lSdHandle, 0, pcEvent, (void**)&pSD); if(FAILED(hres) || pSD == NULL) return NULL; else return pSD; } HRESULT SetSD(IWbemEvent* pEvent, const SECURITY_DESCRIPTOR* pSD) { HRESULT hres; VARIANT vSd; VariantInit(&vSd); CClearMe cm1(&vSd); long lLength = GetSecurityDescriptorLength((SECURITY_DESCRIPTOR*)pSD); V_VT(&vSd) = VT_ARRAY | VT_UI1; SAFEARRAYBOUND sab; sab.cElements = lLength; sab.lLbound = 0; V_ARRAY(&vSd) = SafeArrayCreate(VT_UI1, 1, &sab); if(V_ARRAY(&vSd) == NULL) return WBEM_E_OUT_OF_MEMORY; BYTE* abSd = NULL; hres = SafeArrayAccessData(V_ARRAY(&vSd), (void**)&abSd); if(FAILED(hres)) return WBEM_E_OUT_OF_MEMORY; CUnaccessMe uam(V_ARRAY(&vSd)); memcpy(abSd, pSD, lLength); // Put it into the consumer // ======================== hres = pEvent->Put(SECURITY_DESCRIPTOR_PROPNAME, 0, &vSd, 0); return hres; } CTempMemoryManager CTemporaryHeap::mstatic_Manager; /* CTemporaryHeap::CHeapHandle CTemporaryHeap::mstatic_HeapHandle; CTemporaryHeap::CHeapHandle::CHeapHandle() { m_hHeap = HeapCreate(0, 0, 0); } CTemporaryHeap::CHeapHandle::~CHeapHandle() { HeapDestroy(m_hHeap); } */