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.
 
 
 
 
 
 

488 lines
10 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
MyHeap.h
Abstract:
Implementation of a (dumb and) fast heap allocator
Author:
Hakki T. Bostanci (hakkib) 06-Apr-2000
Revision History:
--*/
#ifndef MYHEAP_H
#define MYHEAP_H
//////////////////////////////////////////////////////////////////////////
//
//
//
#ifdef _WIN32
#undef ALIGNMENT
#define ALIGNMENT 8
#endif //WIN32
#ifdef _WIN64
#undef ALIGNMENT
#define ALIGNMENT 16
#endif //WIN64
//////////////////////////////////////////////////////////////////////////
//
//
//
typedef enum { nAllocBlockSize = 64*1024 };
//////////////////////////////////////////////////////////////////////////
//
//
//
template <size_t nBucketSize = nAllocBlockSize>
class CMyHeap
{
public:
CMyHeap()
{
InitializeCriticalSection(&m_cs);
m_pBucket = 0;
m_pNextFree = 0;
}
~CMyHeap()
{
DumpAllocations();
FreeAllBuckets();
DeleteCriticalSection(&m_cs);
}
void *allocate(size_t nSize, ULONG uFlags = 0)
{
int nAllocSize = AllocSize(nSize);
if (nAllocSize < 0)
{
if (uFlags & HEAP_GENERATE_EXCEPTIONS)
{
RaiseException(STATUS_NO_MEMORY, 0, 0, 0);
}
return 0;
}
if (!(uFlags & HEAP_NO_SERIALIZE))
{
EnterCriticalSection(&m_cs);
}
// do we have enough buffer space?
if (m_pBucket == 0 ||
m_pNextFree + nAllocSize > (PBYTE) m_pBucket + nBucketSize)
{
// if we can manage the requested allocation size,
// try to allocate a new bucket
if (nAllocSize > nBucketSize || AllocNewBucket() == false)
{
// if we fail the allocation, return 0 or raise an exception
if (!(uFlags & HEAP_NO_SERIALIZE))
{
LeaveCriticalSection(&m_cs);
}
if (uFlags & HEAP_GENERATE_EXCEPTIONS)
{
RaiseException(STATUS_NO_MEMORY, 0, 0, 0);
}
return 0;
}
}
// ok, we have enough space, allocate and initialize a block
ASSERT(m_pBucket->Contains(m_pNextFree));
CAllocation *pAllocation = (CAllocation *) m_pNextFree;
pAllocation->m_nRefCount = 1;
pAllocation->m_nDataSize = nSize;
m_pNextFree += nAllocSize;
m_pBucket->m_nAllocated += nAllocSize;
ASSERT(m_pBucket->m_nAllocated < nBucketSize);
// we are done
if (!(uFlags & HEAP_NO_SERIALIZE))
{
LeaveCriticalSection(&m_cs);
}
if (uFlags & HEAP_ZERO_MEMORY)
{
// virtual alloc has already given us zero-init memory
}
return pAllocation->m_Data;
}
template <class T>
T *allocate_array(size_t nItems, ULONG uFlags = 0)
{
return (T *) g_MyHeap.allocate(nItems * sizeof(T), uFlags);
}
void AddRef(void *pMem)
{
if (pMem)
{
CAllocation *pAllocation = CONTAINING_RECORD(pMem, CAllocation, m_Data);
ASSERT(pAllocation->m_nRefCount != 0);
InterlockedIncrement(&pAllocation->m_nRefCount);
}
}
void deallocate(void *pMem, ULONG uFlags = 0)
{
if (!(uFlags & HEAP_NO_SERIALIZE))
{
EnterCriticalSection(&m_cs);
}
// find which bucket this allocation belongs to
CBucket *pBucket;
if (nBucketSize == nAllocBlockSize)
{
// if the bucket size is aligned with the VirtualAlloc block size,
// then simply zero the lower WORD to reach to the base address
pBucket = (CBucket *) ((UINT_PTR)pMem & ~(nAllocBlockSize-1));
}
else
{
// the general case: find the bucket by walking though each one
for (
pBucket = m_pBucket;
pBucket != 0 && !pBucket->Contains(pMem);
pBucket = pBucket->m_pNextBucket
);
}
// if we have found the container bucket, release the allocation
if (pBucket)
{
CAllocation *pAllocation = CONTAINING_RECORD(pMem, CAllocation, m_Data);
pAllocation->m_nRefCount -= 1;
ASSERT(pAllocation->m_nRefCount >= 0);
// delete the allocation if the reference count is zero
if (pAllocation->m_nRefCount == 0)
{
pBucket->m_nAllocated -= AllocSize(pAllocation->m_nDataSize);
ASSERT(pBucket->m_nAllocated >= 0);
// if all the allocation units in this bucket are freed,
// free the bucket
if (pBucket->m_nAllocated == 0)
{
FreeBucket(pBucket);
}
}
}
if (!(uFlags & HEAP_NO_SERIALIZE))
{
LeaveCriticalSection(&m_cs);
}
}
size_t max_size() const
{
return nBucketSize;
}
bool DumpAllocations() const
{
bool bResult = true;
CBucket *pBucket = m_pBucket;
while (pBucket)
{
CAllocation *pAllocation = (CAllocation *) pBucket->m_Data;
while (pAllocation->m_nDataSize != 0)
{
if (pAllocation->m_nRefCount != 0)
{
OutputDebugStringF(
_T("0x%p, DataSize=%d, RefCount=%d; %s\n"),
pAllocation->m_Data,
pAllocation->m_nDataSize,
pAllocation->m_nRefCount,
pAllocation->m_Data
);
}
pAllocation = (CAllocation *)
((PBYTE)pAllocation + AllocSize(pAllocation->m_nDataSize));
}
pBucket = pBucket->m_pNextBucket;
}
return bResult;
}
private:
struct CBucket
{
CBucket *m_pNextBucket;
LONG m_nAllocated;
BYTE m_Data[ANYSIZE_ARRAY];
bool Contains(const void *pMem) const
{
return
(PBYTE)pMem >= (PBYTE)m_Data &&
(PBYTE)pMem < (PBYTE)this + nBucketSize;
}
};
struct CAllocation
{
size_t m_nDataSize;
LONG m_nRefCount;
BYTE m_Data[ANYSIZE_ARRAY];
};
private:
static size_t AllocSize(int nDataSize)
{
return (nDataSize + FIELD_OFFSET(CAllocation, m_Data) + (ALIGNMENT-1)) & ~(ALIGNMENT-1);
}
bool AllocNewBucket()
{
CBucket *pBucket = (CBucket *) VirtualAlloc(
0,
nBucketSize,
MEM_COMMIT,
PAGE_READWRITE
);
if (pBucket)
{
pBucket->m_pNextBucket = m_pBucket;
m_pBucket = pBucket;
m_pNextFree = pBucket->m_Data;
return true;
}
return false;
}
void FreeBucket(CBucket *pThisBucket)
{
CBucket **ppBucket = &m_pBucket;
ASSERT(*ppBucket != 0);
while (*ppBucket != pThisBucket)
{
ppBucket = &((*ppBucket)->m_pNextBucket);
ASSERT(*ppBucket != 0);
}
*ppBucket = pThisBucket->m_pNextBucket;
VirtualFree(pThisBucket, 0, MEM_RELEASE);
}
void FreeAllBuckets()
{
CBucket *pBucket = m_pBucket;
while (pBucket)
{
CBucket *pThisBucket = pBucket;
pBucket = pBucket->m_pNextBucket;
VirtualFree(pThisBucket, 0, MEM_RELEASE);
}
m_pBucket = 0;
m_pNextFree = 0;
}
private:
CRITICAL_SECTION m_cs;
CBucket *m_pBucket;
PBYTE m_pNextFree;
};
//////////////////////////////////////////////////////////////////////////
//
//
//
extern CMyHeap<> g_MyHeap;
//////////////////////////////////////////////////////////////////////////
//
//
//
template <class T>
class CMyAlloc //: public allocator<T>
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
typedef T value_type;
pointer allocate(size_type N, const void *)
{
return (pointer) g_MyHeap.allocate(N);
}
char *_Charalloc(size_type N)
{
return (char *) g_MyHeap.allocate(N);
}
void deallocate(void *P, size_type)
{
g_MyHeap.deallocate(P);
}
size_type max_size() const
{
return g_MyHeap.max_size();
}
};
template<class T, class U>
inline bool operator ==(const CMyAlloc<T>&, const CMyAlloc<U>&)
{
return true;
}
template<class T, class U>
inline bool operator !=(const CMyAlloc<T>&, const CMyAlloc<U>&)
{
return false;
}
//////////////////////////////////////////////////////////////////////////
//
//
//
class CMyStr
{
public:
CMyStr()
{
m_pStr = 0;
}
~CMyStr()
{
g_MyHeap.deallocate(m_pStr);
}
explicit CMyStr(int nLength)
{
m_pStr = (PTSTR) g_MyHeap.allocate(nLength * sizeof(TCHAR));
m_pStr[0] = _T('\0');
}
CMyStr(PCTSTR pStr)
{
DupStr(pStr);
}
CMyStr(const CMyStr &rhs)
{
g_MyHeap.AddRef(rhs.m_pStr);
m_pStr = rhs.m_pStr;
}
CMyStr &operator =(PCTSTR pStr)
{
g_MyHeap.deallocate(m_pStr);
DupStr(pStr);
return *this;
}
CMyStr &operator =(const CMyStr &rhs)
{
g_MyHeap.AddRef(rhs.m_pStr);
g_MyHeap.deallocate(m_pStr);
m_pStr = rhs.m_pStr;
return *this;
}
operator PTSTR()
{
return m_pStr;
}
operator PCTSTR() const
{
return m_pStr;
}
private:
void DupStr(PCTSTR pStr)
{
if (!pStr)
{
pStr = _T("");
}
m_pStr = (PTSTR) g_MyHeap.allocate((_tcslen(pStr) + 1) * sizeof(TCHAR));
if (m_pStr)
{
_tcscpy(m_pStr, pStr);
}
}
private:
PTSTR m_pStr;
};
#endif //MYHEAP_H