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