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.

1298 lines
39 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. WMIMERGER.CPP
  5. Abstract:
  6. Implements the _IWmiMerger interface
  7. History:
  8. sanjes 16-Nov-00 Created.
  9. --*/
  10. #include "precomp.h"
  11. #pragma warning (disable : 4786)
  12. #include <wbemcore.h>
  13. #include <map>
  14. #include <vector>
  15. #include <genutils.h>
  16. #include <oahelp.inl>
  17. #include <wqllex.h>
  18. #include "wmimerger.h"
  19. #include <scopeguard.h>
  20. static long g_lNumMergers = 0L;
  21. //***************************************************************************
  22. //
  23. //***************************************************************************
  24. //
  25. CWmiMerger::CWmiMerger( CWbemNamespace* pNameSpace )
  26. : m_lRefCount( 0 ),
  27. m_pTargetSink( NULL ),
  28. m_pTask( NULL ),
  29. m_pNamespace( pNameSpace ),
  30. m_wsTargetClassName(),
  31. m_dwProviderDeliveryPing( 0L ),
  32. m_pArbitrator( NULL ),
  33. m_lNumArbThrottled( 0L ),
  34. m_lDebugMemUsed( 0L ),
  35. m_hOperationRes( WBEM_S_NO_ERROR ),
  36. m_cs(),
  37. m_dwMaxLevel( 0 ),
  38. m_pRequestMgr( NULL ),
  39. m_dwMinReqLevel( 0xFFFFFFFF ),
  40. m_bMergerThrottlingEnabled( true )
  41. {
  42. if ( NULL != m_pNamespace )
  43. {
  44. m_pNamespace->AddRef();
  45. }
  46. InterlockedIncrement( &g_lNumMergers );
  47. }
  48. //***************************************************************************
  49. //
  50. // CWmiMerger::~CWmiMerger
  51. //
  52. // Notifies the ESS of namespace closure and frees up all the class providers.
  53. //
  54. //***************************************************************************
  55. CWmiMerger::~CWmiMerger()
  56. {
  57. _DBG_ASSERT( 0L == m_lNumArbThrottled );
  58. _DBG_ASSERT( 0L == m_lDebugMemUsed );
  59. if ( NULL != m_pNamespace )
  60. {
  61. m_pNamespace->Release();
  62. }
  63. if ( NULL != m_pArbitrator )
  64. {
  65. m_pArbitrator->Release();
  66. }
  67. if ( NULL != m_pTask )
  68. {
  69. m_pTask->Release();
  70. }
  71. if ( NULL != m_pRequestMgr )
  72. {
  73. delete m_pRequestMgr;
  74. m_pRequestMgr = NULL;
  75. }
  76. InterlockedDecrement( &g_lNumMergers );
  77. }
  78. //***************************************************************************
  79. //
  80. // CWmiMerger::QueryInterface
  81. //
  82. // Exports _IWmiMerger interface.
  83. //
  84. //***************************************************************************
  85. STDMETHODIMP CWmiMerger::QueryInterface(
  86. IN REFIID riid,
  87. OUT LPVOID *ppvObj
  88. )
  89. {
  90. if ( riid == IID__IWmiArbitratee )
  91. {
  92. *ppvObj = (_IWmiArbitratee*) this;
  93. }
  94. else if ( riid == IID__IWmiArbitratedQuery )
  95. {
  96. *ppvObj = (_IWmiArbitratedQuery*) this;
  97. }
  98. else
  99. {
  100. return E_NOINTERFACE;
  101. }
  102. AddRef();
  103. return S_OK;
  104. }
  105. //***************************************************************************
  106. //
  107. //***************************************************************************
  108. //
  109. ULONG CWmiMerger::AddRef()
  110. {
  111. return InterlockedIncrement(&m_lRefCount);
  112. }
  113. //***************************************************************************
  114. //
  115. //***************************************************************************
  116. //
  117. ULONG CWmiMerger::Release()
  118. {
  119. long lNewCount = InterlockedDecrement(&m_lRefCount);
  120. if (0 != lNewCount)
  121. return lNewCount;
  122. delete this;
  123. return 0;
  124. }
  125. // Sets initial parameters for merger. Establishes the target class and sink for the
  126. // query associated with the merger
  127. STDMETHODIMP CWmiMerger::Initialize( _IWmiArbitrator* pArbitrator, _IWmiCoreHandle* pTask, LPCWSTR pwszTargetClass,
  128. IWbemObjectSink* pTargetSink, CMergerSink** ppFinalSink )
  129. {
  130. if ( NULL == pwszTargetClass || NULL == pTargetSink )
  131. {
  132. return WBEM_E_INVALID_PARAMETER;
  133. }
  134. // Cannot initialize twice
  135. if ( NULL != m_pTargetSink )
  136. {
  137. return WBEM_E_INVALID_OPERATION;
  138. }
  139. HRESULT hr = WBEM_S_NO_ERROR;
  140. try
  141. {
  142. m_wsTargetClassName = pwszTargetClass; // throws
  143. // Create the final target sink
  144. hr = CreateMergingSink( eMergerFinalSink, pTargetSink,
  145. NULL, (CMergerSink**) &m_pTargetSink );
  146. if ( SUCCEEDED( hr ) )
  147. {
  148. *ppFinalSink = m_pTargetSink;
  149. m_pTargetSink->AddRef();
  150. m_pArbitrator = pArbitrator;
  151. m_pArbitrator->AddRef();
  152. // AddRef the Task here
  153. m_pTask = pTask;
  154. // Only register for arbitration if we have a task handle
  155. if ( NULL != pTask )
  156. {
  157. m_pTask->AddRef();
  158. hr = m_pArbitrator->RegisterArbitratee( 0L, m_pTask, this );
  159. }
  160. }
  161. }
  162. catch ( CX_Exception & )
  163. {
  164. hr = WBEM_E_OUT_OF_MEMORY;
  165. }
  166. return hr;
  167. }
  168. // Called to request a delivery sink for a class in the query chain. The returned
  169. // sink is determined by the specified flags as well as settings on the parent class
  170. STDMETHODIMP CWmiMerger::RegisterSinkForClass( LPCWSTR pwszClass, _IWmiObject* pClass,
  171. IWbemContext* pContext,
  172. BOOL fHasChildren, BOOL fHasInstances,
  173. BOOL fDerivedFromTarget,
  174. bool bStatic, CMergerSink* pDestSink,
  175. CMergerSink** ppOwnSink, CMergerSink** ppChildSink )
  176. {
  177. try
  178. {
  179. LPCWSTR pwszParentClass = NULL;
  180. DWORD dwSize = NULL;
  181. BOOL fIsNull = NULL;
  182. // Get the derivation information. The number of antecedents determines our
  183. // level in the hierarchy (we're 0 based)
  184. HRESULT hr;
  185. DWORD dwLevel = 0L;
  186. _variant_t vSuperClass;
  187. hr = GetLevelAndSuperClass( pClass, &dwLevel, vSuperClass );
  188. if (FAILED(hr)) return hr;
  189. BSTR wsSuperClass = V_BSTR(&vSuperClass); // it can be NULL if no SuperClass
  190. CCheckedInCritSec ics( &m_cs );
  191. // We're dead - take no positive adjustments
  192. if (FAILED (m_hOperationRes)) return m_hOperationRes;
  193. wmilib::auto_ptr<CWmiMergerRecord> pRecord;
  194. pRecord.reset(new CWmiMergerRecord( this, fHasInstances, fHasChildren,
  195. pwszClass, pDestSink, dwLevel, bStatic )); // throw
  196. if ( NULL == pRecord.get() ) return WBEM_E_OUT_OF_MEMORY;
  197. // Now attach aninternal merger if we have both instances and children
  198. if ( fHasInstances && fHasChildren )
  199. {
  200. // We shouldn't have a NULL task here if this is not a static class.
  201. // Note that the only case this appears to happen is when ESS calls
  202. // into us on internal APIs and uses requests on its own queues and
  203. // not the main Core Queue.
  204. _DBG_ASSERT( NULL != m_pTask || ( NULL == m_pTask && bStatic ) );
  205. // throws
  206. hr = pRecord->AttachInternalMerger( (CWbemClass*) pClass, m_pNamespace, pContext, fDerivedFromTarget, bStatic );
  207. }
  208. // Check that we're still okay
  209. if (FAILED(hr)) return hr;
  210. // Find the record for the superclass if there is one (unless the array is
  211. // empty of course).
  212. if ( wsSuperClass && wsSuperClass[0] && m_MergerRecord.GetSize() > 0 )
  213. {
  214. // There MUST be a record, or something is quite not okay.
  215. CWmiMergerRecord* pSuperClassRecord = m_MergerRecord.Find( wsSuperClass );
  216. _DBG_ASSERT( NULL != pSuperClassRecord );
  217. // Now add the new record to the child array for the superclass record
  218. // This will allow us to quickly determine the classes we need to obtain
  219. // submit requests for if the parent class is throttled.
  220. if ( NULL == pSuperClassRecord ) return WBEM_E_FAILED;
  221. hr = pSuperClassRecord->AddChild(pRecord.get());
  222. }
  223. if (FAILED(hr)) return hr;
  224. // Make sure the add is successful
  225. if ( m_MergerRecord.Insert( pRecord.get() ) < 0 ) return WBEM_E_OUT_OF_MEMORY;
  226. #ifdef __DEBUG_MERGER_THROTTLING
  227. // Verify the sort order for now
  228. m_MergerRecord.Verify();
  229. #endif
  230. *ppOwnSink = pRecord->GetOwnSink();
  231. *ppChildSink = pRecord->GetChildSink();
  232. pRecord.release(); // array took ownership
  233. // Store the maximum level in the hierarchy
  234. if ( dwLevel > m_dwMaxLevel )
  235. {
  236. m_dwMaxLevel = dwLevel;
  237. }
  238. if ( !bStatic && dwLevel < m_dwMinReqLevel )
  239. {
  240. m_dwMinReqLevel = dwLevel;
  241. }
  242. return hr;
  243. }
  244. catch(CX_Exception & )
  245. {
  246. return WBEM_E_OUT_OF_MEMORY;
  247. }
  248. }
  249. // Called to request a delivery sink for child classes in the query chain. This is especially
  250. // important when instances are merged under the covers.
  251. STDMETHODIMP CWmiMerger::GetChildSink( LPCWSTR pwszClass, CBasicObjectSink** ppSink )
  252. {
  253. HRESULT hr = WBEM_S_NO_ERROR;
  254. CInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  255. // Search for a parent class's child sink
  256. for ( int x = 0; SUCCEEDED( hr ) && x < m_MergerRecord.GetSize(); x++ )
  257. {
  258. if ( m_MergerRecord[x]->IsClass( pwszClass ) )
  259. {
  260. *ppSink = m_MergerRecord[x]->GetChildSink();
  261. break;
  262. }
  263. }
  264. // We should never get a failure
  265. _DBG_ASSERT( x < m_MergerRecord.GetSize() );
  266. if ( x >= m_MergerRecord.GetSize() )
  267. {
  268. hr = WBEM_E_NOT_FOUND;
  269. }
  270. return hr;
  271. }
  272. // Can be used to hold off indicates - if we're merging instances from multiple providers, we need
  273. // to ensure that we don't get lopsided in the number of objects we've got queued up for merging.
  274. STDMETHODIMP CWmiMerger::Throttle( void )
  275. {
  276. // We're dead - take no positive adjustments
  277. if ( FAILED ( m_hOperationRes ) )
  278. {
  279. return m_hOperationRes;
  280. }
  281. // Check for NULL m_pTask
  282. HRESULT hr = WBEM_S_NO_ERROR;
  283. if ( NULL != m_pTask )
  284. {
  285. hr = m_pArbitrator->Throttle( 0L, m_pTask );
  286. }
  287. return hr;
  288. }
  289. // Merger will hold information regarding the total number of objects it has queued up waiting
  290. // for merging and the amount of memory consumed by those objects.
  291. STDMETHODIMP CWmiMerger::GetQueuedObjectInfo( DWORD* pdwNumQueuedObjects, DWORD* pdwQueuedObjectMemSize )
  292. {
  293. return WBEM_E_NOT_AVAILABLE;
  294. }
  295. // If this is called, all underlying sinks will be cancelled in order to prevent accepting additional
  296. // objects. This will also automatically free up resources consumed by queued objects.
  297. STDMETHODIMP CWmiMerger::Cancel( void )
  298. {
  299. return Cancel( WBEM_E_CALL_CANCELLED );
  300. }
  301. // Helper function to control sink creation. The merger is responsible for deletion of
  302. // all internally created sinks. So this function ensures that the sinks are added into
  303. // the array that will destroy them.
  304. HRESULT CWmiMerger::CreateMergingSink( MergerSinkType eType, IWbemObjectSink* pDestSink, CInternalMerger* pMerger, CMergerSink** ppSink )
  305. {
  306. if ( eType == eMergerFinalSink )
  307. {
  308. *ppSink = new CMergerTargetSink( this, pDestSink );
  309. if ( NULL == *ppSink ) return WBEM_E_OUT_OF_MEMORY;
  310. }
  311. else
  312. {
  313. HRESULT hr;
  314. hr = CInternalMerger::CreateMergingSink( eType, pMerger, this, ppSink );
  315. if (FAILED(hr)) return hr;
  316. }
  317. // If we have a sink, we should now add it to the
  318. // Sink array, the MergerSinks array will do the operator delete call,
  319. // but the objects will have a special callback on the last release
  320. if ( m_MergerSinks.Add( *ppSink ) < 0 )
  321. {
  322. delete *ppSink;
  323. *ppSink = NULL;
  324. return WBEM_E_OUT_OF_MEMORY;
  325. }
  326. return WBEM_S_NO_ERROR;
  327. }
  328. // Iterates the array of MergerRecords and cancels each of them.
  329. HRESULT CWmiMerger::Cancel( HRESULT hRes )
  330. {
  331. #ifdef __DEBUG_MERGER_THROTTLING
  332. DbgPrintfA(0,"CANCEL CALLED: Merger %p Cancelled with hRes: 0x%x on Thread 0x%x\n",this, hRes, GetCurrentThreadId() );
  333. #endif
  334. // We shouldn't be called with a success code
  335. _DBG_ASSERT( FAILED( hRes ) );
  336. HRESULT hr = WBEM_S_NO_ERROR;
  337. // If we're here and this is non-NULL, tell the Arbitrator to tank us.
  338. if ( NULL != m_pTask )
  339. {
  340. m_pArbitrator->CancelTask( 0L, m_pTask );
  341. }
  342. CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  343. if ( WBEM_S_NO_ERROR == m_hOperationRes ) // if it is the first time
  344. {
  345. m_hOperationRes = hRes;
  346. }
  347. // Search for a parent class's child sink
  348. for ( int x = 0; SUCCEEDED( hr ) && x < m_MergerRecord.GetSize(); x++ )
  349. {
  350. m_MergerRecord[x]->Cancel( hRes );
  351. }
  352. // Copy into a temporary variable, clear the member, exit the critsec
  353. // THEN call delete. Requests can have multiple releases, which could call
  354. // back in here and cause all sorts of problems if we're inside a critsec.
  355. CWmiMergerRequestMgr* pReqMgr = m_pRequestMgr;
  356. m_pRequestMgr = NULL;
  357. ics.Leave();
  358. // Tank any and all outstanding requests
  359. if ( NULL != pReqMgr )
  360. {
  361. delete pReqMgr;
  362. }
  363. return hr;
  364. }
  365. // Final Shutdown. Called when the target sink is released. At this point, we should
  366. // unregister ourselves from the world
  367. HRESULT CWmiMerger::Shutdown( void )
  368. {
  369. HRESULT hr = WBEM_S_NO_ERROR;
  370. CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  371. _IWmiCoreHandle* pTask = m_pTask;
  372. // Done with this, NULL it out - we release and unregister outside the critical section
  373. if ( NULL != m_pTask )
  374. {
  375. m_pTask = NULL;
  376. }
  377. ics.Leave();
  378. if ( NULL != pTask )
  379. {
  380. hr = m_pArbitrator->UnRegisterArbitratee( 0L, pTask, this );
  381. pTask->Release();
  382. }
  383. return hr;
  384. }
  385. // Pas-thru to arbitrator
  386. HRESULT CWmiMerger::ReportMemoryUsage( long lAdjustment )
  387. {
  388. // Task can be NULL
  389. HRESULT hr = WBEM_S_NO_ERROR;
  390. if ( NULL != m_pTask )
  391. {
  392. hr = m_pArbitrator->ReportMemoryUsage( 0L, lAdjustment, m_pTask );
  393. }
  394. // SUCCESS, WBEM_E_ARB_CANCEL or WBEM_E_ARB_THROTTLE means that we need to
  395. // account for the memory
  396. if ( ( SUCCEEDED( hr ) || hr == WBEM_E_ARB_CANCEL || hr == WBEM_E_ARB_THROTTLE ) )
  397. {
  398. InterlockedExchangeAdd( &m_lDebugMemUsed, lAdjustment );
  399. }
  400. return hr;
  401. }
  402. /* _IWmiArbitratee methods. */
  403. STDMETHODIMP CWmiMerger::SetOperationResult( ULONG uFlags, HRESULT hRes )
  404. {
  405. HRESULT hr = WBEM_S_NO_ERROR;
  406. if ( FAILED( hRes ) )
  407. {
  408. hr = Cancel( hRes );
  409. }
  410. return hr;
  411. }
  412. // Why are we here?
  413. STDMETHODIMP CWmiMerger::SetTaskHandle( _IWmiCoreHandle* pTask )
  414. {
  415. _DBG_ASSERT( 0 );
  416. HRESULT hr = WBEM_S_NO_ERROR;
  417. return hr;
  418. }
  419. // Noop for now
  420. STDMETHODIMP CWmiMerger::DumpDebugInfo( ULONG uFlags, const BSTR strFile )
  421. {
  422. HRESULT hr = WBEM_S_NO_ERROR;
  423. return hr;
  424. }
  425. // Returns SUCCESS for now
  426. STDMETHODIMP CWmiMerger::IsMerger( void )
  427. {
  428. return WBEM_S_NO_ERROR;
  429. }
  430. HRESULT CWmiMerger::GetLevelAndSuperClass( _IWmiObject* pObj, DWORD* pdwLevel,
  431. _variant_t & vSuperClass )
  432. {
  433. // Get the derivation information. The number of antecedents determines our
  434. // level in the hierarchy (we're 0 based)
  435. DWORD dwTemp = 0L;
  436. HRESULT hr = pObj->GetDerivation( 0L, 0L, pdwLevel, &dwTemp, NULL );
  437. if ( FAILED( hr ) && WBEM_E_BUFFER_TOO_SMALL != hr )
  438. {
  439. return hr;
  440. }
  441. hr = pObj->Get( L"__SUPERCLASS", 0L, &vSuperClass, NULL, NULL );
  442. if ( SUCCEEDED( hr ))
  443. {
  444. if ( VT_BSTR == V_VT(&vSuperClass)) return S_OK;
  445. if ( VT_NULL == V_VT(&vSuperClass)) { V_BSTR(&vSuperClass) = NULL; return S_OK; };
  446. throw CX_Exception();
  447. }
  448. return hr;
  449. }
  450. HRESULT CWmiMerger::RegisterArbitratedInstRequest( CWbemObject* pClassDef, long lFlags,
  451. IWbemContext* pCtx,
  452. CBasicObjectSink* pSink,
  453. BOOL bComplexQuery,
  454. CWbemNamespace* pNs )
  455. {
  456. HRESULT hr = WBEM_S_NO_ERROR;
  457. // Allocate a new request then place it in the arbitrator.
  458. try
  459. {
  460. wmilib::auto_ptr<CMergerDynReq_DynAux_GetInstances> pReq;
  461. pReq.reset(new CMergerDynReq_DynAux_GetInstances(pNs, pClassDef,
  462. lFlags, pCtx, pSink));
  463. if (NULL == pReq.get()) return WBEM_E_OUT_OF_MEMORY;
  464. // Make sure a context exists under the cover
  465. if (NULL == pReq->GetContext()) return WBEM_E_OUT_OF_MEMORY;
  466. CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  467. if (FAILED(m_hOperationRes)) return m_hOperationRes;
  468. // Allocate a request manager if we need one
  469. if ( NULL == m_pRequestMgr )
  470. {
  471. m_pRequestMgr = new CWmiMergerRequestMgr(this);
  472. if (NULL == m_pRequestMgr) return WBEM_E_OUT_OF_MEMORY;
  473. }
  474. // We need the record to find out what level we need to add
  475. // the request to
  476. CWmiMergerRecord* pRecord = m_MergerRecord.Find( pReq->GetName() );
  477. _DBG_ASSERT( NULL != pRecord );
  478. if ( NULL == pRecord ) return WBEM_E_FAILED;
  479. // Set the task for the request - we'll just use the existing one
  480. m_pTask->AddRef();
  481. pReq->m_phTask = m_pTask;
  482. hr = m_pRequestMgr->AddRequest( pReq.get(), pRecord->GetLevel() );
  483. // Cleanup the request if anything went wrong
  484. if ( FAILED( hr ) ) return hr;
  485. pReq.release();
  486. }
  487. catch(CX_Exception &)
  488. {
  489. ExceptionCounter c;
  490. hr = WBEM_E_OUT_OF_MEMORY;
  491. }
  492. return hr;
  493. }
  494. HRESULT
  495. CWmiMerger::RegisterArbitratedQueryRequest( CWbemObject* pClassDef, long lFlags,
  496. LPCWSTR Query,LPCWSTR QueryFormat,
  497. IWbemContext* pCtx,
  498. CBasicObjectSink* pSink,
  499. CWbemNamespace* pNs )
  500. {
  501. HRESULT hr = WBEM_S_NO_ERROR;
  502. // Allocate a new request then place it in the arbitrator.
  503. try
  504. {
  505. wmilib::auto_ptr<CMergerDynReq_DynAux_ExecQueryAsync> pReq;
  506. pReq.reset(new CMergerDynReq_DynAux_ExecQueryAsync(pNs, pClassDef, lFlags,
  507. Query, QueryFormat,
  508. pCtx, pSink ));
  509. if (NULL == pReq.get()) return WBEM_E_OUT_OF_MEMORY;
  510. // Make sure a context was properly allocated
  511. if (NULL == pReq->GetContext()) return WBEM_E_OUT_OF_MEMORY;
  512. // Make sure the request is functional
  513. if (FAILED(hr = pReq->Initialize())) return hr;
  514. CInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  515. if (FAILED(m_hOperationRes)) return m_hOperationRes;
  516. // Allocate a request manager if we need one
  517. if ( NULL == m_pRequestMgr )
  518. {
  519. m_pRequestMgr = new CWmiMergerRequestMgr( this );
  520. if ( NULL == m_pRequestMgr ) return WBEM_E_OUT_OF_MEMORY;
  521. }
  522. // We need the record to find out what level we need to add
  523. // the request to
  524. CWmiMergerRecord* pRecord = m_MergerRecord.Find( pReq->GetName() );
  525. _DBG_ASSERT( NULL != pRecord );
  526. // Couldn't find the record
  527. if ( NULL == pRecord ) return WBEM_E_FAILED;
  528. // Set the task for the request - we'll just use the existing one
  529. m_pTask->AddRef();
  530. pReq->m_phTask = m_pTask;
  531. hr = m_pRequestMgr->AddRequest( pReq.get(), pRecord->GetLevel() );
  532. if (FAILED(hr)) return hr;
  533. pReq.release();
  534. }
  535. catch(CX_Exception &)
  536. {
  537. ExceptionCounter c;
  538. hr = WBEM_E_OUT_OF_MEMORY;
  539. }
  540. return hr;
  541. }
  542. HRESULT CWmiMerger::RegisterArbitratedStaticRequest( CWbemObject* pClassDef, long lFlags,
  543. IWbemContext* pCtx, CBasicObjectSink* pSink, CWbemNamespace* pNs,
  544. QL_LEVEL_1_RPN_EXPRESSION* pParsedQuery )
  545. {
  546. HRESULT hr = WBEM_S_NO_ERROR;
  547. // Allocate a new request then place it in the arbitrator.
  548. try
  549. {
  550. wmilib::auto_ptr<CMergerDynReq_Static_GetInstances> pReq;
  551. pReq.reset(new CMergerDynReq_Static_GetInstances(
  552. pNs, pClassDef, lFlags, pCtx, pSink,
  553. pParsedQuery ));
  554. if ( NULL == pReq.get() ) return WBEM_E_OUT_OF_MEMORY;
  555. // Make sure a context was properly allocated
  556. if ( NULL == pReq->GetContext() ) return WBEM_E_OUT_OF_MEMORY;
  557. CInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  558. if ( FAILED( m_hOperationRes ) ) return m_hOperationRes;
  559. // Allocate a request manager if we need one
  560. if ( NULL == m_pRequestMgr )
  561. {
  562. m_pRequestMgr = new CWmiMergerRequestMgr( this );
  563. if ( NULL == m_pRequestMgr ) return WBEM_E_OUT_OF_MEMORY;
  564. }
  565. // We need the record to find out what level we need to add
  566. // the request to
  567. CWmiMergerRecord* pRecord = m_MergerRecord.Find( pReq->GetName() );
  568. _DBG_ASSERT( NULL != pRecord );
  569. // Couldn't find the record
  570. if ( NULL == pRecord ) return WBEM_E_FAILED;
  571. // Set the task for the request - we'll just use the existing one
  572. m_pTask->AddRef();
  573. pReq->m_phTask = m_pTask;
  574. hr = m_pRequestMgr->AddRequest( pReq.get(), pRecord->GetLevel() );
  575. if (FAILED(hr)) return hr;
  576. pReq.release();
  577. }
  578. catch(CX_Exception &)
  579. {
  580. ExceptionCounter c;
  581. hr = WBEM_E_OUT_OF_MEMORY;
  582. }
  583. return hr;
  584. }
  585. //
  586. // Executes the parent request. In this case, we simply ask the request manager for the
  587. // next top level request and execute that request. We do this in a loop until something
  588. // goes wrong.
  589. //
  590. HRESULT CWmiMerger::Exec_MergerParentRequest( CWmiMergerRecord* pParentRecord, CBasicObjectSink* pSink )
  591. {
  592. HRESULT hr = WBEM_S_NO_ERROR;
  593. IWbemClassObject * pErr = NULL;
  594. CSetStatusOnMe setOnMe(pSink,hr,pErr);
  595. CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  596. // While we have requests to execute, we should get each next logical one
  597. while ( SUCCEEDED(hr ) && NULL != m_pRequestMgr && m_pRequestMgr->GetNumRequests() > 0 )
  598. {
  599. if ( FAILED( m_hOperationRes ) ) { hr = m_hOperationRes; break; }
  600. // Obtain the next topmost parent record if we have to
  601. if ( NULL == pParentRecord )
  602. {
  603. WString wsClassName; // throw
  604. hr = m_pRequestMgr->GetTopmostParentReqName( wsClassName );
  605. if ( SUCCEEDED( hr ) )
  606. {
  607. pParentRecord = m_MergerRecord.Find( wsClassName );
  608. // If there's a request, there better be a record
  609. _DBG_ASSERT( NULL != pParentRecord );
  610. if ( NULL == pParentRecord )
  611. {
  612. hr = WBEM_E_FAILED;
  613. }
  614. } // IF Got Topmost Parent Request
  615. } // IF NULL == pParentRecord
  616. if ( FAILED( hr ) ) break;
  617. // This will remove the request from its array and return it
  618. // to us - we need to delete it
  619. wmilib::auto_ptr<CMergerReq> pReq;
  620. hr = m_pRequestMgr->RemoveRequest( pParentRecord->GetLevel(),
  621. pParentRecord->GetName(), pReq );
  622. if (FAILED(hr)) break;
  623. hr = pParentRecord->SetExecutionContext( pReq->GetContext() );
  624. if (FAILED(hr)) break;
  625. // Clearly, we should do this outside the critsec
  626. ics.Leave();
  627. #ifdef __DEBUG_MERGER_THROTTLING
  628. DbgPrintfA(0,"BEGIN: Merger 0x%x querying instances of parent class: %S, Level %d on Thread 0x%x\n", (DWORD_PTR) this, pParentRecord->GetName(), pParentRecord->GetLevel(), GetCurrentThreadId() );
  629. #endif
  630. // This will delete the request when it is done with it
  631. hr = CCoreQueue::ExecSubRequest( pReq.get() );
  632. if ( SUCCEEDED(hr) ) pReq.release(); // queue took ownership
  633. #ifdef __DEBUG_MERGER_THROTTLING
  634. DbgPrintfA(0,"END: Merger 0x%x querying instances of parent class: %S, Level %d on Thread 0x%x\n", (DWORD_PTR) this, pParentRecord->GetName(), pParentRecord->GetLevel(), GetCurrentThreadId() );// SEC:REVIEWED 2002-03-22 : OK
  635. #endif
  636. ics.Enter();
  637. // We're done with this record, so we need to get the next top level
  638. // record.
  639. pParentRecord = NULL;
  640. }
  641. // SetStatus called by the guard
  642. return hr;
  643. }
  644. void CWmiMerger::CleanChildRequests(CWmiMergerRecord* pParentRecord, int cleanFrom)
  645. {
  646. CCheckedInCritSec ics(&m_cs);
  647. if (NULL == m_pRequestMgr) return;
  648. // we want to see if there are un-executed requests laying around
  649. int localClean = cleanFrom;
  650. while(true)
  651. {
  652. CWmiMergerRecord* pChildRecord = pParentRecord->GetChildRecord( localClean++ );
  653. if ( NULL == pChildRecord ){ break; }
  654. // This will remove the request from its array and return it
  655. // to us - we need to delete it
  656. wmilib::auto_ptr<CMergerReq> pReq;
  657. m_pRequestMgr->RemoveRequest( pChildRecord->GetLevel(),
  658. pChildRecord->GetName(), pReq );
  659. if (pReq.get() != 0)
  660. {
  661. ERRORTRACE((LOG_WBEMCORE,"deleting un-executed requests for class %S\n",pReq->GetName()));
  662. }
  663. }
  664. }
  665. //
  666. // Executes the child request. In this case, we enumerate the child classes of the parent
  667. // record, and execute the corresponding requests. We do so in a loop until we either
  668. // finish or something goes wrong.
  669. //
  670. HRESULT CWmiMerger::Exec_MergerChildRequest( CWmiMergerRecord* pParentRecord,
  671. CBasicObjectSink* pSink )
  672. {
  673. HRESULT hr = WBEM_S_NO_ERROR;
  674. IWbemClassObject * pErr = NULL;
  675. CSetStatusOnMe setOnMe(pSink,hr,pErr);
  676. int cleanFrom = 0;
  677. ScopeGuard CleanChildReq = MakeObjGuard(*this, CWmiMerger::CleanChildRequests, pParentRecord, ByRef(cleanFrom));
  678. bool bLast = false;
  679. CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  680. // While we have child requests to execute, we should get each one
  681. for (int x = 0; SUCCEEDED( hr ) && NULL != m_pRequestMgr && !bLast; x++ )
  682. {
  683. // m_pRequestMgr will be NULL if we were cancelled, in which
  684. // case m_hOperationRes will be a failure
  685. if (FAILED(m_hOperationRes)){ hr = m_hOperationRes; break; };
  686. CWmiMergerRecord* pChildRecord = pParentRecord->GetChildRecord( x );
  687. if ( NULL == pChildRecord ){ bLast = true; break; }
  688. // This will remove the request from its array and return it
  689. // to us - we need to delete it
  690. wmilib::auto_ptr<CMergerReq> pReq;
  691. hr = m_pRequestMgr->RemoveRequest( pChildRecord->GetLevel(),
  692. pChildRecord->GetName(), pReq );
  693. if ( WBEM_E_NOT_FOUND == hr )
  694. {
  695. // If we don't find the request we're looking for, another thread
  696. // already processed it. We should, however, still look for child
  697. // requests to process before we go away.
  698. hr = WBEM_S_NO_ERROR;
  699. continue;
  700. }
  701. cleanFrom = x+1;
  702. if ( FAILED( hr ) ) break;
  703. hr = pChildRecord->SetExecutionContext(pReq->GetContext());
  704. if (FAILED(hr)) break;
  705. // Clearly, we should do this outside the critsec
  706. ics.Leave();
  707. #ifdef __DEBUG_MERGER_THROTTLING
  708. DbgPrintfA(0,"BEGIN: Merger 0x%x querying instances of child class: %S, Level %d for parent class: %S on Thread 0x%x\n", (DWORD_PTR) this, pChildRecord->GetName(), pChildRecord->GetLevel(), pParentRecord->GetName(), GetCurrentThreadId() );
  709. #endif
  710. // This will delete the request when it is done with it
  711. hr = CCoreQueue::ExecSubRequest( pReq.get() );
  712. if ( SUCCEEDED(hr) ) pReq.release(); // queue took ownership
  713. #ifdef __DEBUG_MERGER_THROTTLING
  714. DbgPrintfA(0,"END: Merger 0x%x querying instances of child class: %S, Level %d for parent class: %S on Thread 0x%x\n", (DWORD_PTR) this, pChildRecord->GetName(), pChildRecord->GetLevel(), pParentRecord->GetName(), GetCurrentThreadId() );
  715. #endif
  716. ics.Enter();
  717. } // FOR enum child requests
  718. // SetStatus invoked by the guard
  719. return hr;
  720. }
  721. // Schedules the parent class request
  722. HRESULT CWmiMerger::ScheduleMergerParentRequest( IWbemContext* pCtx )
  723. {
  724. // Check if query arbitration is enabled
  725. if ( !ConfigMgr::GetEnableQueryArbitration() )
  726. {
  727. return WBEM_S_NO_ERROR;
  728. }
  729. CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  730. HRESULT hr = WBEM_S_NO_ERROR;
  731. do
  732. {
  733. if (FAILED( m_hOperationRes )){ hr = m_hOperationRes; break; }
  734. if ( NULL == m_pRequestMgr )
  735. {
  736. break; // The request manager will be non-NULL
  737. // only if we had to add a request.
  738. }
  739. #ifdef __DEBUG_MERGER_THROTTLING
  740. m_pRequestMgr->DumpRequestHierarchy();
  741. #endif
  742. // Make sure we've got at least one request
  743. if ( 0 == m_pRequestMgr->GetNumRequests() ) break;
  744. // If there isn't a task, we've got a BIG problem.
  745. _DBG_ASSERT( NULL != m_pTask );
  746. if ( NULL == m_pTask )
  747. {
  748. hr = WBEM_E_FAILED; break;
  749. }
  750. // If we have a single static request in the merger, we'll
  751. // execute it now. Otherwise, we'll do normal processing.
  752. // Note that we *could* theoretically do this for single
  753. // dynamic requests as well
  754. if ( IsSingleStaticRequest() )
  755. {
  756. // We MUST leave the critical section here, since the parent request
  757. // could get cancelled or we may end up sleeping and we don't want
  758. // to own the critical section in that time.
  759. ics.Leave();
  760. hr = Exec_MergerParentRequest( NULL, m_pTargetSink );
  761. }
  762. else
  763. {
  764. // If we've never retrieved the number of processors, do so
  765. // now.
  766. static g_dwNumProcessors = 8L;
  767. /*
  768. if ( 0L == g_dwNumProcessors )
  769. {
  770. SYSTEM_INFO sysInfo;
  771. ZeroMemory( &sysInfo, sizeof( sysInfo ) ); // SEC:REVIEWED 2002-03-22 : OK
  772. GetSystemInfo( &sysInfo );
  773. _DBG_ASSERT( sysInfo.dwNumberOfProcessors > 0L );
  774. // Ensure we're always at least 1
  775. g_dwNumProcessors = ( 0L == sysInfo.dwNumberOfProcessors ?
  776. 1L : sysInfo.dwNumberOfProcessors );
  777. }
  778. */
  779. // We will generate a number of parent requests based on the minimum
  780. // of the number of requests and the number of actual processors.
  781. DWORD dwNumToSchedule = min( m_pRequestMgr->GetNumRequests(), g_dwNumProcessors );
  782. for ( DWORD dwCtr = 0L; SUCCEEDED( hr ) && dwCtr < dwNumToSchedule; dwCtr++ )
  783. {
  784. // Parent request will search for the next available request
  785. wmilib::auto_ptr<CMergerParentReq> pReq;
  786. pReq.reset(new CMergerParentReq(this,NULL,m_pNamespace,m_pTargetSink,pCtx));
  787. if ( NULL == pReq.get() ) {
  788. hr = WBEM_E_OUT_OF_MEMORY; break;
  789. }
  790. if ( NULL == pReq->GetContext() ){
  791. hr = WBEM_E_OUT_OF_MEMORY; break;
  792. }
  793. // Set the task for the request - we'll just use the existing one
  794. m_pTask->AddRef();
  795. pReq->m_phTask = m_pTask;
  796. // This may sleep, so exit the critsec before calling into this
  797. ics.Leave();
  798. hr = ConfigMgr::EnqueueRequest( pReq.get() );
  799. if ( SUCCEEDED(hr) ) pReq.release(); // queue took ownership
  800. // reenter the critsec
  801. ics.Enter();
  802. } // For schedule requests
  803. } // IF !SingleStaticRequest
  804. }while(0);
  805. // If we have to cancel, do so OUTSIDE of the critsec
  806. ics.Leave();
  807. if ( FAILED( hr ) )
  808. {
  809. Cancel( hr );
  810. }
  811. return hr;
  812. }
  813. // Schedules a child class request
  814. HRESULT CWmiMerger::ScheduleMergerChildRequest( CWmiMergerRecord* pParentRecord )
  815. {
  816. // Check if query arbitration is enabled
  817. if (!ConfigMgr::GetEnableQueryArbitration()) return WBEM_S_NO_ERROR;
  818. CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  819. HRESULT hr = WBEM_S_NO_ERROR;
  820. // We must be in a success state and not have previously scheduled a child
  821. // request.
  822. do
  823. {
  824. if (FAILED(m_hOperationRes))
  825. {
  826. hr = m_hOperationRes; break;
  827. }
  828. if (pParentRecord->ScheduledChildRequest())
  829. {
  830. break; // if already scheduled, bail out, with success
  831. }
  832. // If there isn't a task, we've got a BIG problem.
  833. _DBG_ASSERT( NULL != m_pTask );
  834. if ( NULL == m_pTask )
  835. {
  836. hr = WBEM_E_FAILED; break;
  837. }
  838. wmilib::auto_ptr<CMergerChildReq> pReq;
  839. pReq.reset(new CMergerChildReq (this,pParentRecord,
  840. m_pNamespace,m_pTargetSink,
  841. pParentRecord->GetExecutionContext()));
  842. if (NULL == pReq.get())
  843. {
  844. hr = WBEM_E_OUT_OF_MEMORY; break;
  845. }
  846. if ( NULL == pReq->GetContext())
  847. {
  848. hr = WBEM_E_OUT_OF_MEMORY; break;
  849. }
  850. // Set the task for the request - we'll just use the existing one
  851. m_pTask->AddRef();
  852. pReq->m_phTask = m_pTask;
  853. // This may sleep, so exit the critsec before calling into this
  854. ics.Leave();
  855. hr = ConfigMgr::EnqueueRequest( pReq.get() );
  856. ics.Enter();
  857. if (SUCCEEDED(hr))
  858. {
  859. // We've basically scheduled one at this point
  860. pParentRecord->SetScheduledChildRequest();
  861. pReq.release();
  862. }
  863. }while(0);
  864. // If we have to cancel, do so OUTSIDE of the critsec
  865. ics.Leave();
  866. if (FAILED(hr)) Cancel(hr);
  867. return hr;
  868. }
  869. // Returns whether or not we have a single static class request in the merger
  870. // or not
  871. BOOL CWmiMerger::IsSingleStaticRequest( void )
  872. {
  873. CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  874. BOOL fRet = FALSE;
  875. if ( NULL != m_pRequestMgr )
  876. {
  877. // Ask if we've got a single request
  878. fRet = m_pRequestMgr->HasSingleStaticRequest();
  879. } // IF NULL != m_pRequestMgr
  880. return fRet;
  881. }
  882. //
  883. // CWmiMergerRecord
  884. //
  885. // Support class for CWmiMerger - encapsulates sub-sink functionality for the CWmiMerger
  886. // class. The merger calls the records which actually know whether or not they sit on
  887. // top of sinks or actual mergers.
  888. //
  889. CWmiMergerRecord::CWmiMergerRecord( CWmiMerger* pMerger, BOOL fHasInstances,
  890. BOOL fHasChildren, LPCWSTR pwszClass, CMergerSink* pDestSink, DWORD dwLevel,
  891. bool bStatic )
  892. : m_pMerger( pMerger ),
  893. m_fHasInstances( fHasInstances ),
  894. m_fHasChildren( fHasChildren ),
  895. m_dwLevel( dwLevel ),
  896. m_wsClass( pwszClass ), // throw
  897. m_pDestSink( pDestSink ),
  898. m_pInternalMerger( NULL ),
  899. m_ChildArray(),
  900. m_bScheduledChildRequest( false ),
  901. m_pExecutionContext( NULL ),
  902. m_bStatic( bStatic )
  903. {
  904. // No Addrefing internal sinks, since they really AddRef the entire merger
  905. // and we don't want to create Circular Dependencies
  906. }
  907. CWmiMergerRecord::~CWmiMergerRecord()
  908. {
  909. if ( NULL != m_pInternalMerger )
  910. {
  911. delete m_pInternalMerger;
  912. }
  913. if ( NULL != m_pExecutionContext )
  914. {
  915. m_pExecutionContext->Release();
  916. }
  917. }
  918. HRESULT CWmiMergerRecord::AttachInternalMerger( CWbemClass* pClass, CWbemNamespace* pNamespace,
  919. IWbemContext* pCtx, BOOL fDerivedFromTarget,
  920. bool bStatic )
  921. {
  922. if ( NULL != m_pInternalMerger )
  923. {
  924. return WBEM_E_INVALID_OPERATION;
  925. }
  926. HRESULT hr = WBEM_S_NO_ERROR;
  927. // m_pDestSink is not addrefed by the MergerRecord
  928. m_pInternalMerger = new CInternalMerger( this, m_pDestSink, pClass, pNamespace, pCtx );
  929. if ( NULL == m_pInternalMerger ) return WBEM_E_OUT_OF_MEMORY;
  930. hr = m_pInternalMerger->Initialize();
  931. if ( FAILED( hr ) )
  932. {
  933. delete m_pInternalMerger;
  934. m_pInternalMerger = NULL;
  935. }
  936. else
  937. {
  938. m_pInternalMerger->SetIsDerivedFromTarget( fDerivedFromTarget );
  939. }
  940. return hr;
  941. }
  942. CMergerSink* CWmiMergerRecord::GetChildSink( void )
  943. {
  944. CMergerSink* pSink = NULL;
  945. if ( NULL != m_pInternalMerger )
  946. {
  947. pSink = m_pInternalMerger->GetChildSink();
  948. }
  949. else if ( m_fHasChildren )
  950. {
  951. m_pDestSink->AddRef(); // addref-it before giving-it out, but not ref for itself
  952. pSink = m_pDestSink;
  953. }
  954. return pSink;
  955. }
  956. CMergerSink* CWmiMergerRecord::GetOwnSink( void )
  957. {
  958. CMergerSink* pSink = NULL;
  959. if ( NULL != m_pInternalMerger )
  960. {
  961. pSink = m_pInternalMerger->GetOwnSink();
  962. }
  963. else if ( !m_fHasChildren )
  964. {
  965. m_pDestSink->AddRef();
  966. pSink = m_pDestSink; // addref-it before giving-it out, but not ref for itself
  967. }
  968. return pSink;
  969. }
  970. CMergerSink* CWmiMergerRecord::GetDestSink( void )
  971. {
  972. if ( NULL != m_pDestSink )
  973. {
  974. m_pDestSink->AddRef();
  975. }
  976. // addref-it before giving-it out, but not ref for itself
  977. CMergerSink* pSink = m_pDestSink;
  978. return pSink;
  979. }
  980. void CWmiMergerRecord::Cancel( HRESULT hRes )
  981. {
  982. if ( NULL != m_pInternalMerger )
  983. {
  984. m_pInternalMerger->Cancel( hRes );
  985. }
  986. }
  987. HRESULT CWmiMergerRecord::AddChild( CWmiMergerRecord* pRecord )
  988. {
  989. HRESULT hr = WBEM_S_NO_ERROR;
  990. if ( m_ChildArray.Add( pRecord ) < 0 )
  991. {
  992. hr = WBEM_E_OUT_OF_MEMORY;
  993. }
  994. return hr;
  995. }
  996. CWmiMergerRecord* CWmiMergerRecord::GetChildRecord( int nIndex )
  997. {
  998. // Check if the index is a valid record, then return it
  999. if ( nIndex < m_ChildArray.GetSize() )
  1000. {
  1001. return m_ChildArray[nIndex];
  1002. }
  1003. return NULL;
  1004. }
  1005. HRESULT CWmiMergerRecord::SetExecutionContext( IWbemContext* pContext )
  1006. {
  1007. // We can only do this once
  1008. _DBG_ASSERT( NULL == m_pExecutionContext );
  1009. if ( NULL != m_pExecutionContext )
  1010. {
  1011. return WBEM_E_INVALID_OPERATION;
  1012. }
  1013. if (pContext)
  1014. {
  1015. pContext->AddRef();
  1016. m_pExecutionContext = pContext;
  1017. }
  1018. else
  1019. {
  1020. return WBEM_E_INVALID_PARAMETER;
  1021. }
  1022. return WBEM_S_NO_ERROR;
  1023. }