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.

650 lines
10 KiB

  1. /*++
  2. Copyright (c) 1999-1999 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. dbgheap.cxx
  6. Abstract:
  7. Debug heap
  8. Author:
  9. Steve Kiraly (SteveKi) 6-Feb-1999
  10. Revision History:
  11. --*/
  12. #include "precomp.hxx"
  13. #pragma hdrstop
  14. #include "dbgheap.hxx"
  15. /*++
  16. Title:
  17. Constructor
  18. Routine Description:
  19. This routine only initialize class variables, you must
  20. call Initialize before the class is in a usable state.
  21. Arguments:
  22. None.
  23. Return Value:
  24. None.
  25. --*/
  26. TDebugHeap::
  27. TDebugHeap(
  28. VOID
  29. )
  30. {
  31. }
  32. /*++
  33. Title:
  34. Destructor
  35. Routine Description:
  36. Class destructor, you must call Destroy to relase this class.
  37. Arguments:
  38. None
  39. Return Value:
  40. None
  41. --*/
  42. TDebugHeap::
  43. ~TDebugHeap(
  44. VOID
  45. )
  46. {
  47. }
  48. /*++
  49. Title:
  50. bValid
  51. Routine Description:
  52. Use this method to determin if the heap is usable.
  53. Arguments:
  54. None.
  55. Return Value:
  56. TRUE class is valid i.e. usable, FALSE class not usable.
  57. --*/
  58. BOOL
  59. TDebugHeap::
  60. Valid(
  61. VOID
  62. ) const
  63. {
  64. return m_bValid;
  65. }
  66. /*++
  67. Title:
  68. Initialize
  69. Routine Description:
  70. Initialize the heap, the bValid method should be called
  71. after this method to determine if the heap is in a usable
  72. state.
  73. Arguments:
  74. None
  75. Return Value:
  76. None
  77. --*/
  78. VOID
  79. TDebugHeap::
  80. Initialize(
  81. VOID
  82. )
  83. {
  84. //
  85. // Initalize the call members.
  86. //
  87. InitalizeClassMembers();
  88. //
  89. // Create the debug heap.
  90. //
  91. m_hHeap = HeapCreate( HEAP_NO_SERIALIZE, m_uSize, 0 );
  92. if (m_hHeap)
  93. {
  94. //
  95. // Allocation the initial heap.
  96. //
  97. m_pHeap = reinterpret_cast<BlockHeader *>( HeapAlloc( m_hHeap, 0, m_uSize ) );
  98. if (m_pHeap)
  99. {
  100. //
  101. // Initialize any needed heap variables.
  102. //
  103. m_pHeap->pNext = NULL;
  104. m_pHeap->uSize = m_uSize - sizeof( BlockHeader );
  105. m_pHeap->eStatus = kFree;
  106. m_bValid = TRUE;
  107. }
  108. else
  109. {
  110. //
  111. // Error occurred cleanup.
  112. //
  113. Destroy();
  114. }
  115. }
  116. }
  117. /*++
  118. Title:
  119. Destroy
  120. Routine Description:
  121. Release any resources for the heap.
  122. Arguments:
  123. None
  124. Return Value:
  125. None
  126. --*/
  127. VOID
  128. TDebugHeap::
  129. Destroy(
  130. VOID
  131. )
  132. {
  133. //
  134. // Destroy the heap if it was allocated.
  135. //
  136. if (m_hHeap)
  137. {
  138. //
  139. // Destroy the heap data.
  140. //
  141. HeapDestroy( m_hHeap );
  142. }
  143. //
  144. // Clear the heap variables.
  145. //
  146. InitalizeClassMembers();
  147. }
  148. /*++
  149. Title:
  150. Malloc
  151. Routine Description:
  152. Allocate a new block of memory.
  153. Arguments:
  154. Size - size in bytes of the requested block to allocate
  155. Return Value:
  156. Pointer to newly allocated block is success, NULL on failure
  157. --*/
  158. PVOID
  159. TDebugHeap::
  160. Malloc(
  161. IN SIZE_T uSize
  162. )
  163. {
  164. BlockHeader *pBlock = NULL;
  165. //
  166. // Ignore zero size requests.
  167. //
  168. if (uSize)
  169. {
  170. //
  171. // Round up to some reasonable even value.
  172. //
  173. uSize = RoundUpToGranularity( uSize );
  174. //
  175. // Find first block that can hold the required size. Coalesce the
  176. // blocks as the chain is traversed.
  177. //
  178. for (pBlock = reinterpret_cast<BlockHeader *>( m_pHeap ); pBlock; pBlock = pBlock->pNext)
  179. {
  180. if (pBlock->eStatus == kFree)
  181. {
  182. //
  183. // Coalesce the blocks as we look for an appropriate block.
  184. //
  185. Coalesce( pBlock );
  186. //
  187. // Found a big enough block
  188. //
  189. if (pBlock->uSize >= uSize)
  190. {
  191. break;
  192. }
  193. }
  194. }
  195. //
  196. // Check for failure
  197. //
  198. if (pBlock)
  199. {
  200. //
  201. // Split the block, if possible
  202. //
  203. SplitBlock( pBlock, uSize );
  204. //
  205. // Mark the block as in use.
  206. //
  207. pBlock->eStatus = kInUse;
  208. //
  209. // Return the appropriate pointer
  210. //
  211. pBlock++;
  212. }
  213. else
  214. {
  215. ErrorText( _T("Error: Unabled to allocate memory, size %d.\n"), uSize );
  216. }
  217. }
  218. return pBlock;
  219. }
  220. /*++
  221. Title:
  222. Free
  223. Routine Description:
  224. Delete the block of memory.
  225. Arguments:
  226. pData - pointer to data to free
  227. Return Value:
  228. None
  229. --*/
  230. VOID
  231. TDebugHeap::
  232. Free(
  233. IN PVOID pData
  234. )
  235. {
  236. //
  237. // Ignore null pointer.
  238. //
  239. if (pData)
  240. {
  241. //
  242. // Back up to start of the header
  243. //
  244. BlockHeader *pBlock = reinterpret_cast<BlockHeader *>( pData ) - 1;
  245. //
  246. // Free the block if not already free.
  247. //
  248. if (pBlock >= m_pHeap && pBlock <= m_pHeap + m_uSize && pBlock->eStatus == kInUse)
  249. {
  250. //
  251. // Mark the block as freed.
  252. //
  253. pBlock->eStatus = kFree;
  254. }
  255. else
  256. {
  257. ErrorText( _T("Error: Invalid or free block passed to free 0x%lx.\n"), pBlock );
  258. }
  259. }
  260. }
  261. /********************************************************************
  262. Private member functions.
  263. ********************************************************************/
  264. /*++
  265. Title:
  266. SplitBlock
  267. Routine Description:
  268. Take the current block and attempt to split it into two.
  269. Arguments:
  270. pBlockHeader - pointer to memory block header
  271. Size - size of requested block
  272. Return Value:
  273. None
  274. --*/
  275. VOID
  276. TDebugHeap::
  277. SplitBlock(
  278. IN BlockHeader *pBlock,
  279. IN SIZE_T uSize
  280. )
  281. {
  282. if (pBlock->uSize >= (uSize + sizeof(BlockHeader)))
  283. {
  284. BlockHeader *pNext;
  285. //
  286. // Split the block into two the size requested and the remainder.
  287. //
  288. pNext = reinterpret_cast<BlockHeader *>( (reinterpret_cast<PBYTE>( pBlock ) + uSize + sizeof(BlockHeader)) );
  289. pNext->pNext = pBlock->pNext;
  290. pNext->uSize = pBlock->uSize - uSize - sizeof(BlockHeader);
  291. //
  292. // Can only split off FREE blocks
  293. //
  294. pNext->eStatus = kFree;
  295. pBlock->pNext = pNext;
  296. pBlock->uSize = uSize;
  297. }
  298. }
  299. /*++
  300. Title:
  301. Coalesce
  302. Routine Description:
  303. Take and collapse any adjacent blocks.
  304. Arguments:
  305. pBlock - pointer to memory block header
  306. Return Value:
  307. None
  308. --*/
  309. VOID
  310. TDebugHeap::
  311. Coalesce(
  312. IN BlockHeader *pBlock
  313. )
  314. {
  315. //
  316. // Check for null pointers
  317. //
  318. if (pBlock)
  319. {
  320. //
  321. // The next block can be tacked onto the end of the current
  322. //
  323. for (BlockHeader *pNext = pBlock->pNext; pNext && pNext->eStatus == kFree; pNext = pBlock->pNext)
  324. {
  325. //
  326. // Remove from the chain
  327. //
  328. pBlock->pNext = pNext->pNext;
  329. //
  330. // Absorb its storage
  331. //
  332. pBlock->uSize += pNext->uSize + sizeof( BlockHeader );
  333. }
  334. }
  335. }
  336. /*++
  337. Title:
  338. WalkDebugHeap
  339. Routine Description:
  340. Walk the heap list.
  341. Arguments:
  342. pEnumProc - pointer function to call at each block
  343. pRefDate - caller defined reference data
  344. Return Value:
  345. Always returns TRUE success.
  346. --*/
  347. BOOL
  348. TDebugHeap::
  349. Walk(
  350. IN pfHeapEnumProc pEnumProc,
  351. IN PVOID pRefData
  352. )
  353. {
  354. //
  355. // If an enumerator was not passed then use the default.
  356. //
  357. if (!pEnumProc)
  358. {
  359. pEnumProc = DefaultHeapEnumProc;
  360. }
  361. BlockHeader *pBlock = reinterpret_cast<BlockHeader *>( m_pHeap );
  362. //
  363. // Coalesce before we walk to decrease free block spew.
  364. //
  365. Coalesce( pBlock );
  366. //
  367. // If we only have one free bock then the heap is empty
  368. // then just skip the walk.
  369. //
  370. if( pBlock->pNext || pBlock->eStatus != kFree )
  371. {
  372. //
  373. // Display the interal heap summary information
  374. //
  375. ErrorText( _T("Internal Heap Information:\n") );
  376. ErrorText( _T("\tHandle : 0x%lx\n"), m_hHeap );
  377. ErrorText( _T("\tStarting Block : 0x%lx\n"), m_pHeap );
  378. ErrorText( _T("\tHeap Size : %d bytes\n"), m_uSize );
  379. ErrorText( _T("\tGranularity : %d bytes\n"), m_uGranularity );
  380. ErrorText( _T("Internal Heap Entries:\n") );
  381. //
  382. // Point to the first block in the heap.
  383. //
  384. pBlock = reinterpret_cast<BlockHeader *>( m_pHeap );
  385. //
  386. // Walk the chain, calling the enumerator at each free node.
  387. //
  388. for ( ; pBlock; pBlock = pBlock->pNext)
  389. {
  390. if( pBlock->eStatus == kFree )
  391. {
  392. if (!pEnumProc( pBlock, pRefData ))
  393. {
  394. break;
  395. }
  396. }
  397. }
  398. //
  399. // Point to the first block in the heap.
  400. //
  401. pBlock = reinterpret_cast<BlockHeader *>( m_pHeap );
  402. //
  403. // Walk the chain, calling the enumerator at each busy node.
  404. //
  405. for ( ; pBlock; pBlock = pBlock->pNext)
  406. {
  407. if( pBlock->eStatus != kFree )
  408. {
  409. if (!pEnumProc( pBlock, pRefData ))
  410. {
  411. break;
  412. }
  413. }
  414. }
  415. }
  416. return TRUE;
  417. }
  418. /*++
  419. Title:
  420. DefaultHeapEnumProc
  421. Routine Description:
  422. Display the heap node data.
  423. Arguments:
  424. pBlockHeader - pointer to memory block
  425. pRefDate - caller defined reference data
  426. Return Value:
  427. Always returns TRUE success.
  428. --*/
  429. BOOL
  430. TDebugHeap::
  431. DefaultHeapEnumProc(
  432. IN BlockHeader *pBlockHeader,
  433. IN PVOID pRefData
  434. )
  435. {
  436. LPCTSTR pszStatus = pBlockHeader->eStatus == kFree ? _T("free") : _T("busy");
  437. ErrorText( _T("\t0x%lx : %s (%d)\n"), pBlockHeader, pszStatus, pBlockHeader->uSize );
  438. return TRUE;
  439. }
  440. /*++
  441. Title:
  442. RoundUpToGranularity
  443. Routine Description:
  444. Rounds up the specified value to the next granular value.
  445. Arguments:
  446. uValue - Value to round up.
  447. Return Value:
  448. Returns rounded up value.
  449. --*/
  450. SIZE_T
  451. TDebugHeap::
  452. RoundUpToGranularity(
  453. IN SIZE_T uValue
  454. ) const
  455. {
  456. return (uValue + m_uGranularity - 1) & ~(m_uGranularity - 1);
  457. }
  458. /*++
  459. Title:
  460. InitalizeClassMembers
  461. Routine Description:
  462. Initalizes the class members.
  463. Arguments:
  464. None.
  465. Return Value:
  466. Nothing.
  467. --*/
  468. VOID
  469. TDebugHeap::
  470. InitalizeClassMembers(
  471. VOID
  472. )
  473. {
  474. m_bValid = FALSE;
  475. m_pHeap = NULL;
  476. m_hHeap = NULL;
  477. m_uSize = kDefaultHeapSize;
  478. m_uGranularity = kDefaultHeapGranularity;
  479. }