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.

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