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.

1070 lines
31 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1993 - 2002.
  5. //
  6. // File: perfCI.cxx
  7. //
  8. // Contents: Functions for collecting data to Performance Monitor
  9. //
  10. // History: 23-March-94 t-joshh Created
  11. // 10-May-99 dlee Cleanup
  12. //
  13. //----------------------------------------------------------------------------
  14. #include <pch.cxx>
  15. #pragma hdrstop
  16. #include <perfci.hxx>
  17. #include "prfutil.hxx"
  18. #include "perfobj2.hxx"
  19. extern FILTER_DATA_DEFINITION FILTERDataDefinition;
  20. extern CI_DATA_DEFINITION CIDataDefinition;
  21. extern BOOL g_fPerfmonCounterHackIsProcessDetached;
  22. CReadUserPerfData * g_pReadUserPerfData = 0;
  23. CReadKernelPerfData * g_pReadKernelPerfData = 0;
  24. WCHAR FILTERPerformanceKeyName[] =
  25. TEXT("SYSTEM\\CurrentControlSet\\Services\\ContentFilter\\Performance");
  26. WCHAR CIPerformanceKeyName[] =
  27. TEXT("SYSTEM\\CurrentControlSet\\Services\\ContentIndex\\Performance");
  28. WCHAR FirstCounterKeyName [] = TEXT("First Counter");
  29. WCHAR FirstHelpKeyName [] = TEXT("First Help");
  30. const CI_DATA_DEFINITION CIDataDefinitionFixed = {
  31. { sizeof(CI_DATA_DEFINITION)+
  32. CI_SIZE_OF_COUNTER_BLOCK, // Total Bytes ( Size of this header, the counter definitions
  33. // and the size of the actual counter data )
  34. sizeof(CI_DATA_DEFINITION), // Definition length ( This header and the counter definitions )
  35. sizeof(PERF_OBJECT_TYPE), // Header Length ( This header )
  36. CIOBJECT, // Object Name Title Index
  37. 0, // Object Name Title
  38. CIOBJECT, // Object Help Title Index
  39. 0, // Object Help Title
  40. PERF_DETAIL_NOVICE, // Detail Level
  41. CI_TOTAL_NUM_COUNTERS, // Number of Counters
  42. 0, // Default Counters
  43. 0, // Num Instances
  44. 0, // Code Page
  45. {0,0}, // Perf Time
  46. {0,0} // Perf Freq
  47. },
  48. { sizeof(PERF_COUNTER_DEFINITION), // Wordlist
  49. NUM_WORDLIST,
  50. 0,
  51. NUM_WORDLIST,
  52. 0,
  53. 0,
  54. PERF_DETAIL_NOVICE,
  55. PERF_COUNTER_RAWCOUNT,
  56. sizeof(DWORD),
  57. NUM_WORDLIST_OFF
  58. },
  59. { sizeof(PERF_COUNTER_DEFINITION), // PersistentIndex
  60. NUM_PERSISTENT_INDEX,
  61. 0,
  62. NUM_PERSISTENT_INDEX,
  63. 0,
  64. 0,
  65. PERF_DETAIL_NOVICE,
  66. PERF_COUNTER_RAWCOUNT,
  67. sizeof(DWORD),
  68. NUM_PERSISTENT_INDEX_OFF
  69. },
  70. { sizeof(PERF_COUNTER_DEFINITION), // Index Size
  71. INDEX_SIZE,
  72. 0,
  73. INDEX_SIZE,
  74. 0,
  75. 0,
  76. PERF_DETAIL_NOVICE,
  77. PERF_COUNTER_RAWCOUNT,
  78. sizeof(DWORD),
  79. INDEX_SIZE_OFF
  80. },
  81. { sizeof(PERF_COUNTER_DEFINITION), // Files to-be-filtered
  82. FILES_TO_BE_FILTERED,
  83. 0,
  84. FILES_TO_BE_FILTERED,
  85. 0,
  86. 0,
  87. PERF_DETAIL_NOVICE,
  88. PERF_COUNTER_RAWCOUNT,
  89. sizeof(DWORD),
  90. FILES_TO_BE_FILTERED_OFF
  91. },
  92. { sizeof(PERF_COUNTER_DEFINITION), // Number of unique keys
  93. NUM_UNIQUE_KEY,
  94. 0,
  95. NUM_UNIQUE_KEY,
  96. 0,
  97. 0,
  98. PERF_DETAIL_NOVICE,
  99. PERF_COUNTER_RAWCOUNT,
  100. sizeof(DWORD),
  101. NUM_UNIQUE_KEY_OFF
  102. },
  103. { sizeof(PERF_COUNTER_DEFINITION), // Running Queries
  104. RUNNING_QUERIES,
  105. 0,
  106. RUNNING_QUERIES,
  107. 0,
  108. 0,
  109. PERF_DETAIL_NOVICE,
  110. PERF_COUNTER_RAWCOUNT,
  111. sizeof(DWORD),
  112. RUNNING_QUERIES_OFF
  113. },
  114. { sizeof(PERF_COUNTER_DEFINITION), // Merge Progress
  115. MERGE_PROGRESS,
  116. 0,
  117. MERGE_PROGRESS,
  118. 0,
  119. 0,
  120. PERF_DETAIL_NOVICE,
  121. PERF_COUNTER_RAWCOUNT,
  122. sizeof(DWORD),
  123. MERGE_PROGRESS_OFF
  124. },
  125. { sizeof(PERF_COUNTER_DEFINITION), // Number of documents filtered
  126. DOCUMENTS_FILTERED,
  127. 0,
  128. DOCUMENTS_FILTERED,
  129. 0,
  130. 0,
  131. PERF_DETAIL_NOVICE,
  132. PERF_COUNTER_RAWCOUNT,
  133. sizeof(DWORD),
  134. DOCUMENTS_FILTERED_OFF
  135. },
  136. { sizeof(PERF_COUNTER_DEFINITION), // Number of unique documents
  137. NUM_DOCUMENTS,
  138. 0,
  139. NUM_DOCUMENTS,
  140. 0,
  141. 0,
  142. PERF_DETAIL_NOVICE,
  143. PERF_COUNTER_RAWCOUNT,
  144. sizeof(DWORD),
  145. NUM_DOCUMENTS_OFF
  146. },
  147. { sizeof(PERF_COUNTER_DEFINITION), // Total queries
  148. TOTAL_QUERIES,
  149. 0,
  150. TOTAL_QUERIES,
  151. 0,
  152. 0,
  153. PERF_DETAIL_NOVICE,
  154. PERF_COUNTER_RAWCOUNT,
  155. sizeof(DWORD),
  156. TOTAL_QUERIES_OFF
  157. },
  158. { sizeof(PERF_COUNTER_DEFINITION), // Files deferred for filtering (Secondary Q)
  159. DEFERRED_FILTER_FILES,
  160. 0,
  161. DEFERRED_FILTER_FILES,
  162. 0,
  163. 0,
  164. PERF_DETAIL_NOVICE,
  165. PERF_COUNTER_RAWCOUNT,
  166. sizeof(DWORD),
  167. DEFERRED_FILTER_FILES_OFF
  168. }
  169. };
  170. const FILTER_DATA_DEFINITION FILTERDataDefinitionFixed = {
  171. { sizeof(FILTER_DATA_DEFINITION)+
  172. FILTER_SIZE_OF_COUNTER_BLOCK, // Total Bytes ( Size of this header, the counter definitions
  173. // and the size of the actual counter data )
  174. sizeof(FILTER_DATA_DEFINITION), // Definition length ( This header and the counter definitions )
  175. sizeof(PERF_OBJECT_TYPE), // Header Length ( This header )
  176. FILTEROBJECT, // Object Name Title Index
  177. 0, // Object Name Title
  178. FILTEROBJECT, // Object Help Title Index
  179. 0, // Object Help Title
  180. PERF_DETAIL_NOVICE, // Detail Level
  181. FILTER_TOTAL_NUM_COUNTERS, // Number of Counters
  182. 0, // Default Counters
  183. 0, // Num Instances
  184. 0, // Code Page
  185. {0,0}, // Perf Time
  186. {0,0} // Perf Freq
  187. },
  188. { sizeof(PERF_COUNTER_DEFINITION), // Total Filter Time
  189. FILTER_TIME_TOTAL,
  190. 0,
  191. FILTER_TIME_TOTAL,
  192. 0,
  193. 0,
  194. PERF_DETAIL_NOVICE,
  195. PERF_COUNTER_RAWCOUNT,
  196. sizeof(DWORD),
  197. FILTER_TIME_TOTAL_OFF
  198. },
  199. { sizeof(PERF_COUNTER_DEFINITION), // Binding Time for one file
  200. BIND_TIME,
  201. 0,
  202. BIND_TIME,
  203. 0,
  204. -1,
  205. PERF_DETAIL_NOVICE,
  206. PERF_COUNTER_RAWCOUNT,
  207. sizeof(DWORD),
  208. BIND_TIME_OFF
  209. },
  210. { sizeof(PERF_COUNTER_DEFINITION), // Filter Time
  211. FILTER_TIME,
  212. 0,
  213. FILTER_TIME,
  214. 0,
  215. 0,
  216. PERF_DETAIL_NOVICE,
  217. PERF_COUNTER_RAWCOUNT,
  218. sizeof(DWORD),
  219. FILTER_TIME_OFF
  220. }
  221. };
  222. //+---------------------------------------------------------------------------
  223. //
  224. // Function: CloseKey
  225. //
  226. // Synopsis: Close the registry key handle
  227. //
  228. // Arguments: [hOpenKey] -- Key. NULL if closed.
  229. //
  230. //----------------------------------------------------------------------------
  231. inline void CloseKey ( HKEY hOpenKey )
  232. {
  233. if ( 0 != hOpenKey )
  234. RegCloseKey (hOpenKey); // close key to registry
  235. }
  236. CStaticMutexSem g_mtxQPerf; // Serialization during "ReadUser/KernelPerfData"
  237. LONG g_cKernelRefs = 0;
  238. LONG g_cUserRefs = 0;
  239. UINT g_KernSeqNo; // "CI" sequence number
  240. UINT g_UserSeqNo; // "Filter" sequence number
  241. //+---------------------------------------------------------------------------
  242. //
  243. // Function : InitializeFILTERPerformanceData
  244. //
  245. // Purpose : Build and initialize the performance data structure and create
  246. // perfCI.ini file
  247. //
  248. // Arguments :
  249. // [pInstance] -- dummy variable
  250. //
  251. // History : 23-March-94 t-joshh Created
  252. //
  253. // Note : Must start cidaemon before executing this function
  254. //
  255. //----------------------------------------------------------------------------
  256. DWORD InitializeFILTERPerformanceData( LPWSTR pInstance )
  257. {
  258. CLock lock( g_mtxQPerf );
  259. g_cUserRefs++;
  260. if ( g_cUserRefs > 1 )
  261. return NO_ERROR;
  262. //
  263. // Start with a clean slate. Note that in some cases the final Done() may
  264. // have been called but the dll wasn't unloaded.
  265. //
  266. RtlCopyMemory( &FILTERDataDefinition,
  267. &FILTERDataDefinitionFixed,
  268. sizeof FILTERDataDefinition );
  269. //
  270. // Open the registry which contain the last key's index
  271. //
  272. HKEY hKeyPerf = 0;
  273. LONG status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  274. FILTERPerformanceKeyName,
  275. 0L, KEY_READ,
  276. &hKeyPerf );
  277. if (status != ERROR_SUCCESS)
  278. {
  279. CloseKey( hKeyPerf );
  280. PerfDebugOut(( DEB_ERROR, "Error in RegOpenKeyEx\n"));
  281. return status;
  282. }
  283. //
  284. // Get the index of the first counter
  285. //
  286. DWORD dwFirstCounter;
  287. DWORD size = sizeof dwFirstCounter;
  288. DWORD type;
  289. status = RegQueryValueEx( hKeyPerf, FirstCounterKeyName, 0L, &type,
  290. (LPBYTE)&dwFirstCounter, &size);
  291. if (status != ERROR_SUCCESS)
  292. {
  293. PerfDebugOut(( DEB_ERROR, "Error in Query First Counter\n"));
  294. CloseKey( hKeyPerf );
  295. return status;
  296. }
  297. //
  298. // Get the index of the first help
  299. //
  300. DWORD dwFirstHelp;
  301. size = sizeof dwFirstHelp;
  302. status = RegQueryValueEx( hKeyPerf, FirstHelpKeyName,
  303. 0L, &type, (LPBYTE)&dwFirstHelp, &size );
  304. if (status != ERROR_SUCCESS)
  305. {
  306. PerfDebugOut(( DEB_ERROR, "Error in Query First Help Key\n"));
  307. CloseKey( hKeyPerf );
  308. return status;
  309. }
  310. //
  311. // Update the index of both title and help of each counter
  312. //
  313. FILTERDataDefinition.FILTERObjectType.ObjectNameTitleIndex += dwFirstCounter;
  314. FILTERDataDefinition.FILTERObjectType.ObjectHelpTitleIndex += dwFirstHelp;
  315. PERF_COUNTER_DEFINITION * pTmp = (PERF_COUNTER_DEFINITION *) ((BYTE *)&FILTERDataDefinition
  316. + sizeof(PERF_OBJECT_TYPE) );
  317. for ( unsigned i = 0;
  318. i < FILTERDataDefinition.FILTERObjectType.NumCounters;
  319. i++)
  320. {
  321. pTmp->CounterNameTitleIndex += dwFirstCounter;
  322. pTmp->CounterHelpTitleIndex += dwFirstHelp;
  323. pTmp++;
  324. }
  325. //
  326. // Close the registry key
  327. //
  328. CloseKey( hKeyPerf );
  329. DWORD dwErr = ERROR_SUCCESS;
  330. BOOL fNoServer = FALSE;
  331. CTranslateSystemExceptions translate;
  332. TRY
  333. {
  334. if ( 0 == g_pReadUserPerfData )
  335. g_pReadUserPerfData = new CReadUserPerfData;
  336. if ( g_pReadUserPerfData->InitForRead() )
  337. g_UserSeqNo = g_pReadUserPerfData->GetSeqNo();
  338. else
  339. {
  340. fNoServer = TRUE;
  341. dwErr = ERROR_CAN_NOT_COMPLETE;
  342. }
  343. PerfDebugOut((DEB_ITRACE, "InitializeFilterPerformanceData : Done\n" ));
  344. }
  345. CATCH( CException, e )
  346. {
  347. dwErr = ERROR_CAN_NOT_COMPLETE; // lie here
  348. }
  349. END_CATCH;
  350. if ( NO_ERROR != dwErr )
  351. {
  352. delete g_pReadUserPerfData;
  353. g_pReadUserPerfData = 0;
  354. // Lie if cisvc isn't running, and Collect() will return no data
  355. if ( fNoServer )
  356. dwErr = NO_ERROR;
  357. }
  358. return dwErr;
  359. } //InitializeFILTERPerformanceData
  360. //+---------------------------------------------------------------------------
  361. //
  362. // Function : CollectFILTERPerformanceData
  363. //
  364. // Purpose : Collect Performance Data of Content Index to PerfMon
  365. //
  366. // Arguments:
  367. // [lpValueName] -- pointer to a wide character string passed by registry
  368. //
  369. // [lppData] -- IN: pointer to the address of the buffer to receive the
  370. // completed PerfDataBlock and subordinate structures. This
  371. // routine will append its data to the buffer starting at
  372. // the point referenced by *lppData.
  373. //
  374. // OUT: points to the first byte after the data structure
  375. // added by this routine. This routine updated the value at
  376. // lppdata after appending its data.
  377. //
  378. // [lpcbTotalBytes] -- IN: the address of the DWORD that tells the size in bytes
  379. // of the buffer referenced by the lppData argument
  380. //
  381. // OUT: the number of bytes added by this routine is written
  382. // to the DWORD pointed to by this argument
  383. //
  384. // [lpNumObjectTypes] -- IN: the address of the DWORD to receive the number of
  385. // objects added by this routine
  386. //
  387. // OUT: the number of objects added by this routine is written
  388. // to the DWORD pointed to by this argument
  389. //
  390. // History : 23-March-94 t-joshh Created
  391. //
  392. // Return : ERROR_MORE_DATA if the size of the input buffer is too small
  393. // ERROR_SUCCESS if success
  394. //----------------------------------------------------------------------------
  395. DWORD CollectFILTERPerformanceData( LPWSTR lpValueName,
  396. LPVOID *lppData,
  397. LPDWORD lpcbTotalBytes,
  398. LPDWORD lpNumObjectTypes)
  399. {
  400. //
  401. // if initial procedure failed, exit
  402. //
  403. if ( 0 == g_pReadUserPerfData || !g_pReadUserPerfData->InitOK())
  404. {
  405. *lpcbTotalBytes = 0;
  406. *lpNumObjectTypes = 0;
  407. return ERROR_SUCCESS; // yes, this is a successful exit
  408. }
  409. if ( g_pReadUserPerfData->GetSeqNo() != g_UserSeqNo )
  410. {
  411. CLock lock( g_mtxQPerf );
  412. g_UserSeqNo = g_pReadUserPerfData->GetSeqNo();
  413. if (!g_pReadUserPerfData->InitForRead())
  414. {
  415. *lpcbTotalBytes = 0;
  416. *lpNumObjectTypes = 0;
  417. return ERROR_SUCCESS; // yes, this is a successful exit
  418. }
  419. }
  420. //
  421. // see if this is a foreign (i.e. non-NT) computer data request
  422. //
  423. DWORD dwQueryType = GetQueryType (lpValueName);
  424. if (dwQueryType == QUERY_FOREIGN)
  425. {
  426. //
  427. // this routine does not service requests for data from
  428. // Non-NT computers
  429. //
  430. *lpcbTotalBytes = 0;
  431. *lpNumObjectTypes = 0;
  432. return ERROR_SUCCESS;
  433. }
  434. //
  435. // If the caller only wanted some counter, check if we have them
  436. //
  437. if (dwQueryType == QUERY_ITEMS)
  438. {
  439. if ( !(IsNumberInUnicodeList (
  440. FILTERDataDefinition.FILTERObjectType.ObjectNameTitleIndex,
  441. lpValueName)))
  442. {
  443. //
  444. // request received for data object not provided by this routine
  445. //
  446. *lpcbTotalBytes = 0;
  447. *lpNumObjectTypes = 0;
  448. return ERROR_SUCCESS;
  449. }
  450. }
  451. //
  452. // Check whether there is enough space allocated in the lppData
  453. //
  454. ULONG ulSpaceNeeded = sizeof(FILTER_DATA_DEFINITION);
  455. if ( *lpcbTotalBytes < (DWORD) ulSpaceNeeded)
  456. {
  457. *lpcbTotalBytes = 0;
  458. *lpNumObjectTypes = 0;
  459. return ERROR_MORE_DATA;
  460. }
  461. //
  462. // Copy the Data Definition to the buffer first
  463. //
  464. FILTER_DATA_DEFINITION * pFILTERDataDefinition = (FILTER_DATA_DEFINITION *) *lppData;
  465. RtlCopyMemory(pFILTERDataDefinition,
  466. &FILTERDataDefinition,
  467. sizeof(FILTER_DATA_DEFINITION));
  468. PERF_INSTANCE_DEFINITION * pFILTERInstanceDefinition = (PERF_INSTANCE_DEFINITION *)( (BYTE *)*lppData
  469. + sizeof(FILTER_DATA_DEFINITION));
  470. PerfDebugOut(( DEB_ITRACE, "No. of Instance %d\n", g_pReadUserPerfData->NumberOfInstance() ));
  471. //
  472. // Check how many instance exist (how many OFS drive have cidaemon running on)
  473. //
  474. for ( int i = 0;
  475. i < g_pReadUserPerfData->NumberOfInstance();
  476. i++ )
  477. {
  478. //
  479. // Check whether there is enough space
  480. //
  481. UINT uiLen = wcslen(g_pReadUserPerfData->GetInstanceName(i));
  482. ulSpaceNeeded += ( sizeof(PERF_INSTANCE_DEFINITION) +
  483. FILTER_SIZE_OF_COUNTER_BLOCK +
  484. (4+1+uiLen) * sizeof(WCHAR) );
  485. if ( *lpcbTotalBytes < ulSpaceNeeded )
  486. {
  487. *lpcbTotalBytes = 0;
  488. *lpNumObjectTypes = 0;
  489. return ERROR_MORE_DATA;
  490. }
  491. //
  492. // Make a copy of the instance name with UNICODE_STRING type
  493. //
  494. UNICODE_STRING usName;
  495. usName.Length = (USHORT) uiLen * sizeof(WCHAR);
  496. usName.MaximumLength = (USHORT) (uiLen+1)*sizeof(WCHAR);
  497. usName.Buffer = g_pReadUserPerfData->GetInstanceName(i);
  498. PERF_COUNTER_BLOCK * pCounterBlock;
  499. MonBuildInstanceDefinition ( pFILTERInstanceDefinition,
  500. (PVOID *) &pCounterBlock,
  501. 0,
  502. 0,
  503. PERF_NO_UNIQUE_ID, // use name, not index
  504. &usName );
  505. pCounterBlock->ByteLength = FILTER_SIZE_OF_COUNTER_BLOCK;
  506. //
  507. // Put each counter value into the buffer
  508. //
  509. DWORD * pdwCounter = (DWORD *) ((BYTE *)pCounterBlock + sizeof(PERF_COUNTER_BLOCK));
  510. for ( UINT j = 0 ;
  511. j < FILTERDataDefinition.FILTERObjectType.NumCounters;
  512. j++)
  513. {
  514. *pdwCounter = g_pReadUserPerfData->GetCounterValue( (int)i, (int)j );
  515. pdwCounter++;
  516. }
  517. //
  518. // Point to the next location of instance definition
  519. //
  520. pFILTERInstanceDefinition = (PERF_INSTANCE_DEFINITION *)pdwCounter;
  521. }
  522. *lppData = (LPVOID) pFILTERInstanceDefinition;
  523. //
  524. // Fill in the number of instances
  525. //
  526. pFILTERDataDefinition->FILTERObjectType.NumInstances = g_pReadUserPerfData->NumberOfInstance();
  527. //
  528. // Number of Object are always 1
  529. //
  530. *lpNumObjectTypes = 1;
  531. //
  532. // Fill in the number of bytes copied including object and counter
  533. // definition and counter data
  534. //
  535. *lpcbTotalBytes = (DWORD) ((BYTE *) *lppData - (BYTE *) pFILTERDataDefinition);
  536. pFILTERDataDefinition->FILTERObjectType.TotalByteLength = *lpcbTotalBytes;
  537. PerfDebugOut((DEB_ITRACE, "CollectFilterPerformanceData : Done\n"));
  538. return ERROR_SUCCESS;
  539. } //CollectFILTERPerformanceData
  540. //+---------------------------------------------------------------------------
  541. //
  542. // Function : DoneFILTERPerformanceData
  543. //
  544. // Purpose : dummy function
  545. //
  546. // Argument : none
  547. //
  548. // History : 23-March-94 t-joshh Created
  549. //
  550. //----------------------------------------------------------------------------
  551. DWORD DoneFILTERPerformanceData( void )
  552. {
  553. CLock lock( g_mtxQPerf );
  554. //
  555. // A bug in a perfmon dll makes them call this function after we've
  556. // been process detached! They call us in their process detach, which
  557. // is well after we've been detached and destroyed our heap.
  558. //
  559. if ( g_fPerfmonCounterHackIsProcessDetached )
  560. return ERROR_SUCCESS;
  561. g_cUserRefs--;
  562. if ( 0 == g_cUserRefs )
  563. {
  564. delete g_pReadUserPerfData;
  565. g_pReadUserPerfData = 0;
  566. }
  567. return ERROR_SUCCESS;
  568. } //DoneFILTERPerformanceData
  569. //+---------------------------------------------------------------------------
  570. //
  571. // Function : InitializeCIPerformanceData
  572. //
  573. // Purpose : Build and initialize the performance data structure and create
  574. // perfCI.ini file
  575. //
  576. // Arguments :
  577. // [pInstance] -- dummy variable
  578. //
  579. // History : 23-March-94 t-joshh Created
  580. //
  581. //----------------------------------------------------------------------------
  582. DWORD InitializeCIPerformanceData( LPWSTR pInstance )
  583. {
  584. LONG status;
  585. HKEY hKeyPerf = 0;
  586. DWORD size;
  587. DWORD type;
  588. DWORD dwFirstCounter;
  589. DWORD dwFirstHelp;
  590. CLock lock( g_mtxQPerf );
  591. g_cKernelRefs++;
  592. if ( g_cKernelRefs > 1 )
  593. return NO_ERROR;
  594. //
  595. // Start with a clean slate. Note that in some cases the final Done() may
  596. // have been called but the dll wasn't unloaded.
  597. //
  598. RtlCopyMemory( &CIDataDefinition,
  599. &CIDataDefinitionFixed,
  600. sizeof CIDataDefinition );
  601. //
  602. // Open the registry which contain the last key's index
  603. //
  604. status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  605. CIPerformanceKeyName,
  606. 0L, KEY_READ,
  607. &hKeyPerf );
  608. if (status != ERROR_SUCCESS)
  609. {
  610. CloseKey( hKeyPerf );
  611. PerfDebugOut(( DEB_ERROR, "Error in RegOpenKeyEx\n"));
  612. return status;
  613. }
  614. //
  615. // Get the index of the first counter
  616. //
  617. size = sizeof (dwFirstCounter);
  618. status = RegQueryValueEx( hKeyPerf, FirstCounterKeyName, 0L, &type,
  619. (LPBYTE)&dwFirstCounter, &size);
  620. if (status != ERROR_SUCCESS)
  621. {
  622. PerfDebugOut(( DEB_ERROR, "Error in Query First Counter\n"));
  623. CloseKey( hKeyPerf );
  624. return status;
  625. }
  626. //
  627. // Get the index of the first help
  628. //
  629. size = sizeof (dwFirstHelp);
  630. status = RegQueryValueEx( hKeyPerf, FirstHelpKeyName,
  631. 0L, &type, (LPBYTE)&dwFirstHelp, &size );
  632. if (status != ERROR_SUCCESS)
  633. {
  634. PerfDebugOut(( DEB_ERROR, "Error in Query First Help Key\n" ));
  635. CloseKey( hKeyPerf );
  636. return status;
  637. }
  638. //
  639. // Update the index of both title and help of each counter
  640. //
  641. CIDataDefinition.CIObjectType.ObjectNameTitleIndex += dwFirstCounter;
  642. CIDataDefinition.CIObjectType.ObjectHelpTitleIndex += dwFirstHelp;
  643. PERF_COUNTER_DEFINITION * pTmp = (PERF_COUNTER_DEFINITION *) ((BYTE *)&CIDataDefinition
  644. + sizeof(PERF_OBJECT_TYPE) );
  645. for ( unsigned i = 0;
  646. i < CIDataDefinition.CIObjectType.NumCounters;
  647. i++)
  648. {
  649. pTmp->CounterNameTitleIndex += dwFirstCounter;
  650. pTmp->CounterHelpTitleIndex += dwFirstHelp;
  651. pTmp += 1;
  652. }
  653. //
  654. // Close the registry key
  655. //
  656. CloseKey( hKeyPerf );
  657. DWORD dwErr = ERROR_SUCCESS;
  658. BOOL fNoServer = FALSE;
  659. CTranslateSystemExceptions translate;
  660. TRY
  661. {
  662. if ( 0 == g_pReadKernelPerfData )
  663. g_pReadKernelPerfData = new CReadKernelPerfData;
  664. BOOL fOK = g_pReadKernelPerfData->InitForRead();
  665. if ( fOK )
  666. g_KernSeqNo = g_pReadKernelPerfData->GetSeqNo();
  667. else
  668. {
  669. fNoServer = TRUE;
  670. dwErr = ERROR_CAN_NOT_COMPLETE;
  671. }
  672. PerfDebugOut(( DEB_ITRACE, "InitialCIPerformanceData : Finish\n" ));
  673. }
  674. CATCH( CException, e )
  675. {
  676. dwErr = ERROR_CAN_NOT_COMPLETE; // lie here
  677. }
  678. END_CATCH;
  679. if ( NO_ERROR != dwErr )
  680. {
  681. delete g_pReadKernelPerfData;
  682. g_pReadKernelPerfData = 0;
  683. // Lie if cisvc isn't running, and Collect() will return no data
  684. if ( fNoServer )
  685. dwErr = NO_ERROR;
  686. }
  687. return dwErr;
  688. } //InitializeCIPerformanceData
  689. //+---------------------------------------------------------------------------
  690. //
  691. // Function : CollectCIPerformanceData
  692. //
  693. // Purpose : Collect Performance Data of Content Index to PerfMon
  694. //
  695. // Arguments:
  696. // [lpValueName] -- pointer to a wide character string passed by registry
  697. //
  698. // [lppData] -- IN: pointer to the address of the buffer to receive the
  699. // completed PerfDataBlock and subordinate structures. This
  700. // routine will append its data to the buffer starting at
  701. // the point referenced by *lppData.
  702. //
  703. // OUT: points to the first byte after the data structure
  704. // added by this routine. This routine updated the value at
  705. // lppdata after appending its data.
  706. //
  707. // [lpcbTotalBytes] -- IN: the address of the DWORD that tells the size in bytes
  708. // of the buffer referenced by the lppData argument
  709. //
  710. // OUT: the number of bytes added by this routine is written
  711. // to the DWORD pointed to by this argument
  712. //
  713. // [lpNumObjectTypes] -- IN: the address of the DWORD to receive the number of
  714. // objects added by this routine
  715. //
  716. // OUT: the number of objects added by this routine is written
  717. // to the DWORD pointed to by this argument
  718. //
  719. // History : 23-March-94 t-joshh Created
  720. //
  721. // Return : ERROR_MORE_DATA if the size of the input buffer is too small
  722. // ERROR_SUCCESS if success
  723. //----------------------------------------------------------------------------
  724. DWORD CollectCIPerformanceData( LPWSTR lpValueName,
  725. LPVOID *lppData,
  726. LPDWORD lpcbTotalBytes,
  727. LPDWORD lpNumObjectTypes)
  728. {
  729. ULONG ulSpaceNeeded = 0;
  730. DWORD dwQueryType;
  731. //
  732. // if initial procedure failed, exit
  733. //
  734. if ( 0 == g_pReadKernelPerfData || !g_pReadKernelPerfData->InitOK())
  735. {
  736. *lpcbTotalBytes = 0;
  737. *lpNumObjectTypes = 0;
  738. return ERROR_SUCCESS; // yes, this is a successful exit
  739. }
  740. if ( g_pReadKernelPerfData->GetSeqNo() != g_KernSeqNo )
  741. {
  742. CLock lock( g_mtxQPerf );
  743. g_pReadKernelPerfData->InitForRead();
  744. if (!g_pReadKernelPerfData->InitOK())
  745. {
  746. *lpcbTotalBytes = 0;
  747. *lpNumObjectTypes = 0;
  748. return ERROR_SUCCESS; // yes, this is a successful exit
  749. }
  750. g_KernSeqNo = g_pReadKernelPerfData->GetSeqNo();
  751. }
  752. //
  753. // see if this is a foreign (i.e. non-NT) computer data request
  754. //
  755. dwQueryType = GetQueryType (lpValueName);
  756. if (dwQueryType == QUERY_FOREIGN)
  757. {
  758. //
  759. // this routine does not service requests for data from
  760. // Non-NT computers
  761. //
  762. *lpcbTotalBytes = 0;
  763. *lpNumObjectTypes = 0;
  764. return ERROR_SUCCESS;
  765. }
  766. //
  767. // If the caller only wanted some counter, check if we have them
  768. //
  769. if (dwQueryType == QUERY_ITEMS)
  770. {
  771. if ( !(IsNumberInUnicodeList(
  772. CIDataDefinition.CIObjectType.ObjectNameTitleIndex,
  773. lpValueName)) )
  774. {
  775. //
  776. // request received for data object not provided by this routine
  777. //
  778. *lpcbTotalBytes = 0;
  779. *lpNumObjectTypes = 0;
  780. return ERROR_SUCCESS;
  781. }
  782. }
  783. //
  784. // Check whether there is enough space allocated in the lppData
  785. //
  786. ulSpaceNeeded = sizeof(CI_DATA_DEFINITION);
  787. if ( *lpcbTotalBytes < (DWORD) ulSpaceNeeded)
  788. {
  789. *lpcbTotalBytes = 0;
  790. *lpNumObjectTypes = 0;
  791. return ERROR_MORE_DATA;
  792. }
  793. //
  794. // Copy the Data Definition to the buffer first
  795. //
  796. CI_DATA_DEFINITION * pCIDataDefinition = (CI_DATA_DEFINITION *) *lppData;
  797. RtlCopyMemory(pCIDataDefinition,
  798. &CIDataDefinition,
  799. sizeof(CI_DATA_DEFINITION));
  800. PERF_INSTANCE_DEFINITION * pCIInstanceDefinition = (PERF_INSTANCE_DEFINITION *)( (BYTE *)*lppData
  801. + sizeof(CI_DATA_DEFINITION));
  802. PerfDebugOut(( DEB_ITRACE, "*lppData: %#x\n", *lppData ));
  803. PerfDebugOut(( DEB_ITRACE, "pCIInstanceDefinition: %#x\n", pCIInstanceDefinition ));
  804. //
  805. // Check how many instance exist (how many OFS drive have cidaemon running on)
  806. //
  807. for ( int i = 0;
  808. i < g_pReadKernelPerfData->NumberOfInstance();
  809. i++ )
  810. {
  811. //
  812. // Check whether there is enough space
  813. //
  814. UINT uiLen = wcslen(g_pReadKernelPerfData->GetInstanceName(i));
  815. ulSpaceNeeded += ( sizeof(PERF_INSTANCE_DEFINITION) +
  816. CI_SIZE_OF_COUNTER_BLOCK +
  817. (4+1+uiLen) * sizeof(WCHAR) );
  818. if ( *lpcbTotalBytes < ulSpaceNeeded )
  819. {
  820. *lpcbTotalBytes = (DWORD) 0;
  821. *lpNumObjectTypes = (DWORD) 0;
  822. return ERROR_MORE_DATA;
  823. }
  824. //
  825. // Make a copy of the instance name with UNICODE_STRING type
  826. //
  827. UNICODE_STRING usName;
  828. usName.Length = (USHORT) uiLen * sizeof(WCHAR);
  829. usName.MaximumLength = (USHORT) (uiLen+1)*sizeof(WCHAR);
  830. usName.Buffer = g_pReadKernelPerfData->GetInstanceName(i);
  831. PERF_COUNTER_BLOCK * pCounterBlock;
  832. MonBuildInstanceDefinition ( pCIInstanceDefinition,
  833. (PVOID *) &pCounterBlock,
  834. 0,
  835. 0,
  836. PERF_NO_UNIQUE_ID, // use name, not index
  837. &usName );
  838. pCounterBlock->ByteLength = CI_SIZE_OF_COUNTER_BLOCK;
  839. //
  840. // Refresh the buffer
  841. //
  842. g_pReadKernelPerfData->Refresh( i );
  843. //
  844. // Put each counter value into the buffer
  845. //
  846. DWORD * pdwCounter = (DWORD *) ((BYTE *)pCounterBlock + sizeof(PERF_COUNTER_BLOCK));
  847. for ( UINT j = 0 ;
  848. j < CIDataDefinition.CIObjectType.NumCounters;
  849. j++)
  850. {
  851. *pdwCounter = g_pReadKernelPerfData->GetCounterValue( (int)j );
  852. pdwCounter++;
  853. }
  854. //
  855. // Point to the next location of instance definition
  856. //
  857. pCIInstanceDefinition = (PERF_INSTANCE_DEFINITION *)pdwCounter;
  858. }
  859. *lppData = (LPVOID) pCIInstanceDefinition;
  860. //
  861. // Fill in the number of instances
  862. //
  863. pCIDataDefinition->CIObjectType.NumInstances = g_pReadKernelPerfData->NumberOfInstance();
  864. //
  865. // Number of Object are always 1
  866. //
  867. *lpNumObjectTypes = 1;
  868. //
  869. // Fill in the number of bytes copied including object and counter
  870. // definition and counter data
  871. //
  872. *lpcbTotalBytes = (DWORD) ((BYTE *) *lppData - (BYTE *) pCIDataDefinition);
  873. pCIDataDefinition->CIObjectType.TotalByteLength = *lpcbTotalBytes;
  874. PerfDebugOut(( DEB_ITRACE, "CollectCIPerformanceData : Done\n" ));
  875. Win4Assert( *lpcbTotalBytes == EIGHT_BYTE_MULTIPLE(*lpcbTotalBytes) );
  876. return ERROR_SUCCESS;
  877. } //CollectCIPerformanceData
  878. //+---------------------------------------------------------------------------
  879. //
  880. // Function : DoneCIPerformanceData
  881. //
  882. // Purpose : dummy function
  883. //
  884. // Argument : none
  885. //
  886. // History : 23-March-94 t-joshh Created
  887. //
  888. //----------------------------------------------------------------------------
  889. DWORD DoneCIPerformanceData( void )
  890. {
  891. CLock lock( g_mtxQPerf );
  892. //
  893. // A bug in a perfmon dll makes them call this function after we've
  894. // been process detached! They call us in their process detach, which
  895. // is well after we've been detached and destroyed our heap.
  896. //
  897. if ( g_fPerfmonCounterHackIsProcessDetached )
  898. return ERROR_SUCCESS;
  899. g_cKernelRefs--;
  900. if ( 0 == g_cKernelRefs )
  901. {
  902. delete g_pReadKernelPerfData;
  903. g_pReadKernelPerfData = 0;
  904. }
  905. return ERROR_SUCCESS;
  906. } //DoneCIPerformanceData