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.

984 lines
29 KiB

  1. /*==========================================================================*\
  2. Module: exprfdll.cpp
  3. Copyright Microsoft Corporation 1998, All Rights Reserved.
  4. Author: WayneC
  5. Descriptions: This is the implementation for exprfdll, a perf dll. This
  6. is for the dll that runs in perfmon. It supports multiple
  7. libraries (monitored services.)
  8. \*==========================================================================*/
  9. ///////////////////////////////////////////////////////////////////////////////
  10. //
  11. // Includes
  12. //
  13. ///////////////////////////////////////////////////////////////////////////////
  14. #include <windows.h>
  15. #include <winperf.h>
  16. #include "snprflib.h"
  17. #include "exprfdll.h"
  18. #include <stdlib.h>
  19. #include "exchmem.h"
  20. ///////////////////////////////////////////////////////////////////////////////
  21. //
  22. // Declare Global variables
  23. //
  24. ///////////////////////////////////////////////////////////////////////////////
  25. LPCWSTR g_wszPrefixGlobal = L"Global\\";
  26. WCHAR g_rgszLibraries[MAX_PERF_LIBS][MAX_PERF_NAME]; // Names of the libraries we are monitoring
  27. BOOL g_rgfInitOk[MAX_PERF_LIBS] = {FALSE}; // Flags to indicate if initialization was a success
  28. // index for g_rgszLibraries & g_rgfInitOk
  29. enum LibIndex
  30. {
  31. LIB_NTFSDRV = 0
  32. };
  33. ///////////////////////////////////////////////////////////////////////////////
  34. //
  35. // Forward declaration of shared memory functions.
  36. //
  37. ///////////////////////////////////////////////////////////////////////////////
  38. BOOL FOpenFileMapping (SharedMemorySegment * pSMS,
  39. LPCWSTR pcwstrInstanceName,
  40. DWORD dwIndex);
  41. void CloseFileMapping (SharedMemorySegment * pSMS);
  42. ///////////////////////////////////////////////////////////////////////////////
  43. //
  44. // PerfLibraryData class implementation
  45. //
  46. ///////////////////////////////////////////////////////////////////////////////
  47. PerfLibraryData::PerfLibraryData()
  48. {
  49. m_hShMem = 0;
  50. m_pbShMem = 0;
  51. m_dwObjects = 0;
  52. }
  53. PerfLibraryData::~PerfLibraryData()
  54. {
  55. Close();
  56. }
  57. BOOL PerfLibraryData::GetPerformanceStatistics (LPCWSTR pcwstrLibrary)
  58. {
  59. BOOL fRet = FALSE;
  60. DWORD i = 0;
  61. //
  62. // Open the mapping for the perf library information
  63. //
  64. m_hShMem = OpenFileMappingW (FILE_MAP_READ, FALSE, pcwstrLibrary);
  65. if (!m_hShMem)
  66. goto Exit;
  67. m_pbShMem = (BYTE*) MapViewOfFile (m_hShMem, FILE_MAP_READ, 0, 0, 0);
  68. if (!m_pbShMem)
  69. goto Exit;
  70. //
  71. // Get the number of objects in the shared memory
  72. //
  73. m_dwObjects = *(DWORD*) m_pbShMem;
  74. m_prgObjectNames = (OBJECTNAME*) (m_pbShMem + sizeof(DWORD));
  75. //
  76. // Loop through objects and get perf data for each
  77. //
  78. for (i = 0; i < m_dwObjects; i++) {
  79. if(!m_rgObjectData[i].GetPerformanceStatistics (m_prgObjectNames[i]))
  80. goto Exit;
  81. }
  82. fRet = TRUE;
  83. Exit:
  84. if (!fRet)
  85. {
  86. if (m_pbShMem)
  87. {
  88. UnmapViewOfFile ((PVOID)m_pbShMem);
  89. m_pbShMem = NULL;
  90. }
  91. if (m_hShMem)
  92. {
  93. CloseHandle (m_hShMem);
  94. m_hShMem = NULL;
  95. }
  96. }
  97. return fRet;
  98. }
  99. VOID PerfLibraryData::Close (VOID)
  100. {
  101. if (m_pbShMem)
  102. {
  103. UnmapViewOfFile ((PVOID) m_pbShMem);
  104. m_pbShMem = 0;
  105. }
  106. if (m_hShMem)
  107. {
  108. CloseHandle (m_hShMem);
  109. m_hShMem = 0;
  110. }
  111. for (DWORD i = 0; i < m_dwObjects; i++)
  112. m_rgObjectData[i].Close();
  113. }
  114. DWORD PerfLibraryData::SpaceNeeded (DWORD dwQueryType, LPCWSTR lpwstrObjects)
  115. {
  116. DWORD dwSpaceNeeded = 0;
  117. for (DWORD i = 0; i < m_dwObjects; i++)
  118. dwSpaceNeeded += m_rgObjectData[i].SpaceNeeded (dwQueryType, lpwstrObjects);
  119. return dwSpaceNeeded;
  120. }
  121. VOID PerfLibraryData::SavePerformanceData (PVOID* ppv, DWORD* pdwBytes, DWORD* pdwObjects )
  122. {
  123. for (DWORD i = 0; i < m_dwObjects; i++)
  124. m_rgObjectData[i].SavePerformanceData (ppv, pdwBytes, pdwObjects);
  125. }
  126. ///////////////////////////////////////////////////////////////////////////////
  127. //
  128. // PerfObjectData class implementation
  129. //
  130. ///////////////////////////////////////////////////////////////////////////////
  131. PerfObjectData::PerfObjectData()
  132. {
  133. m_fObjectRequested = FALSE;
  134. m_dwSpaceNeeded = 0;
  135. m_pSMS = NULL;
  136. m_wszObjectName[0] = L'\0';
  137. }
  138. PerfObjectData::~PerfObjectData()
  139. {
  140. Close();
  141. }
  142. BOOL PerfObjectData::GetPerformanceStatistics (LPCWSTR pcwstrObjectName)
  143. {
  144. DWORD dwPerInstanceData = 0;
  145. DWORD dwShmemMappingSize = SHMEM_MAPPING_SIZE;
  146. BOOL fSuccess = FALSE;
  147. // Remember the object name
  148. wcsncpy (m_wszObjectName, pcwstrObjectName, MAX_OBJECT_NAME);
  149. m_wszObjectName[MAX_OBJECT_NAME-1] = L'\0'; // Ensure NULL Terminated
  150. // Open the 1st shared memory segment
  151. m_pSMS = new SharedMemorySegment;
  152. if (!m_pSMS)
  153. goto Exit;
  154. if (!FOpenFileMapping (m_pSMS, pcwstrObjectName, 0))
  155. goto Exit;
  156. // First in the shared memory is the PERF_OBJECT_TYPE
  157. m_pObjType = (PERF_OBJECT_TYPE*) m_pSMS->m_pbMap;
  158. // Then an array of PERF_COUNTER_DEFINITION
  159. m_prgCounterDef = (PERF_COUNTER_DEFINITION*) (m_pObjType + 1);
  160. // Then a DWORD that tells the size of each counter block
  161. m_pdwCounterData = (DWORD*) (m_pSMS->m_pbMap + sizeof(PERF_OBJECT_TYPE) +
  162. (m_pObjType->NumCounters * sizeof(PERF_COUNTER_DEFINITION)));
  163. if (m_pObjType->NumInstances == PERF_NO_INSTANCES)
  164. {
  165. m_pCounterBlock = (PERF_COUNTER_BLOCK*) (m_pdwCounterData+1);
  166. m_pbCounterBlockTotal = NULL;
  167. }
  168. else
  169. {
  170. m_pCounterBlock = NULL;
  171. m_pbCounterBlockTotal = (PBYTE)(m_pdwCounterData+1) + sizeof(INSTANCE_DATA);
  172. }
  173. // Compute the size of per instance data & object definition.
  174. dwPerInstanceData = sizeof(INSTANCE_DATA) + *m_pdwCounterData;
  175. m_dwDefinitionLength = sizeof(PERF_OBJECT_TYPE) +
  176. m_pObjType->NumCounters * sizeof(PERF_COUNTER_DEFINITION) + sizeof(DWORD);
  177. // Make sure our memory mapping is large enough.
  178. while (dwShmemMappingSize < dwPerInstanceData || dwShmemMappingSize < m_dwDefinitionLength)
  179. dwShmemMappingSize *= 2;
  180. // Compute the number of instances can be stored in one shmem mapping.
  181. m_dwInstancesPerMapping = (DWORD)(dwShmemMappingSize / dwPerInstanceData);
  182. m_dwInstances1stMapping = (DWORD)((dwShmemMappingSize - m_dwDefinitionLength) / dwPerInstanceData);
  183. fSuccess = TRUE;
  184. Exit:
  185. if (!fSuccess && m_pSMS)
  186. {
  187. CloseFileMapping (m_pSMS);
  188. delete m_pSMS;
  189. m_pSMS = NULL;
  190. }
  191. return fSuccess;
  192. }
  193. VOID PerfObjectData::Close (VOID)
  194. {
  195. SharedMemorySegment *pSMS, *pSMSNext;
  196. pSMS = m_pSMS;
  197. m_pSMS = NULL;
  198. while (pSMS)
  199. {
  200. pSMSNext = pSMS->m_pSMSNext;
  201. CloseFileMapping (pSMS);
  202. delete pSMS;
  203. pSMS = pSMSNext;
  204. }
  205. }
  206. DWORD PerfObjectData::SpaceNeeded (DWORD dwQueryType, LPCWSTR lpwstrObjects)
  207. {
  208. DWORD dwSpaceNeeded = 0;
  209. if (dwQueryType == QUERY_GLOBAL ||
  210. IsNumberInUnicodeList (m_pObjType->ObjectNameTitleIndex, lpwstrObjects))
  211. {
  212. // Remember for later that this object was requested.
  213. m_fObjectRequested = TRUE;
  214. // Compute space needed... always need enough for the object def. and
  215. // all the counter defs
  216. dwSpaceNeeded = sizeof(PERF_OBJECT_TYPE) + (m_pObjType->NumCounters * sizeof(PERF_COUNTER_DEFINITION));
  217. // It is a bit different depending on if there are multiple instances
  218. if( m_pObjType->NumInstances != PERF_NO_INSTANCES )
  219. {
  220. // If multi-instance, we have one instance def, one instance name
  221. // plus the counter data for each instance
  222. dwSpaceNeeded += m_pObjType->NumInstances * (sizeof(PERF_INSTANCE_DEFINITION) +
  223. sizeof(INSTANCENAME) + *m_pdwCounterData);
  224. }
  225. else
  226. {
  227. // Else we just have the counter data
  228. dwSpaceNeeded += *m_pdwCounterData;
  229. }
  230. }
  231. m_dwSpaceNeeded = dwSpaceNeeded;
  232. return dwSpaceNeeded;
  233. }
  234. void PerfObjectData::SavePerformanceData (VOID** ppv, DWORD* pdwBytes, DWORD* pdwObjects)
  235. {
  236. BYTE* pb;
  237. INSTANCE_DATA* pInst;
  238. DWORD dwBytes = 0;
  239. PERF_OBJECT_TYPE* pobj;
  240. PERF_COUNTER_BLOCK* pcb;
  241. PERF_COUNTER_BLOCK* pcbTotalCounter = NULL;
  242. SharedMemorySegment* pSMS = NULL;
  243. SharedMemorySegment* pSMSNext = NULL;
  244. DWORD dwMapping = 0;
  245. DWORD dwInstances = 0;
  246. DWORD dwInstIndex = 0;
  247. BYTE* pbTotal = NULL;
  248. BYTE* pbCounterData = NULL;
  249. INSTANCE_DATA* pInstTotal = NULL;
  250. DWORD dwInstancesCopied = 0;
  251. DWORD dwInstanceSize = 0;
  252. //
  253. // If this object wasn't requested (as determined by SpaceNeeded()), then
  254. // we don't do anything.
  255. //
  256. if (!m_fObjectRequested)
  257. return;
  258. // Get pointer to output buffer
  259. pb = (BYTE*) *ppv ;
  260. //
  261. // Copy the performance data to the output buffer
  262. //
  263. // Copy a PERF_OBJECT_TYPE structure
  264. CopyMemory (pb, m_pObjType, sizeof(PERF_OBJECT_TYPE));
  265. pobj = (PERF_OBJECT_TYPE*) pb;
  266. pb += sizeof(PERF_OBJECT_TYPE);
  267. dwBytes += sizeof(PERF_OBJECT_TYPE);
  268. // Copy the counter definitions
  269. CopyMemory (pb, m_prgCounterDef, pobj->NumCounters * sizeof(PERF_COUNTER_DEFINITION));
  270. pb += pobj->NumCounters * sizeof(PERF_COUNTER_DEFINITION) ;
  271. dwBytes += pobj->NumCounters * sizeof(PERF_COUNTER_DEFINITION) ;
  272. if (pobj->NumInstances == PERF_NO_INSTANCES)
  273. {
  274. // Copy the counter block
  275. CopyMemory (pb, m_pCounterBlock, *m_pdwCounterData);
  276. // Fixup the length, because when no instances have been created it
  277. // will not be correct.
  278. pcb = (PERF_COUNTER_BLOCK*) pb;
  279. pcb->ByteLength = *m_pdwCounterData;
  280. pb += *m_pdwCounterData;
  281. dwBytes += *m_pdwCounterData;
  282. }
  283. else
  284. {
  285. // Enumerate through all the instances and copy them out
  286. pSMS = m_pSMS;
  287. dwInstancesCopied = 0;
  288. for (dwMapping = 0; ; dwMapping++)
  289. {
  290. if (0 == dwMapping)
  291. {
  292. //
  293. // If this is the 1st mapping, we have to offset pInst by m_dwDefinitionLength.
  294. //
  295. pInst = (INSTANCE_DATA*)((char *)(pSMS->m_pbMap) + m_dwDefinitionLength);
  296. dwInstances = m_dwInstances1stMapping;
  297. }
  298. else
  299. {
  300. //
  301. // Otherwise, open the next memory mapping and point pInst to the begging of that mapping.
  302. //
  303. pSMSNext = new SharedMemorySegment;
  304. if (!pSMSNext)
  305. goto Exit;
  306. if (!FOpenFileMapping (pSMSNext, m_wszObjectName, dwMapping)) {
  307. delete pSMSNext;
  308. goto Exit;
  309. }
  310. pSMS->m_pSMSNext = pSMSNext;
  311. pSMS = pSMSNext;
  312. pInst = (INSTANCE_DATA*)(pSMS->m_pbMap);
  313. dwInstances = m_dwInstancesPerMapping;
  314. }
  315. for (dwInstIndex = 0;
  316. dwInstIndex < dwInstances && dwInstancesCopied < (DWORD) (pobj->NumInstances);
  317. dwInstIndex++)
  318. {
  319. if (pInst->fActive)
  320. {
  321. //
  322. // pcb is a pointer in shared-memory pointing to the start of the
  323. // PERF_COUNTER_BLOCK and followed by the raw data for the counters.
  324. //
  325. pcb = (PERF_COUNTER_BLOCK *)((PBYTE)pInst + sizeof(INSTANCE_DATA));
  326. //
  327. // dwInstanceSize = Size of output data for this instance that will
  328. // be copied to pb. For _Total, the data is summed (AddTotal) rather
  329. // than copied.
  330. //
  331. dwInstanceSize =
  332. sizeof(PERF_INSTANCE_DEFINITION) +
  333. pInst->perfInstDef.NameLength +
  334. pcb->ByteLength;
  335. if (0 == dwInstancesCopied)
  336. {
  337. //
  338. // The first instance is the _Total instance. The perf-library
  339. // does not write _Total counters to shared memory. Instead, we
  340. // (ther perf-dll) must calculate these counters by adding the
  341. // counter data from the instance counter-data and returning that
  342. // data to perfmon.
  343. //
  344. //
  345. // The headers for the _Total instance should be written to pbTotal.
  346. // This is done by CopyInstanceData which copies the
  347. // PERF_INSTANCE_DEFINITION, PERF_INSTANCE_NAME and PERF_COUNTER_BLOCK
  348. // for _Total.
  349. //
  350. pbTotal = pb;
  351. pInstTotal = pInst;
  352. CopyInstanceData(pbTotal, pInstTotal);
  353. //
  354. // pcbTotalCounter points to the area of memory to which the
  355. // PERF_COUNTER_BLOCK followed by counter data for _Total should
  356. // be written. Each counter is calculated by adding up the
  357. // corresponding counters for the other instances.
  358. //
  359. pcbTotalCounter =
  360. (PERF_COUNTER_BLOCK *) (pb +
  361. sizeof(PERF_INSTANCE_DEFINITION) +
  362. pInst->perfInstDef.NameLength);
  363. // Zero out the counter values for _Total (excluding PERF_COUNTER_BLOCK)
  364. ZeroMemory(
  365. (PBYTE)pcbTotalCounter + sizeof(PERF_COUNTER_BLOCK),
  366. pcb->ByteLength - sizeof(PERF_COUNTER_BLOCK));
  367. }
  368. else
  369. {
  370. //
  371. // Add the values for the counter data for this instance from shared
  372. // memory, to the running total being maintained in the output buffer,
  373. // pcbTotalCounter.
  374. //
  375. if(pbTotal)
  376. AddToTotal (pcbTotalCounter, pcb);
  377. //
  378. // Copy the headers: PERF_INSTANCE_DEFINITION, PERF_INSTANCE_NAME
  379. // and PERF_COUNTER_BLOCK for this instance
  380. //
  381. CopyInstanceData(pb, pInst);
  382. //
  383. // Copy the counter data from shared memory to the output buffer
  384. // PERF_COUNTER_BLOCK has already been copied by CopyInstanceData
  385. // so we exclude that.
  386. //
  387. pbCounterData = pb +
  388. sizeof(PERF_INSTANCE_DEFINITION) +
  389. pInst->perfInstDef.NameLength +
  390. sizeof(PERF_COUNTER_BLOCK);
  391. CopyMemory(
  392. pbCounterData,
  393. (PBYTE)pcb + sizeof(PERF_COUNTER_BLOCK),
  394. pcb->ByteLength - sizeof(PERF_COUNTER_BLOCK));
  395. }
  396. pb += dwInstanceSize;
  397. dwBytes += dwInstanceSize;
  398. dwInstancesCopied++;
  399. }
  400. pInst = (INSTANCE_DATA*)(((char*)pInst) + sizeof(INSTANCE_DATA) + *m_pdwCounterData);
  401. }
  402. }
  403. }
  404. Exit:
  405. // dwBytes must be aligned on an 8-byte boundary
  406. dwBytes = QWORD_MULTIPLE(dwBytes);
  407. // Update parameters in the output buffer
  408. pobj->TotalByteLength = dwBytes;
  409. // Update buffer pointer, count of bytes and count of objects.
  410. *ppv = ((PBYTE) *ppv) + dwBytes;
  411. *pdwBytes += dwBytes;
  412. (*pdwObjects)++;
  413. }
  414. //------------------------------------------------------------------------------
  415. // Description:
  416. // Extracts and copies the PERF_INSTANCE_DEFINITION, perf-instance-name
  417. // and PERF_COUNTER_BLOCK structures given the INSTANCE_DATA pointer within
  418. // shared memory to the output buffer to perfmon.
  419. // Arguments:
  420. // OUT PBYTE pb - Output buffer to perfmon
  421. // IN INSTANCE_DATA *pInst - Pointer within shared-memory segment to the
  422. // INSTANCE_DATA structure. This structure is immediately followed by
  423. // a PERF_COUNTER_BLOCK structure.
  424. // Returns:
  425. // Nothing.
  426. //------------------------------------------------------------------------------
  427. void PerfObjectData::CopyInstanceData(PBYTE pb, INSTANCE_DATA *pInst)
  428. {
  429. PERF_COUNTER_BLOCK *pcb = NULL;
  430. DWORD cbInstanceName = 0;
  431. //
  432. // The first bytes in shared memory are the INSTANCE_DEFINITION
  433. // structure. Copy the PERF_INSTANCE_DEFINITION member of this
  434. // structure into the output buffer.
  435. //
  436. CopyMemory(pb, &(pInst->perfInstDef), sizeof(PERF_INSTANCE_DEFINITION));
  437. pb += sizeof(PERF_INSTANCE_DEFINITION);
  438. //
  439. // Next, within INSTANCE_DEFINITION, there is a buffer sized
  440. // MAX_INSTANCE_NAME. Copy the instance name, which is a NULL
  441. // terminated unicode string in this buffer. The length in bytes
  442. // to be copied is given by PERF_INSTANCE_DEFINITION.NameLength.
  443. // This includes length includes the terminating NULL and possibly
  444. // an extra padding-byte to 32-bit align the end of the buffer.
  445. //
  446. cbInstanceName = pInst->perfInstDef.NameLength;
  447. CopyMemory(pb, (char *)(pInst->wszInstanceName), cbInstanceName);
  448. pb += cbInstanceName;
  449. // Finally there is a PERF_COUNTER_BLOCK structure after the INSTANCE_DATA
  450. pcb = (PERF_COUNTER_BLOCK *)((PBYTE)pInst + sizeof(INSTANCE_DATA));
  451. CopyMemory(pb, pcb, sizeof(PERF_COUNTER_BLOCK));
  452. }
  453. void PerfObjectData::AddToTotal(
  454. PERF_COUNTER_BLOCK *pcbTotalCounters,
  455. PERF_COUNTER_BLOCK *pcbInstCounters)
  456. {
  457. DWORD i;
  458. PBYTE pbTotalCounter = NULL;
  459. PBYTE pbInstCounter = NULL;
  460. for (i = 0; i < m_pObjType->NumCounters; i++)
  461. {
  462. // Offset pointers to the first byte of the actual counter
  463. pbTotalCounter = (PBYTE)(pcbTotalCounters) + m_prgCounterDef[i].CounterOffset;
  464. pbInstCounter = (PBYTE)(pcbInstCounters) + m_prgCounterDef[i].CounterOffset;
  465. // If this is a 'rate' counter, it is referencing some other 'raw' counter.
  466. // In this case, we should not add that raw counter again.
  467. if ((m_prgCounterDef[i].CounterType & PERF_TYPE_COUNTER) &&
  468. (m_prgCounterDef[i].CounterType & PERF_COUNTER_RATE))
  469. continue;
  470. /* we only have LARGE_INTEGER and DWORD counters as of PT 3728 */
  471. if ((m_prgCounterDef[i].CounterType & PERF_TYPE_NUMBER) &&
  472. (m_prgCounterDef[i].CounterType & PERF_SIZE_LARGE))
  473. {
  474. ((LARGE_INTEGER*)pbTotalCounter)->LowPart += ((LARGE_INTEGER*)pbInstCounter)->LowPart;
  475. ((LARGE_INTEGER*)pbTotalCounter)->HighPart += ((LARGE_INTEGER*)pbInstCounter)->LowPart;
  476. }
  477. else
  478. {
  479. *(DWORD*)pbTotalCounter += *(DWORD*)pbInstCounter;
  480. }
  481. }
  482. }
  483. ///////////////////////////////////////////////////////////////////////////////
  484. //
  485. // Shared Memory Functions
  486. //
  487. ///////////////////////////////////////////////////////////////////////////////
  488. BOOL FOpenFileMapping (SharedMemorySegment * pSMS,
  489. LPCWSTR pcwstrInstanceName,
  490. DWORD dwIndex)
  491. {
  492. WCHAR pwstrShMem[MAX_PATH];
  493. WCHAR pwstrIndex[MAX_PATH];
  494. HANDLE hMap = NULL;
  495. PVOID pvMap = NULL;
  496. BOOL fSuccess = FALSE;
  497. if (!pSMS)
  498. goto Exit;
  499. pSMS->m_hMap = NULL;
  500. pSMS->m_pbMap = NULL;
  501. pSMS->m_pSMSNext = NULL;
  502. _ultow (dwIndex, pwstrIndex, 16);
  503. if (wcslen (g_wszPrefixGlobal) + wcslen (pcwstrInstanceName) + wcslen (pwstrIndex) >= MAX_PATH)
  504. goto Exit;
  505. wcscpy (pwstrShMem, g_wszPrefixGlobal);
  506. wcscat (pwstrShMem, pcwstrInstanceName);
  507. wcscat (pwstrShMem, pwstrIndex);
  508. hMap = OpenFileMappingW (FILE_MAP_READ, FALSE, pwstrShMem);
  509. if (!hMap)
  510. goto Exit;
  511. pvMap = MapViewOfFile (hMap, FILE_MAP_READ, 0, 0, 0);
  512. if (!pvMap)
  513. goto Exit;
  514. pSMS->m_hMap = hMap;
  515. pSMS->m_pbMap = (BYTE *)pvMap;
  516. fSuccess = TRUE;
  517. Exit:
  518. if (!fSuccess)
  519. {
  520. if (pvMap)
  521. UnmapViewOfFile (pvMap);
  522. if (hMap)
  523. CloseHandle (hMap);
  524. }
  525. return fSuccess;
  526. }
  527. void CloseFileMapping (SharedMemorySegment * pSMS)
  528. {
  529. if (pSMS)
  530. {
  531. if (pSMS->m_pbMap)
  532. {
  533. UnmapViewOfFile ((PVOID)pSMS->m_pbMap);
  534. pSMS->m_pbMap = NULL;
  535. }
  536. if (pSMS->m_hMap)
  537. {
  538. CloseHandle (pSMS->m_hMap);
  539. pSMS->m_hMap = NULL;
  540. }
  541. pSMS->m_pSMSNext = NULL;
  542. }
  543. }
  544. ///////////////////////////////////////////////////////////////////////////////
  545. //
  546. // Utility Functions
  547. //
  548. ///////////////////////////////////////////////////////////////////////////////
  549. //
  550. // IsPrefix()
  551. // returns TRUE if s1 is a prefix of s2
  552. //
  553. BOOL
  554. IsPrefix (WCHAR* s1, WCHAR* s2)
  555. {
  556. while (*s1 && *s2)
  557. {
  558. if (*s1++ != *s2++)
  559. {
  560. return FALSE;
  561. }
  562. }
  563. return (*s1 == 0);
  564. }
  565. //
  566. // GetQueryType()
  567. //
  568. // returns the type of query described in the lpValue string so that
  569. // the appropriate processing method may be used
  570. //
  571. // Return Value
  572. //
  573. // QUERY_GLOBAL
  574. // if lpValue == 0 (null pointer)
  575. // lpValue == pointer to Null string
  576. // lpValue == pointer to "Global" string
  577. //
  578. // QUERY_FOREIGN
  579. // if lpValue == pointer to "Foreign" string
  580. //
  581. // QUERY_COSTLY
  582. // if lpValue == pointer to "Costly" string
  583. //
  584. // otherwise:
  585. //
  586. // QUERY_ITEMS
  587. //
  588. DWORD GetQueryType (LPWSTR lpValue)
  589. {
  590. if (lpValue == 0 || *lpValue == 0 || IsPrefix( L"Global", lpValue))
  591. return QUERY_GLOBAL;
  592. else if (IsPrefix (L"Foreign", lpValue))
  593. return QUERY_FOREIGN;
  594. else if (IsPrefix (L"Costly" , lpValue))
  595. return QUERY_COSTLY;
  596. else
  597. return QUERY_ITEMS;
  598. }
  599. int inline EvalThisChar (WCHAR c, WCHAR d)
  600. {
  601. if (c == d || c == L'\0')
  602. return DELIMITER;
  603. else if (L'0' <= c && c <= L'9')
  604. return DIGIT;
  605. else
  606. return INVALID;
  607. }
  608. BOOL IsNumberInUnicodeList (DWORD dwNumber, LPCWSTR lpwszUnicodeList)
  609. {
  610. DWORD dwThisNumber = 0;
  611. const WCHAR* pwcThisChar = lpwszUnicodeList;
  612. BOOL bValidNumber = FALSE;
  613. BOOL bNewItem = TRUE;
  614. WCHAR wcDelimiter = L' ';
  615. // If null pointer, number not found
  616. if (lpwszUnicodeList == 0)
  617. return FALSE;
  618. //
  619. // Loop until done...
  620. //
  621. for(;;)
  622. {
  623. switch (EvalThisChar(*pwcThisChar, wcDelimiter))
  624. {
  625. case DIGIT:
  626. //
  627. // If this is the first digit after a delimiter, then
  628. // set flags to start computing the new number
  629. //
  630. if (bNewItem)
  631. {
  632. bNewItem = FALSE;
  633. bValidNumber = TRUE;
  634. }
  635. if (bValidNumber)
  636. {
  637. dwThisNumber *= 10;
  638. dwThisNumber += (*pwcThisChar - L'0');
  639. }
  640. break;
  641. case DELIMITER:
  642. //
  643. // A delimiter is either the delimiter character or the
  644. // end of the string ('\0') if when the delimiter has been
  645. // reached a valid number was found, then compare it to the
  646. // number from the argument list. if this is the end of the
  647. // string and no match was found, then return.
  648. //
  649. if (bValidNumber)
  650. {
  651. if (dwThisNumber == dwNumber)
  652. return TRUE;
  653. bValidNumber = FALSE;
  654. }
  655. if (*pwcThisChar == 0)
  656. {
  657. return FALSE;
  658. }
  659. else
  660. {
  661. bNewItem = TRUE;
  662. dwThisNumber = 0;
  663. }
  664. break;
  665. case INVALID:
  666. //
  667. // If an invalid character was encountered, ignore all
  668. // characters up to the next delimiter and then start fresh.
  669. // the invalid number is not compared.
  670. //
  671. bValidNumber = FALSE;
  672. break;
  673. default:
  674. break;
  675. }
  676. pwcThisChar++;
  677. }
  678. }
  679. ///////////////////////////////////////////////////////////////////////////////
  680. //
  681. // Utility functions called by the exported perfmon APIs
  682. //
  683. ///////////////////////////////////////////////////////////////////////////////
  684. DWORD Open (LibIndex iLib, LPCWSTR pcwstrLib)
  685. {
  686. HANDLE hMHeap = NULL;
  687. hMHeap = ExchMHeapCreate (0, 0, 100 * 1024, 0);
  688. if (NULL == hMHeap)
  689. goto Exit;
  690. lstrcpyW (g_rgszLibraries[iLib], g_wszPrefixGlobal);
  691. lstrcatW (g_rgszLibraries[iLib], pcwstrLib);
  692. g_rgfInitOk[iLib] = TRUE;
  693. Exit:
  694. return ERROR_SUCCESS;
  695. }
  696. DWORD Collect (LibIndex iLib,
  697. LPWSTR lpwszValue,
  698. void** ppdata,
  699. DWORD* pdwBytes,
  700. DWORD* pdwObjectTypes)
  701. {
  702. DWORD dwQueryType;
  703. DWORD dwBytesIn;
  704. DWORD dwSpaceNeeded = 0; // Space needed for counters
  705. DWORD dwRet = ERROR_SUCCESS; // Our return value
  706. PerfLibraryData rgld;
  707. //
  708. // Save the number of bytes in before overwriting it
  709. //
  710. dwBytesIn = *pdwBytes;
  711. //
  712. // Set up the out parameters to indicate an error. We will change them
  713. // later upon success
  714. //
  715. *pdwBytes = 0;
  716. *pdwObjectTypes = 0;
  717. if (!g_rgfInitOk[iLib])
  718. {
  719. //
  720. // Only acceptable error return is ERROR_MORE_DATA. anything else
  721. // should return ERROR_SUCCESS, but set the out parameters to indicate
  722. // that no data is being returned
  723. //
  724. goto Exit;
  725. }
  726. dwQueryType = GetQueryType (lpwszValue);
  727. if (dwQueryType == QUERY_FOREIGN)
  728. {
  729. //
  730. // This routine does not service requests for data from
  731. // Non-NT computers.
  732. //
  733. goto Exit;
  734. }
  735. //
  736. // Enumerate through all the libraries we know of and get their
  737. // performance statistices
  738. //
  739. if (!rgld.GetPerformanceStatistics (g_rgszLibraries[iLib]))
  740. goto Exit;
  741. //
  742. // Compute the space needed
  743. //
  744. dwSpaceNeeded = rgld.SpaceNeeded (dwQueryType, lpwszValue);
  745. // Round up to a multiple of 4.
  746. dwSpaceNeeded = QWORD_MULTIPLE (dwSpaceNeeded);
  747. //
  748. // See if the caller-provided buffer is large enough
  749. //
  750. if (dwBytesIn < dwSpaceNeeded)
  751. {
  752. //
  753. // Not enough space was provided by the caller
  754. //
  755. dwRet = ERROR_MORE_DATA;
  756. goto Exit;
  757. }
  758. //
  759. // Copy the performance data into the buffer
  760. //
  761. rgld.SavePerformanceData (ppdata, pdwBytes, pdwObjectTypes);
  762. Exit:
  763. return dwRet;
  764. }
  765. DWORD Close (LibIndex iLib)
  766. {
  767. if (g_rgfInitOk[iLib])
  768. {
  769. //
  770. // Release the reference to the global ExchMHeap.
  771. //
  772. ExchMHeapDestroy ();
  773. }
  774. return ERROR_SUCCESS;
  775. }
  776. ///////////////////////////////////////////////////////////////////////////////
  777. // PerfMon API functions
  778. // the following functions are exported from this DLL as the entry points
  779. // for a performance monitoring application
  780. ///////////////////////////////////////////////////////////////////////////////
  781. //
  782. // XXXXOpen
  783. // Called by performance monitor to initialize performance gathering.
  784. // The LPWSTR parameter contains the names of monitored devices. This
  785. // is for device driver performance DLL's and is not used by our DLL.
  786. //
  787. // XXXXXCollect
  788. // Called by the performance monitor to retrieve a block of performance
  789. // statistics.
  790. //
  791. // XXXXClose
  792. // Called by the performance monitor to terminate performance gathering
  793. //
  794. /* NTFSDrv */
  795. EXTERN_C
  796. DWORD APIENTRY NTFSDrvOpen (LPWSTR)
  797. {
  798. return Open (LIB_NTFSDRV, L"NTFSDrv");
  799. }
  800. EXTERN_C
  801. DWORD APIENTRY NTFSDrvCollect (LPWSTR lpwszValue,
  802. void** ppdata,
  803. DWORD* pdwBytes,
  804. DWORD* pdwObjectTypes)
  805. {
  806. return Collect (LIB_NTFSDRV, lpwszValue, ppdata, pdwBytes, pdwObjectTypes);
  807. }
  808. EXTERN_C
  809. DWORD APIENTRY NTFSDrvClose (void)
  810. {
  811. return Close (LIB_NTFSDRV);
  812. }