298 lines
7.8 KiB
C++
298 lines
7.8 KiB
C++
#include "precomp.h"
|
||
DEBUG_FILEZONE(ZONE_T120_MEMORY);
|
||
/*
|
||
* memmgr.cpp
|
||
*
|
||
* Copyright (c) 1998 by Microsoft Corporation, Redmond, WA
|
||
*
|
||
* Abstract:
|
||
* This is the implementation file for the T.120 memory allocation mechanism. This
|
||
* file contains the code necessary to allocate and distribute memory
|
||
* in the form of Memory objects.
|
||
*
|
||
* This implementation defines priorities of memory allocations. A lower
|
||
* priority number implies higher priority. Priority-0 allocations will be
|
||
* satisfied, unless the system is out of memory. Priorities 1 and 2
|
||
* limit the amount of total memory that can be allocated, but priority 1 (recv priority)
|
||
* has higher water mark limits than priority 2 (send priority).
|
||
*
|
||
* Protected Member Functions:
|
||
* None.
|
||
*
|
||
* Caveats:
|
||
* None.
|
||
*
|
||
* Author:
|
||
* Christos Tsollis
|
||
*/
|
||
static int s_anCurrentSize[MEMORY_PRIORITIES] = { 0, 0, 0 };
|
||
static const int sc_iLimit[MEMORY_PRIORITIES] = {
|
||
0x7FFFFFFF,
|
||
0x100000,
|
||
0xE0000
|
||
};
|
||
|
||
#ifdef DEBUG
|
||
static int s_TotalSize = 0;
|
||
#endif // DEBUG
|
||
|
||
/*
|
||
* PMemory AllocateMemory ()
|
||
*
|
||
* Public
|
||
*
|
||
* Functional Description:
|
||
* This function is used to allocate a buffer together with a
|
||
* Memory (buffer header) object
|
||
*/
|
||
PMemory AllocateMemory (
|
||
PUChar reference_ptr,
|
||
UINT length,
|
||
MemoryPriority priority)
|
||
{
|
||
|
||
PUChar copy_ptr;
|
||
PMemory memory;
|
||
|
||
ASSERT (length > 0);
|
||
|
||
if (s_anCurrentSize[priority] < sc_iLimit[priority]) {
|
||
/*
|
||
* We attempt to allocate enough space for the buffer and the
|
||
* Memory object.
|
||
*/
|
||
#ifdef DEBUG
|
||
memory = (PMemory) new BYTE[length + sizeof (Memory)];
|
||
#else // DEBUG
|
||
memory = (PMemory) LocalAlloc (LMEM_FIXED, length + sizeof (Memory));
|
||
#endif // DEBUG
|
||
}
|
||
else {
|
||
/*
|
||
* The application has attempted to allocate past its limit
|
||
* It is necessary to fail the request.
|
||
*/
|
||
memory = NULL;
|
||
WARNING_OUT (("AllocateMemory: attempt to allocate past the allowable limit. "
|
||
"Request: %d. Currently allocated: %d. Priority: %d",
|
||
length, s_anCurrentSize[priority], priority));
|
||
}
|
||
|
||
/*
|
||
* Check to see whether the allocation was successful.
|
||
*/
|
||
if (memory != NULL) {
|
||
#ifdef DEBUG
|
||
s_TotalSize += (int) length;
|
||
#endif // DEBUG
|
||
/*
|
||
* Update the currently allocated size. Notice that we only
|
||
* do this for buffers used in the send/recv code path in
|
||
* MCS. Since this is only one thread, we do not have to
|
||
* use a critical section to protect the size variable.
|
||
*/
|
||
ASSERT (s_anCurrentSize[priority] >= 0);
|
||
s_anCurrentSize[priority] += (int) length;
|
||
|
||
copy_ptr = (PUChar) memory + sizeof(Memory);
|
||
memory->Init (reference_ptr, length, priority, copy_ptr);
|
||
|
||
TRACE_OUT (("Allocate: successful request. "
|
||
"Request: %d. Currently allocated: %d. Total: %d. Priority: %d",
|
||
length, s_anCurrentSize[priority], s_TotalSize, priority));
|
||
TRACE_OUT (("AllocateMemory: buffer at address %p; memory segment at address %p",
|
||
copy_ptr, memory));
|
||
}
|
||
else {
|
||
/*
|
||
* We failed to allocate the requested size
|
||
* It is necessary to fail the request.
|
||
*/
|
||
WARNING_OUT (("AllocateMemory: failed to allocated buffer. We are out of system memory. "
|
||
"Request: %d. Last error: %d",
|
||
length, GetLastError()));
|
||
}
|
||
return (memory);
|
||
}
|
||
|
||
/*
|
||
* PUChar ReAllocate ()
|
||
*
|
||
* Public
|
||
*
|
||
* Functional Description:
|
||
* This function is used to re-allocate a buffer with a Memory
|
||
* (buffer header) object. The buffer must have been allocated by
|
||
* a call to AllocateMemory. This call assumes RECV_PRIORITY. However,
|
||
* it's not restricted in allocations, because, if it did, this might
|
||
* cause deadlocks (some memory has already been allocated for the
|
||
* new arriving data).
|
||
*/
|
||
BOOL ReAllocateMemory (PMemory *pmemory,
|
||
UINT length)
|
||
{
|
||
|
||
PUChar copy_ptr = NULL;
|
||
UINT new_length;
|
||
MemoryPriority priority;
|
||
|
||
ASSERT (length > 0);
|
||
ASSERT (pmemory != NULL);
|
||
ASSERT (*pmemory != NULL);
|
||
ASSERT ((*pmemory)->GetPointer());
|
||
|
||
new_length = length + (*pmemory)->GetLength();
|
||
priority = (*pmemory)->GetMemoryPriority();
|
||
|
||
ASSERT (priority == RECV_PRIORITY);
|
||
|
||
// We attempt to allocate enough space for the buffer.
|
||
#ifdef DEBUG
|
||
copy_ptr = (PUChar) new BYTE[new_length + sizeof(Memory)];
|
||
if (copy_ptr != NULL) {
|
||
memcpy (copy_ptr, *pmemory, (*pmemory)->GetLength() + sizeof(Memory));
|
||
delete [] (BYTE *) *pmemory;
|
||
}
|
||
#else // DEBUG
|
||
copy_ptr = (PUChar) LocalReAlloc ((HLOCAL) *pmemory,
|
||
new_length + sizeof(Memory),
|
||
LMEM_MOVEABLE);
|
||
#endif // DEBUG
|
||
|
||
/*
|
||
* Check to see whether the allocation was successful.
|
||
*/
|
||
if (copy_ptr != NULL) {
|
||
|
||
#ifdef DEBUG
|
||
s_TotalSize += (int) length;
|
||
#endif // DEBUG
|
||
/*
|
||
* Update the currently allocated size.
|
||
*/
|
||
ASSERT (s_anCurrentSize[priority] >= 0);
|
||
s_anCurrentSize[priority] += (int) length;
|
||
*pmemory = (PMemory) copy_ptr;
|
||
copy_ptr += sizeof (Memory);
|
||
(*pmemory)->Init (NULL, new_length, priority, copy_ptr);
|
||
|
||
TRACE_OUT (("ReAllocate: successful request. "
|
||
"Request: %d. Currently allocated: %d. Total: %d",
|
||
length, s_anCurrentSize[priority], s_TotalSize));
|
||
TRACE_OUT (("ReAllocate: buffer at address %p; memory segment at address %p",
|
||
copy_ptr, *pmemory));
|
||
}
|
||
else {
|
||
/*
|
||
* We failed to allocate the requested size
|
||
* It is necessary to fail the request.
|
||
*/
|
||
WARNING_OUT (("ReAllocate: failed to allocated buffer. We are out of system memory. "
|
||
"Request: %d. Currently allocated: %d. Last error: %d",
|
||
length, s_anCurrentSize[priority], GetLastError()));
|
||
}
|
||
|
||
return (copy_ptr != NULL);
|
||
}
|
||
|
||
/*
|
||
* Void FreeMemory ()
|
||
*
|
||
* Public
|
||
*
|
||
* Functional Description:
|
||
* This function is used to release a previously allocated Memory object.
|
||
*/
|
||
void FreeMemory (PMemory memory)
|
||
{
|
||
if (memory != NULL) {
|
||
|
||
ASSERT (SIGNATURE_MATCH(memory, MemorySignature));
|
||
ASSERT (memory->GetPointer() == (PUChar) memory + sizeof(Memory));
|
||
|
||
if (memory->Unlock() == 0) {
|
||
|
||
MemoryPriority priority = memory->GetMemoryPriority();
|
||
|
||
TRACE_OUT (("FreeMemory: buffer at address %p (memory segment at address %p) freed. Size: %d. ",
|
||
memory->GetPointer(), memory, memory->GetLength()));
|
||
|
||
// We may need to adjust the variable tracking the allocated amount of mem.
|
||
ASSERT (s_anCurrentSize[priority] >= (int) memory->GetLength());
|
||
s_anCurrentSize[priority] -= memory->GetLength();
|
||
ASSERT(s_anCurrentSize[priority] >= 0);
|
||
#ifdef DEBUG
|
||
s_TotalSize -= memory->GetLength();
|
||
#endif // DEBUG
|
||
TRACE_OUT(("FreeMemory: Currently allocated: %d. Total: %d.",
|
||
s_anCurrentSize[priority], s_TotalSize));
|
||
|
||
// free the buffer, and the memory
|
||
#ifdef DEBUG
|
||
delete [] (BYTE *) memory;
|
||
#else // DEBUG
|
||
LocalFree ((HLOCAL) memory);
|
||
#endif // DEBUG
|
||
}
|
||
}
|
||
}
|
||
|
||
#ifdef DEBUG
|
||
/*
|
||
* PUChar Allocate ()
|
||
*
|
||
* Public
|
||
*
|
||
* Functional Description:
|
||
* This function is used to allocate a buffer without a Memory
|
||
* (buffer header) object.
|
||
*/
|
||
PUChar Allocate (UINT length)
|
||
{
|
||
|
||
PUChar copy_ptr;
|
||
|
||
ASSERT (length > 0);
|
||
|
||
// We attempt to allocate enough space for the buffer.
|
||
copy_ptr = (PUChar) new BYTE[length];
|
||
|
||
/*
|
||
* Check to see whether the allocation was successful.
|
||
*/
|
||
if (copy_ptr == NULL) {
|
||
/*
|
||
* We failed to allocate the requested size
|
||
* It is necessary to fail the request.
|
||
*/
|
||
ERROR_OUT (("Allocate: failed to allocated buffer. We are out of system memory. "
|
||
"Request: %d. Last error: %d",
|
||
length, GetLastError()));
|
||
}
|
||
|
||
return (copy_ptr);
|
||
}
|
||
#endif // DEBUG
|
||
|
||
/*
|
||
* UINT GetFreeMemory ()
|
||
*
|
||
* Public
|
||
*
|
||
* Functional Description:
|
||
* This function returns the amount of space that can still be
|
||
* allocated at the given priority level. The function should be
|
||
* called only when send/recv space is allocated.
|
||
*/
|
||
|
||
UINT GetFreeMemory (MemoryPriority priority)
|
||
{
|
||
int idiff;
|
||
|
||
ASSERT (priority != HIGHEST_PRIORITY);
|
||
|
||
idiff = sc_iLimit[priority] - s_anCurrentSize[priority];
|
||
return ((idiff > 0) ? (UINT) idiff : 0);
|
||
}
|
||
|
||
|