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.

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