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.

1238 lines
36 KiB

  1. #include "precomp.h"
  2. /*
  3. * memmgr.cpp
  4. *
  5. * Copyright (c) 1993 - 1995 by DataBeam Corporation, Lexington, KY
  6. *
  7. * Abstract:
  8. * This is the implementation file for the MemoryManager class. This
  9. * file contains the code necessary to allocate and distribute memory
  10. * in the form of Memory objects.
  11. *
  12. * Protected Instance Variables:
  13. * Memory_Buffer
  14. * This is the base address for the large memory buffer that the
  15. * Memory Manager object allocates during instantiation. This is
  16. * remembered so that the buffer can be freed when the Memory Manager
  17. * object is destroyed.
  18. * Memory_Information
  19. * This is a pointer to the structure in memory that contains general
  20. * information about the memory being managed by this object.
  21. *
  22. * Protected Member Functions:
  23. * ReleaseMemory
  24. * This is a private function releases memory used by a Memory object
  25. * by putting it back into the proper free stack list.
  26. * CalculateMemoryBufferSize
  27. * AllocateMemoryBuffer
  28. * InitializeMemoryBuffer
  29. *
  30. * Caveats:
  31. * None.
  32. *
  33. * Author:
  34. * James P. Galvin, Jr.
  35. */
  36. DWORD MemoryManager::dwSystemPageSize = 0;
  37. /*
  38. * MemoryManager ()
  39. *
  40. * Public
  41. *
  42. * Functional Description:
  43. * This is the default constructor for this class. It does nothing and
  44. * only exists to allow classes to derive from this one without having to
  45. * invoke the defined constructor.
  46. */
  47. MemoryManager::MemoryManager () :
  48. pExternal_Block_Information (NULL), fIsSharedMemory (TRUE),
  49. bAllocs_Restricted (TRUE), Max_External_Blocks (0)
  50. {
  51. }
  52. /*
  53. * MemoryManager ()
  54. *
  55. * Public
  56. *
  57. * Functional Description:
  58. * This is the constructor for the MemoryManager class. It calculates
  59. * how much total memory will be required to hold all the blocks
  60. * asked for in the memory template array that is passed in. It then
  61. * allocates all of that memory in one operating system call. It then
  62. * builds a set of free stacks, each of which contains all the blocks
  63. * of a particular size.
  64. */
  65. MemoryManager::MemoryManager (
  66. PMemoryTemplate memory_template,
  67. ULong memory_count,
  68. PMemoryManagerError memory_manager_error,
  69. ULong ulMaxExternalBlocks,
  70. BOOL bAllocsRestricted) :
  71. bAllocs_Restricted (bAllocsRestricted),
  72. fIsSharedMemory (FALSE), Max_External_Blocks (0)
  73. {
  74. ULong memory_buffer_size;
  75. *memory_manager_error = MEMORY_MANAGER_NO_ERROR;
  76. /*
  77. * Calculate the amount of memory required for this memory manager
  78. * (including all management structures).
  79. */
  80. memory_buffer_size = CalculateMemoryBufferSize (memory_template,
  81. memory_count, NULL);
  82. /*
  83. * Allocate the memory buffer.
  84. */
  85. AllocateMemoryBuffer (memory_buffer_size);
  86. /*
  87. * If the allocation succeeded, then initialize the memory buffer so that
  88. * it can be used.
  89. */
  90. if (Memory_Buffer != NULL)
  91. {
  92. /*
  93. * Initialize the External block information dictionary.
  94. * This is only for allocations that do not come from preallocated
  95. * buffers.
  96. */
  97. if (ulMaxExternalBlocks > 0) {
  98. pExternal_Block_Information = new BlockInformationList (ulMaxExternalBlocks / 3);
  99. if (NULL != pExternal_Block_Information) {
  100. Max_External_Blocks = ulMaxExternalBlocks;
  101. }
  102. else
  103. {
  104. /*
  105. * We were unable to allocate memory for the pre-allocated
  106. * memory pool.
  107. */
  108. ERROR_OUT(("MemoryManager::MemoryManager: "
  109. "failed to allocate the external block information dictionary"));
  110. *memory_manager_error = MEMORY_MANAGER_ALLOCATION_FAILURE;
  111. }
  112. }
  113. if (*memory_manager_error != MEMORY_MANAGER_ALLOCATION_FAILURE) {
  114. /*
  115. * Initialize the memory buffer. Note that no error can occur doing
  116. * this, since the allocation has already succeeded.
  117. */
  118. InitializeMemoryBuffer (memory_template, memory_count);
  119. /*
  120. * Indicate that no error occured.
  121. */
  122. TRACE_OUT(("MemoryManager::MemoryManager: allocation successful"));
  123. TRACE_OUT(("MemoryManager::MemoryManager: Allocated %d memory blocks", GetBufferCount()));
  124. *memory_manager_error = MEMORY_MANAGER_NO_ERROR;
  125. }
  126. }
  127. else
  128. {
  129. /*
  130. * We were unable to allocate memory for the pre-allocated
  131. * memory pool.
  132. */
  133. ERROR_OUT(("MemoryManager::MemoryManager: allocation failed"));
  134. *memory_manager_error = MEMORY_MANAGER_ALLOCATION_FAILURE;
  135. }
  136. }
  137. /*
  138. * ~MemoryManager ()
  139. *
  140. * Public
  141. *
  142. * Functional Description:
  143. * This is the destructor for the Memory Manager class. It frees up the
  144. * memory allocated for the memory pool (if any).
  145. */
  146. MemoryManager::~MemoryManager ()
  147. {
  148. PBlockInformation lpBlockInfo;
  149. /*
  150. * Iterate through the external block information list, deleting all
  151. * block information structures contained therein.
  152. */
  153. if (NULL != pExternal_Block_Information)
  154. {
  155. pExternal_Block_Information->reset();
  156. while (pExternal_Block_Information->iterate ((PDWORD_PTR) &lpBlockInfo))
  157. {
  158. delete lpBlockInfo;
  159. }
  160. delete pExternal_Block_Information;
  161. }
  162. /*
  163. * Free up the memory buffer (if there is one).
  164. */
  165. if (Memory_Buffer != NULL)
  166. {
  167. LocalFree ((HLOCAL) Memory_Buffer);
  168. Memory_Buffer = NULL;
  169. }
  170. }
  171. /*
  172. * PMemory AllocateMemory ()
  173. *
  174. * Public
  175. *
  176. * Functional Description:
  177. * This function is used to allocate a Memory object from the Memory
  178. * Manager object.
  179. */
  180. PMemory MemoryManager::AllocateMemory (
  181. PUChar reference_ptr,
  182. ULong length,
  183. MemoryLockMode memory_lock_mode)
  184. {
  185. PFreeStack free_stack;
  186. ULong count;
  187. PBlockNumber block_stack;
  188. BlockNumber block_number;
  189. PBlockInformation block_information;
  190. PUChar copy_ptr = NULL;
  191. PMemory memory = NULL;
  192. // TRACE_OUT(("MemoryManager::AllocateMemory: Remaining %d memory blocks", GetBufferCount()));
  193. /*
  194. * If the application requests a block of size zero (0), then simply
  195. * return a NULL without allocating a block.
  196. */
  197. if (length != 0)
  198. {
  199. /*
  200. * Walk through the free stack list look for a free stack that meets
  201. * the following two allocation criteria:
  202. *
  203. * 1. It must contain blocks that are big enough to hold the
  204. * reference data. This is why it is important for the block
  205. * sizes to be specified in ascending order in the constructor.
  206. * This code checks for a block that is big enough starting at the
  207. * beginning. By putting them in ascending order, you are insured
  208. * that the smallest available block will be used.
  209. * 2. It must have enough free blocks left to allow the allocation.
  210. * This is where priority is used. Right now it is very simple:
  211. * the allocation will succeed if the number of available blocks
  212. * is greater than the passed in priority (which is why a lower
  213. * number actually reflects a higher priority).
  214. */
  215. free_stack = Free_Stack;
  216. for (count = 0; count < Free_Stack_Count; count++)
  217. {
  218. /*
  219. * Check and see if the blocks in this free stack are big enough
  220. * to hold the reference data. If so, are there enough to satisfy
  221. * this allocation (taking memory priority into consideration).
  222. */
  223. if ((length <= free_stack->block_size) &&
  224. (free_stack->current_block_count > 0))
  225. {
  226. /*
  227. * Calculate the address of the next available block number
  228. * within the block stack. Then read the block number and
  229. * advance the block stack offset to point to the next block.
  230. */
  231. block_stack = (PBlockNumber) (Memory_Buffer +
  232. free_stack->block_stack_offset);
  233. block_number = *block_stack;
  234. free_stack->block_stack_offset += sizeof (BlockNumber);
  235. /*
  236. * Calculate the address of the appropriate block information
  237. * structure. Make sure that the lock count for the newly
  238. * allocated block is zero, and the block is not marked as
  239. * freed.
  240. */
  241. block_information = (PBlockInformation) (Block_Information +
  242. (sizeof (BlockInformation) * block_number));
  243. ASSERT (block_information->flags & FREE_FLAG);
  244. block_information->length = length;
  245. block_information->lock_count = 0;
  246. block_information->flags &= (~FREE_FLAG);
  247. /*
  248. * Decrement the number of blocks remaining, within this free stack.
  249. */
  250. free_stack->current_block_count--;
  251. /*
  252. * Calculate the address of the newly allocated block. Then
  253. * break out of the allocation loop to go use the block.
  254. */
  255. copy_ptr = (PUChar) (Memory_Buffer +
  256. block_information->block_offset);
  257. ASSERT(copy_ptr != Memory_Buffer);
  258. /*
  259. * If this is a shared memory manager, and the block is not
  260. * committed, we need to commit the block.
  261. */
  262. if ((TRUE == fIsSharedMemory) && (0 == (block_information->flags & COMMIT_FLAG))) {
  263. ASSERT ((free_stack->block_size % dwSystemPageSize) == 0);
  264. ASSERT ((((DWORD_PTR) copy_ptr) % dwSystemPageSize) == 0);
  265. PUChar temp = (PUChar) VirtualAlloc ((LPVOID) copy_ptr, free_stack->block_size,
  266. MEM_COMMIT, PAGE_READWRITE);
  267. block_information->flags |= COMMIT_FLAG;
  268. ASSERT (temp == copy_ptr);
  269. ASSERT (temp != NULL);
  270. if (copy_ptr != temp) {
  271. TRACE_OUT((">>>>>#### Copy_ptr: %p, Temp: %p, Committed?: %d",
  272. copy_ptr, temp, block_information->flags & COMMIT_FLAG));
  273. TRACE_OUT((">>>>>#### Size: %d, Req. length: %d",
  274. free_stack->block_size, length));
  275. copy_ptr = NULL;
  276. }
  277. }
  278. break;
  279. }
  280. /*
  281. * Point to the next entry in the free stack list.
  282. */
  283. free_stack++;
  284. }
  285. /*
  286. * If the memory allocation failed and it's for local memory,
  287. * attempt to allocate external memory to hold the block.
  288. */
  289. if ((copy_ptr == NULL) &&
  290. ((FALSE == bAllocs_Restricted) ||
  291. ((NULL != pExternal_Block_Information) &&
  292. (Max_External_Blocks > pExternal_Block_Information->entries()))))
  293. {
  294. ASSERT (FALSE == fIsSharedMemory);
  295. /*
  296. * Try allocating from system memory. Set the free stack to NULL
  297. * to indicate that this block did NOT come from one of our free
  298. * stacks.
  299. */
  300. copy_ptr = (PUChar) LocalAlloc (LMEM_FIXED, length);
  301. if (copy_ptr != NULL)
  302. {
  303. /*
  304. * Allocate a block information structure to hold relevant
  305. * information about this externally allocated block.
  306. */
  307. block_information = new BlockInformation;
  308. if (block_information != NULL)
  309. {
  310. /*
  311. * Fill in the block information structure. Block offset
  312. * is irrelevant for an externally allocated block. A
  313. * newly allocated block has a lock count of zero, and
  314. * is not freed.
  315. */
  316. block_information->length = length;
  317. block_information->lock_count = 0;
  318. block_information->flags = COMMIT_FLAG;
  319. /*
  320. * Put the block information structure into a dictionary
  321. * for future use. This is only necessary for externally
  322. * allocated blocks, since the block information structures
  323. * for internal blocks are in the memory buffer.
  324. */
  325. pExternal_Block_Information->insert ((DWORD_PTR) copy_ptr, (DWORD_PTR) block_information);
  326. /*
  327. * Set block number to be an
  328. * invalid value to indicate that this block is NOT in
  329. * the internally managed memory buffer.
  330. */
  331. block_number = INVALID_BLOCK_NUMBER;
  332. }
  333. else
  334. {
  335. /*
  336. * We were unable to allocate the space for the block
  337. * information structure, so we must free the externally
  338. * memory we just allocated.
  339. */
  340. LocalFree ((HLOCAL) copy_ptr);
  341. copy_ptr = NULL;
  342. }
  343. }
  344. }
  345. /*
  346. * If there was a block available for the allocation, it is still
  347. * necessary to create the Memory object that will hold the block.
  348. */
  349. if (copy_ptr != NULL)
  350. {
  351. ASSERT (block_information->flags == COMMIT_FLAG);
  352. /*
  353. * Create the Memory object. If it fails, then cleanly release
  354. * the memory that was to be used for this block.
  355. */
  356. memory = new Memory (reference_ptr, length, copy_ptr,
  357. block_number, memory_lock_mode);
  358. if (memory == NULL)
  359. {
  360. /*
  361. * If the free stack for the memory is not NULL, then it is
  362. * an internally managed block. Otherwise, this was an
  363. * externally allocated block that resulted from a critical
  364. * allocation above.
  365. */
  366. if (INVALID_BLOCK_NUMBER != block_number)
  367. {
  368. /*
  369. * Adjust the block stack offset to point to the previous
  370. * entry in the list. Note that it is not necessary to
  371. * put the block number into the list since it still there
  372. * from when we pulled it out above.
  373. */
  374. free_stack->block_stack_offset -= sizeof (BlockNumber);
  375. /*
  376. * Indicate that the block is currently freed. Note that
  377. * it is not necessary to calculate the address of the
  378. * block information structure since we did this above.
  379. */
  380. block_information->flags |= FREE_FLAG;
  381. /*
  382. * Decrement the block counter to indicate that there
  383. * is another block in this free stack.
  384. */
  385. free_stack->current_block_count++;
  386. }
  387. else
  388. {
  389. /*
  390. * This block was externally allocated, so it must be
  391. * externally freed. Also eliminate the block information
  392. * structure associated with this memory block.
  393. */
  394. pExternal_Block_Information->remove ((DWORD_PTR) copy_ptr);
  395. delete block_information;
  396. LocalFree ((HLOCAL) copy_ptr);
  397. }
  398. }
  399. }
  400. }
  401. else
  402. {
  403. /*
  404. * The application has attempted to allocate a block of size zero.
  405. * It is necessary to fail the request.
  406. */
  407. ERROR_OUT(("MemoryManager::AllocateMemory: attempt to allocate zero-length block"));
  408. }
  409. /*
  410. * Decrement the number of blocks remaining
  411. * in this memory manager as a whole.
  412. */
  413. if ((TRUE == bAllocs_Restricted) && (memory != NULL))
  414. Memory_Information->current_block_count--;
  415. return (memory);
  416. }
  417. /*
  418. * Void FreeMemory ()
  419. *
  420. * Public
  421. *
  422. * Functional Description:
  423. * This function is used to release a previously allocated Memory object.
  424. */
  425. Void MemoryManager::FreeMemory (
  426. PMemory memory)
  427. {
  428. BlockNumber block_number;
  429. PBlockInformation block_information;
  430. PUChar copy_ptr;
  431. /*
  432. * Ask the specified memory object what block number it represents.
  433. */
  434. block_number = memory->GetBlockNumber ();
  435. /*
  436. * Use the block number to determine if this is an internally
  437. * allocated memory block, or an externally allocated one.
  438. */
  439. if (block_number != INVALID_BLOCK_NUMBER)
  440. {
  441. /*
  442. * From that, calculate the address of the block information structure.
  443. */
  444. block_information = (PBlockInformation) (Block_Information +
  445. (sizeof (BlockInformation) * block_number));
  446. }
  447. else
  448. {
  449. /*
  450. * This is externally allocated memory, so it must be handled
  451. * differently. Ask the memory block what the copy pointer is, and
  452. * use that to look up the address of the block information structure.
  453. */
  454. copy_ptr = memory->GetPointer ();
  455. pExternal_Block_Information->find ((DWORD_PTR) copy_ptr, (PDWORD_PTR) &block_information);
  456. }
  457. /*
  458. * Make sure that the indicated memory block has not already been
  459. * freed.
  460. */
  461. if ((block_information->flags & FREE_FLAG) == 0)
  462. {
  463. /*
  464. * Mark the memory block as being freed.
  465. */
  466. block_information->flags |= FREE_FLAG;
  467. /*
  468. * If the lock count for this block has reached zero, we can free
  469. * the block for re-use. We can also delete the memory object, as it
  470. * is no longer needed.
  471. */
  472. if (block_information->lock_count == 0)
  473. {
  474. ReleaseMemory (memory);
  475. delete memory;
  476. }
  477. else
  478. {
  479. /*
  480. * If the lock count has not yet reached zero, check to see if the
  481. * memory object is to be deleted anyway. If the memory lock mode
  482. * is set to "IGNORED", then delete the memory object immediately.
  483. */
  484. if (memory->GetMemoryLockMode () == MEMORY_LOCK_IGNORED)
  485. delete memory;
  486. }
  487. }
  488. else
  489. {
  490. /*
  491. * The memory block has already been freed, so this call will be
  492. * ignored.
  493. */
  494. ERROR_OUT(("MemoryManager::FreeMemory: memory block already freed"));
  495. }
  496. }
  497. /*
  498. * PMemory CreateMemory ()
  499. *
  500. * Public
  501. *
  502. * Functional Description:
  503. */
  504. PMemory MemoryManager::CreateMemory (
  505. BlockNumber block_number,
  506. MemoryLockMode memory_lock_mode)
  507. {
  508. ULong total_block_count = 0;
  509. PFreeStack free_stack;
  510. ULong count;
  511. PBlockInformation block_information;
  512. PUChar copy_ptr;
  513. PMemory memory = NULL;
  514. /*
  515. * Make sure that this block number lies within the range handled by
  516. * this memory manager.
  517. */
  518. if (block_number < Memory_Information->total_block_count)
  519. {
  520. /*
  521. * We must first walk through the free stack list to determine which
  522. * free stack the specified block is in. Start by pointing to the
  523. * first free stack.
  524. */
  525. free_stack = Free_Stack;
  526. for (count = 0; count < Free_Stack_Count; count++)
  527. {
  528. /*
  529. * Update the counter which keeps track of how many blocks are
  530. * represented by this free stack and the ones already processed.
  531. * This is used to determine if the specified block number is in
  532. * this free stack.
  533. */
  534. total_block_count += free_stack->total_block_count;
  535. /*
  536. * Is the block in this free stack?
  537. */
  538. if (block_number < total_block_count)
  539. {
  540. /*
  541. * Yes it is. Claculate the address of the block information
  542. * structure for this block. Then calculate the address of
  543. * the actual block based on the address of the local memory
  544. * buffer.
  545. */
  546. block_information = (PBlockInformation) (Block_Information +
  547. (sizeof (BlockInformation) * block_number));
  548. copy_ptr = (PUChar) (Memory_Buffer +
  549. block_information->block_offset);
  550. ASSERT (block_information->flags & COMMIT_FLAG);
  551. /*
  552. * Create a memory object to represent this block.
  553. */
  554. memory = new Memory (NULL, block_information->length, copy_ptr,
  555. block_number, memory_lock_mode);
  556. if (memory == NULL)
  557. {
  558. /*
  559. * Allocation of the memory object failed, so we cannot
  560. * create a memory block at this time.
  561. */
  562. ERROR_OUT(("MemoryManager::CreateMemory: memory object allocation failed"));
  563. }
  564. break;
  565. }
  566. /*
  567. * The block was not in the last free stack, so point to the
  568. * next one.
  569. */
  570. free_stack++;
  571. }
  572. }
  573. else
  574. {
  575. /*
  576. * The specified block number is out of range for this memory manager.
  577. * The request must therefore fail.
  578. */
  579. ERROR_OUT(("MemoryManager::CreateMemory: block number out of range"));
  580. }
  581. return (memory);
  582. }
  583. /*
  584. * Void LockMemory ()
  585. *
  586. * Public
  587. *
  588. * Functional Description:
  589. * This function is used to lock a Memory object.
  590. */
  591. Void MemoryManager::LockMemory (
  592. PMemory memory)
  593. {
  594. BlockNumber block_number;
  595. PBlockInformation block_information;
  596. PUChar copy_ptr;
  597. /*
  598. * Ask the specified memory object what block number it represents.
  599. */
  600. block_number = memory->GetBlockNumber ();
  601. /*
  602. * Use the block number to determine if this is an internally
  603. * allocated memory block, or an externally allocated one.
  604. */
  605. if (block_number != INVALID_BLOCK_NUMBER)
  606. {
  607. /*
  608. * From that, calculate the address of the block information structure.
  609. */
  610. block_information = (PBlockInformation) (Block_Information +
  611. (sizeof (BlockInformation) * block_number));
  612. }
  613. else
  614. {
  615. /*
  616. * This is externally allocated memory, so it must be handled
  617. * differently. Ask the memory block what the copy pointer is, and
  618. * use that to look up the address of the block information structure.
  619. */
  620. copy_ptr = memory->GetPointer ();
  621. pExternal_Block_Information->find ((DWORD_PTR) copy_ptr, (PDWORD_PTR) &block_information);
  622. }
  623. ASSERT (block_information->flags & COMMIT_FLAG);
  624. /*
  625. * Increment the lock count for the specified memory block.
  626. */
  627. block_information->lock_count++;
  628. }
  629. /*
  630. * Void UnlockMemory ()
  631. *
  632. * Public
  633. *
  634. * Functional Description:
  635. * This function is used to unlock a previously locked Memory object.
  636. */
  637. Void MemoryManager::UnlockMemory (
  638. PMemory memory)
  639. {
  640. BlockNumber block_number;
  641. PBlockInformation block_information;
  642. PUChar copy_ptr;
  643. /*
  644. * Ask the specified memory object what block number it represents.
  645. */
  646. block_number = memory->GetBlockNumber ();
  647. /*
  648. * Use the block number to determine if this is an internally
  649. * allocated memory block, or an externally allocated one.
  650. */
  651. if (block_number != INVALID_BLOCK_NUMBER)
  652. {
  653. /*
  654. * From that, calculate the address of the block information structure.
  655. */
  656. block_information = (PBlockInformation) (Block_Information +
  657. (sizeof (BlockInformation) * block_number));
  658. }
  659. else
  660. {
  661. /*
  662. * This is externally allocated memory, so it must be handled
  663. * differently. Ask the memory block what the copy pointer is, and
  664. * use that to look up the address of the block information structure.
  665. */
  666. copy_ptr = memory->GetPointer ();
  667. pExternal_Block_Information->find ((DWORD_PTR) copy_ptr, (PDWORD_PTR) &block_information);
  668. }
  669. ASSERT (block_information->flags & COMMIT_FLAG);
  670. /*
  671. * Make sure that the lock isn't already zero before proceeding.
  672. */
  673. if (block_information->lock_count > 0)
  674. {
  675. /*
  676. * Decrement the lock count for the specified memory block.
  677. */
  678. block_information->lock_count--;
  679. /*
  680. * If the lock count has reached zero and the memory block is
  681. * marked as being freed, then we can free the block for re-use.
  682. */
  683. if ((block_information->lock_count == 0) &&
  684. (block_information->flags & FREE_FLAG))
  685. {
  686. ReleaseMemory (memory);
  687. /*
  688. * We have now released the memory buffer, so we must check to
  689. * see if we are supposed to destroy the memory object itself.
  690. */
  691. if (memory->GetMemoryLockMode () == MEMORY_LOCK_NORMAL)
  692. delete memory;
  693. }
  694. }
  695. else
  696. {
  697. /*
  698. * The specified block has a lock count of zero already, so ignore
  699. * this call.
  700. */
  701. ERROR_OUT(("MemoryManager::UnlockMemory: memory block already unlocked"));
  702. }
  703. }
  704. /*
  705. * ULong GetBufferCount ()
  706. *
  707. * Public
  708. *
  709. * Functional Description:
  710. */
  711. ULong MemoryManager::GetBufferCount (
  712. ULong length)
  713. {
  714. PFreeStack free_stack;
  715. ULong count;
  716. ULong buffer_count;
  717. if (FALSE == bAllocs_Restricted)
  718. return (LARGE_BUFFER_COUNT);
  719. buffer_count = Memory_Information->current_block_count;
  720. free_stack = Free_Stack;
  721. for (count = 0; count < Free_Stack_Count; count++)
  722. {
  723. /*
  724. * Check and see if the blocks in this free stack are smaller than
  725. * the specified length. If yes, we need to deduct these buffers.
  726. * Otherwise, we can stop deducting.
  727. */
  728. if (length > free_stack->block_size) {
  729. buffer_count -= free_stack->current_block_count;
  730. /*
  731. * Point to the next entry in the free stack list.
  732. */
  733. free_stack++;
  734. }
  735. else
  736. break;
  737. }
  738. return (buffer_count);
  739. }
  740. /*
  741. * Void ReleaseMemory (
  742. * PMemory memory)
  743. *
  744. * Private
  745. *
  746. * Functional Description:
  747. * This function is used to release a Memory object, and free the memory
  748. * it represents back to the available pool.
  749. *
  750. * Formal Parameters:
  751. * memory
  752. * This is a pointer to the Memory object being released.
  753. *
  754. * Return Value:
  755. * None.
  756. *
  757. * Side Effects:
  758. * None.
  759. *
  760. * Caveats:
  761. * None.
  762. */
  763. Void MemoryManager::ReleaseMemory (
  764. PMemory memory)
  765. {
  766. PFreeStack free_stack;
  767. BlockNumber block_number;
  768. PBlockNumber block_stack;
  769. PBlockInformation block_information;
  770. PUChar copy_ptr;
  771. /*
  772. * Ask the specified memory object what block number it represents.
  773. */
  774. block_number = memory->GetBlockNumber ();
  775. /*
  776. * Use the block number to determine if this is an internally
  777. * allocated memory block, or an externally allocated one.
  778. */
  779. if (block_number != INVALID_BLOCK_NUMBER)
  780. {
  781. /*
  782. * From that, calculate the address of the block information structure.
  783. */
  784. block_information = (PBlockInformation) (Block_Information +
  785. (sizeof (BlockInformation) * block_number));
  786. /*
  787. * Get the address of the free stack from which this block came.
  788. */
  789. free_stack = (PFreeStack) (Memory_Buffer + block_information->free_stack_offset);
  790. /*
  791. * Adjust the block stack offset to point to the previous element,
  792. * and then use it to calculate an address and put the block number
  793. * there. This effectively "pushes" the block number onto the stack.
  794. */
  795. free_stack->block_stack_offset -= sizeof (BlockNumber);
  796. block_stack = (PBlockNumber) (Memory_Buffer +
  797. free_stack->block_stack_offset);
  798. *block_stack = block_number;
  799. /*
  800. * Indicate that this block is freed.
  801. */
  802. block_information->flags = FREE_FLAG | COMMIT_FLAG;
  803. /*
  804. * Increment the counter indicating the number of available blocks
  805. * in this free stack.
  806. */
  807. free_stack->current_block_count++;
  808. }
  809. else
  810. {
  811. /*
  812. * Since the block was allocated from system memory, thats where it
  813. * needs to go back to.
  814. */
  815. copy_ptr = memory->GetPointer ();
  816. pExternal_Block_Information->find ((DWORD_PTR) copy_ptr, (PDWORD_PTR) &block_information);
  817. pExternal_Block_Information->remove ((DWORD_PTR) copy_ptr);
  818. delete block_information;
  819. LocalFree ((HLOCAL) copy_ptr);
  820. }
  821. /*
  822. * Increment the number of blocks available in this memory manager as a whole.
  823. */
  824. if (TRUE == bAllocs_Restricted)
  825. Memory_Information->current_block_count++;
  826. }
  827. /*
  828. * ULong CalculateMemoryBufferSize (
  829. * PMemoryTemplate memory_template,
  830. * ULong memory_count,
  831. * ULong * pulCommittedBytes)
  832. *
  833. * Protected
  834. *
  835. * Functional Description:
  836. * This member function is used to calculate how much memory will be
  837. * required in order to manage the number of memory blocks specified in
  838. * the passed in memory template. Note that this total includes the size
  839. * of the memory blocks as well as the amount of memory used for management
  840. * functions.
  841. *
  842. * Formal Parameters:
  843. * memory_template
  844. * This is an array of structures that identify the blocks to be
  845. * managed by this object.
  846. * memory_count
  847. * This is the number of entries in the above array.
  848. * pulCommittedBytes
  849. * If fIsSharedMemory == FALSE, this can be NULL. Otherwise, it is
  850. * used to return the size of the total memory we need to commit
  851. * when the manager is getting initialized.
  852. *
  853. * Return Value:
  854. * The required size of the memory buffer for this object.
  855. *
  856. * Side Effects:
  857. * None.
  858. *
  859. * Caveats:
  860. * None.
  861. */
  862. ULong MemoryManager::CalculateMemoryBufferSize (
  863. PMemoryTemplate memory_template,
  864. ULong memory_count,
  865. ULong * pulCommittedBytes)
  866. {
  867. ULong memory_buffer_size;
  868. PMemoryTemplate pMemTemplate;
  869. ULong memory_per_block;
  870. /*
  871. * Claculate the amount of memory that will be required to hold the
  872. * memory information structure and the free stacks.
  873. */
  874. memory_buffer_size = (sizeof (MemoryInformation) +
  875. (sizeof (FreeStack) * memory_count));
  876. if (FALSE == fIsSharedMemory) {
  877. /*
  878. * Add in the amount of memory the block stacks, the block information
  879. * structures, and the memory blocks themselves will take up.
  880. */
  881. for (pMemTemplate = memory_template; pMemTemplate - memory_template < (int) memory_count; pMemTemplate++)
  882. {
  883. /*
  884. * The amount of memory required for each managed block of memory can
  885. * be calculated as a sum of the following:
  886. *
  887. * 1. sizeof (BlockNumber) - This is the amount of space taken by the
  888. * block number in the block stack.
  889. * 2. sizeof (BlockInformation) - Every managed block of memory has
  890. * a BlockInformation structure associated with it.
  891. * 3. block_size - The actual size of the block. This is provided
  892. * in the memory template.
  893. */
  894. memory_per_block = sizeof (BlockNumber) + sizeof (BlockInformation) +
  895. pMemTemplate->block_size;
  896. memory_buffer_size += (memory_per_block * pMemTemplate->block_count);
  897. }
  898. }
  899. /*
  900. * For shared memory, we need to do a few more extra things:
  901. *
  902. * Blocks of size greater or equal to the system's page, need to
  903. * start on a page boundary. In addition, they can be expanded to
  904. * end at a page boundary, too.
  905. */
  906. else {
  907. ULong reserved_buffer_size = 0;
  908. ULong temp;
  909. for (pMemTemplate = memory_template; pMemTemplate - memory_template < (int) memory_count; pMemTemplate++) {
  910. if (dwSystemPageSize <= pMemTemplate->block_size) {
  911. pMemTemplate->block_size = EXPAND_TO_PAGE_BOUNDARY(pMemTemplate->block_size);
  912. reserved_buffer_size += pMemTemplate->block_count * pMemTemplate->block_size;
  913. }
  914. memory_per_block = sizeof (BlockNumber) + sizeof (BlockInformation) +
  915. pMemTemplate->block_size;
  916. memory_buffer_size += memory_per_block * pMemTemplate->block_count;
  917. }
  918. *pulCommittedBytes = memory_buffer_size - reserved_buffer_size;
  919. temp = EXPAND_TO_PAGE_BOUNDARY(*pulCommittedBytes);
  920. temp -= (*pulCommittedBytes);
  921. *pulCommittedBytes += temp;
  922. memory_buffer_size += temp;
  923. ASSERT (*pulCommittedBytes <= memory_buffer_size);
  924. ASSERT ((memory_buffer_size % dwSystemPageSize) == 0);
  925. ASSERT ((*pulCommittedBytes % dwSystemPageSize) == 0);
  926. ASSERT ((reserved_buffer_size % dwSystemPageSize) == 0);
  927. }
  928. return (memory_buffer_size);
  929. }
  930. /*
  931. * Void AllocateMemoryBuffer (
  932. * ULong memory_buffer_size)
  933. *
  934. * Protected
  935. *
  936. * Functional Description:
  937. * This member function allocates the memory that is managed by an instance
  938. * of MemoryManager. It does this using the standard Malloc macro.
  939. *
  940. * Formal Parameters:
  941. * memory_buffer_size
  942. * The size of the buffer to be allocated.
  943. *
  944. * Return Value:
  945. * None.
  946. *
  947. * Side Effects:
  948. * The instance variable Memory_Buffer is set to the address of the
  949. * allocated block of memory. If it is NULL after the return from this
  950. * call, that indicates that the memory could not be allocated.
  951. *
  952. * Caveats:
  953. * None.
  954. */
  955. Void MemoryManager::AllocateMemoryBuffer (
  956. ULong memory_buffer_size)
  957. {
  958. TRACE_OUT(("MemoryManager::AllocateMemoryBuffer: allocating %ld bytes", memory_buffer_size));
  959. if (memory_buffer_size != 0)
  960. Memory_Buffer = (HPUChar) LocalAlloc (LMEM_FIXED, memory_buffer_size);
  961. else
  962. Memory_Buffer = NULL;
  963. }
  964. /*
  965. * Void InitializeMemoryBuffer (
  966. * PMemoryTemplate memory_template,
  967. * ULong memory_count)
  968. *
  969. * Protected
  970. *
  971. * Functional Description:
  972. * This member function is used to initialize the memory buffer for use.
  973. * This primarily includes filling in the management structures that lie
  974. * at the beginning of the allocated memory block, so that allocations
  975. * can take place.
  976. *
  977. * Formal Parameters:
  978. * memory_template
  979. * This is an array of structures that identify the blocks to be
  980. * managed by this object.
  981. * memory_count
  982. * This is the number of entries in the above array.
  983. *
  984. * Return Value:
  985. * None.
  986. *
  987. * Side Effects:
  988. * None.
  989. *
  990. * Caveats:
  991. * None.
  992. */
  993. Void MemoryManager::InitializeMemoryBuffer (
  994. PMemoryTemplate memory_template,
  995. ULong memory_count)
  996. {
  997. ULong block_count = 0;
  998. ULong index;
  999. ULong memory_information_size;
  1000. ULong free_stack_size;
  1001. ULong free_stack_offset;
  1002. ULong block_stack_size;
  1003. ULong block_information_size;
  1004. PFreeStack free_stack;
  1005. PBlockNumber block_stack;
  1006. PBlockInformation block_information;
  1007. ULong block_stack_offset;
  1008. BlockNumber block_number;
  1009. ULong block_offset;
  1010. ULong block_size;
  1011. ULong count;
  1012. BOOL fIsFirstTime;
  1013. /*
  1014. * Walk through the memory template calculating how many memory blocks
  1015. * exist (regardless of size).
  1016. */
  1017. for (index = 0; index < memory_count; index++)
  1018. block_count += memory_template[index].block_count;
  1019. /*
  1020. * Calculate the amount of memory required to hold all the various sections
  1021. * of data in the memory buffer.
  1022. */
  1023. memory_information_size = sizeof (MemoryInformation);
  1024. free_stack_size = sizeof (FreeStack) * memory_count;
  1025. block_stack_size = sizeof (BlockNumber) * block_count;
  1026. block_information_size = sizeof (BlockInformation) * block_count;
  1027. /*
  1028. * Initialize all elements of the memory information structure.
  1029. * Note that all offsets in this structure are from the beginning of the
  1030. * memory buffer.
  1031. */
  1032. Memory_Information = (PMemoryInformation) Memory_Buffer;
  1033. Memory_Information->free_stack_offset = memory_information_size;
  1034. Memory_Information->free_stack_count = memory_count;
  1035. Memory_Information->block_information_offset =
  1036. memory_information_size + free_stack_size + block_stack_size;
  1037. Memory_Information->total_block_count = block_count;
  1038. if (TRUE == bAllocs_Restricted) {
  1039. // The current_block_count is only needed when allocations are restricted.
  1040. Memory_Information->current_block_count = block_count + Max_External_Blocks;
  1041. }
  1042. /*
  1043. * Now initialize the instance variables that point to each list within
  1044. * the memory buffer. These instance variables are later used to resolve
  1045. * all other offsets.
  1046. */
  1047. Free_Stack = (PFreeStack) (Memory_Buffer + memory_information_size);
  1048. Free_Stack_Count = memory_count;
  1049. Block_Information = (Memory_Buffer +
  1050. Memory_Information->block_information_offset);
  1051. /*
  1052. * This loop walks through the memory template array again, this time
  1053. * filling in the contents of the free stacks, the blocks stacks, and
  1054. * the block information structures.
  1055. */
  1056. fIsFirstTime = TRUE;
  1057. free_stack = Free_Stack;
  1058. free_stack_offset = memory_information_size;
  1059. block_stack_offset = memory_information_size + free_stack_size;
  1060. block_stack = (PBlockNumber) (Memory_Buffer + block_stack_offset);
  1061. block_information = (PBlockInformation) Block_Information;
  1062. block_number = 0;
  1063. block_offset = block_stack_offset + block_stack_size + block_information_size;
  1064. for (index = 0; index < memory_count; index++)
  1065. {
  1066. /*
  1067. * Get the block size and count from the template entry.
  1068. */
  1069. block_size = memory_template[index].block_size;
  1070. block_count = memory_template[index].block_count;
  1071. /*
  1072. * Initialize the free stack for this block size, and then point to
  1073. * the next free stack in the list.
  1074. */
  1075. free_stack->block_size = block_size;
  1076. free_stack->total_block_count = block_count;
  1077. free_stack->current_block_count = block_count;
  1078. (free_stack++)->block_stack_offset = block_stack_offset;
  1079. /*
  1080. * Adjust the block stack offset to point to the first block number
  1081. * of the next free stack (skip past all of the block numbers for
  1082. * this free stack).
  1083. */
  1084. block_stack_offset += (sizeof (BlockNumber) * block_count);
  1085. /*
  1086. * The following happens only once in this loop:
  1087. * When the memory manager manages shared memory and
  1088. * The block size becomes FOR THE 1ST TIME, bigger than
  1089. * the page size, then, we need to jump to the next page
  1090. * boundary.
  1091. */
  1092. if ((TRUE == fIsSharedMemory) && (TRUE == fIsFirstTime)
  1093. && (block_size >= dwSystemPageSize)) {
  1094. fIsFirstTime = FALSE;
  1095. block_offset = EXPAND_TO_PAGE_BOUNDARY(block_offset);
  1096. }
  1097. /*
  1098. * Initialize the block list for this block size. Also, increment
  1099. * the total number of buffers for each block that is segmented
  1100. * off.
  1101. */
  1102. for (count = 0; count < block_count; count++)
  1103. {
  1104. /*
  1105. * Put the block number for this block into the current block
  1106. * stack. Increment both the block stack pointer and the block
  1107. * number.
  1108. */
  1109. *(block_stack++) = block_number++;
  1110. /*
  1111. * Fill in the block information structure for this block. Then
  1112. * increment the block information pointer to point to the next
  1113. * entry in the list.
  1114. */
  1115. #ifdef _DEBUG
  1116. if ((TRUE == fIsSharedMemory) && (block_size >= dwSystemPageSize)) {
  1117. ASSERT ((block_size % dwSystemPageSize) == 0);
  1118. ASSERT ((block_offset % dwSystemPageSize) == 0);
  1119. }
  1120. #endif
  1121. block_information->block_offset = block_offset;
  1122. block_information->free_stack_offset = free_stack_offset;
  1123. if ((TRUE == fIsSharedMemory) && (block_size >= dwSystemPageSize))
  1124. block_information->flags = FREE_FLAG;
  1125. else
  1126. block_information->flags = FREE_FLAG | COMMIT_FLAG;
  1127. block_information++;
  1128. /*
  1129. * Adjust the block offset to point to the next block.
  1130. */
  1131. block_offset += block_size;
  1132. }
  1133. free_stack_offset += sizeof (FreeStack);
  1134. }
  1135. }
  1136.