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.
 
 
 
 
 
 

1239 lines
36 KiB

#include "precomp.h"
/*
* memmgr.cpp
*
* Copyright (c) 1993 - 1995 by DataBeam Corporation, Lexington, KY
*
* Abstract:
* This is the implementation file for the MemoryManager class. This
* file contains the code necessary to allocate and distribute memory
* in the form of Memory objects.
*
* Protected Instance Variables:
* Memory_Buffer
* This is the base address for the large memory buffer that the
* Memory Manager object allocates during instantiation. This is
* remembered so that the buffer can be freed when the Memory Manager
* object is destroyed.
* Memory_Information
* This is a pointer to the structure in memory that contains general
* information about the memory being managed by this object.
*
* Protected Member Functions:
* ReleaseMemory
* This is a private function releases memory used by a Memory object
* by putting it back into the proper free stack list.
* CalculateMemoryBufferSize
* AllocateMemoryBuffer
* InitializeMemoryBuffer
*
* Caveats:
* None.
*
* Author:
* James P. Galvin, Jr.
*/
DWORD MemoryManager::dwSystemPageSize = 0;
/*
* MemoryManager ()
*
* Public
*
* Functional Description:
* This is the default constructor for this class. It does nothing and
* only exists to allow classes to derive from this one without having to
* invoke the defined constructor.
*/
MemoryManager::MemoryManager () :
pExternal_Block_Information (NULL), fIsSharedMemory (TRUE),
bAllocs_Restricted (TRUE), Max_External_Blocks (0)
{
}
/*
* MemoryManager ()
*
* Public
*
* Functional Description:
* This is the constructor for the MemoryManager class. It calculates
* how much total memory will be required to hold all the blocks
* asked for in the memory template array that is passed in. It then
* allocates all of that memory in one operating system call. It then
* builds a set of free stacks, each of which contains all the blocks
* of a particular size.
*/
MemoryManager::MemoryManager (
PMemoryTemplate memory_template,
ULong memory_count,
PMemoryManagerError memory_manager_error,
ULong ulMaxExternalBlocks,
BOOL bAllocsRestricted) :
bAllocs_Restricted (bAllocsRestricted),
fIsSharedMemory (FALSE), Max_External_Blocks (0)
{
ULong memory_buffer_size;
*memory_manager_error = MEMORY_MANAGER_NO_ERROR;
/*
* Calculate the amount of memory required for this memory manager
* (including all management structures).
*/
memory_buffer_size = CalculateMemoryBufferSize (memory_template,
memory_count, NULL);
/*
* Allocate the memory buffer.
*/
AllocateMemoryBuffer (memory_buffer_size);
/*
* If the allocation succeeded, then initialize the memory buffer so that
* it can be used.
*/
if (Memory_Buffer != NULL)
{
/*
* Initialize the External block information dictionary.
* This is only for allocations that do not come from preallocated
* buffers.
*/
if (ulMaxExternalBlocks > 0) {
pExternal_Block_Information = new BlockInformationList (ulMaxExternalBlocks / 3);
if (NULL != pExternal_Block_Information) {
Max_External_Blocks = ulMaxExternalBlocks;
}
else
{
/*
* We were unable to allocate memory for the pre-allocated
* memory pool.
*/
ERROR_OUT(("MemoryManager::MemoryManager: "
"failed to allocate the external block information dictionary"));
*memory_manager_error = MEMORY_MANAGER_ALLOCATION_FAILURE;
}
}
if (*memory_manager_error != MEMORY_MANAGER_ALLOCATION_FAILURE) {
/*
* Initialize the memory buffer. Note that no error can occur doing
* this, since the allocation has already succeeded.
*/
InitializeMemoryBuffer (memory_template, memory_count);
/*
* Indicate that no error occured.
*/
TRACE_OUT(("MemoryManager::MemoryManager: allocation successful"));
TRACE_OUT(("MemoryManager::MemoryManager: Allocated %d memory blocks", GetBufferCount()));
*memory_manager_error = MEMORY_MANAGER_NO_ERROR;
}
}
else
{
/*
* We were unable to allocate memory for the pre-allocated
* memory pool.
*/
ERROR_OUT(("MemoryManager::MemoryManager: allocation failed"));
*memory_manager_error = MEMORY_MANAGER_ALLOCATION_FAILURE;
}
}
/*
* ~MemoryManager ()
*
* Public
*
* Functional Description:
* This is the destructor for the Memory Manager class. It frees up the
* memory allocated for the memory pool (if any).
*/
MemoryManager::~MemoryManager ()
{
PBlockInformation lpBlockInfo;
/*
* Iterate through the external block information list, deleting all
* block information structures contained therein.
*/
if (NULL != pExternal_Block_Information)
{
pExternal_Block_Information->reset();
while (pExternal_Block_Information->iterate ((PDWORD_PTR) &lpBlockInfo))
{
delete lpBlockInfo;
}
delete pExternal_Block_Information;
}
/*
* Free up the memory buffer (if there is one).
*/
if (Memory_Buffer != NULL)
{
LocalFree ((HLOCAL) Memory_Buffer);
Memory_Buffer = NULL;
}
}
/*
* PMemory AllocateMemory ()
*
* Public
*
* Functional Description:
* This function is used to allocate a Memory object from the Memory
* Manager object.
*/
PMemory MemoryManager::AllocateMemory (
PUChar reference_ptr,
ULong length,
MemoryLockMode memory_lock_mode)
{
PFreeStack free_stack;
ULong count;
PBlockNumber block_stack;
BlockNumber block_number;
PBlockInformation block_information;
PUChar copy_ptr = NULL;
PMemory memory = NULL;
// TRACE_OUT(("MemoryManager::AllocateMemory: Remaining %d memory blocks", GetBufferCount()));
/*
* If the application requests a block of size zero (0), then simply
* return a NULL without allocating a block.
*/
if (length != 0)
{
/*
* Walk through the free stack list look for a free stack that meets
* the following two allocation criteria:
*
* 1. It must contain blocks that are big enough to hold the
* reference data. This is why it is important for the block
* sizes to be specified in ascending order in the constructor.
* This code checks for a block that is big enough starting at the
* beginning. By putting them in ascending order, you are insured
* that the smallest available block will be used.
* 2. It must have enough free blocks left to allow the allocation.
* This is where priority is used. Right now it is very simple:
* the allocation will succeed if the number of available blocks
* is greater than the passed in priority (which is why a lower
* number actually reflects a higher priority).
*/
free_stack = Free_Stack;
for (count = 0; count < Free_Stack_Count; count++)
{
/*
* Check and see if the blocks in this free stack are big enough
* to hold the reference data. If so, are there enough to satisfy
* this allocation (taking memory priority into consideration).
*/
if ((length <= free_stack->block_size) &&
(free_stack->current_block_count > 0))
{
/*
* Calculate the address of the next available block number
* within the block stack. Then read the block number and
* advance the block stack offset to point to the next block.
*/
block_stack = (PBlockNumber) (Memory_Buffer +
free_stack->block_stack_offset);
block_number = *block_stack;
free_stack->block_stack_offset += sizeof (BlockNumber);
/*
* Calculate the address of the appropriate block information
* structure. Make sure that the lock count for the newly
* allocated block is zero, and the block is not marked as
* freed.
*/
block_information = (PBlockInformation) (Block_Information +
(sizeof (BlockInformation) * block_number));
ASSERT (block_information->flags & FREE_FLAG);
block_information->length = length;
block_information->lock_count = 0;
block_information->flags &= (~FREE_FLAG);
/*
* Decrement the number of blocks remaining, within this free stack.
*/
free_stack->current_block_count--;
/*
* Calculate the address of the newly allocated block. Then
* break out of the allocation loop to go use the block.
*/
copy_ptr = (PUChar) (Memory_Buffer +
block_information->block_offset);
ASSERT(copy_ptr != Memory_Buffer);
/*
* If this is a shared memory manager, and the block is not
* committed, we need to commit the block.
*/
if ((TRUE == fIsSharedMemory) && (0 == (block_information->flags & COMMIT_FLAG))) {
ASSERT ((free_stack->block_size % dwSystemPageSize) == 0);
ASSERT ((((DWORD_PTR) copy_ptr) % dwSystemPageSize) == 0);
PUChar temp = (PUChar) VirtualAlloc ((LPVOID) copy_ptr, free_stack->block_size,
MEM_COMMIT, PAGE_READWRITE);
block_information->flags |= COMMIT_FLAG;
ASSERT (temp == copy_ptr);
ASSERT (temp != NULL);
if (copy_ptr != temp) {
TRACE_OUT((">>>>>#### Copy_ptr: %p, Temp: %p, Committed?: %d",
copy_ptr, temp, block_information->flags & COMMIT_FLAG));
TRACE_OUT((">>>>>#### Size: %d, Req. length: %d",
free_stack->block_size, length));
copy_ptr = NULL;
}
}
break;
}
/*
* Point to the next entry in the free stack list.
*/
free_stack++;
}
/*
* If the memory allocation failed and it's for local memory,
* attempt to allocate external memory to hold the block.
*/
if ((copy_ptr == NULL) &&
((FALSE == bAllocs_Restricted) ||
((NULL != pExternal_Block_Information) &&
(Max_External_Blocks > pExternal_Block_Information->entries()))))
{
ASSERT (FALSE == fIsSharedMemory);
/*
* Try allocating from system memory. Set the free stack to NULL
* to indicate that this block did NOT come from one of our free
* stacks.
*/
copy_ptr = (PUChar) LocalAlloc (LMEM_FIXED, length);
if (copy_ptr != NULL)
{
/*
* Allocate a block information structure to hold relevant
* information about this externally allocated block.
*/
block_information = new BlockInformation;
if (block_information != NULL)
{
/*
* Fill in the block information structure. Block offset
* is irrelevant for an externally allocated block. A
* newly allocated block has a lock count of zero, and
* is not freed.
*/
block_information->length = length;
block_information->lock_count = 0;
block_information->flags = COMMIT_FLAG;
/*
* Put the block information structure into a dictionary
* for future use. This is only necessary for externally
* allocated blocks, since the block information structures
* for internal blocks are in the memory buffer.
*/
pExternal_Block_Information->insert ((DWORD_PTR) copy_ptr, (DWORD_PTR) block_information);
/*
* Set block number to be an
* invalid value to indicate that this block is NOT in
* the internally managed memory buffer.
*/
block_number = INVALID_BLOCK_NUMBER;
}
else
{
/*
* We were unable to allocate the space for the block
* information structure, so we must free the externally
* memory we just allocated.
*/
LocalFree ((HLOCAL) copy_ptr);
copy_ptr = NULL;
}
}
}
/*
* If there was a block available for the allocation, it is still
* necessary to create the Memory object that will hold the block.
*/
if (copy_ptr != NULL)
{
ASSERT (block_information->flags == COMMIT_FLAG);
/*
* Create the Memory object. If it fails, then cleanly release
* the memory that was to be used for this block.
*/
memory = new Memory (reference_ptr, length, copy_ptr,
block_number, memory_lock_mode);
if (memory == NULL)
{
/*
* If the free stack for the memory is not NULL, then it is
* an internally managed block. Otherwise, this was an
* externally allocated block that resulted from a critical
* allocation above.
*/
if (INVALID_BLOCK_NUMBER != block_number)
{
/*
* Adjust the block stack offset to point to the previous
* entry in the list. Note that it is not necessary to
* put the block number into the list since it still there
* from when we pulled it out above.
*/
free_stack->block_stack_offset -= sizeof (BlockNumber);
/*
* Indicate that the block is currently freed. Note that
* it is not necessary to calculate the address of the
* block information structure since we did this above.
*/
block_information->flags |= FREE_FLAG;
/*
* Decrement the block counter to indicate that there
* is another block in this free stack.
*/
free_stack->current_block_count++;
}
else
{
/*
* This block was externally allocated, so it must be
* externally freed. Also eliminate the block information
* structure associated with this memory block.
*/
pExternal_Block_Information->remove ((DWORD_PTR) copy_ptr);
delete block_information;
LocalFree ((HLOCAL) copy_ptr);
}
}
}
}
else
{
/*
* The application has attempted to allocate a block of size zero.
* It is necessary to fail the request.
*/
ERROR_OUT(("MemoryManager::AllocateMemory: attempt to allocate zero-length block"));
}
/*
* Decrement the number of blocks remaining
* in this memory manager as a whole.
*/
if ((TRUE == bAllocs_Restricted) && (memory != NULL))
Memory_Information->current_block_count--;
return (memory);
}
/*
* Void FreeMemory ()
*
* Public
*
* Functional Description:
* This function is used to release a previously allocated Memory object.
*/
Void MemoryManager::FreeMemory (
PMemory memory)
{
BlockNumber block_number;
PBlockInformation block_information;
PUChar copy_ptr;
/*
* Ask the specified memory object what block number it represents.
*/
block_number = memory->GetBlockNumber ();
/*
* Use the block number to determine if this is an internally
* allocated memory block, or an externally allocated one.
*/
if (block_number != INVALID_BLOCK_NUMBER)
{
/*
* From that, calculate the address of the block information structure.
*/
block_information = (PBlockInformation) (Block_Information +
(sizeof (BlockInformation) * block_number));
}
else
{
/*
* This is externally allocated memory, so it must be handled
* differently. Ask the memory block what the copy pointer is, and
* use that to look up the address of the block information structure.
*/
copy_ptr = memory->GetPointer ();
pExternal_Block_Information->find ((DWORD_PTR) copy_ptr, (PDWORD_PTR) &block_information);
}
/*
* Make sure that the indicated memory block has not already been
* freed.
*/
if ((block_information->flags & FREE_FLAG) == 0)
{
/*
* Mark the memory block as being freed.
*/
block_information->flags |= FREE_FLAG;
/*
* If the lock count for this block has reached zero, we can free
* the block for re-use. We can also delete the memory object, as it
* is no longer needed.
*/
if (block_information->lock_count == 0)
{
ReleaseMemory (memory);
delete memory;
}
else
{
/*
* If the lock count has not yet reached zero, check to see if the
* memory object is to be deleted anyway. If the memory lock mode
* is set to "IGNORED", then delete the memory object immediately.
*/
if (memory->GetMemoryLockMode () == MEMORY_LOCK_IGNORED)
delete memory;
}
}
else
{
/*
* The memory block has already been freed, so this call will be
* ignored.
*/
ERROR_OUT(("MemoryManager::FreeMemory: memory block already freed"));
}
}
/*
* PMemory CreateMemory ()
*
* Public
*
* Functional Description:
*/
PMemory MemoryManager::CreateMemory (
BlockNumber block_number,
MemoryLockMode memory_lock_mode)
{
ULong total_block_count = 0;
PFreeStack free_stack;
ULong count;
PBlockInformation block_information;
PUChar copy_ptr;
PMemory memory = NULL;
/*
* Make sure that this block number lies within the range handled by
* this memory manager.
*/
if (block_number < Memory_Information->total_block_count)
{
/*
* We must first walk through the free stack list to determine which
* free stack the specified block is in. Start by pointing to the
* first free stack.
*/
free_stack = Free_Stack;
for (count = 0; count < Free_Stack_Count; count++)
{
/*
* Update the counter which keeps track of how many blocks are
* represented by this free stack and the ones already processed.
* This is used to determine if the specified block number is in
* this free stack.
*/
total_block_count += free_stack->total_block_count;
/*
* Is the block in this free stack?
*/
if (block_number < total_block_count)
{
/*
* Yes it is. Claculate the address of the block information
* structure for this block. Then calculate the address of
* the actual block based on the address of the local memory
* buffer.
*/
block_information = (PBlockInformation) (Block_Information +
(sizeof (BlockInformation) * block_number));
copy_ptr = (PUChar) (Memory_Buffer +
block_information->block_offset);
ASSERT (block_information->flags & COMMIT_FLAG);
/*
* Create a memory object to represent this block.
*/
memory = new Memory (NULL, block_information->length, copy_ptr,
block_number, memory_lock_mode);
if (memory == NULL)
{
/*
* Allocation of the memory object failed, so we cannot
* create a memory block at this time.
*/
ERROR_OUT(("MemoryManager::CreateMemory: memory object allocation failed"));
}
break;
}
/*
* The block was not in the last free stack, so point to the
* next one.
*/
free_stack++;
}
}
else
{
/*
* The specified block number is out of range for this memory manager.
* The request must therefore fail.
*/
ERROR_OUT(("MemoryManager::CreateMemory: block number out of range"));
}
return (memory);
}
/*
* Void LockMemory ()
*
* Public
*
* Functional Description:
* This function is used to lock a Memory object.
*/
Void MemoryManager::LockMemory (
PMemory memory)
{
BlockNumber block_number;
PBlockInformation block_information;
PUChar copy_ptr;
/*
* Ask the specified memory object what block number it represents.
*/
block_number = memory->GetBlockNumber ();
/*
* Use the block number to determine if this is an internally
* allocated memory block, or an externally allocated one.
*/
if (block_number != INVALID_BLOCK_NUMBER)
{
/*
* From that, calculate the address of the block information structure.
*/
block_information = (PBlockInformation) (Block_Information +
(sizeof (BlockInformation) * block_number));
}
else
{
/*
* This is externally allocated memory, so it must be handled
* differently. Ask the memory block what the copy pointer is, and
* use that to look up the address of the block information structure.
*/
copy_ptr = memory->GetPointer ();
pExternal_Block_Information->find ((DWORD_PTR) copy_ptr, (PDWORD_PTR) &block_information);
}
ASSERT (block_information->flags & COMMIT_FLAG);
/*
* Increment the lock count for the specified memory block.
*/
block_information->lock_count++;
}
/*
* Void UnlockMemory ()
*
* Public
*
* Functional Description:
* This function is used to unlock a previously locked Memory object.
*/
Void MemoryManager::UnlockMemory (
PMemory memory)
{
BlockNumber block_number;
PBlockInformation block_information;
PUChar copy_ptr;
/*
* Ask the specified memory object what block number it represents.
*/
block_number = memory->GetBlockNumber ();
/*
* Use the block number to determine if this is an internally
* allocated memory block, or an externally allocated one.
*/
if (block_number != INVALID_BLOCK_NUMBER)
{
/*
* From that, calculate the address of the block information structure.
*/
block_information = (PBlockInformation) (Block_Information +
(sizeof (BlockInformation) * block_number));
}
else
{
/*
* This is externally allocated memory, so it must be handled
* differently. Ask the memory block what the copy pointer is, and
* use that to look up the address of the block information structure.
*/
copy_ptr = memory->GetPointer ();
pExternal_Block_Information->find ((DWORD_PTR) copy_ptr, (PDWORD_PTR) &block_information);
}
ASSERT (block_information->flags & COMMIT_FLAG);
/*
* Make sure that the lock isn't already zero before proceeding.
*/
if (block_information->lock_count > 0)
{
/*
* Decrement the lock count for the specified memory block.
*/
block_information->lock_count--;
/*
* If the lock count has reached zero and the memory block is
* marked as being freed, then we can free the block for re-use.
*/
if ((block_information->lock_count == 0) &&
(block_information->flags & FREE_FLAG))
{
ReleaseMemory (memory);
/*
* We have now released the memory buffer, so we must check to
* see if we are supposed to destroy the memory object itself.
*/
if (memory->GetMemoryLockMode () == MEMORY_LOCK_NORMAL)
delete memory;
}
}
else
{
/*
* The specified block has a lock count of zero already, so ignore
* this call.
*/
ERROR_OUT(("MemoryManager::UnlockMemory: memory block already unlocked"));
}
}
/*
* ULong GetBufferCount ()
*
* Public
*
* Functional Description:
*/
ULong MemoryManager::GetBufferCount (
ULong length)
{
PFreeStack free_stack;
ULong count;
ULong buffer_count;
if (FALSE == bAllocs_Restricted)
return (LARGE_BUFFER_COUNT);
buffer_count = Memory_Information->current_block_count;
free_stack = Free_Stack;
for (count = 0; count < Free_Stack_Count; count++)
{
/*
* Check and see if the blocks in this free stack are smaller than
* the specified length. If yes, we need to deduct these buffers.
* Otherwise, we can stop deducting.
*/
if (length > free_stack->block_size) {
buffer_count -= free_stack->current_block_count;
/*
* Point to the next entry in the free stack list.
*/
free_stack++;
}
else
break;
}
return (buffer_count);
}
/*
* Void ReleaseMemory (
* PMemory memory)
*
* Private
*
* Functional Description:
* This function is used to release a Memory object, and free the memory
* it represents back to the available pool.
*
* Formal Parameters:
* memory
* This is a pointer to the Memory object being released.
*
* Return Value:
* None.
*
* Side Effects:
* None.
*
* Caveats:
* None.
*/
Void MemoryManager::ReleaseMemory (
PMemory memory)
{
PFreeStack free_stack;
BlockNumber block_number;
PBlockNumber block_stack;
PBlockInformation block_information;
PUChar copy_ptr;
/*
* Ask the specified memory object what block number it represents.
*/
block_number = memory->GetBlockNumber ();
/*
* Use the block number to determine if this is an internally
* allocated memory block, or an externally allocated one.
*/
if (block_number != INVALID_BLOCK_NUMBER)
{
/*
* From that, calculate the address of the block information structure.
*/
block_information = (PBlockInformation) (Block_Information +
(sizeof (BlockInformation) * block_number));
/*
* Get the address of the free stack from which this block came.
*/
free_stack = (PFreeStack) (Memory_Buffer + block_information->free_stack_offset);
/*
* Adjust the block stack offset to point to the previous element,
* and then use it to calculate an address and put the block number
* there. This effectively "pushes" the block number onto the stack.
*/
free_stack->block_stack_offset -= sizeof (BlockNumber);
block_stack = (PBlockNumber) (Memory_Buffer +
free_stack->block_stack_offset);
*block_stack = block_number;
/*
* Indicate that this block is freed.
*/
block_information->flags = FREE_FLAG | COMMIT_FLAG;
/*
* Increment the counter indicating the number of available blocks
* in this free stack.
*/
free_stack->current_block_count++;
}
else
{
/*
* Since the block was allocated from system memory, thats where it
* needs to go back to.
*/
copy_ptr = memory->GetPointer ();
pExternal_Block_Information->find ((DWORD_PTR) copy_ptr, (PDWORD_PTR) &block_information);
pExternal_Block_Information->remove ((DWORD_PTR) copy_ptr);
delete block_information;
LocalFree ((HLOCAL) copy_ptr);
}
/*
* Increment the number of blocks available in this memory manager as a whole.
*/
if (TRUE == bAllocs_Restricted)
Memory_Information->current_block_count++;
}
/*
* ULong CalculateMemoryBufferSize (
* PMemoryTemplate memory_template,
* ULong memory_count,
* ULong * pulCommittedBytes)
*
* Protected
*
* Functional Description:
* This member function is used to calculate how much memory will be
* required in order to manage the number of memory blocks specified in
* the passed in memory template. Note that this total includes the size
* of the memory blocks as well as the amount of memory used for management
* functions.
*
* Formal Parameters:
* memory_template
* This is an array of structures that identify the blocks to be
* managed by this object.
* memory_count
* This is the number of entries in the above array.
* pulCommittedBytes
* If fIsSharedMemory == FALSE, this can be NULL. Otherwise, it is
* used to return the size of the total memory we need to commit
* when the manager is getting initialized.
*
* Return Value:
* The required size of the memory buffer for this object.
*
* Side Effects:
* None.
*
* Caveats:
* None.
*/
ULong MemoryManager::CalculateMemoryBufferSize (
PMemoryTemplate memory_template,
ULong memory_count,
ULong * pulCommittedBytes)
{
ULong memory_buffer_size;
PMemoryTemplate pMemTemplate;
ULong memory_per_block;
/*
* Claculate the amount of memory that will be required to hold the
* memory information structure and the free stacks.
*/
memory_buffer_size = (sizeof (MemoryInformation) +
(sizeof (FreeStack) * memory_count));
if (FALSE == fIsSharedMemory) {
/*
* Add in the amount of memory the block stacks, the block information
* structures, and the memory blocks themselves will take up.
*/
for (pMemTemplate = memory_template; pMemTemplate - memory_template < (int) memory_count; pMemTemplate++)
{
/*
* The amount of memory required for each managed block of memory can
* be calculated as a sum of the following:
*
* 1. sizeof (BlockNumber) - This is the amount of space taken by the
* block number in the block stack.
* 2. sizeof (BlockInformation) - Every managed block of memory has
* a BlockInformation structure associated with it.
* 3. block_size - The actual size of the block. This is provided
* in the memory template.
*/
memory_per_block = sizeof (BlockNumber) + sizeof (BlockInformation) +
pMemTemplate->block_size;
memory_buffer_size += (memory_per_block * pMemTemplate->block_count);
}
}
/*
* For shared memory, we need to do a few more extra things:
*
* Blocks of size greater or equal to the system's page, need to
* start on a page boundary. In addition, they can be expanded to
* end at a page boundary, too.
*/
else {
ULong reserved_buffer_size = 0;
ULong temp;
for (pMemTemplate = memory_template; pMemTemplate - memory_template < (int) memory_count; pMemTemplate++) {
if (dwSystemPageSize <= pMemTemplate->block_size) {
pMemTemplate->block_size = EXPAND_TO_PAGE_BOUNDARY(pMemTemplate->block_size);
reserved_buffer_size += pMemTemplate->block_count * pMemTemplate->block_size;
}
memory_per_block = sizeof (BlockNumber) + sizeof (BlockInformation) +
pMemTemplate->block_size;
memory_buffer_size += memory_per_block * pMemTemplate->block_count;
}
*pulCommittedBytes = memory_buffer_size - reserved_buffer_size;
temp = EXPAND_TO_PAGE_BOUNDARY(*pulCommittedBytes);
temp -= (*pulCommittedBytes);
*pulCommittedBytes += temp;
memory_buffer_size += temp;
ASSERT (*pulCommittedBytes <= memory_buffer_size);
ASSERT ((memory_buffer_size % dwSystemPageSize) == 0);
ASSERT ((*pulCommittedBytes % dwSystemPageSize) == 0);
ASSERT ((reserved_buffer_size % dwSystemPageSize) == 0);
}
return (memory_buffer_size);
}
/*
* Void AllocateMemoryBuffer (
* ULong memory_buffer_size)
*
* Protected
*
* Functional Description:
* This member function allocates the memory that is managed by an instance
* of MemoryManager. It does this using the standard Malloc macro.
*
* Formal Parameters:
* memory_buffer_size
* The size of the buffer to be allocated.
*
* Return Value:
* None.
*
* Side Effects:
* The instance variable Memory_Buffer is set to the address of the
* allocated block of memory. If it is NULL after the return from this
* call, that indicates that the memory could not be allocated.
*
* Caveats:
* None.
*/
Void MemoryManager::AllocateMemoryBuffer (
ULong memory_buffer_size)
{
TRACE_OUT(("MemoryManager::AllocateMemoryBuffer: allocating %ld bytes", memory_buffer_size));
if (memory_buffer_size != 0)
Memory_Buffer = (HPUChar) LocalAlloc (LMEM_FIXED, memory_buffer_size);
else
Memory_Buffer = NULL;
}
/*
* Void InitializeMemoryBuffer (
* PMemoryTemplate memory_template,
* ULong memory_count)
*
* Protected
*
* Functional Description:
* This member function is used to initialize the memory buffer for use.
* This primarily includes filling in the management structures that lie
* at the beginning of the allocated memory block, so that allocations
* can take place.
*
* Formal Parameters:
* memory_template
* This is an array of structures that identify the blocks to be
* managed by this object.
* memory_count
* This is the number of entries in the above array.
*
* Return Value:
* None.
*
* Side Effects:
* None.
*
* Caveats:
* None.
*/
Void MemoryManager::InitializeMemoryBuffer (
PMemoryTemplate memory_template,
ULong memory_count)
{
ULong block_count = 0;
ULong index;
ULong memory_information_size;
ULong free_stack_size;
ULong free_stack_offset;
ULong block_stack_size;
ULong block_information_size;
PFreeStack free_stack;
PBlockNumber block_stack;
PBlockInformation block_information;
ULong block_stack_offset;
BlockNumber block_number;
ULong block_offset;
ULong block_size;
ULong count;
BOOL fIsFirstTime;
/*
* Walk through the memory template calculating how many memory blocks
* exist (regardless of size).
*/
for (index = 0; index < memory_count; index++)
block_count += memory_template[index].block_count;
/*
* Calculate the amount of memory required to hold all the various sections
* of data in the memory buffer.
*/
memory_information_size = sizeof (MemoryInformation);
free_stack_size = sizeof (FreeStack) * memory_count;
block_stack_size = sizeof (BlockNumber) * block_count;
block_information_size = sizeof (BlockInformation) * block_count;
/*
* Initialize all elements of the memory information structure.
* Note that all offsets in this structure are from the beginning of the
* memory buffer.
*/
Memory_Information = (PMemoryInformation) Memory_Buffer;
Memory_Information->free_stack_offset = memory_information_size;
Memory_Information->free_stack_count = memory_count;
Memory_Information->block_information_offset =
memory_information_size + free_stack_size + block_stack_size;
Memory_Information->total_block_count = block_count;
if (TRUE == bAllocs_Restricted) {
// The current_block_count is only needed when allocations are restricted.
Memory_Information->current_block_count = block_count + Max_External_Blocks;
}
/*
* Now initialize the instance variables that point to each list within
* the memory buffer. These instance variables are later used to resolve
* all other offsets.
*/
Free_Stack = (PFreeStack) (Memory_Buffer + memory_information_size);
Free_Stack_Count = memory_count;
Block_Information = (Memory_Buffer +
Memory_Information->block_information_offset);
/*
* This loop walks through the memory template array again, this time
* filling in the contents of the free stacks, the blocks stacks, and
* the block information structures.
*/
fIsFirstTime = TRUE;
free_stack = Free_Stack;
free_stack_offset = memory_information_size;
block_stack_offset = memory_information_size + free_stack_size;
block_stack = (PBlockNumber) (Memory_Buffer + block_stack_offset);
block_information = (PBlockInformation) Block_Information;
block_number = 0;
block_offset = block_stack_offset + block_stack_size + block_information_size;
for (index = 0; index < memory_count; index++)
{
/*
* Get the block size and count from the template entry.
*/
block_size = memory_template[index].block_size;
block_count = memory_template[index].block_count;
/*
* Initialize the free stack for this block size, and then point to
* the next free stack in the list.
*/
free_stack->block_size = block_size;
free_stack->total_block_count = block_count;
free_stack->current_block_count = block_count;
(free_stack++)->block_stack_offset = block_stack_offset;
/*
* Adjust the block stack offset to point to the first block number
* of the next free stack (skip past all of the block numbers for
* this free stack).
*/
block_stack_offset += (sizeof (BlockNumber) * block_count);
/*
* The following happens only once in this loop:
* When the memory manager manages shared memory and
* The block size becomes FOR THE 1ST TIME, bigger than
* the page size, then, we need to jump to the next page
* boundary.
*/
if ((TRUE == fIsSharedMemory) && (TRUE == fIsFirstTime)
&& (block_size >= dwSystemPageSize)) {
fIsFirstTime = FALSE;
block_offset = EXPAND_TO_PAGE_BOUNDARY(block_offset);
}
/*
* Initialize the block list for this block size. Also, increment
* the total number of buffers for each block that is segmented
* off.
*/
for (count = 0; count < block_count; count++)
{
/*
* Put the block number for this block into the current block
* stack. Increment both the block stack pointer and the block
* number.
*/
*(block_stack++) = block_number++;
/*
* Fill in the block information structure for this block. Then
* increment the block information pointer to point to the next
* entry in the list.
*/
#ifdef _DEBUG
if ((TRUE == fIsSharedMemory) && (block_size >= dwSystemPageSize)) {
ASSERT ((block_size % dwSystemPageSize) == 0);
ASSERT ((block_offset % dwSystemPageSize) == 0);
}
#endif
block_information->block_offset = block_offset;
block_information->free_stack_offset = free_stack_offset;
if ((TRUE == fIsSharedMemory) && (block_size >= dwSystemPageSize))
block_information->flags = FREE_FLAG;
else
block_information->flags = FREE_FLAG | COMMIT_FLAG;
block_information++;
/*
* Adjust the block offset to point to the next block.
*/
block_offset += block_size;
}
free_stack_offset += sizeof (FreeStack);
}
}