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.

1115 lines
25 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. poolmem.c
  5. Abstract:
  6. poolmem provides a managed allocation scheme in which large blocks of memory are
  7. allocated (pools) and then divided up by request into low overhead memory chunks
  8. upon request. poolmem provides for easy creation/clean-up of memory, freeing the
  9. developer for more important tasks.
  10. Author:
  11. Marc R. Whitten (marcw) 13-Feb-1997
  12. Revision History:
  13. marcw 2-Sep-1999 Moved over from Win9xUpg project.
  14. jimschm 28-Sep-1998 Debug message fixes
  15. --*/
  16. #include "pch.h"
  17. #ifdef UNICODE
  18. #error UNICODE not allowed
  19. #endif
  20. //
  21. // Includes
  22. //
  23. #include "utilsp.h"
  24. #define DBG_POOLMEM "Poolmem"
  25. //
  26. // Strings
  27. //
  28. // None
  29. //
  30. // Constants
  31. //
  32. //
  33. // Tree Memory Allocation structure.
  34. //
  35. #ifdef DEBUG
  36. #define VALIDDOGTAG 0x021371
  37. #define FREEDOGTAG 0x031073
  38. #endif
  39. #define MAX_POOL_NAME 32
  40. //
  41. // Macros
  42. //
  43. // None
  44. //
  45. // Types
  46. //
  47. typedef struct _PMBLOCK PMBLOCK, *PPMBLOCK;
  48. struct _PMBLOCK {
  49. UINT_PTR Index; // Tracks into RawMemory.
  50. SIZE_T Size; // the size in bytes of RawMemory.
  51. PPMBLOCK NextBlock; // A pointer to the next block in the pool chain.
  52. PPMBLOCK PrevBlock; // A pointer to the prev block in the pool chain.
  53. DWORD UseCount; // The number of allocations currently referring
  54. // to this block.
  55. PBYTE RawMemory; // The actual bytes of allocable memory in this block.
  56. };
  57. typedef struct _ALLOCATION ALLOCATION, * PALLOCATION;
  58. struct _ALLOCATION {
  59. #ifdef DEBUG
  60. DWORD DogTag; // A signature to ensure validity.
  61. SIZE_T Size;
  62. PALLOCATION Next; // The next allocation in the list.
  63. PALLOCATION Prev; // The previous allocation in the list.
  64. #endif
  65. PPMBLOCK ParentBlock; // A reference to the block from which this allocation
  66. // was created.
  67. };
  68. typedef enum {
  69. FREE_NOT_CALLED,
  70. FREE_CALLED,
  71. WHO_CARES
  72. } FREESTATE;
  73. typedef struct _POOLHEADER {
  74. PPMBLOCK PoolHead; // The active memory block in this pool.
  75. SIZE_T MinimumBlockSize; // minimum size to allocate when a new block is needed.
  76. #ifdef DEBUG
  77. CHAR Name[MAX_POOL_NAME];
  78. SIZE_T TotalAllocationRequestBytes;
  79. SIZE_T CurrentAllocationSize;
  80. SIZE_T MaxAllocationSize;
  81. SIZE_T CurrentlyAllocatedMemory;
  82. SIZE_T MaximumAllocatedMemory;
  83. UINT NumAllocationRequests;
  84. UINT NumFreeRequests;
  85. UINT NumBlockFrees;
  86. UINT NumBlockClears;
  87. UINT NumBlockAllocations;
  88. PALLOCATION AllocationList; // A linked list of all of the allocations active in the
  89. // pool.
  90. FREESTATE FreeCalled; // A state variable indicating that PoolMemReleaseMemory()
  91. // has been called at least once on this pool.
  92. #endif
  93. } POOLHEADER, *PPOOLHEADER;
  94. //
  95. // Globals
  96. //
  97. #ifdef DEBUG
  98. DWORD g_PmDisplayed;
  99. DWORD g_PmNotDisplayed;
  100. UINT g_PoolCurrPools = 0;
  101. SIZE_T g_PoolCurrTotalAlloc = 0;
  102. SIZE_T g_PoolCurrActiveAlloc = 0;
  103. SIZE_T g_PoolCurrUsedAlloc = 0;
  104. UINT g_PoolMaxPools = 0;
  105. SIZE_T g_PoolMaxTotalAlloc = 0;
  106. SIZE_T g_PoolMaxActiveAlloc = 0;
  107. SIZE_T g_PoolMaxUsedAlloc = 0;
  108. #endif
  109. //
  110. // Macro expansion list
  111. //
  112. // None
  113. //
  114. // Private function prototypes
  115. //
  116. // None
  117. //
  118. // Macro expansion definition
  119. //
  120. // None
  121. //
  122. // Code
  123. //
  124. BOOL
  125. pPmAddMemory (
  126. IN PMHANDLE Handle,
  127. IN SIZE_T Size
  128. )
  129. /*++
  130. Routine Description:
  131. pPmAddMemory is the function responsible for actually growing the size of
  132. the pool by adding a new block of memory. This function is used by
  133. PmCreatePool and PmGetMemory.
  134. when called, this function attempts to allocate at least poolHeader ->
  135. MinimumBlockSize bytes of memory. If the requested size is actually larger
  136. than the minimum, the requested size is allocated instead. This is consistent
  137. with PoolMem's main purpose: An efficient allocator for larger numbers of small
  138. objects. If PoolMem is being used to allocate very large objects, the benefits
  139. are lost and poolmem becomes a very inefficient allocator.
  140. Arguments:
  141. Handle - A Handle to a Pool of Memory.
  142. Size - Size to allocate.
  143. Return Value:
  144. returns TRUE if memory was successfully added, FALSE otherwise.
  145. --*/
  146. {
  147. PBYTE allocedMemory;
  148. PPMBLOCK newBlock;
  149. PPOOLHEADER poolHeader = (PPOOLHEADER) Handle;
  150. SIZE_T sizeNeeded;
  151. MYASSERT(poolHeader != NULL);
  152. //
  153. // Determine size needed and attempt to allocate memory.
  154. //
  155. if (Size + sizeof(PMBLOCK) > poolHeader->MinimumBlockSize) {
  156. sizeNeeded = Size + sizeof(PMBLOCK);
  157. }
  158. else {
  159. sizeNeeded = poolHeader->MinimumBlockSize;
  160. }
  161. MYASSERT (g_TrackFile);
  162. allocedMemory = MemAlloc(g_hHeap,0,sizeNeeded);
  163. if (allocedMemory) {
  164. #ifdef DEBUG
  165. g_PoolCurrTotalAlloc += sizeNeeded;
  166. if (g_PoolMaxTotalAlloc < g_PoolCurrTotalAlloc) {
  167. g_PoolMaxTotalAlloc = g_PoolCurrTotalAlloc;
  168. }
  169. g_PoolCurrActiveAlloc += (sizeNeeded - sizeof(PMBLOCK));
  170. if (g_PoolMaxActiveAlloc < g_PoolCurrActiveAlloc) {
  171. g_PoolMaxActiveAlloc = g_PoolCurrActiveAlloc;
  172. }
  173. #endif
  174. //
  175. // Use the beginning of the alloc'ed block as the poolblock structure.
  176. //
  177. newBlock = (PPMBLOCK) allocedMemory;
  178. newBlock->Size = sizeNeeded - sizeof(PMBLOCK);
  179. newBlock->RawMemory = allocedMemory + sizeof(PMBLOCK);
  180. newBlock->Index = 0;
  181. newBlock->UseCount = 0;
  182. //
  183. // Link the block into the list.
  184. //
  185. if (poolHeader->PoolHead) {
  186. poolHeader->PoolHead->PrevBlock = newBlock;
  187. }
  188. newBlock->NextBlock = poolHeader->PoolHead;
  189. newBlock->PrevBlock = NULL;
  190. poolHeader->PoolHead = newBlock;
  191. #ifdef DEBUG
  192. //
  193. // Keep track of pool statistics.
  194. //
  195. poolHeader->CurrentlyAllocatedMemory += sizeNeeded;
  196. poolHeader->MaximumAllocatedMemory =
  197. max(poolHeader->MaximumAllocatedMemory,poolHeader->CurrentlyAllocatedMemory);
  198. poolHeader->NumBlockAllocations++;
  199. #endif
  200. }
  201. //
  202. // Assuming allocedMemory is non-NULL, we have succeeded.
  203. //
  204. return allocedMemory != NULL;
  205. }
  206. PMHANDLE
  207. RealPmCreatePoolEx (
  208. IN DWORD BlockSize OPTIONAL
  209. )
  210. /*++
  211. Routine Description:
  212. Initializes a new memory pool and returns a handle to it.
  213. Arguments:
  214. None.
  215. Return Value:
  216. If the function completes succssessfully, it returns a valid PMHANDLE, otherwise,
  217. it returns NULL.
  218. --*/
  219. {
  220. BOOL ableToAddMemory;
  221. PPOOLHEADER header = NULL;
  222. EnterCriticalSection (&g_PmCs);
  223. __try {
  224. //
  225. // Allocate the header of this pool.
  226. //
  227. header = MemAlloc(g_hHeap,0,sizeof(POOLHEADER));
  228. #ifdef DEBUG
  229. g_PoolCurrTotalAlloc += sizeof(POOLHEADER);
  230. if (g_PoolMaxTotalAlloc < g_PoolCurrTotalAlloc) {
  231. g_PoolMaxTotalAlloc = g_PoolCurrTotalAlloc;
  232. }
  233. #endif
  234. //
  235. // Allocation was successful. Now, initialize the pool.
  236. //
  237. header->MinimumBlockSize = BlockSize?BlockSize:POOLMEMORYBLOCKSIZE;
  238. header->PoolHead = NULL;
  239. #ifdef DEBUG
  240. //
  241. // Statistics for the debug version.
  242. //
  243. header->TotalAllocationRequestBytes = 0;
  244. header->CurrentAllocationSize = 0;
  245. header->MaxAllocationSize = 0;
  246. header->CurrentlyAllocatedMemory = 0;
  247. header->MaximumAllocatedMemory = 0;
  248. header->NumAllocationRequests = 0;
  249. header->NumFreeRequests = 0;
  250. header->NumBlockFrees = 0;
  251. header->NumBlockClears = 0;
  252. header->NumBlockAllocations = 0;
  253. header->Name[0] = 0;
  254. #endif
  255. //
  256. // Actually add some memory to the pool.
  257. //
  258. ableToAddMemory = pPmAddMemory(header,0);
  259. if (!ableToAddMemory) {
  260. //
  261. // Unable to add memory to the pool.
  262. //
  263. MemFree(g_hHeap,0,header);
  264. #ifdef DEBUG
  265. g_PoolCurrTotalAlloc -= sizeof(POOLHEADER);
  266. #endif
  267. header = NULL;
  268. DEBUGMSG((DBG_ERROR,"PoolMem: Unable to initialize memory pool."));
  269. }
  270. #ifdef DEBUG
  271. //
  272. // These are 'cookie' variables that hold tracking information when dogtag checking
  273. // is enabled.
  274. //
  275. g_PmNotDisplayed = 12;
  276. g_PmDisplayed = 24;
  277. if (ableToAddMemory) {
  278. header->AllocationList = NULL; //lint !e613
  279. header->FreeCalled = FREE_NOT_CALLED; //lint !e613
  280. }
  281. #endif
  282. } __finally {
  283. LeaveCriticalSection (&g_PmCs);
  284. }
  285. #ifdef DEBUG
  286. if (header) {
  287. g_PoolCurrPools ++;
  288. if (g_PoolMaxPools < g_PoolCurrPools) {
  289. g_PoolMaxPools = g_PoolCurrPools;
  290. }
  291. }
  292. #endif
  293. return (PMHANDLE) header;
  294. }
  295. VOID
  296. pDeregisterPoolAllocations (
  297. PPOOLHEADER PoolHeader
  298. )
  299. {
  300. #ifdef DEBUG
  301. PALLOCATION p,cur;
  302. if (PoolHeader->FreeCalled == WHO_CARES) {
  303. return;
  304. }
  305. p = PoolHeader->AllocationList;
  306. while (p) {
  307. cur = p;
  308. p = p->Next;
  309. g_PoolCurrUsedAlloc -= cur->Size;
  310. DebugUnregisterAllocation(POOLMEM_POINTER,cur);
  311. }
  312. PoolHeader->AllocationList = NULL;
  313. #endif
  314. }
  315. VOID
  316. PmEmptyPool (
  317. IN PMHANDLE Handle
  318. )
  319. /*++
  320. Routine Description:
  321. PmEmptyPool resets the index pointer of the index block back
  322. to zero, so the next allocation will come from the already allocated
  323. active block.
  324. Calling this function invalidates all pointers previously allocated from
  325. the active block.
  326. Arguments:
  327. Handle - Specifies the pool to reset
  328. Return Value:
  329. None.
  330. --*/
  331. {
  332. PPOOLHEADER poolHeader = (PPOOLHEADER) Handle;
  333. if (!Handle) {
  334. return;
  335. }
  336. EnterCriticalSection (&g_PmCs);
  337. __try {
  338. poolHeader->PoolHead->UseCount = 0;
  339. poolHeader->PoolHead->Index = 0;
  340. #ifdef DEBUG
  341. poolHeader->NumBlockClears++;
  342. #endif
  343. #ifdef DEBUG
  344. pDeregisterPoolAllocations(poolHeader);
  345. #endif
  346. } __finally {
  347. LeaveCriticalSection (&g_PmCs);
  348. }
  349. }
  350. VOID
  351. PmSetMinimumGrowthSize (
  352. IN PMHANDLE Handle,
  353. IN SIZE_T Size
  354. )
  355. /*++
  356. Routine Description:
  357. Sets the minimum growth size for a memory pool. This value is used when new blocks
  358. are actually added to the pool. The PoolMem allocator will attempt to allocate at
  359. least this minimum size.
  360. Arguments:
  361. Handle - A valid PMHANDLE.
  362. Size - The minimum size in bytes to grow the pool by on each allocation.
  363. Return Value:
  364. None.
  365. --*/
  366. {
  367. PPOOLHEADER poolHeader = (PPOOLHEADER) Handle;
  368. MYASSERT(Handle != NULL);
  369. poolHeader->MinimumBlockSize = max(Size,0);
  370. }
  371. VOID
  372. PmDestroyPool (
  373. PMHANDLE Handle
  374. )
  375. /*++
  376. Routine Description:
  377. PmDestroyPool completely cleans up the memory pool identified by Handle. It
  378. simply walks the list of memory blocks associated with the memory pool, freeing each of them.
  379. Arguments:
  380. Handle - A valid PMHANDLE.
  381. Return Value:
  382. None.
  383. --*/
  384. {
  385. PPMBLOCK nextBlock;
  386. PPMBLOCK blockToFree;
  387. PPOOLHEADER poolHeader;
  388. if (!Handle) {
  389. return;
  390. }
  391. poolHeader = (PPOOLHEADER) Handle;
  392. #ifdef DEBUG
  393. if (poolHeader->NumAllocationRequests) {
  394. CHAR FloatWorkaround[32];
  395. _gcvt (
  396. ((DOUBLE) (poolHeader->TotalAllocationRequestBytes)) / poolHeader->NumAllocationRequests,
  397. 8,
  398. FloatWorkaround
  399. );
  400. //
  401. // Spew the statistics of this pool to the debug log.
  402. //
  403. DEBUGMSG ((
  404. DBG_POOLMEM,
  405. "Pool Statistics for %s\n"
  406. "\n"
  407. "Requested Size in Bytes\n"
  408. " Average: %s\n"
  409. " Maximum: %u\n"
  410. "\n"
  411. "Pool Size in Bytes\n"
  412. " Current: %u\n"
  413. " Maximum: %u\n"
  414. "\n"
  415. "Allocation Requests\n"
  416. " Caller Requests: %u\n"
  417. " Block Allocations: %u\n"
  418. "\n"
  419. "Free Requests\n"
  420. " Caller Requests: %u\n"
  421. " Block Frees: %u\n"
  422. " Block Clears: %u",
  423. poolHeader->Name[0] ? poolHeader->Name : "[Unnamed Pool]",
  424. FloatWorkaround,
  425. poolHeader->MaxAllocationSize,
  426. poolHeader->CurrentlyAllocatedMemory,
  427. poolHeader->MaximumAllocatedMemory,
  428. poolHeader->NumAllocationRequests,
  429. poolHeader->NumBlockAllocations,
  430. poolHeader->NumFreeRequests,
  431. poolHeader->NumBlockFrees,
  432. poolHeader->NumBlockClears
  433. ));
  434. } else if (poolHeader->Name[0]) {
  435. DEBUGMSG ((
  436. DBG_POOLMEM,
  437. "Pool %s was allocated but was never used",
  438. poolHeader->Name
  439. ));
  440. }
  441. #endif
  442. //
  443. // Walk the list, freeing as we go.
  444. //
  445. blockToFree = poolHeader-> PoolHead;
  446. while (blockToFree != NULL) {
  447. nextBlock = blockToFree->NextBlock;
  448. #ifdef DEBUG
  449. g_PoolCurrTotalAlloc -= (blockToFree->Size + sizeof(PMBLOCK));
  450. g_PoolCurrActiveAlloc -= blockToFree->Size;
  451. #endif
  452. MemFree(g_hHeap,0,blockToFree);
  453. blockToFree = nextBlock;
  454. }
  455. //
  456. // Also, deallocate the poolheader itself.
  457. //
  458. #ifdef DEBUG
  459. g_PoolCurrTotalAlloc -= sizeof (POOLHEADER);
  460. g_PoolCurrPools --;
  461. #endif
  462. MemFree(g_hHeap,0,poolHeader);
  463. }
  464. PVOID
  465. RealPmGetMemory (
  466. IN PMHANDLE Handle,
  467. IN SIZE_T Size,
  468. IN DWORD AlignSize
  469. )
  470. /*++
  471. Routine Description:
  472. RealPmGetMemory is the worker routine that processes all requests to retrieve memory
  473. from a pool. Other calls eventually decay into a call to this common routine. This routine
  474. attempts to service the request out of the current memory block, or, if it cannot, out of
  475. a newly allocated block.
  476. Arguments:
  477. Handle - A valid PMHANDLE.
  478. Size - Contains the size in bytes that the caller needs from the pool.
  479. AlignSize - Provides an alignment value. The returned memory will be aligned on <alignsize> byte
  480. boundaries.
  481. Return Value:
  482. The allocated memory, or, NULL if no memory could be allocated.
  483. --*/
  484. {
  485. BOOL haveEnoughMemory = TRUE;
  486. PVOID rMemory = NULL;
  487. PPOOLHEADER poolHeader = (PPOOLHEADER) Handle;
  488. PPMBLOCK currentBlock;
  489. PALLOCATION allocation;
  490. SIZE_T sizeNeeded;
  491. UINT_PTR padLength;
  492. MYASSERT(poolHeader != NULL);
  493. MYASSERT(Size);
  494. EnterCriticalSection (&g_PmCs);
  495. __try {
  496. //
  497. // Assume that the current block of memory will be sufficient.
  498. //
  499. currentBlock = poolHeader->PoolHead;
  500. #ifdef DEBUG
  501. //
  502. // Update stats.
  503. //
  504. poolHeader->CurrentAllocationSize += Size;
  505. poolHeader->MaxAllocationSize = max(poolHeader->MaxAllocationSize,poolHeader->CurrentAllocationSize);
  506. poolHeader->NumAllocationRequests++;
  507. poolHeader->TotalAllocationRequestBytes += Size;
  508. #endif
  509. //
  510. // Determine if more memory is needed, attempt to add if needed. Note that the size
  511. // must include the size of an ALLOCATION struct in addition to the size required
  512. // by the callee. Note the references to AlignSize in the test below. This is to ensure
  513. // that there is enough memory to allocate after taking into acount data alignment.
  514. //
  515. sizeNeeded = Size + sizeof(ALLOCATION);
  516. if (currentBlock->Size - currentBlock->Index < sizeNeeded + AlignSize) {
  517. haveEnoughMemory = pPmAddMemory(poolHeader,sizeNeeded + AlignSize);
  518. //
  519. // Make sure that the currentBlock is correctly set
  520. //
  521. currentBlock = poolHeader->PoolHead;
  522. }
  523. //
  524. // If there is enough memory available, return it.
  525. //
  526. if (haveEnoughMemory) {
  527. if (AlignSize) {
  528. padLength = (UINT_PTR) currentBlock + sizeof(PMBLOCK)
  529. + currentBlock->Index + sizeof(ALLOCATION);
  530. currentBlock->Index += (AlignSize - (padLength % AlignSize)) % AlignSize;
  531. }
  532. //
  533. // Save a reference to this block in the memorys ALLOCATION structure.
  534. // This will be used to decrease the use count on a block when releasing
  535. // memory.
  536. //
  537. allocation = (PALLOCATION) &(currentBlock->RawMemory[currentBlock->Index]);
  538. allocation->ParentBlock = currentBlock;
  539. #ifdef DEBUG
  540. //
  541. // Track this memory.
  542. //
  543. allocation->DogTag = VALIDDOGTAG;
  544. allocation->Size = Size;
  545. allocation->Next = poolHeader->AllocationList;
  546. allocation->Prev = NULL;
  547. if (poolHeader->AllocationList) {
  548. poolHeader->AllocationList->Prev = allocation;
  549. }
  550. poolHeader->AllocationList = allocation;
  551. if (poolHeader->FreeCalled != WHO_CARES) {
  552. g_PoolCurrUsedAlloc += Size;
  553. if (g_PoolMaxUsedAlloc < g_PoolCurrUsedAlloc) {
  554. g_PoolMaxUsedAlloc = g_PoolCurrUsedAlloc;
  555. }
  556. DebugRegisterAllocationEx (
  557. POOLMEM_POINTER,
  558. allocation,
  559. g_TrackFile,
  560. g_TrackLine,
  561. g_TrackAlloc
  562. );
  563. }
  564. #endif
  565. //
  566. // Ok, get a reference to the actual memory to return to the user.
  567. //
  568. rMemory = (PVOID)
  569. &(currentBlock->RawMemory[currentBlock->Index + sizeof(ALLOCATION)]);
  570. //
  571. // Update memory block data fields.
  572. //
  573. currentBlock->Index += sizeNeeded;
  574. currentBlock->UseCount++;
  575. }
  576. else {
  577. DEBUGMSG((DBG_ERROR,
  578. "GetPoolMemory Failed. Size: %u",Size));
  579. }
  580. } __finally {
  581. LeaveCriticalSection (&g_PmCs);
  582. }
  583. return rMemory;
  584. }
  585. VOID
  586. PmReleaseMemory (
  587. IN PMHANDLE Handle,
  588. IN PCVOID Memory
  589. )
  590. /*++
  591. Routine Description:
  592. PmReleaseMemory notifies the Pool that a piece of memory is no longer needed.
  593. if all memory within a non-active block (i.e. not the first block) is released,
  594. that block will be freed. If all memory is released within an active block, that blocks
  595. stats are simply cleared, effectively reclaiming its space.
  596. Arguments:
  597. Handle - A Handle to a Pool of Memory.
  598. Memory - Contains the address of the memory that is no longer needed.
  599. Return Value:
  600. None.
  601. --*/
  602. {
  603. PALLOCATION allocation;
  604. PPOOLHEADER poolHeader = (PPOOLHEADER) Handle;
  605. MYASSERT(poolHeader != NULL && Memory != NULL);
  606. EnterCriticalSection (&g_PmCs);
  607. __try {
  608. //
  609. // Get a reference to the ALLOCATION struct that precedes the actual memory.
  610. //
  611. allocation = (PALLOCATION) Memory - 1;
  612. #ifdef DEBUG
  613. //
  614. // Update stats.
  615. //
  616. poolHeader->NumFreeRequests++; //lint !e613
  617. poolHeader->CurrentAllocationSize -= allocation->Size;
  618. #endif
  619. #ifdef DEBUG
  620. if (poolHeader->FreeCalled == FREE_NOT_CALLED) { //lint !e613
  621. poolHeader->FreeCalled = FREE_CALLED; //lint !e613
  622. }
  623. //
  624. // Check the dog tag on the allocation to provide sanity checking on the memory passed in.
  625. //
  626. if (allocation->DogTag != VALIDDOGTAG) {
  627. if (allocation->DogTag == FREEDOGTAG) {
  628. DEBUGMSG((
  629. DBG_WHOOPS,
  630. "Poolmem Error! This dogtag has already been freed! Pool: %s",
  631. poolHeader->Name
  632. ));
  633. } else {
  634. DEBUGMSG ((
  635. DBG_WHOOPS,
  636. "Poolmem Error! Unknown value found in allocation dogtag. Pool: %s",
  637. poolHeader->Name
  638. ));
  639. MYASSERT (FALSE); //lint !e506
  640. }
  641. __leave;
  642. } else {
  643. allocation->DogTag = FREEDOGTAG;
  644. }
  645. if (allocation->Next) {
  646. allocation->Next->Prev = allocation->Prev;
  647. }
  648. if (poolHeader->AllocationList == allocation) { //lint !e613
  649. poolHeader->AllocationList = allocation->Next; //lint !e613
  650. } else {
  651. allocation->Prev->Next = allocation->Next;
  652. }
  653. if (poolHeader->FreeCalled != WHO_CARES) { //lint !e613
  654. g_PoolCurrUsedAlloc -= allocation->Size;
  655. DebugUnregisterAllocation(POOLMEM_POINTER,allocation);
  656. }
  657. #endif
  658. //
  659. // Check to make sure this memory has not previously been freed.
  660. //
  661. if (allocation->ParentBlock == NULL) {
  662. DEBUGMSG((
  663. DBG_WHOOPS,
  664. "PoolMem Error! previously freed memory passed to PoolMemReleaseMemory. Pool: %s",
  665. poolHeader->Name
  666. ));
  667. __leave;
  668. }
  669. //
  670. // Update the use count on this allocations parent block.
  671. //
  672. allocation->ParentBlock->UseCount--;
  673. if (allocation->ParentBlock->UseCount == 0) {
  674. //
  675. // This was the last allocation still referring to the parent block.
  676. //
  677. if (allocation->ParentBlock != poolHeader->PoolHead) { //lint !e613
  678. //
  679. // Since the parent block isn't the active block, simply delete it.
  680. //
  681. #ifdef DEBUG
  682. //
  683. // Adjust stats.
  684. //
  685. poolHeader->NumBlockFrees++; //lint !e613
  686. poolHeader->CurrentlyAllocatedMemory -=
  687. allocation->ParentBlock->Size + sizeof(PMBLOCK); //lint !e613
  688. #endif
  689. if (allocation->ParentBlock->NextBlock) {
  690. allocation->ParentBlock->NextBlock->PrevBlock =
  691. allocation->ParentBlock->PrevBlock;
  692. }
  693. allocation->ParentBlock->PrevBlock->NextBlock =
  694. allocation->ParentBlock->NextBlock;
  695. #ifdef DEBUG
  696. g_PoolCurrTotalAlloc -= (allocation->ParentBlock->Size + sizeof(PMBLOCK));
  697. g_PoolCurrActiveAlloc -= allocation->ParentBlock->Size;
  698. #endif
  699. MemFree(g_hHeap,0,allocation->ParentBlock);
  700. }
  701. else {
  702. //
  703. // Since this is the active block, reset it.
  704. //
  705. allocation->ParentBlock->Index = 0;
  706. allocation->ParentBlock = NULL;
  707. #ifdef DEBUG
  708. poolHeader->NumBlockClears++; //lint !e613
  709. #endif
  710. }
  711. }
  712. else {
  713. allocation->ParentBlock = NULL;
  714. }
  715. } __finally {
  716. LeaveCriticalSection (&g_PmCs);
  717. }
  718. }
  719. #ifdef DEBUG
  720. PMHANDLE
  721. RealPmCreateNamedPoolEx (
  722. IN PCSTR Name,
  723. IN DWORD BlockSize OPTIONAL
  724. )
  725. {
  726. PMHANDLE pool;
  727. PPOOLHEADER poolHeader;
  728. pool = RealPmCreatePoolEx (BlockSize);
  729. if (pool) {
  730. poolHeader = (PPOOLHEADER) pool;
  731. StringCopyByteCountA (poolHeader->Name, Name, MAX_POOL_NAME);
  732. MYASSERT (!poolHeader->TotalAllocationRequestBytes);
  733. }
  734. return pool;
  735. }
  736. #endif
  737. PSTR
  738. PmDuplicateMultiSzA (
  739. IN PMHANDLE Handle,
  740. IN PCSTR MultiSzToCopy
  741. )
  742. {
  743. PSTR rString = (PSTR)MultiSzToCopy;
  744. SIZE_T size;
  745. if (MultiSzToCopy == NULL) {
  746. return NULL;
  747. }
  748. while (rString [0] != 0) {
  749. rString = GetEndOfStringA (rString) + 1; //lint !e613
  750. }
  751. size = (rString - MultiSzToCopy + 1) * sizeof(CHAR);
  752. rString = PmGetAlignedMemory(Handle, size);
  753. memcpy (rString, MultiSzToCopy, size);
  754. return rString;
  755. }
  756. PWSTR
  757. PmDuplicateMultiSzW (
  758. IN PMHANDLE Handle,
  759. IN PCWSTR MultiSzToCopy
  760. )
  761. {
  762. PWSTR rString = (PWSTR)MultiSzToCopy;
  763. SIZE_T size;
  764. if (MultiSzToCopy == NULL) {
  765. return NULL;
  766. }
  767. while (rString [0] != 0) {
  768. rString = GetEndOfStringW (rString) + 1;
  769. }
  770. size = (rString - MultiSzToCopy + 1) * sizeof(WCHAR);
  771. rString = PmGetAlignedMemory(Handle, size);
  772. memcpy (rString, MultiSzToCopy, size);
  773. return rString;
  774. }
  775. #ifdef DEBUG
  776. VOID
  777. PmDisableTracking (
  778. IN PMHANDLE Handle
  779. )
  780. /*++
  781. Routine Description:
  782. PmDisableTracking suppresses the debug output caused by a pool
  783. that has a mix of freed and non-freed blocks.
  784. Arguments:
  785. Handle - A Handle to a Pool of Memory.
  786. Return Value:
  787. None.
  788. --*/
  789. {
  790. PPOOLHEADER poolHeader = (PPOOLHEADER) Handle;
  791. MYASSERT(poolHeader != NULL);
  792. poolHeader->FreeCalled = WHO_CARES;
  793. }
  794. VOID
  795. PmDumpStatistics (
  796. VOID
  797. )
  798. {
  799. DEBUGMSG ((
  800. DBG_STATS,
  801. "Pools usage:\nPeak : Pools:%-3d Total:%-8d Usable:%-8d Used:%-8d\nCurrent: Pools:%-3d Total:%-8d Usable:%-8d Leak:%-8d",
  802. g_PoolMaxPools,
  803. g_PoolMaxTotalAlloc,
  804. g_PoolMaxActiveAlloc,
  805. g_PoolMaxUsedAlloc,
  806. g_PoolCurrPools,
  807. g_PoolCurrTotalAlloc,
  808. g_PoolCurrActiveAlloc,
  809. g_PoolCurrUsedAlloc
  810. ));
  811. }
  812. #endif