367 lines
7.7 KiB
C
367 lines
7.7 KiB
C
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// This thing is COMPLETELY single-threaded.
|
|
// Use no serialize to speed things up.
|
|
//
|
|
|
|
HANDLE Heap;
|
|
|
|
//
|
|
// Define structure used to track preallocations.
|
|
//
|
|
typedef struct _PREALLOC {
|
|
|
|
DWORD BlockSize;
|
|
DWORD BlockCount;
|
|
|
|
PVOID BaseAddress;
|
|
PVOID EndAddress;
|
|
|
|
LONG FreeIndex;
|
|
|
|
PVOID bitmap;
|
|
RTL_BITMAP Bitmap;
|
|
|
|
//
|
|
// Just for statistics
|
|
//
|
|
DWORD NumUsed;
|
|
|
|
} PREALLOC, *PPREALLOC;
|
|
|
|
PREALLOC Prealloc[] = { { 32,1000 },
|
|
{ 128,1000 },
|
|
{ 512,20 },
|
|
{ 4096,30 },
|
|
{ 8192,10 },
|
|
{ 16384 , 5 },
|
|
{ 0 }
|
|
};
|
|
|
|
|
|
PVOID
|
|
pAllocPreAlloc(
|
|
IN OUT PPREALLOC Prealloc
|
|
);
|
|
|
|
VOID
|
|
pFreePreAlloc(
|
|
IN OUT PPREALLOC Prealloc,
|
|
IN PVOID p
|
|
);
|
|
|
|
|
|
|
|
BOOL
|
|
SInit(
|
|
IN BOOL Init
|
|
)
|
|
{
|
|
BOOL b;
|
|
unsigned u;
|
|
PPREALLOC p;
|
|
|
|
if(Init) {
|
|
if(Heap) {
|
|
b = TRUE;
|
|
} else {
|
|
if(Heap = HeapCreate(HEAP_NO_SERIALIZE,512*1024,0)) {
|
|
|
|
b = TRUE;
|
|
for(u=0; b && Prealloc[u].BlockSize; u++) {
|
|
|
|
p = &Prealloc[u];
|
|
|
|
p->BaseAddress = HeapAlloc(Heap,0,p->BlockSize*p->BlockCount);
|
|
if(p->BaseAddress) {
|
|
|
|
p->EndAddress = (PUCHAR)p->BaseAddress + (p->BlockSize*p->BlockCount);
|
|
|
|
p->FreeIndex = 0;
|
|
|
|
p->bitmap = HeapAlloc(Heap,HEAP_ZERO_MEMORY,(p->BlockCount+7) / 8);
|
|
if(p->bitmap) {
|
|
RtlInitializeBitMap(&p->Bitmap,p->bitmap,p->BlockCount);
|
|
} else {
|
|
b = FALSE;
|
|
}
|
|
} else {
|
|
b = FALSE;
|
|
}
|
|
}
|
|
} else {
|
|
b = FALSE;
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// If heap is null this will return FALSE which is what we want.
|
|
//
|
|
b = HeapDestroy(Heap);
|
|
Heap = NULL;
|
|
}
|
|
|
|
return(b);
|
|
}
|
|
|
|
|
|
|
|
PVOID
|
|
SAlloc(
|
|
IN DWORD Size
|
|
)
|
|
{
|
|
PVOID p;
|
|
PPREALLOC prealloc;
|
|
|
|
if(!Heap) {
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// Determine which block size to use.
|
|
//
|
|
for(prealloc=Prealloc; prealloc->BlockSize; prealloc++) {
|
|
|
|
if(Size < prealloc->BlockSize) {
|
|
|
|
//
|
|
// Found the right size block.
|
|
//
|
|
p = pAllocPreAlloc(prealloc);
|
|
if(!p) {
|
|
//
|
|
// None available. Go to the heap.
|
|
//
|
|
break;
|
|
}
|
|
|
|
return(p);
|
|
}
|
|
}
|
|
|
|
//
|
|
// No preallocated block will suffice. Go to the heap.
|
|
//
|
|
return(HeapAlloc(Heap,HEAP_NO_SERIALIZE,(DWORD)Size));
|
|
}
|
|
|
|
|
|
VOID
|
|
SFree(
|
|
IN PVOID Block
|
|
)
|
|
{
|
|
PPREALLOC prealloc;
|
|
|
|
if(!Heap) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// See whether the block comes from our prealloced memory.
|
|
//
|
|
for(prealloc=Prealloc; prealloc->BlockSize; prealloc++) {
|
|
|
|
if((Block >= prealloc->BaseAddress) && (Block < prealloc->EndAddress)) {
|
|
|
|
pFreePreAlloc(prealloc,Block);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Not a preallocated block. Go to the heap.
|
|
//
|
|
HeapFree(Heap,HEAP_NO_SERIALIZE,Block);
|
|
}
|
|
|
|
|
|
PVOID
|
|
SRealloc(
|
|
IN PVOID Block,
|
|
IN DWORD NewSize
|
|
)
|
|
{
|
|
SIZE_T u;
|
|
PVOID p;
|
|
BOOL b;
|
|
PPREALLOC NewPrealloc,OldPrealloc;
|
|
|
|
if(!Heap) {
|
|
return(NULL);
|
|
}
|
|
|
|
NewPrealloc = NULL;
|
|
OldPrealloc = NULL;
|
|
b = FALSE;
|
|
|
|
for(u=0; Prealloc[u].BlockSize; u++) {
|
|
|
|
//
|
|
// See whether the original block comes from this prealloc.
|
|
//
|
|
if((OldPrealloc == NULL)
|
|
&& (Block >= Prealloc[u].BaseAddress)
|
|
&& (Block < Prealloc[u].EndAddress)) {
|
|
|
|
OldPrealloc = &Prealloc[u];
|
|
}
|
|
|
|
//
|
|
// See whether we have a prealloc block appropriate
|
|
// to satisfy the request. Only the smallest appropriate
|
|
// size is allowed.
|
|
//
|
|
if(!b && (NewSize < Prealloc[u].BlockSize)) {
|
|
|
|
//
|
|
// Special case: the old block is from prealloc memory
|
|
// and the same size prealloc block would satisfy the request.
|
|
// Just reuse the existing block.
|
|
//
|
|
if(OldPrealloc == &Prealloc[u]) {
|
|
return(Block);
|
|
}
|
|
|
|
if(Prealloc[u].FreeIndex != -1) {
|
|
NewPrealloc = &Prealloc[u];
|
|
}
|
|
b = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if the current block is from prealloc memory and we can
|
|
// satisfy the request from a different prealloc block size.
|
|
//
|
|
if(OldPrealloc && NewPrealloc) {
|
|
|
|
p = pAllocPreAlloc(NewPrealloc);
|
|
if(!p) {
|
|
//
|
|
// Something is very wrong, because NewPrealloc can be set
|
|
// only if there was a free block!
|
|
//
|
|
return(NULL);
|
|
}
|
|
|
|
CopyMemory(p,Block,__min(NewPrealloc->BlockSize,OldPrealloc->BlockSize));
|
|
|
|
pFreePreAlloc(OldPrealloc,Block);
|
|
return(p);
|
|
}
|
|
|
|
//
|
|
// If the current block is from prealloc memory but we can't
|
|
// satisfy the request from prealloc memory, allocate memory from
|
|
// the heap.
|
|
//
|
|
if(OldPrealloc && !NewPrealloc) {
|
|
|
|
if(p = HeapAlloc(Heap,HEAP_NO_SERIALIZE,NewSize)) {
|
|
|
|
CopyMemory(p,Block,__min(OldPrealloc->BlockSize,NewSize));
|
|
pFreePreAlloc(OldPrealloc,Block);
|
|
}
|
|
|
|
return(p);
|
|
}
|
|
|
|
//
|
|
// If the current block is not from prealloc memory and we can
|
|
// satisy the request from prealloc memory, copy the current memory
|
|
// into the prealloc block and return the prealloc block.
|
|
//
|
|
if(!OldPrealloc && NewPrealloc) {
|
|
|
|
u = HeapSize(Heap,HEAP_NO_SERIALIZE,Block);
|
|
if(u == (SIZE_T)(-1)) {
|
|
return(NULL);
|
|
}
|
|
|
|
p = pAllocPreAlloc(NewPrealloc);
|
|
if(!p) {
|
|
//
|
|
// Something is very wrong, because NewPrealloc can be set
|
|
// only if there was a free block!
|
|
//
|
|
return(NULL);
|
|
}
|
|
|
|
CopyMemory(p,Block,__min(u,NewPrealloc->BlockSize));
|
|
|
|
HeapFree(Heap,HEAP_NO_SERIALIZE,Block);
|
|
return(p);
|
|
}
|
|
|
|
//
|
|
// The current block is not from prealloc memory and there's no
|
|
// preallocated memory to satisfy the request. Pass the request
|
|
// to the heap.
|
|
//
|
|
return(HeapReAlloc(Heap,HEAP_NO_SERIALIZE,Block,NewSize));
|
|
}
|
|
|
|
|
|
PVOID
|
|
pAllocPreAlloc(
|
|
IN OUT PPREALLOC Prealloc
|
|
)
|
|
{
|
|
PVOID p;
|
|
|
|
if(Prealloc->FreeIndex == -1) {
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// Calculate the address of the block.
|
|
//
|
|
p = (PUCHAR)Prealloc->BaseAddress + (Prealloc->FreeIndex * Prealloc->BlockSize);
|
|
|
|
Prealloc->NumUsed++;
|
|
|
|
//
|
|
// Mark the block we are going to return as used.
|
|
//
|
|
RtlSetBits(&Prealloc->Bitmap,Prealloc->FreeIndex,1);
|
|
|
|
//
|
|
// Locate the next free block. This sets FreeIndex to -1
|
|
// if there are no more free blocks of this size.
|
|
//
|
|
Prealloc->FreeIndex = (LONG)RtlFindClearBits(
|
|
&Prealloc->Bitmap,
|
|
1,
|
|
Prealloc->FreeIndex
|
|
);
|
|
|
|
return(p);
|
|
}
|
|
|
|
|
|
VOID
|
|
pFreePreAlloc(
|
|
IN OUT PPREALLOC Prealloc,
|
|
IN PVOID p
|
|
)
|
|
{
|
|
LONG Index;
|
|
|
|
//
|
|
// Figure out which block this is.
|
|
//
|
|
Index = (LONG)((LONG_PTR)p - (LONG_PTR)Prealloc->BaseAddress) / Prealloc->BlockSize;
|
|
|
|
Prealloc->NumUsed--;
|
|
|
|
//
|
|
// Mark the block free.
|
|
//
|
|
RtlClearBits(&Prealloc->Bitmap,Index,1);
|
|
Prealloc->FreeIndex = Index;
|
|
}
|