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.
 
 
 
 
 
 

389 lines
8.4 KiB

//******************************************************************************
//
// EVTOOLS.CPP
//
// Copyright (C) 1996-1999 Microsoft Corporation
//
//******************************************************************************
#include "precomp.h"
#include <stdio.h>
#include <wbemcomn.h>
#include <evtools.h>
#include <cominit.h>
//*****************************************************************************
//
// 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);
}
*/