Windows-Server-2003/base/crts/crtw32/rtc/chsyheap.cpp

237 lines
6.8 KiB
C++

/***
*chsyheap.cpp - RTC support
*
* Copyright (c) 1998-2001, Microsoft Corporation. All rights reserved.
*
*
*Revision History:
* 07-28-98 JWM Module incorporated into CRTs (from KFrei)
* 05-11-99 KBF Error if RTC support define not enabled
* 05-25-99 KBF Renamed - _RTC_SimpleHeap instead of CheesyHeap
* 05-26-99 KBF Removed RTCl and RTCv, added _RTC_ADVMEM stuff
*
****/
#ifndef _RTC
#error RunTime Check support not enabled!
#endif
#include "rtcpriv.h"
#ifdef _RTC_ADVMEM
// This is my 'Cheesy Heap' implementation...
/* Here are the sizes that I need:
BinaryNode 3 DWORDS - use heap4
BinaryTree 1 DWORD - use heap2
Container 2 DWORDS - use heap2
BreakPoint 2 DWORDS - use heap2
HashTable<HeapBlock> 2 DWORDS - use heap2
HeapBlock 6 DWORDS - use heap8
Container[] - short term...
CallSite[] - permanent
HeapBlock[] - permanent
*/
_RTC_SimpleHeap *_RTC_heap2 = 0;
_RTC_SimpleHeap *_RTC_heap4 = 0;
_RTC_SimpleHeap *_RTC_heap8 = 0;
void *
_RTC_SimpleHeap::operator new(unsigned) throw()
{
void *res = VirtualAlloc(NULL, ALLOC_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#ifdef _RTC_SHADOW
if (shadow)
_RTC_MSCommitRange((memptr)res, ALLOC_SIZE, IDX_STATE_ILLEGAL);
#endif
return res;
}
void
_RTC_SimpleHeap::operator delete(void *addr) throw()
{
VirtualFree(addr, 0, MEM_RELEASE);
#ifdef _RTC_SHADOW
if (shadow)
_RTC_MSDecommitRange((memptr)addr, ALLOC_SIZE);
#endif
}
_RTC_SimpleHeap::_RTC_SimpleHeap(unsigned blockSize) throw()
{
// Flag it as the only item in the heap
head.next = 0;
head.inf.top.nxtFree = 0;
// Align the block size
head.inf.top.wordSize = 8;
blockSize = (blockSize - 1) >> 3;
while (blockSize) {
blockSize >>= 1;
head.inf.top.wordSize <<= 1;
}
// Build up the free-list
head.free = (FreeList*)(((unsigned)&head) +
((head.inf.top.wordSize < sizeof(HeapNode)) ?
sizeof(HeapNode) :
head.inf.top.wordSize));
FreeList *t = head.free;
while (((unsigned)t) + head.inf.top.wordSize < ((unsigned)&head) + ALLOC_SIZE)
{
t->next = (FreeList*)(((unsigned)t) + head.inf.top.wordSize);
t = t->next;
}
t->next = 0;
}
_RTC_SimpleHeap::~_RTC_SimpleHeap() throw()
{
// Free all sections that we have allocated
HeapNode *n, *c = head.next;
while(c) {
n = c->next;
_RTC_SimpleHeap::operator delete(c);
c = n;
}
// the 'head' page will be handled by delete
}
void *
_RTC_SimpleHeap::alloc() throw()
{
void *res;
// If there's a free item, remove it from the list
// And decrement the free count for it's parent page
if (head.free)
{
// There's a free block on the first page
res = head.free;
head.free = head.free->next;
// Since it's on the top page, there's no free-count to update,
// And it ain't on no stinkin' free-list
} else if (head.inf.top.nxtFree)
{
// There's a free block on some page
HeapNode *n = head.inf.top.nxtFree;
res = n->free;
n->free = n->free->next;
n->inf.nontop.freeCount--;
if (!n->free)
{
// This page is now full, so it must be removed from the freelist
for (n = head.next; n && !n->free; n = n->next) {}
// Now the nxtFree pointer is either null (indicating a full heap)
// or it's pointing to a page that has free nodes
head.inf.top.nxtFree = n;
}
} else
{
// No pages have any free blocks
// Get a new page, and add it to the list
HeapNode *n = (HeapNode *)_RTC_SimpleHeap::operator new(0);
// Count the number of free nodes
n->inf.nontop.freeCount =
(ALLOC_SIZE - sizeof(HeapNode)) / head.inf.top.wordSize - 1;
res = (void *)(((unsigned)n) +
((head.inf.top.wordSize < sizeof(HeapNode)) ?
sizeof(HeapNode) :
head.inf.top.wordSize));
// Build the free-list for this node
FreeList *f;
for (f = n->free = (FreeList*)(((unsigned)res) + head.inf.top.wordSize);
((unsigned)f) + head.inf.top.wordSize < ((unsigned)n) + ALLOC_SIZE;
f = f->next)
f->next = (FreeList*)(((unsigned)f) + head.inf.top.wordSize);
f->next = 0;
// Stick it in the page list
n->next = head.next;
n->inf.nontop.prev = &head;
head.next = n;
// Flag this as a page with free stuff on it...
head.inf.top.nxtFree = n;
}
return res;
}
void
_RTC_SimpleHeap::free(void *addr) throw()
{
// Get the heap node for this address
HeapNode *n = (HeapNode *)(((unsigned)addr) & ~(ALLOC_SIZE - 1));
// Stick this sucker back in the free list
FreeList *f = (FreeList *)addr;
f->next = n->free;
n->free = f;
if (n == &head)
// If this is in the head node, just return...
return;
if (++n->inf.nontop.freeCount ==
(ALLOC_SIZE - sizeof(HeapNode)) / head.inf.top.wordSize)
{
// This page is free
if (head.inf.top.freePage)
{
// There's already another free page, go ahead and free this one
// (there's always a previous node)
n->inf.nontop.prev->next = n->next;
if (n->next)
n->next->inf.nontop.prev = n->inf.nontop.prev;
_RTC_SimpleHeap::operator delete(n);
if (head.inf.top.nxtFree == n)
{
// This was the free page
// find a page with some free nodes on it...
for (n = head.next; !n->free; n = n->next) {}
// ASSERT(n)
// If n is null, we're in some serious trouble...
head.inf.top.nxtFree = n;
}
// If it wasn't the free page, we're just fine...
} else
{
// flag the freePages to say we have a 100% free page
head.inf.top.freePage = true;
if (head.inf.top.nxtFree == n)
{
// If this is the free page,
// try to find another page with some free nodes
HeapNode *t;
for (t = head.next; t && (!t->free || t == n) ; t = t->next) {}
// if there was a different page with some nodes, pick it
head.inf.top.nxtFree = t ? t : n;
}
}
} else
// This page isn't empty, so just set it as the next free
head.inf.top.nxtFree = n;
}
#endif // _RTC_ADVMEM