windows-nt/Source/XPSP1/NT/termsrv/remdsk/rds/t120/mst120/memmgr.cpp
2020-09-26 16:20:57 +08:00

298 lines
7.8 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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);
}