|
|
/*++
Copyright (C) 2000-2001 Microsoft Corporation
Module Name:
WmiFinalizer2
Abstract: Implementation of the finalizer. The finalizer if the class which delivers the resultant objects back to the client. It could do that sychronously or asynchronously.
History:
paulall 27-Mar-2000 Created. marioh 20-Aug-2000 Batching capabilities added marioh 17-Oct-2000 Major updates completed
--*/
#include <flexarry.h>
#include <wbemcore.h>
#ifndef __FINALIZER__
#define __FINALIZER__
#define DEFAULT_BATCH_TRANSMIT_BYTES 0x40000 // 128K, Max batching size to deliver on one indicate call
#define MAX_SINGLE_OBJECT_SIZE 0x200000 // Max single object size
#define ABANDON_PROXY_THRESHOLD 60000 // Max proxy timeout [60secs]
#define MAX_BUFFER_SIZE_BEFORE_SLOWDOWN 0x400000 // Max size of queue before slowdown of inbound flow
#define LOWER_AUTH_LEVEL_NOTSET 0xFFFFFFFF
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Finalizer constructor exceptions
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class CWmiFinalizerEnumerator; class CWmiFinalizerInboundSink; class CWmiFinalizerEnumeratorSink; class CWmiFinalizerCallResult; class CWmiFinalizer ;
class CWmiFinalizerObj { public: IWbemClassObject *m_pObj; enum ObjectType { unknown, object, status, shutdown, set } m_objectType; BSTR m_bStr;
HRESULT m_hRes; HRESULT m_hArb ;
void* m_pvObj; _IWmiFinalizer* m_pFin ; IID m_iid; ULONG m_uSize; ULONG m_lFlags;
CWmiFinalizerObj(ObjectType objType) : m_pObj(NULL), m_objectType(objType), m_lFlags(0), m_bStr(NULL), m_hRes(0), m_pvObj(0), m_uSize(0), m_pFin ( NULL ), m_hArb ( WBEM_S_ARB_NOTHROTTLING ) {} CWmiFinalizerObj(IWbemClassObject *pObj, _IWmiFinalizer* pFin ) ; CWmiFinalizerObj(ULONG lFlags, REFIID riid, void *pvObj) ;
CWmiFinalizerObj(ULONG lFlags, HRESULT hRes, BSTR bStr, IWbemClassObject *pObj) ; CWmiFinalizerObj(CWmiFinalizerObj& obj);
virtual ~CWmiFinalizerObj(); };
struct InsertableEvent { LIST_ENTRY m_Entry; CWmiFinalizerEnumerator * pEnum; DWORD ThreadId; };
class CWmiFinalizer : public _IWmiFinalizer, public _IWmiArbitratee, public IWbemShutdown { private: LONG m_lRefCount; // External/client refcount
LONG m_lInternalRefCount; // Internal refcount
public: enum QueueStatus { NoError, RequestReleased, CallCancelled, QuotaViolation, QueueFailure }; private: QueueStatus m_hStatus; // Status once thread is woken up from PullObjects
BOOL m_bSetStatusEnqueued; // We've recieved and enqueued the setstatus (COMPLETE)
BOOL m_bSetStatusWithError; // SetStatus called with error
BOOL m_bTaskInitialized ; // Has SetTaskHandle been called?
BOOL m_bClonedFinalizer ; // Is this a cloned finalizer?
BOOL m_bSetStatusDelivered ; // Has the setstatus been delivered?
ULONG m_ulOperationType; // Sync/Semisync/Async
ULONG m_ulSemisyncWakeupCall; // For semisync operations, once number of objects on the queue reaches this, wake up client
IWbemClassObject** m_apAsyncDeliveryBuffer; // Used during async deliveries for batching objects together
ULONG m_ulAsyncDeliveryCount; // Used during async deliveries for the number of objects to deliver in one batch
ULONG m_ulAsyncDeliverySize; // Async deliver size
LONG m_lCurrentlyDelivering; // Are we in the process of already delivering the batch
LONG m_lCurrentlyCancelling; // Special case for cancellations
enum { forwarding_type_none = 0, forwarding_type_fast = 1, //Use pass through mechanism
forwarding_type_decoupled = 2 //Pass off to another thread for delivery
} m_uForwardingType; enum { FinalizerBatch_StatusMsg = 0, FinalizerBatch_BufferOverFlow = 1, FinalizerBatch_NoError = 2 } m_enumBatchStatus;
enum { PauseInboundDelivery = 0, ResumeInboundDelivery = 1, };
enum { Operation_Type_Async = 0, Operation_Type_Semisync = 1, Operation_Type_Sync = 2 };
_IWmiCoreHandle *m_phTask; // Task associated with this finalizer
_IWmiArbitrator *m_pArbitrator; // Access to arbitrator to help keep control of system
IID m_iidDestSink; // Client destination sink with async deliveries [IID]
IWbemObjectSink *m_pDestSink; // Client destination sink with async deliveries
CFlexArray m_inboundSinks; // Array of inbound sinks [not sure we need safe array since we only support one inbound sink]
CFlexArray m_objects; // Object queue. All objects are inserted into this array [except async fasttrack]
CFlexArray m_enumerators ; // All enumerators associated with this finalizer (cloning)
HRESULT m_hresFinalResult; // Final result of operation
CWmiFinalizerCallResult *m_pCallResult; // CallResult
bool m_bSetStatusCalled; // Has anyone called setstatus yet?
CCritSec m_destCS; // Protects the destination sink
CCritSec m_arbitratorCS; // Protects the arbitrator
bool m_bRestartable; // Is the enumerator restartable
bool m_bSetStatusConsumed; // Have we finished the operation?
LONG m_lMemoryConsumption ; // Control for checking memory consumption
ULONG m_ulStatus; // Status used to determine what woke a client from PullObjects
ULONG m_uCurObjectPosition; // Keeps a current object position in object queue for restartable purposes
HANDLE m_hResultReceived; HANDLE m_hCancelEvent; // Threads that are waiting on objects will wake up in case of cancelled operation
HANDLE m_hWaitForSetStatus ; ULONG m_ulQueueSize; // Total current object queue size
LONG m_bCancelledCall; // Has the call been cancelled?
BOOL m_bNaughtyClient; // Did we stop delivering due to client being naughty?
protected: static DWORD WINAPI ThreadBootstrap ( PVOID pvContext );
static VOID WINAPI ProxyThreshold ( PVOID pvContext, BOOLEAN bTimerOrWait );
HRESULT BootstrapDeliveryThread ( ); VOID ProxyThresholdImp ( ); ULONG AsyncDeliveryProcessor();
HRESULT TriggerShutdown();
HRESULT ShutdownFinalizer();
HRESULT DeliverPushObject(bool bDoPassthrough);
HRESULT QueueOperation(CWmiFinalizerObj *pObj);
HRESULT DequeueObject(CWmiFinalizerObj **ppObj, CWmiFinalizerEnumerator* pEnum );
HRESULT BuildTransmitBuffer ( );
HRESULT DeliverSingleObjFromQueue ( ); HRESULT DeliverBatch ( );
HRESULT CancelCall(); HRESULT CancelCall( int Line ){m_LineCancelCall = Line; return CancelCall(); };
VOID ZeroAsyncDeliveryBuffer ( );
public: CWmiFinalizer(CCoreServices *pSrvs); ~CWmiFinalizer();
STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj); STDMETHOD_(ULONG, AddRef)(THIS); STDMETHOD_(ULONG, Release)(THIS); STDMETHOD_(ULONG, InternalAddRef)(THIS); STDMETHOD_(ULONG, InternalRelease)(THIS);
void CallBackRelease () ;
STDMETHOD(Configure)( /*[in]*/ ULONG uConfigID, /*[in]*/ ULONG uValue ); // Allows decoupled & fast-track configuration with no thread switches
STDMETHOD(SetTaskHandle)( /*[in]*/ _IWmiCoreHandle *phTask ); // Task handle has user-specific stuff. Finalizer just
// passes this through to _IWmiArbitrator::CheckTask
STDMETHOD(SetDestinationSink)( /*[in]*/ ULONG uFlags, /*[in]*/ REFIID riid, /*[in], iid_is(riid)]*/ LPVOID pSink ); // For async operations
STDMETHOD(SetSelfDestructCallback)( /*[in]*/ ULONG uFlags, /*[in]*/ IWbemObjectSink *pSink ); // The callback called during final Release(); Set() is called with the task handle, followed by SetStatus()
//
STDMETHOD(GetStatus)( /*[out]*/ ULONG* pFlags );
STDMETHOD(NewInboundSink)( /*[in]*/ ULONG uFlags, /*[out]*/ IWbemObjectSink **pSink );
STDMETHOD(Merge)( /*[in]*/ ULONG uFlags, /*[in]*/ REFIID riid, /*[in]*/ LPVOID pObj ); // Allows merging another Finalizer, _IWmiCache, etc.
// For sorting, we will create a sorted _IWmiCache and merge it in later when
// the sort is completed.
// For setting, getting objects
STDMETHOD(SetResultObject)( /*[in]*/ ULONG uFlags, /*[in]*/ REFIID riid, /*[in]*/ LPVOID pObj );
STDMETHOD(GetResultObject)( /*[in]*/ ULONG uFlags, /*[in]*/ REFIID riid, /*[out, iid_is(riid)]*/ LPVOID *pObj ); // Support _IWmiObject, IWbemClassObject, etc.
// IEnumWbemClassObject
// _IWmiCache
// For status-only operations
STDMETHOD(SetOperationResult)( /*[in]*/ ULONG uFlags, /*[in]*/ HRESULT hRes );
STDMETHOD(GetOperationResult)( /*[in]*/ ULONG uFlags, /*[in]*/ ULONG uTimeout, /*[out]*/ HRESULT *phRes );
//Set status is called from the inbound sink to notify us of the status.
//We will queue up the request and pass it on to the client if necessary
HRESULT SetStatus( /*[in]*/ long lFlags, /*[in]*/ HRESULT hResult, /*[in]*/ BSTR strParam, /*[in]*/ IWbemClassObject* pObjParam ); STDMETHOD(CancelTask) ( /*[in]*/ ULONG uFlags );
STDMETHOD(DumpDebugInfo) ( /*[in]*/ ULONG uFlags, /*[in]*/ const BSTR fHandle );
STDMETHOD(Shutdown)( /*[in]*/ LONG uReason, /*[in]*/ ULONG uMaxMilliseconds, /*[in]*/ IWbemContext *pCtx);
//When the sink goes away, in the destructor, it will call back to unregister
//itself. That way we know when they are all done. If they are all gone
//we can send the status back to the client and we are all done!
HRESULT GetFinalResult ( ) { return m_hresFinalResult ; } HRESULT CancelWaitHandle ( ); HRESULT SetClientCancellationHandle ( HANDLE ) ; HRESULT NotifyClientOfCancelledCall ( ) ; BOOL IsValidDestinationSink ( ) ; HRESULT ReleaseDestinationSink ( ) ;
HRESULT ReportMemoryUsage ( ULONG, LONG ) ; HRESULT CancelTaskInternal ( ); HRESULT Reset ( ); // If there is an EnumClassObject calling Reset, it calls back into us...
HRESULT SetSinkToIdentity ( IWbemObjectSink* ); // Waits until the timeout for a new object to arrive, or a shutdown state
HRESULT WaitForCompletion ( ULONG uTimeout ); // Wait for the operition to complete.
HRESULT NextAsync ( CWmiFinalizerEnumerator* pEnum ); HRESULT Skip ( long lTimeout, ULONG nCount, CWmiFinalizerEnumerator* pEnum ); HRESULT PullObjects ( long lTimeout, ULONG uCount, IWbemClassObject** apObjects, ULONG* puReturned, CWmiFinalizerEnumerator* pEnum, BOOL bAddToObjQueue=TRUE, BOOL bSetErrorObj=TRUE ); HRESULT Set ( long lFlags, REFIID riid, void *pComObject ); HRESULT Indicate ( long lObjectCount, IWbemClassObject** apObjArray ); HRESULT UnregisterInboundSink( CWmiFinalizerInboundSink *pSink ); HRESULT GetNextObject ( CWmiFinalizerObj **ppObj ); HRESULT ZapWriteOnlyProps ( IWbemClassObject *pObj ); BOOL HasWriteOnlyProps ( IWbemClassObject* pObj );
HRESULT DoSetStatusCancel ( IWbemObjectSink * pSink, HRESULT lParam ); HRESULT DoSetStatus ( IWbemObjectSink * psink, long lFlags, HRESULT lParam, BSTR strParam, IWbemClassObject* pObjParam, BOOL bAllowMultipleCalls = FALSE ); HRESULT DoIndicate ( IWbemObjectSink * psink, int nBatchSize, IWbemClassObject **pBatch ); HRESULT FinalizerLowerAuthLevel ( IWbemObjectSink * psink, DWORD* pdwLastAuthnLevel ); IWbemObjectSink* ReturnProtectedDestinationSink ( ); bool GetSetStatusConsumed ( ) { return m_bSetStatusConsumed; } bool IsRestartable ( void ) { return m_bRestartable; } LONG GetInternalStatus ( ) { return m_hStatus; } void SetInternalStatus ( QueueStatus lStatus ) { m_hStatus = lStatus; } ULONG GetObjectQueueSize ( ) { return m_objects.Size(); } LONG IsCallCancelled ( ) { return m_bCancelledCall; } VOID UpdateStatus ( ULONG ulFlags ) { m_ulStatus |= ulFlags; }
VOID SetSemisyncWakeupCall ( ULONG ulNum ) { m_ulSemisyncWakeupCall = ulNum; } ULONG GetSemisyncWakeupCall ( ) { return m_ulSemisyncWakeupCall; }
HRESULT NotifyAllEnumeratorsOfCompletion ( ) ; HRESULT UnregisterEnumerator ( CWmiFinalizerEnumerator* ) ;
// Other public:
static void Dump(FILE* f);
CCritSec m_cs; // Protects the object queue
int m_LineCancelCall;
};
//*****************************************************************************
//**** ****
//**** Private WmiFinalizer classes... ****
//**** ****
//*****************************************************************************
class CWmiFinalizerInboundSink : public IWbemObjectSink { private: LONG m_lRefCount; LONG m_lInternalRefCount; CWmiFinalizer * m_pFinalizer; bool m_bSetStatusCalled; LIST_ENTRY m_Entry; public: CWmiFinalizerInboundSink(CWmiFinalizer *pFinalizer); ~CWmiFinalizerInboundSink();
STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj); STDMETHOD_(ULONG, AddRef)(THIS); STDMETHOD_(ULONG, Release)(THIS); STDMETHOD_(ULONG, InternalAddRef)(THIS); STDMETHOD_(ULONG, InternalRelease)(THIS);
void CallBackRelease () ;
STDMETHOD(Indicate)( /*[in]*/ long lObjectCount, /*[in, size_is(lObjectCount)]*/ IWbemClassObject** apObjArray );
STDMETHOD(SetStatus)( /*[in]*/ long lFlags, /*[in]*/ HRESULT hResult, /*[in]*/ BSTR strParam, /*[in]*/ IWbemClassObject* pObjParam );
STDMETHOD(Set)( /*[in]*/ long lFlags, /*[in]*/ REFIID riid, /*[in, iid_is(riid)]*/ void *pComObject ); };
class CWmiFinalizerEnumerator : public IEnumWbemClassObject, IWbemFetchSmartEnum { private: LONG m_lRefCount; LONG m_lInternalRefCount; ULONG m_ulCount; HANDLE m_hSignalCompletion;
CWmiFinalizer* m_pFinalizer; IServerSecurity* m_pSec; IWbemObjectSink* m_pDestSink; _IWbemEnumMarshaling* m_pEnumMarshal;
CCritSec m_clientLock;
CIdentitySecurity m_Security; LIST_ENTRY m_Entry; LIST_ENTRY m_HeadNextAsync; protected: // ============================
// SMART ENUM!!!!!!!!!!!!!
// ============================
class XSmartEnum : public IWbemWCOSmartEnum { private: CWmiFinalizerEnumerator* m_pOuter;
public:
XSmartEnum( CWmiFinalizerEnumerator* pOuter ) : m_pOuter( pOuter ) {}; ~XSmartEnum(){};
STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj); STDMETHOD_(ULONG, AddRef)(THIS); STDMETHOD_(ULONG, Release)(THIS);
// IWbemWCOSmartEnum Methods
STDMETHOD(Next)( REFGUID proxyGUID, LONG lTimeout, ULONG uCount, ULONG* puReturned, ULONG* pdwBuffSize, BYTE** pBuffer); } m_XSmartEnum;
friend XSmartEnum;
public: CWmiFinalizerEnumerator(CWmiFinalizer *pFinalizer); ~CWmiFinalizerEnumerator();
void Add_NextAsync(InsertableEvent * pInsert); void Remove_NextAsync(InsertableEvent * pInsert);
STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj); STDMETHOD_(ULONG, AddRef)(THIS); STDMETHOD_(ULONG, Release)(THIS); STDMETHOD_(ULONG, InternalAddRef)(THIS); STDMETHOD_(ULONG, InternalRelease)(THIS);
static DWORD WINAPI ThreadBootstrapNextAsync ( PVOID pvContext ); void CallBackRelease(); HRESULT _NextAsync(); HRESULT SetCompletionSignalEvent(){ if ( m_hSignalCompletion ) SetEvent (m_hSignalCompletion); return WBEM_S_NO_ERROR; } IWbemObjectSink* GetDestSink(){ return m_pDestSink; } VOID NULLDestSink(){ m_pDestSink = NULL; } HRESULT ReleaseFinalizer(){ if ( m_pFinalizer ) m_pFinalizer->Release(); return WBEM_S_NO_ERROR; }
// ============================
// IEnumWbemClassObject methods
// ============================
STDMETHOD(Reset)();
STDMETHOD(Next)( /*[in]*/ long lTimeout, /*[in]*/ ULONG uCount, /*[out, size_is(uCount), length_is(*puReturned)]*/ IWbemClassObject** apObjects, /*[out]*/ ULONG* puReturned );
STDMETHOD(NextAsync)( /*[in]*/ ULONG uCount, /*[in]*/ IWbemObjectSink* pSink );
STDMETHOD(Clone)( /*[out]*/ IEnumWbemClassObject** ppEnum );
STDMETHOD(Skip)( /*[in]*/ long lTimeout, /*[in]*/ ULONG nCount );
// ===========================
// IWbemFetchSmartEnum methods
// ===========================
STDMETHOD (GetSmartEnum) ( /*[out]*/ IWbemWCOSmartEnum** ppSmartEnum );
BOOL HasSmartEnum(){ return (NULL != m_pEnumMarshal); };
ULONG m_uCurObjectPosition ; HANDLE m_hWaitOnResultSet ; ULONG m_ulSemisyncWakeupCall; BOOL m_bSetStatusConsumed ; };
class CWmiFinalizerCallResult : IWbemCallResult { private: LONG m_lInternalRefCount; LONG m_lRefCount;
CWmiFinalizer *m_pFinalizer; long m_lFlags; HRESULT m_hResult; BSTR m_strParam; IWbemClassObject *m_pObj; IWbemClassObject *m_pErrorObj; IWbemServices *m_pServices; bool m_bGotObject; bool m_bGotServices; CIdentitySecurity m_Security; LIST_ENTRY m_Entry;
public: CWmiFinalizerCallResult(CWmiFinalizer *pFinalizer); ~CWmiFinalizerCallResult();
STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj); STDMETHOD_(ULONG, AddRef)(THIS); STDMETHOD_(ULONG, Release)(THIS); STDMETHOD_(ULONG, InternalAddRef)(THIS); STDMETHOD_(ULONG, InternalRelease)(THIS);
STDMETHOD(GetResultObject)( /*[in]*/ long lTimeout, /*[out]*/ IWbemClassObject** ppResultObject );
STDMETHOD(GetResultString)( /*[in]*/ long lTimeout, /*[out]*/ BSTR* pstrResultString );
STDMETHOD(GetResultServices)( /*[in]*/ long lTimeout, /*[out]*/ IWbemServices** ppServices );
STDMETHOD(GetCallStatus)( /*[in]*/ long lTimeout, /*[out]*/ long* plStatus );
STDMETHOD(GetResult)( /*[in]*/ long lTimeout, /*[in]*/ long lFlags, /*[in]*/ REFIID riid, /*[out, iid_is(riid)]*/ void **ppvResult );
HRESULT SetStatus( /*[in]*/ long lFlags, /*[in]*/ HRESULT hResult, /*[in]*/ BSTR strParam, /*[in]*/ IWbemClassObject* pObjParam );
void SetErrorInfo();
}; #endif
|