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.

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