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.

627 lines
15 KiB

  1. /*++
  2. Copyright (C) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. History:
  6. --*/
  7. //***************************************************************************
  8. //
  9. // REFRESHR.CPP
  10. //
  11. // Mapped NT5 Perf Counter Provider
  12. //
  13. // raymcc 02-Dec-97 Created.
  14. // raymcc 20-Feb-98 Updated to use new initializer.
  15. //
  16. //***************************************************************************
  17. #include "precomp.h"
  18. #include <stdio.h>
  19. #include <wbemidl.h>
  20. #include <wbemint.h>
  21. #include "flexarry.h"
  22. #include "ntperf.h"
  23. #include "oahelp.inl"
  24. #include "refreshr.h"
  25. #include "perfhelp.h"
  26. inline wchar_t *Macro_CloneLPWSTR(LPCWSTR src)
  27. {
  28. if (!src)
  29. return 0;
  30. wchar_t *dest = new wchar_t[wcslen(src) + 1];
  31. if (!dest)
  32. return 0;
  33. return wcscpy(dest, src);
  34. }
  35. //***************************************************************************
  36. //
  37. // RefresherCacheEl::RefresherCacheEl
  38. //
  39. // Constructor
  40. //
  41. //***************************************************************************
  42. // ok
  43. RefresherCacheEl::RefresherCacheEl()
  44. {
  45. m_dwPerfObjIx = 0;
  46. m_pClassMap = 0;
  47. m_pSingleton = 0;
  48. }
  49. //***************************************************************************
  50. //
  51. // RefresherCacheEl::~RefresherCacheEl()
  52. //
  53. // Destructor
  54. //
  55. //***************************************************************************
  56. // ok
  57. RefresherCacheEl::~RefresherCacheEl()
  58. {
  59. delete m_pClassMap;
  60. if (m_pSingleton)
  61. m_pSingleton->Release();
  62. for (int i = 0; i < m_aInstances.Size(); i++)
  63. delete (CachedInst *) m_aInstances[i];
  64. }
  65. //***************************************************************************
  66. //
  67. // CNt5Refresher constructor
  68. //
  69. //***************************************************************************
  70. // ok
  71. CNt5Refresher::CNt5Refresher()
  72. {
  73. m_lRef = 0; // COM Ref Count
  74. m_lProbableId = 1; // Used for new IDs
  75. }
  76. //***************************************************************************
  77. //
  78. // CNt5Refresher destructor
  79. //
  80. //***************************************************************************
  81. // ok
  82. CNt5Refresher::~CNt5Refresher()
  83. {
  84. for (int i = 0; i < m_aCache.Size(); i++)
  85. delete PRefresherCacheEl(m_aCache[i]);
  86. }
  87. //***************************************************************************
  88. //
  89. // CNt5Refresher::Refresh
  90. //
  91. // Executed to refresh a set of instances bound to the particular
  92. // refresher.
  93. //
  94. //***************************************************************************
  95. // ok
  96. HRESULT CNt5Refresher::Refresh(/* [in] */ long lFlags)
  97. {
  98. BOOL bRes = PerfHelper::RefreshInstances(this);
  99. if (!bRes)
  100. return WBEM_E_FAILED;
  101. return WBEM_S_NO_ERROR;
  102. }
  103. //***************************************************************************
  104. //
  105. // CNt5Refresher::AddRef
  106. //
  107. // Standard COM AddRef().
  108. //
  109. //***************************************************************************
  110. // ok
  111. ULONG CNt5Refresher::AddRef()
  112. {
  113. return InterlockedIncrement(&m_lRef);
  114. }
  115. //***************************************************************************
  116. //
  117. // CNt5Refresher::Release
  118. //
  119. // Standard COM Release().
  120. //
  121. //***************************************************************************
  122. // ok
  123. ULONG CNt5Refresher::Release()
  124. {
  125. long lRef = InterlockedDecrement(&m_lRef);
  126. if(lRef == 0)
  127. delete this;
  128. return lRef;
  129. }
  130. //***************************************************************************
  131. //
  132. // CNt5Refresher::QueryInterface
  133. //
  134. // Standard COM QueryInterface().
  135. //
  136. //***************************************************************************
  137. // ok
  138. HRESULT CNt5Refresher::QueryInterface(REFIID riid, void** ppv)
  139. {
  140. if (riid == IID_IUnknown || riid == IID_IWbemRefresher)
  141. {
  142. *ppv = (IWbemRefresher *) this;
  143. AddRef();
  144. return S_OK;
  145. }
  146. else return E_NOINTERFACE;
  147. }
  148. //***************************************************************************
  149. //
  150. // CNt5Refresher::RemoveObject
  151. //
  152. // Removes an object from the refresher. Since we don't know
  153. // by ID alone which class it is, we loop through all the ones we
  154. // have until somebody claims it and returns TRUE for a removal.(
  155. //
  156. //***************************************************************************
  157. // ok
  158. BOOL CNt5Refresher::RemoveObject(LONG lId)
  159. {
  160. for (int i = 0; i < m_aCache.Size(); i++)
  161. {
  162. PRefresherCacheEl pCacheEl = PRefresherCacheEl(m_aCache[i]);
  163. BOOL bRes = pCacheEl->RemoveInst(lId);
  164. if (bRes == TRUE)
  165. return TRUE;
  166. }
  167. return FALSE;
  168. }
  169. //***************************************************************************
  170. //
  171. // CNt5Refresher::FindSingletonInst
  172. //
  173. // Based on a perf object identification, locates a singleton WBEM
  174. // instance of that class within this refresher and returns the pointer
  175. // to it and its WBEM class info.
  176. //
  177. // Note that the <dwPerfObjIx> maps directly to a WBEM Class entry.
  178. //
  179. // To save execution time, we don't AddRef() the return value and the
  180. // caller doesn't Release().
  181. //
  182. //***************************************************************************
  183. // ok
  184. BOOL CNt5Refresher::FindSingletonInst(
  185. IN DWORD dwPerfObjIx,
  186. OUT IWbemObjectAccess **pInst,
  187. OUT CClassMapInfo **pClsMap
  188. )
  189. {
  190. // Binary search the cache.
  191. // ========================
  192. int l = 0, u = m_aCache.Size() - 1;
  193. while (l <= u)
  194. {
  195. int m = (l + u) / 2;
  196. PRefresherCacheEl pCacheEl = PRefresherCacheEl(m_aCache[m]);
  197. if (dwPerfObjIx < pCacheEl->m_dwPerfObjIx)
  198. u = m - 1;
  199. else if (dwPerfObjIx > pCacheEl->m_dwPerfObjIx)
  200. l = m + 1;
  201. else
  202. {
  203. *pClsMap = pCacheEl->m_pClassMap;
  204. *pInst = pCacheEl->m_pSingleton; // No AddRef() caller doesn't
  205. // change ref count
  206. return TRUE;
  207. }
  208. }
  209. // Not found
  210. // =========
  211. return FALSE;
  212. }
  213. //***************************************************************************
  214. //
  215. // CNt5Refresher::FindInst
  216. //
  217. // Based on a perf object identification, locates a WBEM instance of
  218. // that class within this refresher and returns the pointer to it.
  219. //
  220. // Note that the <dwPerfObjIx> maps directly to a WBEM Class entry.
  221. //
  222. // To save execution time, we don't AddRef() the return value and the
  223. // caller doesn't Release().
  224. //
  225. //***************************************************************************
  226. // ok
  227. BOOL CNt5Refresher::FindInst(
  228. IN DWORD dwPerfObjIx,
  229. IN LPWSTR pszInstName,
  230. OUT IWbemObjectAccess **pInst,
  231. OUT CClassMapInfo **pClsMap
  232. )
  233. {
  234. // Binary search the cache.
  235. // ========================
  236. int l = 0, u = m_aCache.Size() - 1;
  237. while (l <= u)
  238. {
  239. int m = (l + u) / 2;
  240. PRefresherCacheEl pCacheEl = PRefresherCacheEl(m_aCache[m]);
  241. if (dwPerfObjIx < pCacheEl->m_dwPerfObjIx)
  242. u = m - 1;
  243. else if (dwPerfObjIx > pCacheEl->m_dwPerfObjIx)
  244. l = m + 1;
  245. else
  246. {
  247. // We found the class. Now do we have the instance?
  248. // =================================================
  249. IWbemObjectAccess *pTmp = pCacheEl->FindInst(pszInstName);
  250. if (pTmp == 0)
  251. return FALSE; // Didn't have it.
  252. *pInst = pTmp;
  253. *pClsMap = pCacheEl->m_pClassMap;
  254. return TRUE;
  255. }
  256. }
  257. // Not found
  258. // =========
  259. return FALSE;
  260. }
  261. //***************************************************************************
  262. //
  263. // CNt5Refresher::GetObjectIds
  264. //
  265. // Gets a list of all the perf object Ids corresponding to the instances
  266. // in the refresher.
  267. //
  268. // Caller uses operator delete to deallocate the returned array.
  269. //
  270. //***************************************************************************
  271. // ok
  272. BOOL CNt5Refresher::GetObjectIds(
  273. DWORD *pdwNumIds,
  274. DWORD **pdwIdList
  275. )
  276. {
  277. DWORD *pdwIds = new DWORD[m_aCache.Size()];
  278. for (int i = 0; i < m_aCache.Size(); i++)
  279. pdwIds[i] = PRefresherCacheEl(m_aCache[i])->m_dwPerfObjIx;
  280. *pdwIdList = pdwIds;
  281. *pdwNumIds = DWORD(m_aCache.Size());
  282. return TRUE;
  283. }
  284. //***************************************************************************
  285. //
  286. // CNt5Refresher::FindUnusedId
  287. //
  288. // Finds an ID not in use for new objects to be added to the refresher.
  289. //
  290. //***************************************************************************
  291. // ok
  292. LONG CNt5Refresher::FindUnusedId()
  293. {
  294. PRefresherCacheEl pEl;
  295. int nRetries = 0x100000; // A million retries
  296. Restart: while (nRetries--)
  297. {
  298. for (int i = 0; i < m_aCache.Size(); i++)
  299. pEl = PRefresherCacheEl(m_aCache[i]);
  300. {
  301. for (int i2 = 0; i2 < pEl->m_aInstances.Size(); i2++)
  302. {
  303. PCachedInst pInst = (PCachedInst) pEl->m_aInstances[i2];
  304. if (pInst->m_lId == m_lProbableId)
  305. {
  306. m_lProbableId++;
  307. goto Restart;
  308. }
  309. }
  310. }
  311. return m_lProbableId;
  312. }
  313. return -1;
  314. }
  315. //***************************************************************************
  316. //
  317. // RefresherCacheEl::RemoveInst
  318. //
  319. // Removes the requested instances from the cache element for a particular
  320. // class.
  321. //
  322. //***************************************************************************
  323. // ok
  324. BOOL RefresherCacheEl::RemoveInst(LONG lId)
  325. {
  326. for (int i = 0; i < m_aInstances.Size(); i++)
  327. {
  328. PCachedInst pInst = (PCachedInst) m_aInstances[i];
  329. if (lId == pInst->m_lId)
  330. {
  331. delete pInst;
  332. m_aInstances.RemoveAt(i);
  333. return TRUE;
  334. }
  335. }
  336. return FALSE;
  337. }
  338. //***************************************************************************
  339. //
  340. // CNt5Refresher::AddObject
  341. //
  342. // Adds the requested object to the refresher and assigns an ID
  343. // to it.
  344. //
  345. //***************************************************************************
  346. // ?
  347. BOOL CNt5Refresher::AddObject(
  348. IN IWbemObjectAccess *pObj, // Object to add
  349. IN CClassMapInfo *pClsMap, // Class of object
  350. OUT LONG *plId // The id of the object added
  351. )
  352. {
  353. BOOL bRes;
  354. LONG lNewId = FindUnusedId();
  355. if (lNewId == -1)
  356. return FALSE;
  357. // First, find the cache element corresponding to this object.
  358. // ===========================================================
  359. PRefresherCacheEl pWorkEl = GetCacheEl(pClsMap);
  360. // If <pWorkEl> is NULL, we didn't have anything in the cache
  361. // and have to add a new one.
  362. // ==========================================================
  363. if (pWorkEl == 0)
  364. {
  365. bRes = AddNewCacheEl(pClsMap, &pWorkEl);
  366. if (bRes == FALSE)
  367. return FALSE;
  368. }
  369. // If here, we have successfully added a new cache element.
  370. // ========================================================
  371. bRes = pWorkEl->InsertInst(pObj, lNewId);
  372. return bRes;
  373. }
  374. //***************************************************************************
  375. //
  376. // CNt5Refresher::AddNewCacheEl
  377. //
  378. // Adds a new cache element in the proper position so that a binary
  379. // search on perf object id can occur later.
  380. //
  381. //***************************************************************************
  382. // ok
  383. BOOL CNt5Refresher::AddNewCacheEl(
  384. IN CClassMapInfo *pClsMap,
  385. PRefresherCacheEl *pOutput
  386. )
  387. {
  388. PRefresherCacheEl pWorkEl;
  389. PRefresherCacheEl pNew = new RefresherCacheEl;
  390. pNew->m_dwPerfObjIx = pClsMap->GetObjectId();
  391. pNew->m_pClassMap = pClsMap;
  392. for (int i = 0; i < m_aCache.Size(); i++)
  393. {
  394. pWorkEl = PRefresherCacheEl(m_aCache[i]);
  395. if (pNew->m_dwPerfObjIx < pWorkEl->m_dwPerfObjIx)
  396. {
  397. m_aCache.InsertAt(i, pNew);
  398. *pOutput = pNew;
  399. return TRUE;
  400. }
  401. }
  402. // Add it to the end.
  403. // ==================
  404. m_aCache.Add(pNew);
  405. *pOutput = pNew;
  406. return TRUE;
  407. }
  408. //***************************************************************************
  409. //
  410. // CNt5Refresher::GetCacheEl
  411. //
  412. //***************************************************************************
  413. // ok
  414. PRefresherCacheEl CNt5Refresher::GetCacheEl(
  415. CClassMapInfo *pClsMap
  416. )
  417. {
  418. PRefresherCacheEl pWorkEl;
  419. for (int i = 0; i < m_aCache.Size(); i++)
  420. {
  421. pWorkEl = PRefresherCacheEl(m_aCache[i]);
  422. if (pWorkEl->m_pClassMap == pClsMap)
  423. return pWorkEl;
  424. }
  425. return 0;
  426. }
  427. //***************************************************************************
  428. //
  429. // RefresherCacheEl::FindInstance
  430. //
  431. // Finds an instance in the current cache element for a particular instance.
  432. // For this to work, the instances have to be sorted by name.
  433. //
  434. //***************************************************************************
  435. // ok
  436. IWbemObjectAccess *RefresherCacheEl::FindInst(
  437. LPWSTR pszInstName
  438. )
  439. {
  440. // Binary search the cache.
  441. // ========================
  442. int l = 0, u = m_aInstances.Size() - 1;
  443. while (l <= u)
  444. {
  445. int m = (l + u) / 2;
  446. CachedInst *pInst = PCachedInst(m_aInstances[m]);
  447. if (_wcsicmp(pszInstName, pInst->m_pName) < 0)
  448. u = m - 1;
  449. else if (_wcsicmp(pszInstName, pInst->m_pName) > 0)
  450. l = m + 1;
  451. else
  452. {
  453. // We found the instance.
  454. // ======================
  455. return pInst->m_pInst;
  456. }
  457. }
  458. // Not found
  459. // =========
  460. return 0;
  461. }
  462. //***************************************************************************
  463. //
  464. // Inserts a new instance.
  465. //
  466. //***************************************************************************
  467. BOOL RefresherCacheEl::InsertInst(IWbemObjectAccess *pNew, LONG lNewId)
  468. {
  469. // Check for singleton.
  470. // ====================
  471. if (m_pClassMap->IsSingleton())
  472. {
  473. m_pSingleton = pNew;
  474. m_lSingletonId = lNewId;
  475. m_pSingleton->AddRef();
  476. return TRUE;
  477. }
  478. // For multi-instance, get the instance name.
  479. // ==========================================
  480. IWbemClassObject *pObj;
  481. pNew->QueryInterface(IID_IWbemClassObject, (LPVOID *) &pObj);
  482. VARIANT v;
  483. VariantInit(&v);
  484. BSTR pNameProp = SysAllocString(L"Name");
  485. pObj->Get(pNameProp, 0, &v, 0, 0);
  486. SysFreeString(pNameProp);
  487. pObj->Release();
  488. // Construct the new instance.
  489. // ===========================
  490. PCachedInst pNewInst = new CachedInst;
  491. pNewInst->m_lId = lNewId;
  492. pNewInst->m_pInst = pNew;
  493. pNewInst->m_pInst->AddRef();
  494. pNewInst->m_pName = Macro_CloneLPWSTR(V_BSTR(&v));
  495. // Now place the name in the instance cache element.
  496. // =================================================
  497. for (int i = 0; i < m_aInstances.Size(); i++)
  498. {
  499. PCachedInst pTest = PCachedInst(m_aInstances[i]);
  500. if (_wcsicmp(V_BSTR(&v), pTest->m_pName) < 0)
  501. {
  502. m_aInstances.InsertAt(i, pNewInst);
  503. return TRUE;
  504. }
  505. }
  506. m_aInstances.Add(pNewInst);
  507. return TRUE;
  508. }
  509.