|
|
/***
*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
|