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.

646 lines
24 KiB

  1. /*++
  2. Copyright (C) 1995-1999 Microsoft Corporation
  3. Module Name:
  4. qutils.c
  5. Abstract:
  6. Query management utility functions
  7. --*/
  8. #include <windows.h>
  9. #include <assert.h>
  10. #include <pdh.h>
  11. #include "pdhitype.h"
  12. #include "pdhidef.h"
  13. #include "pdhmsg.h"
  14. #include "strings.h"
  15. #include "log_bin.h"
  16. #include "log_wmi.h"
  17. #include "perftype.h"
  18. #include "perfdata.h"
  19. BOOL
  20. IsValidQuery (
  21. IN HQUERY hQuery
  22. )
  23. {
  24. BOOL bReturn = FALSE; // assume it's not a valid query
  25. PPDHI_QUERY pQuery;
  26. #if DBG
  27. LONG lStatus = ERROR_SUCCESS;
  28. #endif
  29. __try {
  30. if (hQuery != NULL) {
  31. // see if a valid signature
  32. pQuery = (PPDHI_QUERY)hQuery;
  33. if ((*(DWORD *)&pQuery->signature[0] == SigQuery) &&
  34. (pQuery->dwLength == sizeof (PDHI_QUERY))){
  35. bReturn = TRUE;
  36. } else {
  37. // this is not a valid query because the sig is bad
  38. }
  39. } else {
  40. // this is not a valid query because the handle is NULL
  41. }
  42. } __except (EXCEPTION_EXECUTE_HANDLER) {
  43. // something failed miserably so we can assume this is invalid
  44. #if DBG
  45. lStatus = GetExceptionCode();
  46. #endif
  47. }
  48. return bReturn;
  49. }
  50. BOOL
  51. AddMachineToQueryLists (
  52. IN PPERF_MACHINE pMachine,
  53. IN PPDHI_COUNTER pNewCounter
  54. )
  55. {
  56. BOOL bReturn = FALSE; // assume failure
  57. PPDHI_QUERY pQuery;
  58. PPDHI_QUERY_MACHINE pQMachine;
  59. PPDHI_QUERY_MACHINE pLastQMachine;
  60. pQuery = pNewCounter->pOwner;
  61. if (IsValidQuery(pQuery)) {
  62. assert (!(pQuery->dwFlags & PDHIQ_WBEM_QUERY));
  63. if (pQuery->pFirstQMachine != NULL) {
  64. // look for machine in list
  65. pLastQMachine = pQMachine = pQuery->pFirstQMachine;
  66. while (pQMachine != NULL) {
  67. if (pQMachine->pMachine == pMachine) {
  68. // found the machine already in the list so continue
  69. bReturn = TRUE;
  70. break;
  71. } else {
  72. pLastQMachine = pQMachine;
  73. pQMachine = pQMachine->pNext;
  74. }
  75. }
  76. if (pQMachine == NULL) {
  77. // add this machine to the end of the list
  78. pQMachine = G_ALLOC (
  79. (sizeof (PDHI_QUERY_MACHINE) +
  80. (sizeof (WCHAR) * MAX_PATH)));
  81. if (pQMachine != NULL) {
  82. pQMachine->pMachine = pMachine;
  83. pQMachine->szObjectList = (LPWSTR)(&pQMachine[1]);
  84. pQMachine->pNext = NULL;
  85. pQMachine->lQueryStatus = pMachine->dwStatus;
  86. pQMachine->llQueryTime = 0;
  87. bReturn = TRUE;
  88. // the pPerfData pointer will be tested prior to usage
  89. pQMachine->pPerfData = G_ALLOC (MEDIUM_BUFFER_SIZE);
  90. if (pQMachine->pPerfData == NULL) {
  91. G_FREE(pQMachine);
  92. pQMachine = NULL;
  93. bReturn = FALSE;
  94. SetLastError(PDH_MEMORY_ALLOCATION_FAILURE);
  95. }
  96. else {
  97. pLastQMachine->pNext = pQMachine;
  98. }
  99. } else {
  100. // unable to alloc memory block so machine cannot
  101. // be added
  102. SetLastError (PDH_MEMORY_ALLOCATION_FAILURE);
  103. }
  104. }
  105. } else {
  106. // add this as the first machine
  107. pQMachine = G_ALLOC (
  108. (sizeof (PDHI_QUERY_MACHINE) +
  109. (sizeof (WCHAR) * MAX_PATH)));
  110. if (pQMachine != NULL) {
  111. pQMachine->pMachine = pMachine;
  112. pQMachine->szObjectList = (LPWSTR)(&pQMachine[1]);
  113. pQMachine->pNext = NULL;
  114. pQMachine->lQueryStatus = pMachine->dwStatus;
  115. pQMachine->llQueryTime = 0;
  116. bReturn = TRUE;
  117. // the pPerfData pointer will be tested prior to usage
  118. pQMachine->pPerfData = G_ALLOC (MEDIUM_BUFFER_SIZE);
  119. if (pQMachine->pPerfData == NULL) {
  120. G_FREE(pQMachine);
  121. pQMachine = NULL;
  122. bReturn = FALSE;
  123. SetLastError(PDH_MEMORY_ALLOCATION_FAILURE);
  124. }
  125. else {
  126. pQuery->pFirstQMachine = pQMachine;
  127. }
  128. } else {
  129. // unable to alloc memory block so machine cannot
  130. // be added
  131. SetLastError (PDH_MEMORY_ALLOCATION_FAILURE);
  132. }
  133. }
  134. // here pQMachine should be the pointer to the correct machine
  135. // entry or NULL if unable to create
  136. if (pQMachine != NULL) {
  137. assert (bReturn == TRUE);
  138. // save the new pointer
  139. pNewCounter->pQMachine = pQMachine;
  140. // increment reference count for this machine
  141. pMachine->dwRefCount++;
  142. // update query perf. object list
  143. AppendObjectToValueList (pNewCounter->plCounterInfo.dwObjectId,
  144. pQMachine->szObjectList);
  145. }
  146. } else {
  147. SetLastError (PDH_INVALID_HANDLE);
  148. bReturn = FALSE;
  149. }
  150. return bReturn;
  151. }
  152. extern PDH_FUNCTION
  153. PdhiGetBinaryLogCounterInfo (
  154. IN PPDHI_LOG pLog,
  155. IN PPDHI_COUNTER pCounter
  156. );
  157. PDH_FUNCTION
  158. PdhiGetCounterFromDataBlock(
  159. IN PPDHI_LOG pLog,
  160. IN PVOID pDataBuffer,
  161. IN PPDHI_COUNTER pCounter)
  162. {
  163. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  164. PERFLIB_COUNTER * pPerfCounter = & pCounter->plCounterInfo;
  165. PPDH_RAW_COUNTER pRawValue = & pCounter->ThisValue;
  166. WCHAR szCompositeInstance[1024];
  167. DWORD dwDataItemIndex;
  168. LPWSTR szThisInstanceName;
  169. PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord;
  170. PPDHI_BINARY_LOG_RECORD_HEADER pThisSubRecord;
  171. PPDHI_RAW_COUNTER_ITEM_BLOCK pDataBlock;
  172. PPDHI_RAW_COUNTER_ITEM pDataItem;
  173. PPDH_RAW_COUNTER pRawItem;
  174. PPERF_DATA_BLOCK pPerfData;
  175. FILETIME ftDataBlock;
  176. FILETIME ftGmtDataBlock;
  177. LONGLONG TimeStamp;
  178. memset(pRawValue, 0, sizeof(PDH_RAW_COUNTER));
  179. pThisMasterRecord = (PPDHI_BINARY_LOG_RECORD_HEADER) pDataBuffer;
  180. assert (pThisMasterRecord->dwType == BINLOG_TYPE_DATA);
  181. pThisSubRecord = PdhiGetSubRecord(pThisMasterRecord,
  182. pCounter->dwIndex);
  183. if (pThisSubRecord != NULL) {
  184. if (pThisSubRecord->dwType == BINLOG_TYPE_DATA_PSEUDO) {
  185. PDH_STATUS Status = ERROR_SUCCESS;
  186. DWORD dwOriginal = pCounter->dwIndex;
  187. DWORD dwPrevious;
  188. while (Status == ERROR_SUCCESS && pThisSubRecord) {
  189. if (pThisSubRecord->dwType != BINLOG_TYPE_DATA_PSEUDO) {
  190. break;
  191. }
  192. dwPrevious = pCounter->dwIndex;
  193. Status = PdhiGetBinaryLogCounterInfo(pLog, pCounter);
  194. if ( Status == ERROR_SUCCESS
  195. && dwPrevious != pCounter->dwIndex) {
  196. pThisSubRecord = PdhiGetSubRecord(pThisMasterRecord,
  197. pCounter->dwIndex);
  198. }
  199. }
  200. if ( pThisSubRecord == NULL
  201. || Status == PDH_ENTRY_NOT_IN_LOG_FILE) {
  202. pCounter->dwIndex = 0;
  203. do {
  204. dwPrevious = pCounter->dwIndex;
  205. Status = PdhiGetBinaryLogCounterInfo(pLog, pCounter);
  206. if ( Status == ERROR_SUCCESS
  207. && dwPrevious != pCounter->dwIndex) {
  208. pThisSubRecord = PdhiGetSubRecord(pThisMasterRecord,
  209. pCounter->dwIndex);
  210. }
  211. if (pThisSubRecord->dwType != BINLOG_TYPE_DATA_PSEUDO) {
  212. break;
  213. }
  214. }
  215. while ( Status == ERROR_SUCCESS
  216. && pCounter->dwIndex < dwOriginal
  217. && pThisSubRecord);
  218. if ( pThisSubRecord == NULL
  219. || pCounter->dwIndex >= dwOriginal) {
  220. Status = PDH_ENTRY_NOT_IN_LOG_FILE;
  221. }
  222. }
  223. if (Status == PDH_ENTRY_NOT_IN_LOG_FILE) {
  224. pCounter->dwIndex = dwOriginal;
  225. pThisSubRecord = PdhiGetSubRecord(pThisMasterRecord,
  226. pCounter->dwIndex);
  227. }
  228. }
  229. }
  230. if (pLog->pLastRecordRead != pDataBuffer) {
  231. pLog->pLastRecordRead = pDataBuffer;
  232. }
  233. if (pThisSubRecord != NULL) {
  234. switch (pThisSubRecord->dwType) {
  235. case BINLOG_TYPE_DATA_LOC_OBJECT:
  236. case BINLOG_TYPE_DATA_OBJECT:
  237. pPerfData = (PPERF_DATA_BLOCK) ((LPBYTE)pThisSubRecord +
  238. sizeof (PDHI_BINARY_LOG_RECORD_HEADER));
  239. if (pThisSubRecord->dwType == BINLOG_TYPE_DATA_OBJECT) {
  240. SystemTimeToFileTime(& pPerfData->SystemTime, & ftGmtDataBlock);
  241. FileTimeToLocalFileTime(& ftGmtDataBlock, & ftDataBlock);
  242. }
  243. else {
  244. SystemTimeToFileTime(& pPerfData->SystemTime, & ftDataBlock);
  245. }
  246. TimeStamp = MAKELONGLONG(ftDataBlock.dwLowDateTime,
  247. ftDataBlock.dwHighDateTime);
  248. if (pCounter->dwFlags & PDHIC_MULTI_INSTANCE) {
  249. UpdateMultiInstanceCounterValue(pCounter, pPerfData, TimeStamp);
  250. }
  251. else {
  252. UpdateCounterValue(pCounter, pPerfData);
  253. pCounter->ThisValue.TimeStamp = ftDataBlock;
  254. }
  255. break;
  256. case BINLOG_TYPE_DATA_PSEUDO:
  257. case BINLOG_TYPE_DATA_SINGLE:
  258. pRawItem = (PPDH_RAW_COUNTER) ((LPBYTE)pThisSubRecord +
  259. sizeof (PDHI_BINARY_LOG_RECORD_HEADER));
  260. RtlCopyMemory(pRawValue, pRawItem, sizeof (PDH_RAW_COUNTER));
  261. pdhStatus = ERROR_SUCCESS;
  262. break;
  263. case BINLOG_TYPE_DATA_MULTI:
  264. if (pCounter->dwFlags & PDHIC_MULTI_INSTANCE) {
  265. // this is a wild card query
  266. //
  267. ULONG i;
  268. ULONG CopySize = pThisSubRecord->dwLength
  269. - sizeof(PDHI_BINARY_LOG_RECORD_HEADER);
  270. PPDHI_RAW_COUNTER_ITEM_BLOCK pNewBlock = G_ALLOC(CopySize);
  271. if (pNewBlock == NULL) {
  272. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  273. }
  274. else if (pCounter->pThisRawItemList != NULL) {
  275. if (pCounter->pLastRawItemList != NULL) {
  276. G_FREE(pCounter->pLastRawItemList);
  277. }
  278. pCounter->pLastRawItemList = pCounter->pThisRawItemList;
  279. }
  280. pCounter->pThisRawItemList = pNewBlock;
  281. RtlCopyMemory(pNewBlock,
  282. ( ((LPBYTE) pThisSubRecord)
  283. + sizeof(PDHI_BINARY_LOG_RECORD_HEADER)),
  284. CopySize);
  285. assert(CopySize == pNewBlock->dwLength);
  286. }
  287. else if (pPerfCounter->szInstanceName != NULL) {
  288. DWORD dwInstanceId = pCounter->pCounterPath->dwIndex;
  289. if (pPerfCounter->szParentInstanceName != NULL) {
  290. lstrcpyW(szCompositeInstance,
  291. pPerfCounter->szParentInstanceName);
  292. lstrcatW(szCompositeInstance, cszSlash);
  293. lstrcatW(szCompositeInstance, pPerfCounter->szInstanceName);
  294. }
  295. else {
  296. lstrcpyW(szCompositeInstance, pPerfCounter->szInstanceName);
  297. }
  298. pDataBlock = (PPDHI_RAW_COUNTER_ITEM_BLOCK)
  299. ( (LPBYTE) pThisSubRecord
  300. + sizeof (PDHI_BINARY_LOG_RECORD_HEADER));
  301. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  302. pRawValue->CStatus = PDH_CSTATUS_NO_INSTANCE;
  303. for (dwDataItemIndex = 0;
  304. dwDataItemIndex < pDataBlock->dwItemCount;
  305. dwDataItemIndex++) {
  306. pDataItem = &pDataBlock->pItemArray[dwDataItemIndex];
  307. szThisInstanceName = (LPWSTR)
  308. ( (LPBYTE) pDataBlock
  309. + (DWORD_PTR)pDataItem->szName);
  310. if (lstrcmpiW(szThisInstanceName,
  311. szCompositeInstance) == 0) {
  312. if (dwInstanceId == 0) {
  313. pdhStatus = ERROR_SUCCESS;
  314. pRawValue->CStatus = pDataBlock->CStatus;
  315. pRawValue->TimeStamp = pDataBlock->TimeStamp;
  316. pRawValue->FirstValue = pDataItem->FirstValue;
  317. pRawValue->SecondValue = pDataItem->SecondValue;
  318. pRawValue->MultiCount = pDataItem->MultiCount;
  319. break;
  320. }
  321. else {
  322. dwInstanceId --;
  323. }
  324. }
  325. }
  326. }
  327. else {
  328. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  329. pRawValue->CStatus = PDH_CSTATUS_INVALID_DATA;
  330. }
  331. break;
  332. default:
  333. pdhStatus = PDH_LOG_TYPE_NOT_FOUND;
  334. pRawValue->CStatus = PDH_CSTATUS_INVALID_DATA;
  335. break;
  336. }
  337. }
  338. else {
  339. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  340. pRawValue->CStatus = PDH_CSTATUS_INVALID_DATA;
  341. }
  342. return pdhStatus;
  343. }
  344. LONG
  345. GetQueryPerfData (
  346. IN PPDHI_QUERY pQuery,
  347. IN LONGLONG *pTimeStamp
  348. )
  349. {
  350. LONG lStatus = PDH_INVALID_DATA;
  351. PPDHI_COUNTER pCounter;
  352. PPDHI_QUERY_MACHINE pQMachine;
  353. LONGLONG llCurrentTime;
  354. LONGLONG llTimeStamp = 0;
  355. BOOLEAN bCounterCollected = FALSE;
  356. BOOL bLastLogEntry;
  357. if (pQuery->hLog == H_REALTIME_DATASOURCE) {
  358. FILETIME LocFileTime;
  359. // this is a real-time query so
  360. // get the current data from each of the machines in the query
  361. // (after this "sequential" approach is perfected, then the
  362. // "parallel" approach of multiple threads can be developed
  363. //
  364. // get time stamp now so each machine will have the same time
  365. GetSystemTimeAsFileTime(& LocFileTime);
  366. llTimeStamp = MAKELONGLONG(LocFileTime.dwLowDateTime,
  367. LocFileTime.dwHighDateTime);
  368. assert (!(pQuery->dwFlags & PDHIQ_WBEM_QUERY));
  369. //
  370. pQMachine = pQuery->pFirstQMachine;
  371. while (pQMachine != NULL) {
  372. pQMachine->llQueryTime = llTimeStamp;
  373. lStatus = ValidateMachineConnection (pQMachine->pMachine);
  374. if (lStatus == ERROR_SUCCESS) {
  375. // machine is connected so get data
  376. lStatus = GetSystemPerfData (
  377. pQMachine->pMachine->hKeyPerformanceData,
  378. &pQMachine->pPerfData,
  379. pQMachine->szObjectList,
  380. FALSE); // never query the costly data objects as a group
  381. // save the machine's last status
  382. pQMachine->pMachine->dwStatus = lStatus;
  383. // if there was an error in the data collection,
  384. // set the retry counter and wait to try again.
  385. if (lStatus != ERROR_SUCCESS) {
  386. GetLocalFileTime (&llCurrentTime);
  387. pQMachine->pMachine->llRetryTime =
  388. llCurrentTime + RETRY_TIME_INTERVAL;
  389. }
  390. }
  391. pQMachine->lQueryStatus = lStatus;
  392. // get next machine in query
  393. pQMachine = pQMachine->pNext;
  394. }
  395. // now update the counters using this new data
  396. if ((pCounter = pQuery->pCounterListHead) != NULL) {
  397. DWORD dwCollected = 0;
  398. do {
  399. if (pCounter->dwFlags & PDHIC_COUNTER_OBJECT) {
  400. if (UpdateCounterObject(pCounter)) {
  401. dwCollected ++;
  402. }
  403. }
  404. else if (pCounter->dwFlags & PDHIC_MULTI_INSTANCE) {
  405. if (UpdateRealTimeMultiInstanceCounterValue (pCounter)) {
  406. dwCollected ++;
  407. }
  408. } else {
  409. // update single instance counter values
  410. if (UpdateRealTimeCounterValue(pCounter)) {
  411. dwCollected ++;
  412. }
  413. }
  414. pCounter = pCounter->next.flink;
  415. } while (pCounter != NULL && pCounter != pQuery->pCounterListHead);
  416. lStatus = (dwCollected > 0) ? ERROR_SUCCESS : PDH_NO_DATA;
  417. } else {
  418. // no counters in the query (?!)
  419. lStatus = PDH_NO_DATA;
  420. }
  421. } else {
  422. // read data from log file
  423. // get the next log record entry and update the
  424. // corresponding counter entries
  425. PPDHI_LOG pLog = NULL;
  426. DWORD dwLogType = 0;
  427. __try {
  428. pLog = (PPDHI_LOG) (pQuery->hLog);
  429. dwLogType = LOWORD(pLog->dwLogFormat);
  430. lStatus = ERROR_SUCCESS;
  431. }
  432. __except (EXCEPTION_EXECUTE_HANDLER) {
  433. pQuery->dwLastLogIndex = (ULONG)-1;
  434. lStatus = PDH_INVALID_HANDLE;
  435. }
  436. if (lStatus == ERROR_SUCCESS) {
  437. if (dwLogType == PDH_LOG_TYPE_BINARY) {
  438. if (pQuery->dwLastLogIndex == 0) {
  439. lStatus = PdhiReadTimeWmiRecord(
  440. pLog,
  441. * (ULONGLONG *) & pQuery->TimeRange.StartTime,
  442. NULL,
  443. 0);
  444. pQuery->dwLastLogIndex = BINLOG_FIRST_DATA_RECORD;
  445. }
  446. else {
  447. lStatus = PdhiReadNextWmiRecord(pLog, NULL, 0, TRUE);
  448. }
  449. if (lStatus != ERROR_SUCCESS && lStatus != PDH_MORE_DATA) {
  450. pQuery->dwLastLogIndex = (DWORD) -1;
  451. }
  452. else {
  453. pQuery->dwLastLogIndex --;
  454. }
  455. } else if (pQuery->dwLastLogIndex == 0) {
  456. // then the first matching entry needs to be
  457. // located in the log file
  458. lStatus = PdhiGetMatchingLogRecord (
  459. pQuery->hLog,
  460. (LONGLONG *)&pQuery->TimeRange.StartTime,
  461. &pQuery->dwLastLogIndex);
  462. if (lStatus != ERROR_SUCCESS) {
  463. // the matching time entry wasn't found in the log
  464. pQuery->dwLastLogIndex = (DWORD) -1;
  465. } else {
  466. // decrement the index so it can be incremented
  467. // below. 0 is not a valid entry so there's no
  468. // worry about -1 being attempted accidently.
  469. pQuery->dwLastLogIndex--;
  470. }
  471. } else {
  472. // not WMI and not a time record no positioning required
  473. }
  474. if (pQuery->dwLastLogIndex != (DWORD)-1) {
  475. bLastLogEntry = FALSE;
  476. pQuery->dwLastLogIndex++; // go to next entry
  477. if ((pCounter = pQuery->pCounterListHead) != NULL) {
  478. DWORD dwCounter = 0;
  479. do {
  480. if (dwLogType == PDH_LOG_TYPE_BINARY) {
  481. // save current value as last value since we are getting
  482. // a new one, hopefully.
  483. pCounter->LastValue = pCounter->ThisValue;
  484. lStatus = PdhiGetCounterFromDataBlock(
  485. pLog,
  486. pLog->pLastRecordRead,
  487. pCounter);
  488. }
  489. else {
  490. lStatus = PdhiGetCounterValueFromLogFile(
  491. pQuery->hLog,
  492. pQuery->dwLastLogIndex,
  493. pCounter);
  494. }
  495. if (lStatus != ERROR_SUCCESS) {
  496. // see if this is because there's no more entries
  497. if (lStatus == PDH_NO_MORE_DATA) {
  498. bLastLogEntry = TRUE;
  499. break;
  500. }
  501. } else {
  502. // single entry or multiple entries
  503. //
  504. if (pCounter->ThisValue.CStatus == PDH_CSTATUS_VALID_DATA) {
  505. llTimeStamp = MAKELONGLONG(
  506. pCounter->ThisValue.TimeStamp.dwLowDateTime,
  507. pCounter->ThisValue.TimeStamp.dwHighDateTime);
  508. if (llTimeStamp > (pQuery->TimeRange.EndTime)) {
  509. lStatus = PDH_NO_MORE_DATA;
  510. bLastLogEntry = TRUE;
  511. break;
  512. }
  513. dwCounter ++;
  514. }
  515. bCounterCollected = TRUE;
  516. }
  517. // go to next counter in list
  518. pCounter = pCounter->next.flink;
  519. } while (pCounter != NULL && pCounter != pQuery->pCounterListHead);
  520. if (bLastLogEntry){
  521. lStatus = PDH_NO_MORE_DATA;
  522. }
  523. else if (dwCounter == 0) {
  524. lStatus = PDH_NO_DATA;
  525. }
  526. else if (bCounterCollected) {
  527. lStatus = ERROR_SUCCESS;
  528. }
  529. } else {
  530. // no counters in the query (?!)
  531. lStatus = PDH_NO_DATA;
  532. }
  533. } else {
  534. // all samples in the requested time frame have
  535. // been returned.
  536. lStatus = PDH_NO_MORE_DATA;
  537. }
  538. }
  539. }
  540. *pTimeStamp = llTimeStamp;
  541. return lStatus;
  542. }
  543. DWORD
  544. WINAPI
  545. PdhiAsyncTimerThreadProc (
  546. LPVOID pArg
  547. )
  548. {
  549. PPDHI_QUERY pQuery;
  550. DWORD dwMsWaitTime;
  551. PDH_STATUS Status;
  552. FILETIME ftStart;
  553. FILETIME ftStop;
  554. LONGLONG llAdjustment;
  555. DWORD dwInterval;
  556. LONG lStatus = ERROR_SUCCESS;
  557. LONGLONG llTimeStamp;
  558. pQuery = (PPDHI_QUERY)pArg;
  559. dwInterval =
  560. dwMsWaitTime = pQuery->dwInterval * 1000; // convert sec. to mS.
  561. // wait for timeout or exit event, then update the specified query
  562. while ((lStatus = WaitForSingleObject (pQuery->hExitEvent, dwMsWaitTime)) != WAIT_OBJECT_0) {
  563. // time out elapsed so get new sample.
  564. GetSystemTimeAsFileTime (&ftStart);
  565. lStatus = WAIT_FOR_AND_LOCK_MUTEX(pQuery->hMutex);
  566. if (lStatus == ERROR_SUCCESS) {
  567. if (pQuery->dwFlags & PDHIQ_WBEM_QUERY) {
  568. Status = GetQueryWbemData (pQuery, &llTimeStamp);
  569. } else {
  570. Status = GetQueryPerfData (pQuery, &llTimeStamp);
  571. }
  572. SetEvent (pQuery->hNewDataEvent);
  573. RELEASE_MUTEX(pQuery->hMutex);
  574. GetSystemTimeAsFileTime (&ftStop);
  575. llAdjustment = *(LONGLONG *)&ftStop;
  576. llAdjustment -= *(LONGLONG *)&ftStart;
  577. llAdjustment += 5000; // for rounding
  578. llAdjustment /= 10000; // convert 100ns Units to ms
  579. if (dwInterval > llAdjustment) {
  580. dwMsWaitTime = dwInterval -
  581. (DWORD)(llAdjustment & 0x00000000FFFFFFFF);
  582. } else {
  583. dwMsWaitTime = 0; // overdue so do it now.
  584. }
  585. }
  586. }
  587. return lStatus;
  588. }