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.
398 lines
12 KiB
398 lines
12 KiB
|
|
|
|
/*++
|
|
|
|
Copyright (C) 1996-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
WMIMERGER.H
|
|
|
|
Abstract:
|
|
|
|
Implements _IWmiMerger
|
|
|
|
History:
|
|
|
|
16-Nov-00 sanjes Created.
|
|
|
|
--*/
|
|
|
|
#ifndef _WMIMERGER_H_
|
|
#define _WMIMERGER_H_
|
|
|
|
#include "internalmerger.h"
|
|
#include "mergerreq.h"
|
|
|
|
// forward class definitions
|
|
class CWmiMerger;
|
|
|
|
//
|
|
// Support class for CWmiMerger.
|
|
//
|
|
// Basically, CWmiMerger holds onto many instances of CWmiMergerRecord
|
|
//
|
|
|
|
class CWmiMergerRecord
|
|
{
|
|
private:
|
|
BOOL m_fHasInstances;
|
|
BOOL m_fHasChildren;
|
|
DWORD m_dwLevel;
|
|
WString m_wsClass;
|
|
CWmiMerger* m_pMerger;
|
|
CInternalMerger* m_pInternalMerger;
|
|
CMergerSink* m_pDestSink;
|
|
CPointerArray<CWmiMergerRecord> m_ChildArray;
|
|
bool m_bScheduledChildRequest;
|
|
IWbemContext* m_pExecutionContext;
|
|
bool m_bStatic;
|
|
|
|
|
|
public:
|
|
CWmiMergerRecord( CWmiMerger* pMerger, BOOL fHasInstances, BOOL fHasChildren,
|
|
LPCWSTR pwszClass, CMergerSink* pDestSink, DWORD dwLevel,
|
|
bool bStatic );
|
|
~CWmiMergerRecord();
|
|
|
|
CMergerSink* GetChildSink( void );
|
|
CMergerSink* GetOwnSink( void );
|
|
CMergerSink* GetDestSink( void );
|
|
LPCWSTR GetClass( void ) { return m_wsClass; }
|
|
LPCWSTR GetName( void ) { return GetClass(); }
|
|
BOOL IsClass( LPCWSTR pwszClass ) { return m_wsClass.EqualNoCase( pwszClass ); }
|
|
DWORD GetLevel( void ) { return m_dwLevel; }
|
|
bool IsStatic( void ) { return m_bStatic; }
|
|
|
|
HRESULT AttachInternalMerger( CWbemClass* pClass, CWbemNamespace* pNamespace, IWbemContext* pCtx,
|
|
BOOL fDerivedFromTarget, bool bStatic );
|
|
|
|
HRESULT AddChild( CWmiMergerRecord* pRecord );
|
|
|
|
CWmiMerger* GetWmiMerger( void ) { return m_pMerger; }
|
|
|
|
// If we have an internal merger, we tell it to cancel
|
|
void Cancel( HRESULT hRes );
|
|
|
|
bool ScheduledChildRequest( void ) { return m_bScheduledChildRequest; }
|
|
void SetScheduledChildRequest( void ) { m_bScheduledChildRequest = true; }
|
|
|
|
CWmiMergerRecord* GetChildRecord( int nIndex );
|
|
|
|
HRESULT SetExecutionContext( IWbemContext* pContext );
|
|
|
|
IWbemContext* GetExecutionContext( void ) { return m_pExecutionContext; }
|
|
|
|
// We can only cancel child sinks if we have an internal merger.
|
|
//void CancelChildSink( void ) { if ( NULL != m_pInternalMerger ) m_pInternalMerger->CancelChildSink(); }
|
|
|
|
void SetIsStatic( bool b ) { m_bStatic = b; }
|
|
|
|
|
|
};
|
|
|
|
// Allows us to locate values quickly by name
|
|
template<class TMember>
|
|
class CSortedUniquePointerArray :
|
|
public CUniquePointerArray<TMember>
|
|
{
|
|
public:
|
|
int Insert( TMember* pNewElement );
|
|
TMember* Find( LPCWSTR pwszName, int* pnIndex = NULL );
|
|
int RemoveAtNoDelete( int nIndex );
|
|
BOOL Verify( void );
|
|
};
|
|
|
|
template <class TMember>
|
|
int CSortedUniquePointerArray<TMember>::Insert( TMember* pNewElement )
|
|
{
|
|
int nLowIndex = 0,
|
|
nHighIndex = m_Array.Size();
|
|
|
|
// Binary search of the ids to find an index at which to insert
|
|
// If we find our element, this is a failure.
|
|
|
|
while ( nLowIndex < nHighIndex )
|
|
{
|
|
int nMid = (nLowIndex + nHighIndex) / 2;
|
|
|
|
int nTest = _wcsicmp( ((TMember*) m_Array[nMid])->GetName(), pNewElement->GetName() );
|
|
|
|
if ( nTest < 0 )
|
|
{
|
|
nLowIndex = nMid + 1;
|
|
}
|
|
else if ( nTest > 0 )
|
|
{
|
|
nHighIndex = nMid;
|
|
}
|
|
else
|
|
{
|
|
_DBG_ASSERT( 0 );
|
|
// Index already exists
|
|
return -1;
|
|
}
|
|
} // WHILE looking for index
|
|
|
|
// Found the location, if it's at the end, check if we need to do an insert or add
|
|
// We insert if the element at the end is > the element we want to insert
|
|
BOOL bInsert = true;
|
|
|
|
if ( nLowIndex == GetSize() - 1 )
|
|
{
|
|
bInsert = ( _wcsicmp( ((TMember*) m_Array[nLowIndex])->GetName(), pNewElement->GetName() ) > 0 );
|
|
}
|
|
|
|
// Stick it in (careful to add to the end if the selected index is the end
|
|
// and the current element is not greater than the new one).
|
|
|
|
if ( bInsert )
|
|
{
|
|
return InsertAt( nLowIndex, pNewElement );
|
|
}
|
|
|
|
return Add( pNewElement );
|
|
|
|
}
|
|
|
|
template <class TMember>
|
|
TMember* CSortedUniquePointerArray<TMember>::Find( LPCWSTR pwszName, int* pnIndex )
|
|
{
|
|
|
|
int nLowIndex = 0,
|
|
nHighIndex = m_Array.Size();
|
|
|
|
// Binary search of the values to find a the requested name.
|
|
while ( nLowIndex < nHighIndex )
|
|
{
|
|
int nMid = (nLowIndex + nHighIndex) / 2;
|
|
|
|
int nTest = _wcsicmp( ((TMember*) m_Array[nMid])->GetName(), pwszName );
|
|
|
|
if ( nTest < 0 )
|
|
{
|
|
nLowIndex = nMid + 1;
|
|
}
|
|
else if ( nTest > 0 )
|
|
{
|
|
nHighIndex = nMid;
|
|
}
|
|
else
|
|
{
|
|
// Found it
|
|
if ( NULL != pnIndex )
|
|
{
|
|
*pnIndex = nMid;
|
|
}
|
|
|
|
return (TMember*) m_Array[nMid];
|
|
}
|
|
} // WHILE looking for index
|
|
|
|
// Didn't find it
|
|
return NULL;
|
|
|
|
}
|
|
|
|
// Removes the element, but does not auto-delete it
|
|
template <class TMember>
|
|
int CSortedUniquePointerArray<TMember>::RemoveAtNoDelete( int nIndex )
|
|
{
|
|
if ( nIndex >= m_Array.Size() )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
m_Array.RemoveAt( nIndex );
|
|
|
|
return nIndex;
|
|
}
|
|
|
|
template <class TMember>
|
|
BOOL CSortedUniquePointerArray<TMember>::Verify( void )
|
|
{
|
|
BOOL fReturn = TRUE;
|
|
|
|
for ( int x = 0; fReturn && x < GetSize() - 1; x++ )
|
|
{
|
|
// Should be in ascending order
|
|
LPCWSTR pwszFirst = GetAt( x )->GetName();
|
|
LPCWSTR pwszSecond = GetAt( x+1 )->GetName();
|
|
|
|
fReturn = ( _wcsicmp( GetAt( x )->GetName(), GetAt( x+1 )->GetName() ) < 0 );
|
|
_DBG_ASSERT( fReturn );
|
|
|
|
if ( !fReturn )
|
|
{
|
|
CSortedUniquePointerArray<TMember> tempArray;
|
|
|
|
for ( int y = 0; y < GetSize(); y++ )
|
|
{
|
|
tempArray.Insert( GetAt( y ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//******************************************************************************
|
|
//
|
|
// class CWmiMerger
|
|
//
|
|
// This class implements the WMI Merger.
|
|
//
|
|
//******************************************************************************
|
|
|
|
class CWmiMerger : public _IWmiArbitratee, public _IWmiArbitratedQuery
|
|
{
|
|
private:
|
|
long m_lRefCount;
|
|
WString m_wsTargetClassName;
|
|
CMergerTargetSink* m_pTargetSink;
|
|
_IWmiCoreHandle* m_pTask;
|
|
_IWmiArbitrator* m_pArbitrator;
|
|
CWbemNamespace* m_pNamespace;
|
|
DWORD m_dwProviderDeliveryPing;
|
|
DWORD m_dwMaxLevel;
|
|
DWORD m_dwMinReqLevel;
|
|
CSortedUniquePointerArray<CWmiMergerRecord> m_MergerRecord;
|
|
//
|
|
// the sinks of the merger are wired objects
|
|
// thy have a refcount a-la-COM, but they are destructed by the
|
|
// Manager of the m_MergerSinks Array
|
|
//
|
|
CUniquePointerArray<CMergerSink> m_MergerSinks;
|
|
long m_lNumArbThrottled;
|
|
HRESULT m_hOperationRes;
|
|
bool m_bMergerThrottlingEnabled;
|
|
CCritSec m_cs;
|
|
|
|
long m_lDebugMemUsed;
|
|
|
|
CWmiMergerRequestMgr* m_pRequestMgr;
|
|
|
|
void CleanChildRequests(CWmiMergerRecord* pParentRecord, int startingWith);
|
|
|
|
public:
|
|
// No access
|
|
CWmiMerger( CWbemNamespace* pNamespace );
|
|
~CWmiMerger();
|
|
|
|
protected:
|
|
|
|
HRESULT GetLevelAndSuperClass( _IWmiObject* pObj, DWORD* pdwLevel,
|
|
_variant_t & vSuperClass );
|
|
|
|
public:
|
|
/* IUnknown methods */
|
|
STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
|
|
STDMETHOD_(ULONG, AddRef)(THIS);
|
|
STDMETHOD_(ULONG, Release)(THIS);
|
|
|
|
/* _IWmiArbitratee methods */
|
|
STDMETHOD(SetOperationResult)( ULONG uFlags, HRESULT hRes );
|
|
STDMETHOD(SetTaskHandle)( _IWmiCoreHandle* pTask );
|
|
STDMETHOD(DumpDebugInfo)( ULONG uFlags, const BSTR strFile );
|
|
|
|
/* _IWmiArbitratedQuery methods */
|
|
STDMETHOD(IsMerger)( void );
|
|
|
|
// Sets initial parameters for merger. Establishes the target class and sink for the
|
|
// query associated with the merger
|
|
STDMETHOD(Initialize)( _IWmiArbitrator* pArbitrator, _IWmiCoreHandle* pTask, LPCWSTR pwszTargetClass, IWbemObjectSink* pTargetSink, CMergerSink** ppFinalSink );
|
|
|
|
// Called to request a delivery sink for a class in the query chain. The returned
|
|
// sink is determined by the specified flags as well as settings on the parent class
|
|
STDMETHOD(RegisterSinkForClass)( LPCWSTR pwszClass, _IWmiObject* pClass, IWbemContext* pContext,
|
|
BOOL fHasChildren, BOOL fHasInstances, BOOL fDerivedFromTarget,
|
|
bool bStatic, CMergerSink* pDestSink, CMergerSink** ppOwnSink, CMergerSink** ppChildSink );
|
|
|
|
// Called to request a delivery sink for child classes in the query chain. This is especially
|
|
// important when instances are merged under the covers.
|
|
STDMETHOD(GetChildSink)( LPCWSTR pwszClass, CBasicObjectSink** ppSink );
|
|
|
|
// Can be used to holdoff indicates - if we're merging instances from multiple providers, we need
|
|
// to ensure that we don't get lopsided in the number of objects we've got queued up for merging.
|
|
STDMETHOD(Throttle)( void );
|
|
|
|
// Merger will hold information regarding the total number of objects it has queued up waiting
|
|
// for merging and the amount of memory consumed by those objects.
|
|
STDMETHOD(GetQueuedObjectInfo)( DWORD* pdwNumQueuedObjects, DWORD* pdwQueuedObjectMemSize );
|
|
|
|
// If this is called, all underlying sinks will be cancelled in order to prevent accepting additional
|
|
// objects. This will also automatically free up resources consumed by queued objects.
|
|
STDMETHOD(Cancel)( void );
|
|
|
|
// Helper function for creating our sinks - this will add the sink to our array of
|
|
// sinks which will get destroyed when we are released
|
|
HRESULT CreateMergingSink( MergerSinkType eType, IWbemObjectSink* pDestSink, CInternalMerger* pMerger, CMergerSink** ppSink );
|
|
|
|
// If this is called, all underlying sinks will be cancelled in order to prevent accepting additional
|
|
// objects. This will also automatically free up resources consumed by queued objects.
|
|
HRESULT Cancel( HRESULT hRes );
|
|
|
|
// Final Shutdown. Called when the target sink is released. At this point, we should
|
|
// unregister ourselves from the world
|
|
HRESULT Shutdown( void );
|
|
|
|
// Registers arbitrated requests
|
|
HRESULT RegisterArbitratedInstRequest( CWbemObject* pClassDef, long lFlags, IWbemContext* pCtx,
|
|
CBasicObjectSink* pSink, BOOL bComplexQuery, CWbemNamespace* pNs );
|
|
|
|
HRESULT RegisterArbitratedQueryRequest( CWbemObject* pClassDef, long lFlags, LPCWSTR Query,
|
|
LPCWSTR QueryFormat, IWbemContext* pCtx, CBasicObjectSink* pSink,
|
|
CWbemNamespace* pNs );
|
|
|
|
HRESULT RegisterArbitratedStaticRequest( CWbemObject* pClassDef, long lFlags,
|
|
IWbemContext* pCtx, CBasicObjectSink* pSink, CWbemNamespace* pNs,
|
|
QL_LEVEL_1_RPN_EXPRESSION* pParsedQuery );
|
|
|
|
// Executes a Merger Parent Request - Cycles through parent object requests and executes
|
|
// them as appropriate
|
|
HRESULT Exec_MergerParentRequest( CWmiMergerRecord* pParentRecord, CBasicObjectSink* pSink );
|
|
|
|
// Executes a Merger Child Request - Cycles through child classes of the given parent
|
|
// class, and executes the appropriate requests
|
|
HRESULT Exec_MergerChildRequest( CWmiMergerRecord* pParentRecord, CBasicObjectSink* pSink );
|
|
|
|
// Schedules a Merger Parent Request if one is necessary
|
|
HRESULT ScheduleMergerParentRequest( IWbemContext* pCtx );
|
|
|
|
// Schedules a Merger Child Request
|
|
HRESULT ScheduleMergerChildRequest( CWmiMergerRecord* pParentRecord );
|
|
|
|
// Enables/Disables merger throttling in all records (on by default)
|
|
void EnableMergerThrottling( bool b ) { m_bMergerThrottlingEnabled = b; }
|
|
|
|
// Returns whether or not we have a single static request in the merger
|
|
BOOL IsSingleStaticRequest( void );
|
|
|
|
bool MergerThrottlingEnabled( void ) { return m_bMergerThrottlingEnabled; }
|
|
|
|
_IWmiCoreHandle* GetTask( void ) { return m_pTask; }
|
|
|
|
// Help us track that *something* is going on
|
|
// We are intentionally not wrapping thread safety around these guys, since assigning and
|
|
// retrieving the value is an atomic operation and realistically, if any contention occurs
|
|
// setting the values, they should all, more or less reflect the same tick (remember, they're
|
|
// all jumping in at the same time, so this shouldn't really be a problem.
|
|
void PingDelivery( DWORD dwLastPing ) { m_dwProviderDeliveryPing = dwLastPing; }
|
|
DWORD GetLastDeliveryTime( void ) { return m_dwProviderDeliveryPing; }
|
|
|
|
HRESULT ReportMemoryUsage( long lAdjustment );
|
|
|
|
// Helper functions for tracking the number of threads potentially being throttled by
|
|
// the arbitrator
|
|
long IncrementArbitratorThrottling( void ) { return InterlockedIncrement( &m_lNumArbThrottled ); }
|
|
long DecrementArbitratorThrottling( void ) { return InterlockedDecrement( &m_lNumArbThrottled ); }
|
|
long NumArbitratorThrottling( void ) { return m_lNumArbThrottled ; }
|
|
|
|
};
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|