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.
 
 
 
 
 
 

498 lines
12 KiB

/////////////////////////////////////////////////////////////////////////////
// INTEL Corporation Proprietary Information
// This listing is supplied under the terms of a license agreement with Intel
// Corporation and many not be copied nor disclosed except in accordance
// with the terms of that agreement.
// Copyright (c) 1995, 1996 Intel Corporation.
//
//
// Module Name: freelist.cpp
// Abstract: source file. a data structure for maintaining a pool of memory.
// Environment: MSVC 4.0, OLE 2
/////////////////////////////////////////////////////////////////////////////
#include "freelist.h"
#include "que.h"
#include "ppmerr.h"
#include "debug.h" // for the ASSERT macro and assert.h; OK since compile time only
long lFreeListHeapCreate = 0;
long lFreeListHeapDestroy = 0;
long lFreeListHeapAlloc = 0;
long lFreeListHeapFree = 0;
long lFreeListHeapCreateFailed = 0;
// Uncomment next line to have some extra debug information
// (also in free builds)
// set to 1 for checking but no messages
// set to 2 for error messages
// set to 3 for the max available and DebugBreak
// DEBUG_FREELIST is defined in sources
#if DEBUG_FREELIST > 0
long lFreeListLeak = 0;
long lFreeListEnqueueTwice = 0;
long lFreeListFreeTwice = 0;
long lFreeListCorruptBegin = 0;
long lFreeListCorruptEnd = 0;
char begin_buf_pattern[FREE_LIST_SIG_SIZE] =
{'F', 'R', 'E', 'E', 'B', 'E','G', 'N'};
char end_buf_pattern[FREE_LIST_SIG_SIZE] =
{'F', 'R', 'E', 'E', ' ', 'E', 'N','D'};
char free_buf_pattern[FREE_LIST_SIG_SIZE] =
{'F', 'R', 'E', 'E', 'B', 'U', 'F','F'};
#endif
#if DEBUG_FREELIST > 2
#define DEBUGBREAK() DebugBreak()
#else
#define DEBUGBREAK()
#endif
FreeList::FreeList(HRESULT *phr)
{
DBG_MSG(DBG_ERROR, ("FreeList::FreeList: Constructor with no Params"));
m_Size = 0;
InitializeCriticalSection(&m_CritSect);
m_HighWaterCount = 0;
m_AllocatedCount = 0;
m_Increment = 0;
m_Tag = FREE_LIST_TAG;
*phr = PPMERR(PPM_E_OUTOFMEMORY);
//m_hMemAlloc = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 1, 0);
m_hMemAlloc = HeapCreate(0, 1, 0);
ASSERT(m_hMemAlloc);
if (m_hMemAlloc) {
SetHandleInformation(m_hMemAlloc,
HANDLE_FLAG_PROTECT_FROM_CLOSE,
HANDLE_FLAG_PROTECT_FROM_CLOSE);
InterlockedIncrement(&lFreeListHeapCreate);
*phr = NOERROR;
} else {
InterlockedIncrement(&lFreeListHeapCreateFailed);
}
}
FreeList::FreeList(int NumElements, size_t Size, HRESULT *phr)
{
int enqueued = 0;
#ifdef PDEBUG
DBG_MSG(DBG_TRACE, ("FreeList::Freelist: Constructor with 2 params"));
#endif
/*
//Make sure there is enough memory to typecast
//each item to a QueItem for storage.
ASSERT(Size >= sizeof(QueueItem));
ASSERT( NumElements > 0 );
InitializeCriticalSection(&m_CritSect);
EnterCriticalSection(&m_CritSect);
m_Size = Size;
m_pMemory = new char [(Size*NumElements)]; //new may not be the best memory allocator here.
if (m_pMemory) {
for (int i=0; i < NumElements; i++)
{
m_List.Enqueue((QueueItem*)&(m_pMemory[Size*i]));
}
}
*/
//Make sure there is enough memory to typecast
//each item to a QueItem for storage.
ASSERT(Size >= sizeof(QueueItem));
ASSERT( NumElements > 0 );
InitializeCriticalSection(&m_CritSect);
m_Size = Size;
m_AllocatedCount = 0;
m_Tag = FREE_LIST_TAG;
*phr = PPMERR(PPM_E_OUTOFMEMORY);
m_hMemAlloc = HeapCreate(0, 1, 0);
ASSERT(m_hMemAlloc);
if (m_hMemAlloc) {
SetHandleInformation(m_hMemAlloc,
HANDLE_FLAG_PROTECT_FROM_CLOSE,
HANDLE_FLAG_PROTECT_FROM_CLOSE);
InterlockedIncrement(&lFreeListHeapCreate);
} else {
InterlockedIncrement(&lFreeListHeapCreateFailed);
}
if ( (enqueued = AllocateAndEnqueue( NumElements )) > 0 )
*phr = NOERROR;
EnterCriticalSection(&m_CritSect);
m_HighWaterCount = enqueued;
m_Increment = 0;
LeaveCriticalSection(&m_CritSect);
}
FreeList::FreeList(int NumElements, size_t Size, unsigned HighWaterCount,
unsigned Increment, HRESULT *phr)
{
int enqueued = 0;
ASSERT(HighWaterCount >= (unsigned)NumElements);
//Make sure there is enough memory to typecast
//each item to a QueItem for storage.
ASSERT(Size >= sizeof(QueueItem));
ASSERT( NumElements > 0 );
InitializeCriticalSection(&m_CritSect);
m_Size = Size;
m_AllocatedCount = 0;
m_Tag = FREE_LIST_TAG;
*phr = PPMERR(PPM_E_OUTOFMEMORY);
m_hMemAlloc = HeapCreate(0, 1, 0);
ASSERT(m_hMemAlloc);
if (m_hMemAlloc) {
SetHandleInformation(m_hMemAlloc,
HANDLE_FLAG_PROTECT_FROM_CLOSE,
HANDLE_FLAG_PROTECT_FROM_CLOSE);
InterlockedIncrement(&lFreeListHeapCreate);
} else {
InterlockedIncrement(&lFreeListHeapCreateFailed);
}
if ( (enqueued = AllocateAndEnqueue( NumElements )) > 0 )
*phr = NOERROR;
EnterCriticalSection(&m_CritSect);
m_HighWaterCount = HighWaterCount;
m_Increment = Increment;
LeaveCriticalSection(&m_CritSect);
}
void * FreeList::Get()
{
void *v_ptr;
int enqueued = 0;
EnterCriticalSection(&m_CritSect);
v_ptr = (void *) m_List.DequeueHead();
#if DEBUG_FREELIST > 2
{
char str[128];
wsprintf(str, "0x%X +++ %5d %5d/%2d 0x%X\n",
this, m_Size, m_List.NumItems(), m_AllocatedCount, v_ptr);
OutputDebugString(str);
}
#endif
LeaveCriticalSection(&m_CritSect);
if( v_ptr != NULL )
{
#ifdef PDEBUG
DBG_MSG(DBG_TRACE, ("FreeList::Get: Successful deque"));
#endif
#if DEBUG_FREELIST > 0
// Set signature in boundaries
memcpy((char *)v_ptr - FREE_LIST_SIG_SIZE,
begin_buf_pattern, FREE_LIST_SIG_SIZE);
memcpy((char *)v_ptr + m_Size, end_buf_pattern, FREE_LIST_SIG_SIZE);
#endif
return v_ptr;
}
else
{
#ifdef PDEBUG
DBG_MSG(DBG_TRACE, ("FreeList::Get: High Water Mark-case deque"));
#endif
if( m_AllocatedCount < m_HighWaterCount )
{
#if DEBUG_FREELIST > 1
{
char msg[128];
wsprintf(msg,
"0x%X +++ %5d %5d/%2d add +%d\n",
this, m_Size, 0, m_AllocatedCount, m_Increment);
OutputDebugString(msg);
DEBUGBREAK();
}
#endif
enqueued = AllocateAndEnqueue( m_Increment );
if( enqueued > 0 )
{
#ifdef PDEBUG
DBG_MSG(DBG_TRACE, ("FreeList::Get: High Water Mark-Successful allocate & deque"));
#endif
EnterCriticalSection(&m_CritSect);
v_ptr = (void *)m_List.DequeueHead();
#if DEBUG_FREELIST > 2
{
char str[128];
wsprintf(str, "0x%X +++ %5d %5d/%2d 0x%X\n",
this, m_Size, m_List.NumItems(),
m_AllocatedCount, v_ptr);
OutputDebugString(str);
}
#endif
LeaveCriticalSection(&m_CritSect);
#if DEBUG_FREELIST > 0
// Set signature in boundaries
memcpy((char *)v_ptr - FREE_LIST_SIG_SIZE,
begin_buf_pattern, FREE_LIST_SIG_SIZE);
memcpy((char *)v_ptr + m_Size,
end_buf_pattern, FREE_LIST_SIG_SIZE);
#endif
return(v_ptr);
}
else
{
DBG_MSG(DBG_ERROR, ("FreeList::Get: High Water Mark-Could not allocate"));
return NULL;
}
}
else
{
DBG_MSG(DBG_ERROR, ("FreeList::Get: High Water mark-exceeded"));
return NULL;
}
}
}
HRESULT FreeList::Free(void * Element)
{
#if DEBUG_FREELIST > 0
int error = 0;
int nofree = 0;
#endif
EnterCriticalSection(&m_CritSect);
#if DEBUG_FREELIST > 2
{
char str[128];
wsprintf(str, "0x%X --- %5d %5d/%2d 0x%X\n",
this, m_Size, m_List.NumItems()+1, m_AllocatedCount, Element);
OutputDebugString(str);
}
#endif
#if DEBUG_FREELIST > 0
// Check if the buffer was already released
if (!memcmp((char *)Element - FREE_LIST_SIG_SIZE,
free_buf_pattern, FREE_LIST_SIG_SIZE)) {
#if DEBUG_FREELIST > 1
char str[128];
wsprintf(str,
"0x%X --- Heap[0x%X]: Element in 0x%X size=0x%X "
"is been freed twice\n",
this, m_hMemAlloc,
(char *)Element - FREE_LIST_SIG_SIZE,
m_Size);
OutputDebugString(str);
#endif
InterlockedIncrement(&lFreeListFreeTwice);
nofree = 1;
}
// Check signatures on each boundary
if (memcmp((char *)Element - FREE_LIST_SIG_SIZE,
begin_buf_pattern, FREE_LIST_SIG_SIZE)) {
#if DEBUG_FREELIST > 1
char str[128];
wsprintf(str,
"0x%X --- Heap[0x%X]: Element in 0x%X size=0x%X "
"has beginning signature corrupted at: 0x%X\n",
this, m_hMemAlloc,
(char *)Element - FREE_LIST_SIG_SIZE,
m_Size,
(char *)Element - FREE_LIST_SIG_SIZE);
OutputDebugString(str);
#endif
InterlockedIncrement(&lFreeListCorruptBegin);
error = 1;
}
if (memcmp((char *)Element + m_Size,
end_buf_pattern, FREE_LIST_SIG_SIZE)) {
#if DEBUG_FREELIST > 1
char str[128];
wsprintf(str,
"0x%X --- Heap[0x%X]: Element in 0x%X size=0x%X "
"has ending signature corrupted at: 0x%X\n",
this, m_hMemAlloc,
(char *)Element - FREE_LIST_SIG_SIZE,
m_Size,
(char *)Element + m_Size);
OutputDebugString(str);
#endif
InterlockedIncrement(&lFreeListCorruptEnd);
error = 1;
}
if (error || nofree) {
DEBUGBREAK();
}
#endif
HRESULT err;
#if DEBUG_FREELIST > 0
if (!nofree) {
memcpy((char *)Element - FREE_LIST_SIG_SIZE,
free_buf_pattern, FREE_LIST_SIG_SIZE);
err = m_List.EnqueueHead((QueueItem *)Element);
} else {
err = NOERROR;
}
#else
err = m_List.EnqueueHead((QueueItem *)Element);
#endif
LeaveCriticalSection(&m_CritSect);
return(err);
}
int FreeList::AllocateAndEnqueue(int NumElements)
{
int enqueued = 0;
char * pMemory = NULL;
ASSERT( NumElements > 0 );
// Replacement for the ASSERTs
if( NumElements <= 0 )
{
return 0;
}
EnterCriticalSection(&m_CritSect);
//pMemory = new char [(m_Size*NumElements)]; //new may not be the best memory allocator here.
if (m_hMemAlloc) {
for (int i=0; i < NumElements; i++)
{
// Get some more bytes to put a signature
// at the beggining and end of buffer
#if DEBUG_FREELIST > 0
pMemory = (char *)HeapAlloc(m_hMemAlloc,
0,
m_Size + FREE_LIST_SIG_SIZE*2);
#else
pMemory = (char *)HeapAlloc(m_hMemAlloc,
0,
m_Size);
#endif
if(pMemory )
{
#ifdef PDEBUG
DBG_MSG(DBG_TRACE,
("FreeList::AllocateAndEnqueue: Allocated"));
#endif
#if DEBUG_FREELIST > 0
// Shift to make room for beggining signature
pMemory += FREE_LIST_SIG_SIZE;
#endif
m_List.EnqueueTail((QueueItem*)(pMemory));
enqueued++;
InterlockedIncrement(&lFreeListHeapAlloc);
pMemory = NULL;
}
}
m_AllocatedCount+= enqueued;
}
LeaveCriticalSection(&m_CritSect);
return enqueued;
}
FreeList::~FreeList()
{
void * v_ptr;
unsigned free_count = 0;
EnterCriticalSection(&m_CritSect);
if (m_hMemAlloc) {
while( (v_ptr = (void *) m_List.DequeueTail()) != NULL ) {
// Shift pointer before freeing
v_ptr = (char *)v_ptr - FREE_LIST_SIG_SIZE;
if (HeapFree(m_hMemAlloc, 0, v_ptr)) {
InterlockedIncrement(&lFreeListHeapFree);
++free_count;
} else {
#if DEBUG_FREELIST > 1
char msg[128];
DWORD error = GetLastError();
wsprintf(msg,
"0x%X FreeList::~FreeList: "
"HeapFree failed: %d (0x%x)\n",
this, error, error);
DBG_MSG(DBG_ERROR, (msg));
OutputDebugString(msg);
DEBUGBREAK();
#endif
}
}
}
LeaveCriticalSection(&m_CritSect);
#if defined(_DEBUG) || DEBUG_FREELIST > 0
if( free_count != m_AllocatedCount )
{
#if defined(_DEBUG) || DEBUG_FREELIST > 1
char msg[128];
wsprintf(msg,"0x%X FreeList::~FreeList: "
"Memory leak in Freelist(size=%d) "
"(free_count:%d != %d:m_AllocatedCount)\n",
this, m_Size, free_count, m_AllocatedCount);
OutputDebugString(msg);
#endif
#if DEBUG_FREELIST > 0
InterlockedIncrement(&lFreeListLeak);
DEBUGBREAK();
#endif
}
#endif
if (m_hMemAlloc) {
SetHandleInformation(m_hMemAlloc, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
HeapDestroy(m_hMemAlloc);
InterlockedIncrement(&lFreeListHeapDestroy);
}
m_hMemAlloc = NULL;
DeleteCriticalSection(&m_CritSect);
}