#ifndef ___VMEM_H_INC___
#define ___VMEM_H_INC___
#define _USE_MSVCRT_MEM_ALLOC
#define _USE_LINKED_LIST
#ifdef _DEBUG_MEM
#define ASSERT(f) if(!(f)) DebugBreak();
inline
void
MEMODS(
char
*str)
{
OutputDebugString(str);
OutputDebugString(
"\n"
);
}
inline
void
MEMODSlx(
char
*str,
long
x)
{
char
szBuffer[512];
sprintf
(szBuffer,
"%s %lx\n"
, str, x);
OutputDebugString(szBuffer);
}
#define WALKHEAP() WalkHeap(0)
#define WALKHEAPTRACE() WalkHeap(1)
#else
#define ASSERT(f)
#define MEMODS(x)
#define MEMODSlx(x, y)
#define WALKHEAP()
#define WALKHEAPTRACE()
#endif
#ifdef _USE_MSVCRT_MEM_ALLOC
#ifndef _USE_LINKED_LIST
#endif
#ifdef _USE_LINKED_LIST
class
VMem;
typedef
struct
_MemoryBlockHeader* PMEMORY_BLOCK_HEADER;
typedef
struct
_MemoryBlockHeader {
PMEMORY_BLOCK_HEADER pNext;
PMEMORY_BLOCK_HEADER pPrev;
VMem *owner;
} MEMORY_BLOCK_HEADER, *PMEMORY_BLOCK_HEADER;
#endif
class
VMem
{
public
:
VMem();
~VMem();
void
* Malloc(
size_t
size);
void
* Realloc(
void
* pMem,
size_t
size);
void
Free(
void
* pMem);
void
GetLock(
void
);
void
FreeLock(
void
);
int
IsLocked(
void
);
long
Release(
void
);
long
AddRef(
void
);
inline
BOOL
CreateOk(
void
)
{
return
TRUE;
};
protected
:
#ifdef _USE_LINKED_LIST
void
LinkBlock(PMEMORY_BLOCK_HEADER ptr)
{
PMEMORY_BLOCK_HEADER next = m_Dummy.pNext;
m_Dummy.pNext = ptr;
ptr->pPrev = &m_Dummy;
ptr->pNext = next;
ptr->owner =
this
;
next->pPrev = ptr;
}
void
UnlinkBlock(PMEMORY_BLOCK_HEADER ptr)
{
PMEMORY_BLOCK_HEADER next = ptr->pNext;
PMEMORY_BLOCK_HEADER prev = ptr->pPrev;
prev->pNext = next;
next->pPrev = prev;
}
MEMORY_BLOCK_HEADER m_Dummy;
CRITICAL_SECTION m_cs;
#endif
long
m_lRefCount;
};
VMem::VMem()
{
m_lRefCount = 1;
#ifdef _USE_LINKED_LIST
InitializeCriticalSection(&m_cs);
m_Dummy.pNext = m_Dummy.pPrev = &m_Dummy;
m_Dummy.owner =
this
;
#endif
}
VMem::~VMem(
void
)
{
#ifdef _USE_LINKED_LIST
while
(m_Dummy.pNext != &m_Dummy) {
Free(m_Dummy.pNext+1);
}
DeleteCriticalSection(&m_cs);
#endif
}
void
* VMem::Malloc(
size_t
size)
{
#ifdef _USE_LINKED_LIST
GetLock();
PMEMORY_BLOCK_HEADER ptr = (PMEMORY_BLOCK_HEADER)
malloc
(size+
sizeof
(MEMORY_BLOCK_HEADER));
if
(!ptr) {
FreeLock();
return
NULL;
}
LinkBlock(ptr);
FreeLock();
return
(ptr+1);
#else
return
malloc
(size);
#endif
}
void
* VMem::Realloc(
void
* pMem,
size_t
size)
{
#ifdef _USE_LINKED_LIST
if
(!pMem)
return
Malloc(size);
if
(!size) {
Free(pMem);
return
NULL;
}
GetLock();
PMEMORY_BLOCK_HEADER ptr = (PMEMORY_BLOCK_HEADER)(((
char
*)pMem)-
sizeof
(MEMORY_BLOCK_HEADER));
UnlinkBlock(ptr);
ptr = (PMEMORY_BLOCK_HEADER)
realloc
(ptr, size+
sizeof
(MEMORY_BLOCK_HEADER));
if
(!ptr) {
FreeLock();
return
NULL;
}
LinkBlock(ptr);
FreeLock();
return
(ptr+1);
#else
return
realloc
(pMem, size);
#endif
}
void
VMem::Free(
void
* pMem)
{
#ifdef _USE_LINKED_LIST
if
(pMem) {
PMEMORY_BLOCK_HEADER ptr = (PMEMORY_BLOCK_HEADER)(((
char
*)pMem)-
sizeof
(MEMORY_BLOCK_HEADER));
if
(ptr->owner !=
this
) {
if
(ptr->owner) {
#if 1
int
*nowhere = NULL;
Perl_warn_nocontext(
"Free to wrong pool %p not %p"
,
this
,ptr->owner);
*nowhere = 0;
#else
ptr->owner->Free(pMem);
#endif
}
return
;
}
GetLock();
UnlinkBlock(ptr);
ptr->owner = NULL;
free
(ptr);
FreeLock();
}
#else /*_USE_LINKED_LIST*/
free
(pMem);
#endif
}
void
VMem::GetLock(
void
)
{
#ifdef _USE_LINKED_LIST
EnterCriticalSection(&m_cs);
#endif
}
void
VMem::FreeLock(
void
)
{
#ifdef _USE_LINKED_LIST
LeaveCriticalSection(&m_cs);
#endif
}
int
VMem::IsLocked(
void
)
{
#if 0
BOOL
bAccessed = TryEnterCriticalSection(&m_cs);
if
(bAccessed) {
LeaveCriticalSection(&m_cs);
}
return
!bAccessed;
#else
ASSERT(0);
return
0;
#endif
}
long
VMem::Release(
void
)
{
long
lCount = InterlockedDecrement(&m_lRefCount);
if
(!lCount)
delete
this
;
return
lCount;
}
long
VMem::AddRef(
void
)
{
long
lCount = InterlockedIncrement(&m_lRefCount);
return
lCount;
}
#else /* _USE_MSVCRT_MEM_ALLOC */
const
long
lAllocStart = 0x00020000;
const
long
minBlockSize =
sizeof
(
void
*)*2;
const
long
sizeofTag =
sizeof
(
long
);
const
long
blockOverhead = sizeofTag*2;
const
long
minAllocSize = minBlockSize+blockOverhead;
#ifdef _USE_BUDDY_BLOCKS
const
long
lSmallBlockSize = 1024;
const
size_t
nListEntries = ((lSmallBlockSize-minAllocSize)/
sizeof
(
long
));
inline
size_t
CalcEntry(
size_t
size)
{
ASSERT((size&(
sizeof
(
long
)-1)) == 0);
return
((size - minAllocSize) /
sizeof
(
long
));
}
#endif
typedef
BYTE
* PBLOCK;
#define SIZE(block) (*(ULONG*)(((PBLOCK)(block))-sizeofTag))
#define PSIZE(block) (*(ULONG*)(((PBLOCK)(block))-(blockOverhead)))
inline
void
SetTags(PBLOCK block,
long
size)
{
SIZE(block) = size;
PSIZE(block+(size&~1)) = size;
}
#define PREV(block) (*(PBLOCK*)(block))
#define NEXT(block) (*(PBLOCK*)((block)+sizeof(PBLOCK)))
inline
void
SetLink(PBLOCK block, PBLOCK prev, PBLOCK next)
{
PREV(block) = prev;
NEXT(block) = next;
}
inline
void
Unlink(PBLOCK p)
{
PBLOCK next = NEXT(p);
PBLOCK prev = PREV(p);
NEXT(prev) = next;
PREV(next) = prev;
}
#ifndef _USE_BUDDY_BLOCKS
inline
void
AddToFreeList(PBLOCK block, PBLOCK pInList)
{
PBLOCK next = NEXT(pInList);
NEXT(pInList) = block;
SetLink(block, pInList, next);
PREV(next) = block;
}
#endif
#define ROUND_UP(n) (((ULONG)(n)+sizeof(long)-1)&~(sizeof(long)-1))
#define ROUND_UP64K(n) (((ULONG)(n)+0x10000-1)&~(0x10000-1))
#define ROUND_DOWN(n) ((ULONG)(n)&~(sizeof(long)-1))
const
int
maxHeaps = 32;
const
long
lAllocMax = 0x80000000;
#ifdef _USE_BUDDY_BLOCKS
typedef
struct
_FreeListEntry
{
BYTE
Dummy[minAllocSize];
} FREE_LIST_ENTRY, *PFREE_LIST_ENTRY;
#endif
#ifndef _USE_BUDDY_BLOCKS
#define USE_BIGBLOCK_ALLOC
#endif
#ifdef USE_BIGBLOCK_ALLOC
const
int
nMaxHeapAllocSize = (1024*512);
#endif
typedef
struct
_HeapRec
{
PBLOCK base;
ULONG
len;
#ifdef USE_BIGBLOCK_ALLOC
BOOL
bBigBlock;
#endif
} HeapRec;
class
VMem
{
public
:
VMem();
~VMem();
void
* Malloc(
size_t
size);
void
* Realloc(
void
* pMem,
size_t
size);
void
Free(
void
* pMem);
void
GetLock(
void
);
void
FreeLock(
void
);
int
IsLocked(
void
);
long
Release(
void
);
long
AddRef(
void
);
inline
BOOL
CreateOk(
void
)
{
#ifdef _USE_BUDDY_BLOCKS
return
TRUE;
#else
return
m_hHeap != NULL;
#endif
};
void
ReInit(
void
);
protected
:
void
Init(
void
);
int
Getmem(
size_t
size);
int
HeapAdd(
void
* ptr,
size_t
size
#ifdef USE_BIGBLOCK_ALLOC
,
BOOL
bBigBlock
#endif
);
void
* Expand(
void
* block,
size_t
size);
#ifdef _USE_BUDDY_BLOCKS
inline
PBLOCK GetFreeListLink(
int
index)
{
if
(index >= nListEntries)
index = nListEntries-1;
return
&m_FreeList[index].Dummy[sizeofTag];
}
inline
PBLOCK GetOverSizeFreeList(
void
)
{
return
&m_FreeList[nListEntries-1].Dummy[sizeofTag];
}
inline
PBLOCK GetEOLFreeList(
void
)
{
return
&m_FreeList[nListEntries].Dummy[sizeofTag];
}
void
AddToFreeList(PBLOCK block,
size_t
size)
{
PBLOCK pFreeList = GetFreeListLink(CalcEntry(size));
PBLOCK next = NEXT(pFreeList);
NEXT(pFreeList) = block;
SetLink(block, pFreeList, next);
PREV(next) = block;
}
#endif
inline
size_t
CalcAllocSize(
size_t
size)
{
return
(size < minBlockSize) ? minAllocSize : (
size_t
)ROUND_UP(size) + blockOverhead;
}
#ifdef _USE_BUDDY_BLOCKS
FREE_LIST_ENTRY m_FreeList[nListEntries+1];
#else
HANDLE
m_hHeap;
char
m_FreeDummy[minAllocSize];
PBLOCK m_pFreeList;
#endif
PBLOCK m_pRover;
HeapRec m_heaps[maxHeaps];
int
m_nHeaps;
long
m_lAllocSize;
long
m_lRefCount;
CRITICAL_SECTION m_cs;
#ifdef _DEBUG_MEM
void
WalkHeap(
int
complete);
void
MemoryUsageMessage(
char
*str,
long
x,
long
y,
int
c);
FILE
* m_pLog;
#endif
};
VMem::VMem()
{
m_lRefCount = 1;
#ifndef _USE_BUDDY_BLOCKS
BOOL
bRet = (NULL != (m_hHeap = HeapCreate(HEAP_NO_SERIALIZE,
lAllocStart,
0)));
ASSERT(bRet);
#endif
InitializeCriticalSection(&m_cs);
#ifdef _DEBUG_MEM
m_pLog = 0;
#endif
Init();
}
VMem::~VMem(
void
)
{
#ifndef _USE_BUDDY_BLOCKS
ASSERT(HeapValidate(m_hHeap, HEAP_NO_SERIALIZE, NULL));
#endif
WALKHEAPTRACE();
DeleteCriticalSection(&m_cs);
#ifdef _USE_BUDDY_BLOCKS
for
(
int
index = 0; index < m_nHeaps; ++index) {
VirtualFree(m_heaps[index].base, 0, MEM_RELEASE);
}
#else /* !_USE_BUDDY_BLOCKS */
#ifdef USE_BIGBLOCK_ALLOC
for
(
int
index = 0; index < m_nHeaps; ++index) {
if
(m_heaps[index].bBigBlock) {
VirtualFree(m_heaps[index].base, 0, MEM_RELEASE);
}
}
#endif
BOOL
bRet = HeapDestroy(m_hHeap);
ASSERT(bRet);
#endif /* _USE_BUDDY_BLOCKS */
}
void
VMem::ReInit(
void
)
{
for
(
int
index = 0; index < m_nHeaps; ++index) {
#ifdef _USE_BUDDY_BLOCKS
VirtualFree(m_heaps[index].base, 0, MEM_RELEASE);
#else
#ifdef USE_BIGBLOCK_ALLOC
if
(m_heaps[index].bBigBlock) {
VirtualFree(m_heaps[index].base, 0, MEM_RELEASE);
}
else
#endif
HeapFree(m_hHeap, HEAP_NO_SERIALIZE, m_heaps[index].base);
#endif /* _USE_BUDDY_BLOCKS */
}
Init();
}
void
VMem::Init(
void
)
{
#ifdef _USE_BUDDY_BLOCKS
PBLOCK pFreeList;
for
(
int
index = 0; index < nListEntries; ++index) {
pFreeList = GetFreeListLink(index);
SIZE(pFreeList) = PSIZE(pFreeList+minAllocSize) = 0;
PREV(pFreeList) = NEXT(pFreeList) = pFreeList;
}
pFreeList = GetEOLFreeList();
SIZE(pFreeList) = PSIZE(pFreeList+minAllocSize) = 0;
PREV(pFreeList) = NEXT(pFreeList) = NULL;
m_pRover = GetOverSizeFreeList();
#else
m_pFreeList = m_pRover = (PBLOCK)(&m_FreeDummy[sizeofTag]);
PSIZE(m_pFreeList+minAllocSize) = SIZE(m_pFreeList) = 0;
PREV(m_pFreeList) = NEXT(m_pFreeList) = m_pFreeList;
#endif
m_nHeaps = 0;
m_lAllocSize = lAllocStart;
}
void
* VMem::Malloc(
size_t
size)
{
WALKHEAP();
PBLOCK ptr;
size_t
lsize, rem;
size_t
realsize = CalcAllocSize(size);
if
((
int
)realsize < minAllocSize || size == 0)
return
NULL;
#ifdef _USE_BUDDY_BLOCKS
{
int
index = CalcEntry(realsize);
if
(index < nListEntries-1) {
ptr = GetFreeListLink(index);
lsize = SIZE(ptr);
if
(lsize >= realsize) {
rem = lsize - realsize;
if
(rem < minAllocSize) {
Unlink(ptr);
}
else
{
SetTags(ptr, rem);
ptr += SIZE(ptr);
lsize = realsize;
}
SetTags(ptr, lsize | 1);
return
ptr;
}
ptr = m_pRover;
lsize = SIZE(ptr);
if
(lsize >= realsize) {
rem = lsize - realsize;
if
(rem < minAllocSize) {
Unlink(ptr);
}
else
{
SetTags(ptr, rem);
ptr += SIZE(ptr);
lsize = realsize;
}
SetTags(ptr, lsize | 1);
return
ptr;
}
ptr = GetFreeListLink(index+1);
while
(NEXT(ptr)) {
lsize = SIZE(ptr);
if
(lsize >= realsize) {
size_t
rem = lsize - realsize;
if
(rem < minAllocSize) {
Unlink(ptr);
}
else
{
SetTags(ptr, rem);
ptr += SIZE(ptr);
lsize = realsize;
}
SetTags(ptr, lsize | 1);
return
ptr;
}
ptr +=
sizeof
(FREE_LIST_ENTRY);
}
}
}
#endif
ptr = m_pRover;
int
loops = 2;
for
(;;) {
lsize = SIZE(ptr);
ASSERT((lsize&1)==0);
if
(lsize >= realsize) {
rem = lsize - realsize;
if
(rem < minAllocSize) {
if
(m_pRover == ptr)
m_pRover = NEXT(ptr);
Unlink(ptr);
}
else
{
SetTags(ptr, rem);
ptr += SIZE(ptr);
lsize = realsize;
}
SetTags(ptr, lsize | 1);
return
((
void
*)ptr);
}
ptr = NEXT(ptr);
if
(ptr == m_pRover) {
if
(!(loops-- && Getmem(realsize))) {
return
NULL;
}
ptr = m_pRover;
}
}
}
void
* VMem::Realloc(
void
* block,
size_t
size)
{
WALKHEAP();
if
(size == 0) {
Free(block);
return
(NULL);
}
if
(block == NULL)
return
Malloc(size);
if
(Expand(block, size) != NULL)
return
block;
size_t
realsize = CalcAllocSize(size);
if
((
int
)realsize < minAllocSize)
return
NULL;
PBLOCK ptr = (PBLOCK)block;
size_t
cursize = SIZE(ptr) & ~1;
size_t
psize = PSIZE(ptr);
if
((psize&1) == 0 && (psize + cursize) >= realsize) {
PBLOCK prev = ptr - psize;
if
(m_pRover == prev)
m_pRover = NEXT(prev);
Unlink(prev);
memmove
(prev, ptr, cursize);
cursize += psize;
ptr = prev;
size_t
rem = cursize - realsize;
if
(rem >= minAllocSize) {
prev = ptr + realsize;
SetTags(prev, rem);
#ifdef _USE_BUDDY_BLOCKS
AddToFreeList(prev, rem);
#else
AddToFreeList(prev, m_pFreeList);
#endif
cursize = realsize;
}
SetTags(ptr, cursize | 1);
return
((
void
*)ptr);
}
if
((ptr = (PBLOCK)Malloc(size)) != NULL) {
memmove
(ptr, block, cursize-blockOverhead);
Free(block);
}
return
((
void
*)ptr);
}
void
VMem::Free(
void
* p)
{
WALKHEAP();
if
(p == NULL)
return
;
PBLOCK ptr = (PBLOCK)p;
size_t
size = SIZE(ptr);
if
((size&1) == 0) {
MEMODSlx(
"Attempt to free previously freed block"
, (
long
)p);
return
;
}
size &= ~1;
#ifndef _USE_BUDDY_BLOCKS
int
linked = FALSE;
#endif
size_t
psize = PSIZE(ptr);
if
((psize&1) == 0) {
ptr -= psize;
size += psize;
#ifdef _USE_BUDDY_BLOCKS
Unlink(ptr);
#else
linked = TRUE;
#endif
}
PBLOCK next = ptr + size;
size_t
nsize = SIZE(next);
if
((nsize&1) == 0) {
if
(m_pRover == next)
m_pRover = NEXT(next);
Unlink(next);
size += nsize;
}
SetTags(ptr, size);
#ifdef _USE_BUDDY_BLOCKS
AddToFreeList(ptr, size);
#else
if
(!linked) {
AddToFreeList(ptr, m_pFreeList);
}
#endif
}
void
VMem::GetLock(
void
)
{
EnterCriticalSection(&m_cs);
}
void
VMem::FreeLock(
void
)
{
LeaveCriticalSection(&m_cs);
}
int
VMem::IsLocked(
void
)
{
#if 0
BOOL
bAccessed = TryEnterCriticalSection(&m_cs);
if
(bAccessed) {
LeaveCriticalSection(&m_cs);
}
return
!bAccessed;
#else
ASSERT(0);
return
0;
#endif
}
long
VMem::Release(
void
)
{
long
lCount = InterlockedDecrement(&m_lRefCount);
if
(!lCount)
delete
this
;
return
lCount;
}
long
VMem::AddRef(
void
)
{
long
lCount = InterlockedIncrement(&m_lRefCount);
return
lCount;
}
int
VMem::Getmem(
size_t
requestSize)
{
#ifdef USE_BIGBLOCK_ALLOC
BOOL
bBigBlock;
#endif
void
*ptr;
size_t
size = (
size_t
)ROUND_UP64K(requestSize);
if
(size < (unsigned
long
)m_lAllocSize)
size = m_lAllocSize;
if
(m_lAllocSize != lAllocMax)
m_lAllocSize <<= 2;
#ifndef _USE_BUDDY_BLOCKS
if
(m_nHeaps != 0
#ifdef USE_BIGBLOCK_ALLOC
&& !m_heaps[m_nHeaps-1].bBigBlock
#endif
) {
ptr = HeapReAlloc(m_hHeap, HEAP_REALLOC_IN_PLACE_ONLY|HEAP_NO_SERIALIZE,
m_heaps[m_nHeaps-1].base,
m_heaps[m_nHeaps-1].len + size);
if
(ptr != 0) {
HeapAdd(((
char
*)ptr) + m_heaps[m_nHeaps-1].len, size
#ifdef USE_BIGBLOCK_ALLOC
, FALSE
#endif
);
return
-1;
}
}
#endif /* _USE_BUDDY_BLOCKS */
if
(size == requestSize)
size = (
size_t
)ROUND_UP64K(requestSize+(blockOverhead));
Restart:
#ifdef _USE_BUDDY_BLOCKS
ptr = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
#else
#ifdef USE_BIGBLOCK_ALLOC
bBigBlock = FALSE;
if
(size >= nMaxHeapAllocSize) {
bBigBlock = TRUE;
ptr = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
}
else
#endif
ptr = HeapAlloc(m_hHeap, HEAP_NO_SERIALIZE, size);
#endif /* _USE_BUDDY_BLOCKS */
if
(!ptr) {
size >>= 1;
if
(size > requestSize)
goto
Restart;
}
if
(ptr == 0) {
MEMODSlx(
"HeapAlloc failed on size!!!"
, size);
return
0;
}
#ifdef _USE_BUDDY_BLOCKS
if
(HeapAdd(ptr, size)) {
VirtualFree(ptr, 0, MEM_RELEASE);
return
0;
}
#else
#ifdef USE_BIGBLOCK_ALLOC
if
(HeapAdd(ptr, size, bBigBlock)) {
if
(bBigBlock) {
VirtualFree(ptr, 0, MEM_RELEASE);
}
}
#else
HeapAdd(ptr, size);
#endif
#endif /* _USE_BUDDY_BLOCKS */
return
-1;
}
int
VMem::HeapAdd(
void
* p,
size_t
size
#ifdef USE_BIGBLOCK_ALLOC
,
BOOL
bBigBlock
#endif
)
{
int
index;
if
(size < minAllocSize)
return
-1;
size = (
size_t
)ROUND_DOWN(size);
PBLOCK ptr = (PBLOCK)p;
#ifdef USE_BIGBLOCK_ALLOC
if
(!bBigBlock) {
#endif
for
(index = 0; index < m_nHeaps; ++index) {
if
(ptr == m_heaps[index].base + (
int
)m_heaps[index].len) {
m_heaps[index].len += size;
break
;
}
}
#ifdef USE_BIGBLOCK_ALLOC
}
else
{
index = m_nHeaps;
}
#endif
if
(index == m_nHeaps) {
if
(m_nHeaps == maxHeaps) {
return
-1;
}
m_heaps[m_nHeaps].base = ptr;
m_heaps[m_nHeaps].len = size;
#ifdef USE_BIGBLOCK_ALLOC
m_heaps[m_nHeaps].bBigBlock = bBigBlock;
#endif
m_nHeaps++;
size -= blockOverhead;
ptr += blockOverhead;
PSIZE(ptr) = 1;
}
SetTags(ptr, size | 1);
PBLOCK next = ptr + size;
SIZE(next) = 1;
Free(ptr);
return
0;
}
void
* VMem::Expand(
void
* block,
size_t
size)
{
size_t
realsize = CalcAllocSize(size);
if
((
int
)realsize < minAllocSize || size == 0)
return
NULL;
PBLOCK ptr = (PBLOCK)block;
size_t
cursize = SIZE(ptr) & ~1;
if
(cursize == realsize) {
return
block;
}
if
(realsize <= cursize) {
size_t
nextsize = cursize - realsize;
if
(nextsize >= minAllocSize) {
SetTags(ptr, realsize | 1);
ptr += realsize;
SetTags(ptr, nextsize | 1);
Free(ptr);
}
return
block;
}
PBLOCK next = ptr + cursize;
size_t
nextsize = SIZE(next);
if
((nextsize&1) == 0 && (nextsize + cursize) >= realsize) {
if
(m_pRover == next)
m_pRover = NEXT(next);
Unlink(next);
cursize += nextsize;
size_t
rem = cursize - realsize;
if
(rem >= minAllocSize) {
next = ptr + realsize;
SetTags(next, rem);
#ifdef _USE_BUDDY_BLOCKS
AddToFreeList(next, rem);
#else
AddToFreeList(next, m_pFreeList);
#endif
cursize = realsize;
}
SetTags(ptr, cursize | 1);
return
((
void
*)ptr);
}
return
NULL;
}
#ifdef _DEBUG_MEM
#define LOG_FILENAME ".\\MemLog.txt"
void
VMem::MemoryUsageMessage(
char
*str,
long
x,
long
y,
int
c)
{
char
szBuffer[512];
if
(str) {
if
(!m_pLog)
m_pLog =
fopen
(LOG_FILENAME,
"w"
);
sprintf
(szBuffer, str, x, y, c);
fputs
(szBuffer, m_pLog);
}
else
{
if
(m_pLog) {
fflush
(m_pLog);
fclose
(m_pLog);
m_pLog = 0;
}
}
}
void
VMem::WalkHeap(
int
complete)
{
if
(complete) {
MemoryUsageMessage(NULL, 0, 0, 0);
size_t
total = 0;
for
(
int
i = 0; i < m_nHeaps; ++i) {
total += m_heaps[i].len;
}
MemoryUsageMessage(
"VMem heaps used %d. Total memory %08x\n"
, m_nHeaps, total, 0);
for
(
int
index = 0; index < m_nHeaps; ++index) {
PBLOCK ptr = m_heaps[index].base;
size_t
size = m_heaps[index].len;
#ifndef _USE_BUDDY_BLOCKS
#ifdef USE_BIGBLOCK_ALLOC
if
(!m_heaps[m_nHeaps].bBigBlock)
#endif
ASSERT(HeapValidate(m_hHeap, HEAP_NO_SERIALIZE, ptr));
#endif
size -= blockOverhead;
ptr += blockOverhead;
PBLOCK pLast = ptr + size;
ASSERT(PSIZE(ptr) == 1);
ASSERT(SIZE(pLast) == 1);
while
(ptr < pLast) {
ASSERT(ptr > m_heaps[index].base);
size_t
cursize = SIZE(ptr) & ~1;
ASSERT((PSIZE(ptr+cursize) & ~1) == cursize);
MemoryUsageMessage(
"Memory Block %08x: Size %08x %c\n"
, (
long
)ptr, cursize, (SIZE(ptr)&1) ?
'x'
:
' '
);
if
(!(SIZE(ptr)&1)) {
PBLOCK tmp = NEXT(ptr);
while
(tmp != ptr) {
ASSERT((SIZE(tmp)&1)==0);
if
(tmp == m_pFreeList)
break
;
ASSERT(NEXT(tmp));
tmp = NEXT(tmp);
}
if
(tmp == ptr) {
MemoryUsageMessage(
"Memory Block %08x: Size %08x free but not in free list\n"
, (
long
)ptr, cursize, 0);
}
}
ptr += cursize;
}
}
MemoryUsageMessage(NULL, 0, 0, 0);
}
}
#endif /* _DEBUG_MEM */
#endif /* _USE_MSVCRT_MEM_ALLOC */
#endif /* ___VMEM_H_INC___ */