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.

670 lines
16 KiB

  1. //
  2. // Copyright (c) 2000 Microsoft Corporation
  3. //
  4. // Module Name
  5. //
  6. // heapwalk.c
  7. //
  8. // Abstract
  9. //
  10. // Contains functions that create/modify/update the datastructure
  11. // HEAP_ENTRY_LIST. HEAP_ENTRY_LIST maintains miminum amount of data
  12. // for a HEAP Object.
  13. //
  14. // Author
  15. //
  16. // Narayana Batchu (nbatchu) [May 11, 2001]
  17. //
  18. #include <windows.h>
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <tchar.h>
  22. #include "heapwalk.h"
  23. //
  24. // Initialize
  25. //
  26. // Initializes and allocates memory for the private member
  27. // variables of the HEAP_ENTRY_LIST datastructure.
  28. //
  29. // Arguments
  30. //
  31. // pList Pointer to HEAP_ENTRY_LIST whose member variables
  32. // to be initialized.
  33. //
  34. // Return Value
  35. //
  36. VOID Initialize(LPHEAP_ENTRY_LIST pList)
  37. {
  38. if (!pList) return;
  39. pList->HeapEntryCount = 0;
  40. pList->ListSorted = TRUE;
  41. pList->PresentCapacity = INITIAL_CAPACITY;
  42. pList->pHeapEntries = (LPHEAP_ENTRY_INFO)HeapAlloc(
  43. GetProcessHeap(),
  44. HEAP_ZERO_MEMORY,
  45. sizeof(HEAP_ENTRY_INFO) * pList->PresentCapacity
  46. );
  47. if (!pList->pHeapEntries)
  48. pList->PresentCapacity = 0;
  49. }
  50. //
  51. // DestroyList
  52. //
  53. // Cleans up the datastructure HEAP_ENTRY_LIST and frees up the
  54. // memory associated with the pHeapEntries member.
  55. //
  56. // Arguments
  57. //
  58. // pList Pointer to HEAP_ENTRY_LIST whose member variables
  59. // to be cleaned up.
  60. //
  61. // Return Value
  62. //
  63. VOID DestroyList(LPHEAP_ENTRY_LIST pList)
  64. {
  65. if (!pList) return;
  66. pList->HeapEntryCount = 0;
  67. pList->ListSorted = TRUE;
  68. pList->PresentCapacity = 0;
  69. if (NULL != pList->pHeapEntries) {
  70. HeapFree(GetProcessHeap(), 0, pList->pHeapEntries);
  71. pList->pHeapEntries = NULL;
  72. }
  73. }
  74. //
  75. // GetMaxBlockSize
  76. //
  77. // This function searches through the HEAP_ENTRY_LIST to find out
  78. // the maximum block size whose status is defined by 'State'.
  79. //
  80. // Arguments
  81. //
  82. // pList Pointer to HEAP_ENTRY_LIST.
  83. //
  84. // State Specifies the status to search for the maximum size.
  85. // State of any block can be 0 (FREE) and 1 (BUSY).
  86. // There are other valid status values also,
  87. // but we dont maintain those entries.
  88. //
  89. // Return Value
  90. //
  91. // DWORD Returns the maximum size of the block with status 'State'.
  92. //
  93. ULONG GetMaxBlockSize(LPHEAP_ENTRY_LIST pList, BLOCK_STATE State)
  94. {
  95. ULONG MaxBlockSize = 0;
  96. UINT Index;
  97. if (!pList) goto ERROR1;
  98. if (FALSE == pList->ListSorted)
  99. {
  100. SortHeapEntries(pList);
  101. }
  102. for (Index=0; Index < pList->HeapEntryCount; Index++)
  103. {
  104. if (State == pList->pHeapEntries[Index].BlockState)
  105. {
  106. MaxBlockSize = pList->pHeapEntries[Index].BlockSize;
  107. break;
  108. }
  109. }
  110. ERROR1:
  111. return MaxBlockSize;
  112. }
  113. //
  114. // GetMaxFreeBlockSize
  115. //
  116. // This function searches through the HEAP_ENTRY_LIST to find out
  117. // the maximum free block size.
  118. //
  119. // Arguments
  120. //
  121. // pList Pointer to HEAP_ENTRY_LIST.
  122. //
  123. // Return Value
  124. //
  125. // DWORD Returns the maximum size of the available block
  126. //
  127. ULONG GetMaxFreeBlockSize(LPHEAP_ENTRY_LIST pList)
  128. {
  129. return GetMaxBlockSize(pList, HEAP_BLOCK_FREE);
  130. }
  131. //
  132. // GetMaxAllocBlockSize
  133. //
  134. // This function searches through the HEAP_ENTRY_LIST to find out
  135. // the maximum allocated block size.
  136. //
  137. // Arguments
  138. //
  139. // pList Pointer to HEAP_ENTRY_LIST.
  140. //
  141. // Return Value
  142. //
  143. // DWORD Returns the maximum size of the allocated block.
  144. //
  145. ULONG GetMaxAllocBlockSize(LPHEAP_ENTRY_LIST pList)
  146. {
  147. return GetMaxBlockSize(pList, HEAP_BLOCK_BUSY);
  148. }
  149. //
  150. // GetTopNfreeEntries
  151. //
  152. // This function scans through the entry list to find the top
  153. // n free entries in the list.
  154. //
  155. // Arguments
  156. //
  157. // pList Pointer to HEAP_ENTRY_LIST.
  158. //
  159. // pArray Array of HEAP_ENTRY_INFO structures. This holds the
  160. // top n free block sizes available for the process.
  161. //
  162. // Entries Specifies the top number of entries to be read from
  163. // the list.
  164. //
  165. // Return Value
  166. //
  167. // BOOL Returns TRUE if successful.
  168. //
  169. BOOL GetTopNfreeEntries(
  170. LPHEAP_ENTRY_LIST pList,
  171. LPHEAP_ENTRY_INFO pArray,
  172. UINT EntriesToRead)
  173. {
  174. return GetTopNentries(
  175. HEAP_BLOCK_FREE,
  176. pList,
  177. pArray,
  178. EntriesToRead
  179. );
  180. }
  181. //
  182. // GetTopNallocEntries
  183. //
  184. // This function scans through the entry list to find the top
  185. // n allocated entries in the list.
  186. //
  187. // Arguments
  188. //
  189. // pList Pointer to HEAP_ENTRY_LIST.
  190. //
  191. // pArray Array of HEAP_ENTRY_INFO structures. This holds the
  192. // top n allocated block sizes available for the process.
  193. //
  194. // Entries Specifies the top number of entries to be read from
  195. // the list.
  196. //
  197. // Return Value
  198. //
  199. // BOOL Returns TRUE if successful.
  200. //
  201. BOOL GetTopNallocEntries(
  202. LPHEAP_ENTRY_LIST pList,
  203. LPHEAP_ENTRY_INFO pArray,
  204. UINT EntriesToRead
  205. )
  206. {
  207. return GetTopNentries(
  208. HEAP_BLOCK_BUSY,
  209. pList,
  210. pArray,
  211. EntriesToRead
  212. );
  213. }
  214. //
  215. // GetTopNallocEntries
  216. //
  217. // This function scans through the entry list to find the top
  218. // n entries in the list, whose staus matches 'State'.
  219. //
  220. // Arguments
  221. //
  222. // pList Pointer to HEAP_ENTRY_LIST.
  223. //
  224. // pArray Array of HEAP_ENTRY_INFO structures. This holds the
  225. // top n block sizes available for the process, whose status
  226. // matches 'State'.
  227. //
  228. // Entries Specifies the top number of entries to be read from
  229. // the list.
  230. //
  231. // Return Value
  232. //
  233. // BOOL Returns TRUE if successful.
  234. //
  235. BOOL GetTopNentries(
  236. BLOCK_STATE State,
  237. LPHEAP_ENTRY_LIST pList,
  238. LPHEAP_ENTRY_INFO pArray,
  239. UINT EntriesToRead
  240. )
  241. {
  242. BOOL fSuccess = FALSE;
  243. UINT EntriesRead = 0;
  244. UINT Index;
  245. if (!pArray || !pList) goto ERROR2;
  246. if (FALSE == pList->ListSorted)
  247. {
  248. SortHeapEntries(pList);
  249. }
  250. for (Index=0; Index < pList->HeapEntryCount; Index++)
  251. {
  252. if (EntriesRead == EntriesToRead)
  253. break;
  254. if (State == pList->pHeapEntries[Index].BlockState)
  255. {
  256. pArray[EntriesRead].BlockSize =
  257. pList->pHeapEntries[Index].BlockSize;
  258. pArray[EntriesRead].BlockCount =
  259. pList->pHeapEntries[Index].BlockCount;
  260. pArray[EntriesRead].BlockState =
  261. pList->pHeapEntries[Index].BlockState;
  262. EntriesRead++;
  263. }
  264. }
  265. if (EntriesRead == EntriesToRead)
  266. fSuccess = TRUE;
  267. ERROR2:
  268. return fSuccess;
  269. }
  270. //
  271. // IncreaseCapacity
  272. //
  273. // Increases the array capacity by double. This function is called
  274. // when tried to insert at the end of the array which is full.
  275. //
  276. // Arguments
  277. //
  278. // pList Pointer to HEAP_ENTRY_LIST.
  279. //
  280. // Return Value
  281. //
  282. // BOOL Returns TRUE if successful in increasing the capacity.
  283. //
  284. BOOL IncreaseCapacity(LPHEAP_ENTRY_LIST pList)
  285. {
  286. BOOL fSuccess = FALSE;
  287. UINT NewCapacity = 0;
  288. PVOID pvTemp = NULL;
  289. if (NULL == pList) {
  290. goto Exit;
  291. }
  292. if (0 == pList->PresentCapacity) {
  293. NewCapacity = INITIAL_CAPACITY;
  294. pvTemp = HeapAlloc(GetProcessHeap(),
  295. HEAP_ZERO_MEMORY,
  296. NewCapacity * sizeof(HEAP_ENTRY_INFO));
  297. }
  298. else {
  299. NewCapacity = pList->PresentCapacity * 2;
  300. pvTemp = HeapReAlloc(GetProcessHeap(),
  301. HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY,
  302. pList->pHeapEntries,
  303. NewCapacity * sizeof(HEAP_ENTRY_INFO));
  304. }
  305. if (NULL != pvTemp) {
  306. pList->pHeapEntries = pvTemp;
  307. pList->PresentCapacity = NewCapacity;
  308. fSuccess = TRUE;
  309. }
  310. Exit:
  311. return fSuccess;
  312. /*
  313. BOOL fSuccess = FALSE;
  314. UINT NewCapacity;
  315. if (!pList) goto ERROR3;
  316. NewCapacity = pList->PresentCapacity * 2;
  317. if (0 == NewCapacity)
  318. NewCapacity = INITIAL_CAPACITY;
  319. __try
  320. {
  321. pList->pHeapEntries = (LPHEAP_ENTRY_INFO)HeapReAlloc(
  322. GetProcessHeap(),
  323. HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY,
  324. pList->pHeapEntries,
  325. NewCapacity * sizeof(HEAP_ENTRY_INFO)
  326. );
  327. pList->PresentCapacity = NewCapacity;
  328. fSuccess = TRUE;
  329. }
  330. __except(GetExceptionCode() == STATUS_NO_MEMORY ||
  331. GetExceptionCode() == STATUS_ACCESS_VIOLATION)
  332. {
  333. //
  334. // Ignoring the exceptions raised by HeapReAlloc().
  335. //
  336. }
  337. ERROR3:
  338. return fSuccess;
  339. */
  340. }
  341. //
  342. // FindMatch
  343. //
  344. // Finds an entry in the HEAP_ENTRY_LIST that matches the size and
  345. // status of pHeapEntry.
  346. //
  347. // Arguments
  348. //
  349. // pList Pointer to HEAP_ENTRY_LIST.
  350. //
  351. // pHeapEntry Pointer to HEAP_ENTRY_INFO to be serached for in 'pList'.
  352. //
  353. // Return Value
  354. //
  355. // DWORD Index of the heap entry that matched the input heap entry
  356. // 'pHeapEntry'
  357. //
  358. //
  359. UINT FindMatch(LPHEAP_ENTRY_LIST pList, LPHEAP_ENTRY_INFO pHeapEntry)
  360. {
  361. UINT MatchedEntry = NO_MATCH;
  362. UINT Index;
  363. if (!pList || !pHeapEntry) goto ERROR4;
  364. for (Index = 0; Index < pList->HeapEntryCount; Index++)
  365. {
  366. if (pList->pHeapEntries[Index].BlockSize == pHeapEntry->BlockSize &&
  367. pList->pHeapEntries[Index].BlockState == pHeapEntry->BlockState)
  368. {
  369. MatchedEntry = Index;
  370. break;
  371. }
  372. }
  373. ERROR4:
  374. return MatchedEntry;
  375. }
  376. //
  377. // InsertHeapEntry
  378. //
  379. // Inserts a new heap entry to the list. It updates the block count if
  380. // a match is found else a new entry is made at the end of the HEAP_
  381. // ENTRY_INFO array.
  382. //
  383. // Arguments
  384. //
  385. // pList Pointer to HEAP_ENTRY_LIST.
  386. //
  387. // pHeapEntry Pointer to HEAP_ENTRY_INFO that is to be added to 'pList'.
  388. //
  389. // Return Value
  390. //
  391. // DWORD Returns the index at which it is added to the array. If
  392. // for any reason, it is not added to the list, then it
  393. // returns NO_MATCH value.
  394. //
  395. UINT InsertHeapEntry(LPHEAP_ENTRY_LIST pList, LPHEAP_ENTRY_INFO pHeapEntry)
  396. {
  397. UINT MatchedEntry = NO_MATCH;
  398. if (!pList || !pHeapEntry) goto ERROR5;
  399. MatchedEntry = FindMatch(pList, pHeapEntry);
  400. if (NO_MATCH != MatchedEntry)
  401. pList->pHeapEntries[MatchedEntry].BlockCount++;
  402. else
  403. {
  404. UINT Index = pList->HeapEntryCount;
  405. if (Index == pList->PresentCapacity && !IncreaseCapacity(pList))
  406. goto ERROR5;
  407. pList->pHeapEntries[Index].BlockSize = pHeapEntry->BlockSize;
  408. pList->pHeapEntries[Index].BlockState = pHeapEntry->BlockState;
  409. pList->pHeapEntries[Index].BlockCount = 1;
  410. MatchedEntry = Index;
  411. pList->HeapEntryCount++;
  412. pList->ListSorted = FALSE;
  413. }
  414. ERROR5:
  415. return MatchedEntry;
  416. }
  417. VOID
  418. SetHeapEntry(
  419. LPHEAP_ENTRY_INFO HeapEntryInfo,
  420. USHORT Status,
  421. ULONG Size
  422. )
  423. {
  424. if (NULL == HeapEntryInfo) {
  425. return;
  426. }
  427. HeapEntryInfo->BlockState = Status;
  428. HeapEntryInfo->BlockSize = Size;
  429. HeapEntryInfo->BlockCount = 1;
  430. }
  431. //
  432. // DeleteHeapEntry
  433. //
  434. // Deletes a new heap entry to the list. It decrements the block count
  435. // if a match is found.
  436. //
  437. // Its possible that the block size is zero and still the heap entry
  438. // exits. In such cases we dont decrement the block count (which would
  439. // make it negative) and return a NO_MATCH.
  440. //
  441. // Arguments
  442. //
  443. // pList Pointer to HEAP_ENTRY_LIST
  444. //
  445. // pHeapEntry Pointer to HEAP_ENTRY_INFO that is to be removed from 'pList'.
  446. //
  447. // Return Value
  448. //
  449. // DWORD Returns the index at which it is removed from the array. If for
  450. // any reason (Count==0), it is not removed to the list, then it
  451. // returns NO_MATCH value.
  452. //
  453. UINT DeleteHeapEntry(LPHEAP_ENTRY_LIST pList, LPHEAP_ENTRY_INFO pHeapEntry)
  454. {
  455. UINT MatchedEntry = NO_MATCH;
  456. if (!pList || !pHeapEntry) goto ERROR6;
  457. MatchedEntry = FindMatch(pList, pHeapEntry);
  458. if (NO_MATCH != MatchedEntry &&
  459. 0 != pList->pHeapEntries[MatchedEntry].BlockCount)
  460. {
  461. pList->pHeapEntries[MatchedEntry].BlockCount--;
  462. }
  463. else
  464. MatchedEntry = NO_MATCH;
  465. ERROR6:
  466. return MatchedEntry;
  467. }
  468. //
  469. // SortByBlockSize
  470. //
  471. // Compare function required by qsort (uses quick sort to sort
  472. // the elements in the array).
  473. //
  474. // More info about the arguments and the return values could be
  475. // found in MSDN.
  476. //
  477. int __cdecl SortByBlockSize(const void * arg1, const void *arg2)
  478. {
  479. int iCompare;
  480. LPHEAP_ENTRY_INFO hpEntry1 = (LPHEAP_ENTRY_INFO)arg1;
  481. LPHEAP_ENTRY_INFO hpEntry2 = (LPHEAP_ENTRY_INFO)arg2;
  482. iCompare = (hpEntry2->BlockSize - hpEntry1->BlockSize);
  483. return iCompare;
  484. }
  485. //
  486. // DisplayHeapFragStatistics
  487. //
  488. // Sorts and displays the fragmentation statistics. It displays
  489. // two tables one for free blocks and another for allocated blocks.
  490. //
  491. // Arguments
  492. //
  493. // File Pointer to C FILE structure, to which the heap frag-
  494. // mentation statistics have to be dumped.
  495. //
  496. // pList Pointer to HEAP_ENTRY_LIST, to be sorted and
  497. // dumped to 'File'.
  498. //
  499. // Return Value
  500. //
  501. VOID DisplayHeapFragStatistics(
  502. FILE * File,
  503. PVOID HeapAddress,
  504. LPHEAP_ENTRY_LIST pList
  505. )
  506. {
  507. if (!pList) return;
  508. fprintf(
  509. File,
  510. "\n*- - - - - - - - - - Heap %p Fragmentation Statistics - - - - - - - - - -\n\n",
  511. HeapAddress
  512. );
  513. SortHeapEntries(pList);
  514. PrintList(File, pList, HEAP_BLOCK_BUSY);
  515. PrintList(File, pList, HEAP_BLOCK_FREE);
  516. }
  517. //
  518. // SortHeapEntries
  519. //
  520. // Sorts the heap entries based on their sizes. The top most entry
  521. // would be having the maximun block size.
  522. //
  523. // Also, removes those heap entries from the array whose block count
  524. // has dropped to zero, making available more space.
  525. //
  526. // Arguments
  527. //
  528. // pList Pointer to HEAP_ENTRY_LIST, whose entries to be sorted by
  529. // their sizes.
  530. //
  531. // Return Value
  532. //
  533. VOID SortHeapEntries(LPHEAP_ENTRY_LIST pList)
  534. {
  535. UINT Index;
  536. if (!pList) return;
  537. if (FALSE == pList->ListSorted)
  538. {
  539. qsort(
  540. pList->pHeapEntries,
  541. pList->HeapEntryCount,
  542. sizeof(HEAP_ENTRY_INFO),
  543. &SortByBlockSize
  544. );
  545. for (Index = pList->HeapEntryCount-1; Index > 0; Index--)
  546. {
  547. if (0 != pList->pHeapEntries[Index].BlockCount)
  548. break;
  549. }
  550. pList->HeapEntryCount = Index + 1;
  551. pList->ListSorted = TRUE;
  552. }
  553. }
  554. //
  555. // PrintList
  556. //
  557. // Utility function that prints out the heap entries to the stdout/
  558. // file, whose status is equal to "State".
  559. //
  560. // Arguments
  561. //
  562. // File Pointer to C FILE structure, to which the heap frag-
  563. // mentation statistics have to be dumped.
  564. //
  565. // pList Pointer to HEAP_ENTRY_LIST, to be sorted and
  566. // dumped to 'File'.
  567. //
  568. // State State of the blocks to be displayed.
  569. //
  570. // Return Value
  571. //
  572. VOID PrintList(FILE * File, LPHEAP_ENTRY_LIST pList, BLOCK_STATE State)
  573. {
  574. UINT Index;
  575. if (!pList) return;
  576. if (HEAP_BLOCK_FREE == State)
  577. fprintf(File, "\nTable of Free Blocks\n\n");
  578. else if (HEAP_BLOCK_BUSY == State)
  579. fprintf(File, "\nTable of Allocated Blocks\n\n");
  580. fprintf(File, " SIZE | COUNT\n");
  581. fprintf(File, " ------------------------\n");
  582. for (Index = 0; Index < pList->HeapEntryCount; Index++)
  583. {
  584. if (State == pList->pHeapEntries[Index].BlockState)
  585. {
  586. fprintf(
  587. File,
  588. " 0x%08x | 0x%08x\n",
  589. pList->pHeapEntries[Index].BlockSize,
  590. pList->pHeapEntries[Index].BlockCount
  591. );
  592. }
  593. }
  594. fprintf(File, "\n");
  595. }