windows-nt/Source/XPSP1/NT/base/ntsetup/legacy/dll/mem_32.c

367 lines
7.7 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
#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;
}