SBSPSS/Utils/Libs/GLib/gal.c
2000-12-04 14:13:40 +00:00

2653 lines
61 KiB
C

/* ===========================================================================
File: GAL.C
Notes: Memory allocation \ deallocation Module
Author: G Robert Liddon @ 73b
Version: 1.1
Copyright (C) 1996 DCI Ltd All rights reserved.
============================================================================ */
/* ---------------------------------------------------------------------------
Includes
-------- */
/* Standard Library
---------------- */
#include "stdio.h"
/* Glib
---- */
#include "gal.h"
#include "gdebug.h"
#include "tick.h"
/* ---------------------------------------------------------------------------
Defines
------- */
#define MAX_MEM_BLOCKS 400 /* Maximum amount of memory blocks */
#define VER_STR "1.4"
#define MAX_NAME_SIZE 8
/* ---------------------------------------------------------------------------
Structure Declarations
---------------------- */
/* Description of an area of memory, each free or alloced block has one
-------------------------------------------------------------------- */
typedef struct MEM_HDR
{
struct MEM_HDR * Prev; /* Previous block in list */
struct MEM_HDR * Next; /* Next block in this list */
void * Mem; /* Mem owned by this block */
u32 Size; /* Size of it */
u16 TimeStamp; /* A time stamp */
u16 Type; /* Unique mem type of this block */
u16 Owners; /* How many owners this block has */
U16 Handle; /* Handle for this block */
#ifdef __GL_DEBUG__
u8 Name[MAX_NAME_SIZE];
#endif
} MEM_HDR;
/* Description of a region of mem
------------------------------ */
typedef struct MEM_REG
{
void * Mem;
int Size;
} MEM_REG;
/* ---------------------------------------------------------------------------
Typedefs
-------- */
typedef MEM_HDR * (*FIND_ROUTINE)(MEM_HDR *Head, U32 Size);
/* ---------------------------------------------------------------------------
Module Variables
---------------- */
static MEM_INIT_INFO * MemInitBlocks; /* Head of list of descriptions of different types of mem */
static MEM_HDR MemHdrBlocks[MAX_MEM_BLOCKS]; /* Memory Header Blocks */
static MEM_HDR * FreeBlocks; /* List of unused header blocks */
static GAL_ERROR_CODE LastError; /* Last error that happened */
static int TimeStamp; /* Blocks alloced are stamped with this time */
static BOOL FullErrorChecking; /* Perform full error and consistancy cheaking on mem areas after defrags */
static U32 LastAttemptedAlloc; /* Last alloc we tried */
static U32 LastDeallocedBlock; /* Last alloc we tried */
static GAL_VERB_LEV VerbLev; /* How noisy gal is */
static int NumOfFreeHdrs; /* How many headers are free */
static u32 LastTypeAlloced;
static GAL_FILTER AllocFilter;
static BOOL HaltOnError; /* Set to true if we want GAL to halt if there is an error */
/* ---------------------------------------------------------------------------
Function Prototypes for internal functions
------------------------------------------ */
static void GraftMemHdrList(MEM_HDR ** ToList,MEM_HDR ** FromList);
static MEM_HDR * FindNextBlock(void *Addr,MEM_HDR * Blocks);
static BOOL CollideRegions(MEM_REG *Reg1,MEM_REG *Reg2);
static U32 ShuffleBlocks(MEM_HDR *Blocks,MEM_REG *Reg,MEM_INIT_INFO *M);
static void PutBlocksInRegionIntoList(MEM_REG *Reg,MEM_HDR **ToList,MEM_HDR **FromList);
static BOOL GazDefragMem(U32 MemType);
static void DeleteEmptyBlocks(MEM_INIT_INFO *M);
static BOOL GetRegion(MEM_REG *Reg,MEM_HDR * LockedBlocks,MEM_INIT_INFO *M);
static void SortMemHdrListByAddr(MEM_HDR **Head);
static void PutAllLockedBlocksOntoList(MEM_HDR **ToHead,MEM_HDR **FromHead);
static void AttachHdrToList(MEM_HDR **Head,MEM_HDR *Block);
static void DetachHdrFromList(MEM_HDR **Head,MEM_HDR *Block);
static BOOL IsActiveValidHandle(MHANDLE Handle);
static void * AlignPtr(void *P,U32 Align);
static U32 AlignSize(U32 Size,U32 Align);
static void MergeToEmptyList(MEM_INIT_INFO *MI,MEM_HDR *M);
static MHANDLE LoAlloc(MEM_INIT_INFO *M,MEM_HDR *Block,void *Addr,U32 Size,const char *Name);
static MEM_HDR * GetFreeMemHdrBlock(void);
static void ReleaseMemHdrBlock(MEM_HDR * Hdr);
static MEM_HDR * FindBlockInTheseBounds(MEM_HDR *Head,void *Addr,U32 Size);
static BOOL CheckCollisions(MEM_INIT_INFO * M,MEM_HDR *MemHdr);
static BOOL AreBlocksColliding(MEM_HDR *Hdr1,MEM_HDR *Hdr2);
static BOOL GSetError(GAL_ERROR_CODE Err);
static MEM_INIT_INFO * GetMemInitInfoBlockFromType(U32 Type);
static MEM_HDR * FindHighestMemBlock(MEM_HDR *Head, U32 Size);
MEM_HDR * FindClosestSizedBlock(MEM_HDR *Head, U32 Size);
static MEM_HDR * FindLowestMemBlock(MEM_HDR *Head, U32 Size);
static int CountFreeBlocks(void);
static void SetBlockName(MEM_HDR * MemHdr,const char * NewName);
static char const * GetBlockName(MEM_HDR * MemHdr);
static BOOL SortAddr(MEM_HDR *B1,MEM_HDR * B2);
static BOOL SortSize(MEM_HDR *B1,MEM_HDR * B2);
static void SortMemHdrList(MEM_HDR **Head,BOOL (*CompFunc)(MEM_HDR *B1,MEM_HDR * B2));
/* ---------------------------------------------------------------------------
Tables
------ */
char *GalErrors[]=
{
NULL,
"Run out of mem handles",
"Mem type already existed",
"Mem type added overlaps previously defined one",
"Invalid mem type",
"Invalid handle",
"Handle already unlocked",
"Memory blocks in type overlap",
"Not all memory of type covered",
"Defrag attempted but no mem functions available",
"Not enough memory to allocate block",
};
/* Phantom mem you want a MHANDLE but is actually static (Not in yet)
------------------------------------------------------------------ */
MEM_INIT_INFO PhantomMem=
{
NULL,
0,
GAL_PHANTOM_MEM,
};
/* ---------------------------------------------------------------------------
Function: void GAL_SetErrorChecking(BOOL OnOff)
Purpose: Set error checking of mem regions after defrag
Params: OnOff = what to do
--------------------------------------------------------------------------- */
void GAL_SetErrorChecking(BOOL OnOff)
{
FullErrorChecking=OnOff;
}
/* ---------------------------------------------------------------------------
Function: MHANDLE GAL_SplitBlock(MHANDLE CurBlock,U32 Split)
Purpose: Split a Block into two. If Split point outside
block to be split then this will return an error.
Split is rounded rounded up to be on mem type alignment
boundary
Params: CurBlock = block to split
Size = New Size
Returns: Handle of second block else
NULL_HANDLE if unsucessful
--------------------------------------------------------------------------- */
MHANDLE GAL_SplitBlock(MHANDLE CurBlock,U32 Size)
{
MEM_INIT_INFO * M;
MEM_HDR * MemHdr;
MEM_HDR * SplitBlock;
if (!IsActiveValidHandle(CurBlock))
{
GSetError(ERR_GAL_INVALID_MEM_HANDLE);
return NULL_HANDLE;
}
MemHdr=&MemHdrBlocks[CurBlock];
if (!(M=GetMemInitInfoBlockFromType(MemHdr->Type)))
{
GSetError(ERR_GAL_INVALID_MEM_TYPE);
return NULL_HANDLE;
}
/* Round up split to size lie on mem types alignment & Check to see if it's not too big */
Size=AlignSize(Size,M->Alignment);
if (Size >= MemHdr->Size)
return NULL_HANDLE;
/* Get a free block to put split into */
if (!(SplitBlock=GetFreeMemHdrBlock()))
{
GSetError(ERR_RUN_OUT_OF_MEM_HDRS);
return NULL_HANDLE;
}
/* Fill it up with the correct details */
SplitBlock->Type=MemHdr->Type;
SplitBlock->Owners=1;
SplitBlock->Mem=(void *)((U32)(MemHdr->Mem)+Size);
SplitBlock->Size=MemHdr->Size-Size;
SplitBlock->TimeStamp=MemHdr->TimeStamp;
SetBlockName(SplitBlock,GetBlockName(MemHdr));
/* And add to the list of used blocks */
AttachHdrToList(&M->Used,SplitBlock);
/* Now Adjust Block that's been split */
MemHdr->Size=Size;
/* Return handle of the split block */
return SplitBlock->Handle;
}
/* ---------------------------------------------------------------------------
Function: void GAL_InitModule(void);
Purpose: Initialise memory manager
--------------------------------------------------------------------------- */
void GAL_InitModule(void)
{
int f;
MemInitBlocks=NULL;
FreeBlocks=NULL;
NumOfFreeHdrs=0;
GAL_SetVerbosity(GAL_SILENT);
GAL_SetTimeStamp(0);
LastError=ERR_GAL_NO_ERROR;
GAL_SetErrorChecking(FALSE);
GAL_ReturnOnError();
for (f=0;f<MAX_MEM_BLOCKS;f++)
{
MemHdrBlocks[f].Prev=NULL;
MemHdrBlocks[f].Next=NULL;
MemHdrBlocks[f].Handle=f;
ReleaseMemHdrBlock(&MemHdrBlocks[f]);
}
}
/* ---------------------------------------------------------------------------
Function: int GAL_AddMemType(MEM_INIT_INFO *M)
Purpose: Add a type of memory to the list of mem types
Params: M -> to structure describing new mem type
Returns: FALSE if there was an error
--------------------------------------------------------------------------- */
BOOL GAL_AddMemType(MEM_INIT_INFO *M)
{
MEM_INIT_INFO * P;
MEM_HDR * FreeMemHdr;
U32 Addr1;
U32 Addr2;
/* Scan through any memory regions GAL has in it's charge to
see if there's any conflict with the block we want to add */
P=MemInitBlocks;
while (P)
{
/* See if this block overlaps any others */
Addr1=(U32) M->Mem;
Addr2=(U32) P->Mem;
if (Addr1 < (Addr2+P->Size))
{
if (Addr1+M->Size >= Addr2)
{
GSetError(ERR_GAL_MEM_TYPE_OVERLAP);
return FALSE;
}
}
/* Check to see if there's a memory region already designated of
this type */
if (P->Type == M->Type)
return ERR_GAL_MEM_TYPE_EXISTS;
/* Next Block */
P=P->NextInitBlock;
}
/* Add to the list of memory regions */
M->NextInitBlock=MemInitBlocks;
MemInitBlocks=M;
/* Initialise Info Block */
M->Flags=0;
M->Used=NULL;
M->Empty=NULL;
/* Get A Mem HDR for the free region if we can */
FreeMemHdr=GetFreeMemHdrBlock();
if (!FreeMemHdr)
{
GSetError(ERR_RUN_OUT_OF_MEM_HDRS);
return FALSE;
}
/* Set empty region to be this mem header */
AttachHdrToList(&M->Empty,FreeMemHdr);
/* Init this mem hdr as the empty region */
FreeMemHdr->Mem=AlignPtr(M->Mem,M->Alignment);
Addr1=(U32)FreeMemHdr->Mem-(U32)M->Mem;
FreeMemHdr->Size=M->Size-Addr1;
/* Return without an error */
return TRUE;
}
/* ---------------------------------------------------------------------------
Function: MHANDLE GAL_Alloc(U32 MemNeeded,U32 Type,const char *Name)
Purpose: Alloc some memory
Parms: MemNeeded = Amount Wanted
Type = Type of mem wanted
Name = Name of mem block (NULL if no name wanted)
Returns: A handle to memory if succesful
NULL_HANDLE if failed
--------------------------------------------------------------------------- */
MHANDLE GAL_Alloc(U32 Size,U32 Type,const char *Name)
{
MEM_HDR * Block;
MEM_INIT_INFO * M;
U32 FullSize;
FIND_ROUTINE FRoute;
BOOL High;
High = (Type&GAL_HIGH) == GAL_HIGH;
Type&=~GAL_FLAGS;
if (High)
FRoute=FindHighestMemBlock;
else
FRoute=FindLowestMemBlock;
LastAttemptedAlloc=Size;
LastTypeAlloced=Type;
/* Find out the full mem aligned size of this chunk */
/* If this is a valid memory type get info about this mem type */
if (!(M=GetMemInitInfoBlockFromType(Type)))
{
GSetError(ERR_GAL_INVALID_MEM_TYPE);
return NULL_HANDLE;
}
FullSize=AlignSize(Size,M->Alignment);
if (AllocFilter)
AllocFilter(Type,FullSize,Name);
/* Find a smallest block in memory pool that is big enough in size and error if not*/
if (!(Block=FRoute(M->Empty,FullSize)))
{
/* Oh dear couldn't alloc, is it worth trying a defrag? */
if (FullSize<=GAL_GetFreeMem(Type))
{
/* Yes, it could be worth it so lets try */
if (!GAL_DefragMem(Type))
return NULL_HANDLE;
else
{
/* Sucessfully defraged, now try again */
if (!(Block=FRoute(M->Empty,FullSize)))
{
GSetError(ERR_GAL_NOT_ENOUGH_MEM);
return NULL_HANDLE;
}
}
}
else
{
GSetError(ERR_GAL_NOT_ENOUGH_MEM);
return NULL_HANDLE;
}
}
/* Take it out of the empty list */
DetachHdrFromList(&M->Empty,Block);
/* No Do the grunt work */
if (High)
{
u8 * BaseAddr;
BaseAddr=(void*)((u32) Block->Mem + Block->Size-FullSize);
return LoAlloc(M,Block,BaseAddr,Size,Name);
}
else
return LoAlloc(M,Block,Block->Mem,Size,Name);
}
/* ---------------------------------------------------------------------------
Function: UINT GAL_GetMemSize(MHANDLE Handle)
Purpose: Find out how much memory is attached to this handle
Parms: MHANDLE Handle = handle of allocated memory
Returns: Size of block (not neccesarily the allocated size, but the rounded
up according to the memory region it was allocated in size )
--------------------------------------------------------------------------- */
UINT GAL_GetMemSize(MHANDLE Handle)
{
MEM_HDR *MemHdr;
if (!IsActiveValidHandle(Handle))
{
GSetError(ERR_GAL_INVALID_MEM_HANDLE);
return 0;
}
MemHdr=&MemHdrBlocks[Handle];
return(MemHdr->Size);
}
/* ---------------------------------------------------------------------------
Function: void *GAL_Lock(MHANDLE Handle)
Purpose: Lock some alloced memory
Parms: MHANDLE Handle = handle to alloced memory
Returns: A handle to memory if succesful
NULL_HANDLE if failed
--------------------------------------------------------------------------- */
void *GAL_Lock(MHANDLE Handle)
{
MEM_HDR *MemHdr;
/* check to see if this is a valid handle, error if not */
if (!IsActiveValidHandle(Handle))
{
GSetError(ERR_GAL_INVALID_MEM_HANDLE);
return NULL;
}
/* get ptr to memory block */
MemHdr=&MemHdrBlocks[Handle];
/* Everything ok so bump up the amount of owners */
MemHdr->Owners++;
/* return pointer to blocks memory */
return MemHdr->Mem;
}
/* ---------------------------------------------------------------------------
Function: void *GAL_Unlock(MHANDLE Handle)
Purpose: Unlock previously locked memory
Parms: MHANDLE Handle to mem block
Returns: TRUE if succesfully unlocked
FALSE if not
--------------------------------------------------------------------------- */
BOOL GAL_Unlock(MHANDLE Handle)
{
MEM_HDR *MemHdr;
/* check to see if this is a valid handle, error if not */
if (!IsActiveValidHandle(Handle))
{
GSetError(ERR_GAL_INVALID_MEM_HANDLE);
return FALSE;
}
/* get ptr to memory block */
MemHdr=&MemHdrBlocks[Handle];
/* If this mem block has no owners error */
if (!MemHdr->Owners)
{
GSetError(ERR_GAL_MEM_ALREADY_UNLOCKED);
return FALSE;
}
/* Decrease amount of owners */
MemHdr->Owners--;
/* Complete Succesfully */
return TRUE;
}
/* ---------------------------------------------------------------------------
Function: BOOL GAL_Free(MHANDLE Handle);
Purpose: Free up previously allocated memory
Parms: MEMINFO *Mem -> Linked list of memory information blocks
Returns: How succesful it all was
--------------------------------------------------------------------------- */
BOOL GAL_Free(MHANDLE Handle)
{
MEM_INIT_INFO * M;
MEM_HDR * MemHdr;
/* check to see if this is a valid handle, error if not */
if (!IsActiveValidHandle(Handle))
{
GSetError(ERR_GAL_INVALID_MEM_HANDLE);
return FALSE;
}
/* get ptr to memory block */
MemHdr=&MemHdrBlocks[Handle];
/* Get -> to memory region structure this block belongs to and error if there wasn't one */
if (!(M=GetMemInitInfoBlockFromType(MemHdr->Type)))
{
GSetError(ERR_GAL_INVALID_MEM_TYPE);
return FALSE;
}
/* Report what amount of mem this was being freed */
LastDeallocedBlock=MemHdr->Size;
/* Take mem block from used list */
DetachHdrFromList(&M->Used,MemHdr);
/* Merge into the empty blocks list */
MergeToEmptyList(M,MemHdr);
return TRUE;
}
/* ---------------------------------------------------------------------------
Function: U32 GAL_GetFreeMem(U32 Type)
Purpose: Return how much free mem this mem type has
Parms: U32 Type = memory type to do
Returns: Total size of free mem
--------------------------------------------------------------------------- */
U32 GAL_GetFreeMem(U32 Type)
{
U32 FreeMem;
MEM_INIT_INFO * M;
Type&=~GAL_FLAGS;
FreeMem=0;
if ((M=GetMemInitInfoBlockFromType(Type)))
{
MEM_HDR * Block;
Block=M->Empty;
while (Block)
{
FreeMem+=Block->Size;
Block=Block->Next;
}
}
else
GSetError(ERR_GAL_INVALID_MEM_TYPE);
return(FreeMem);
}
/* ---------------------------------------------------------------------------
Function: U32 GAL_GetFreeMem(U32 Type)
Purpose: Return how much free mem this mem type has
Parms: U32 Type = memory type to do
Returns: Total size of free mem
--------------------------------------------------------------------------- */
U32 GAL_GetUsedMem(U32 Type)
{
U32 FreeMem;
MEM_INIT_INFO * M;
Type&=~GAL_FLAGS;
FreeMem=0;
if ((M=GetMemInitInfoBlockFromType(Type)))
{
MEM_HDR * Block;
Block=M->Used;
while (Block)
{
FreeMem+=Block->Size;
Block=Block->Next;
}
}
else
GSetError(ERR_GAL_INVALID_MEM_TYPE);
return(FreeMem);
}
/* ---------------------------------------------------------------------------
Function: U32 GAL_LargestFreeBlock(U32 Type)
Purpose: Return the largest block of mem available
Parms: U32 Type = memory type to do
Returns: Size of largest mem
--------------------------------------------------------------------------- */
U32 GAL_LargestFreeBlock(U32 Type)
{
U32 Largest;
MEM_HDR * Index;
MEM_INIT_INFO * MI;
Type&=~GAL_FLAGS;
if (!(MI=GetMemInitInfoBlockFromType(Type)))
{
GSetError(ERR_GAL_INVALID_MEM_TYPE);
return 0;
}
Largest = 0;
Index=MI->Empty;
while (Index)
{
if (Index->Size > Largest)
Largest=Index->Size;
Index=Index->Next;
}
return Largest;
}
/* ---------------------------------------------------------------------------
Function: static void AttachHdrToList(MEM_HDR **Head,MEM_HDR *Block)
Purpose: Attach this block to a linked list
Parms: MEM_HDR **Head -> Head of list holder
MEM_HDR *Block -> Block to add
--------------------------------------------------------------------------- */
static void AttachHdrToList(MEM_HDR **Head,MEM_HDR *Block)
{
Block->Prev=NULL;
if ((Block->Next=*Head))
Block->Next->Prev=Block;
*Head=Block;
}
/* ---------------------------------------------------------------------------
Function: static void DetachHdrFromList(MEM_HDR **Head,MEM_HDR *Block)
Purpose: Detach this block from a linked list
Parms: MEM_HDR **Head -> Head of list holder
MEM_HDR *Block -> Block to detach
--------------------------------------------------------------------------- */
static void DetachHdrFromList(MEM_HDR **Head,MEM_HDR *Block)
{
if (Block->Prev)
Block->Prev->Next=Block->Next;
else
*Head=Block->Next;
if (Block->Next)
Block->Next->Prev=Block->Prev;
}
/* ---------------------------------------------------------------------------
Function: BOOL IsActiveValidHandle(MHANDLE Handle)
Purpose: Is this an active valid handle
Parms: MHANDLE Handle to mem block
Returns: TRUE if is
FALSE if not
--------------------------------------------------------------------------- */
static BOOL IsActiveValidHandle(MHANDLE Handle)
{
MEM_HDR *MemHdr;
if (Handle >= MAX_MEM_BLOCKS || Handle < 0)
return FALSE;
MemHdr=&MemHdrBlocks[Handle];
if (!(MemHdr->Mem))
return FALSE;
return TRUE;
}
/* ---------------------------------------------------------------------------
Function: static void *AlignPtr(void *P,U32 Align)
Purpose: Align this PTR to next aligned memory
Parms: P = Ptr to align
Align = aligment
Returns: Aligned ptr
--------------------------------------------------------------------------- */
static void *AlignPtr(void *P,U32 Align)
{
U32 Addr,Temp;
Addr= (U32) P;
Temp=Align-(Addr%Align);
Addr+=(Temp == Align ? 0 : Temp);
return (void *) Addr;
}
/* ---------------------------------------------------------------------------
Function: static U32 AlignSize(U32 Size,U32 Align)
Purpose: Pad out a size to this aligment
Parms: Size = Size to pad out
Align = aligmnet to pad if out to
Returns: Aligned Size
--------------------------------------------------------------------------- */
static U32 AlignSize(U32 Size,U32 Align)
{
Size+= Size%Align ? (Align-(Size%Align)) : 0;
return Size;
}
/* ---------------------------------------------------------------------------
Function: MEM_HDR *FindClosestSizedBlock(MEM_HDR *Head, U32 Size)
Purpose: Get the mem info structure for this type of memory
Parms: U32 Type = Type of mem MEM_INIT_INFO needed for
Returns: -> MEM_INIT_INFO if succesful else NULL
--------------------------------------------------------------------------- */
MEM_HDR *FindClosestSizedBlock(MEM_HDR *Head, U32 Size)
{
MEM_HDR * Closest;
MEM_HDR * Index;
Closest=NULL;
Index=Head;
while (Index)
{
if (Index->Size >= Size)
{
if (Closest)
{
if ((Index->Size - Size) < (Closest->Size - Size))
Closest=Index;
}
else
Closest=Index;
}
Index=Index->Next;
}
return Closest;
}
/* ---------------------------------------------------------------------------
Function: MEM_HDR *FindClosestSizedBlock(MEM_HDR *Head, U32 Size)
Purpose: Get the mem info structure for this type of memory
Parms: U32 Type = Type of mem MEM_INIT_INFO needed for
Returns: -> MEM_INIT_INFO if succesful else NULL
--------------------------------------------------------------------------- */
MEM_HDR *FindHighestMemBlock(MEM_HDR *Head, U32 Size)
{
MEM_HDR * Closest;
MEM_HDR * Index;
void * Highest;
Closest=NULL;
Highest=NULL;
Index=Head;
while (Index)
{
if (Index->Size >= Size)
{
if (Closest)
{
if ((u32) Index->Mem > (u32) Highest)
{
Closest=Index;
Highest=Index->Mem;
}
}
else
{
Closest=Index;
Highest=Index->Mem;
}
}
Index=Index->Next;
}
return Closest;
}
/* ---------------------------------------------------------------------------
Function: static MEM_HDR *FindLowestMemBlock(MEM_HDR *Head, U32 Size)
Purpose: Get the mem info structure for this type of memory
Parms: U32 Type = Type of mem MEM_INIT_INFO needed for
Returns: -> MEM_INIT_INFO if succesful else NULL
--------------------------------------------------------------------------- */
MEM_HDR *FindLowestMemBlock(MEM_HDR *Head, U32 Size)
{
MEM_HDR * Closest;
MEM_HDR * Index;
u32 Lowest;
Closest=NULL;
Index=Head;
Lowest=0xffffffff;
Closest=NULL;
while (Index)
{
if (Index->Size >= Size)
{
if (Closest)
{
if ((u32) Index->Mem < Lowest)
{
Closest=Index;
Lowest=(u32)Index->Mem;
}
}
else
{
Closest=Index;
Lowest=(u32)Index->Mem;
}
}
Index=Index->Next;
}
return Closest;
}
/* ---------------------------------------------------------------------------
Function: static MEM_INIT_INFO *GetMemInitInfoBlockFromType(U32 Type)
Purpose: Get the mem info structure for this type of memory
Parms: U32 Type = Type of mem MEM_INIT_INFO needed for
Returns: -> MEM_INIT_INFO if succesful else NULL
--------------------------------------------------------------------------- */
static MEM_INIT_INFO *GetMemInitInfoBlockFromType(U32 Type)
{
MEM_INIT_INFO * P;
MEM_INIT_INFO * RetBlock;
RetBlock=NULL;
P=MemInitBlocks;
while (P)
{
/* Is the type we are looking for? */
if (P->Type==Type)
return P;
/* No, so go onto next block */
P=P->NextInitBlock;
}
return RetBlock;
}
/* ---------------------------------------------------------------------------
Function: void MergeFromUsedtoFreeList(MEM_HDR *M,MEM_INIT_INFO *MI)
Purpose: Merge this block into this mem info's empty list. Merge
it with any adjacent blocks
Parms: U32 Type = Type of mem MEM_INIT_INFO needed for
Returns: -> MEM_INIT_INFO if succesful else NULL
--------------------------------------------------------------------------- */
static void MergeToEmptyList(MEM_INIT_INFO *MI,MEM_HDR *M)
{
MEM_HDR * Index;
MEM_HDR * NextIndex;
void * Start;
void * End;
/* Work out end address of this block */
Start=M->Mem;
End=(void *)(((U32) M->Mem) + M->Size);
/* Init Loop Vars */
Index=MI->Empty;
/* Tumble through empty list grabbing empty blocks adjacent to our block we're freeing */
while (Index)
{
void * ThisStart;
void * ThisEnd;
/* Work out end of address of current header */
ThisStart=Index->Mem;
ThisEnd=(void *)(((U32) Index->Mem)+Index->Size);
/* Work out next block in list */
NextIndex=Index->Next;
/* If we're adjacent then merge and remove from empty list */
if (Start==ThisEnd || End==ThisStart)
{
/* Merge found block to me */
M->Size+=Index->Size;
if (Start==ThisEnd)
M->Mem=Index->Mem;
/* Detach from empty and chuck into free */
DetachHdrFromList(&MI->Empty,Index);
ReleaseMemHdrBlock(Index);
}
Index=NextIndex;
}
AttachHdrToList(&MI->Empty,M);
}
/* ---------------------------------------------------------------------------
Function: MHANDLE GAL_AllocAt(U32 MemNeeded,void *Addr,U32 Type,const char *Name)
Purpose: Alloc some memory at a specefic address
WARNING ***
if Addr is not aligned to this memory types alignment then
block allocated will be at next aligned address, size will
still be correct.
Parms: MemNeeded = Amount Wanted
Addr = Address needed at
Type = Type of mem wanted
Name = Name of mem block (NULL if no name wanted)
Returns: A handle to memory if succesful
NULL_HANDLE if failed
--------------------------------------------------------------------------- */
MHANDLE GAL_AllocAt(U32 Size,void *Addr,U32 Type,const char *Name)
{
MEM_HDR * Block;
MEM_INIT_INFO * M;
U32 PhysSize;
/* If this is a valid memory type get info about this mem type */
Type&=~GAL_FLAGS;
if (!(M=GetMemInitInfoBlockFromType(Type)))
{
GSetError(ERR_GAL_INVALID_MEM_TYPE);
return NULL_HANDLE;
}
/* Align address asked for and align size */
Addr=AlignPtr(Addr,M->Alignment);
PhysSize=AlignSize(Size,M->Alignment);
/* Find block we can fit into else error out if one not found */
if (!(Block=FindBlockInTheseBounds(M->Empty,Addr,PhysSize)))
return NULL_HANDLE;
/* Take it out of the empty list */
DetachHdrFromList(&M->Empty,Block);
/* Now do the business */
return LoAlloc(M,Block,Addr,Size,Name);
}
/* ---------------------------------------------------------------------------
Function: static MHANDLE LoAlloc(MEM_INIT_INFO *M,MEM_HDR *Block,void *Addr,U32 Size,const char *Name)
Purpose: Lo level alloc used by GAL_AllocAt && GAL_Alloc
Alloc some memory at a specefic address
WARNING ***
if Addr is not aligned to this memory types alignment then
block allocated will be at next aligned address, size will
still be correct.
Parms: M = Mem region to alloc from
Block = Free block in mem region to alloc into
Size = Amount Wanted
Addr = Address needed at
Name = Name of block
Returns: A handle to memory if succesful
NULL_HANDLE if failed
--------------------------------------------------------------------------- */
static MHANDLE LoAlloc(MEM_INIT_INFO *M,MEM_HDR *Block,void *Addr,U32 Size,const char *Name)
{
MEM_HDR * SplitBlock;
U32 PhysSize;
PhysSize=AlignSize(Size,M->Alignment);
/* if block base isn't the as address we asked for ... */
if (Block->Mem != Addr)
{
/* Pare of begining go block and chuck back onto free list*/
if (!(SplitBlock=GetFreeMemHdrBlock()))
{
GSetError(ERR_RUN_OUT_OF_MEM_HDRS);
return NULL_HANDLE;
}
SplitBlock->Mem=Block->Mem;
SplitBlock->Size=(U32) Addr-(U32)(Block->Mem);
SplitBlock->Type=(u16) M->Type;
/* And put it into empty list in MEM_INIT_INFO */
MergeToEmptyList(M,SplitBlock);
/* And adjust this block */
Block->Mem=Addr;
Block->Size-=SplitBlock->Size;
}
/* if block found is bigger than memory wanted ... */
if ((Block->Size > PhysSize))
{
/* if can't find an unsused MEM_HDR in global pool then error */
if (!(SplitBlock=GetFreeMemHdrBlock()))
{
GSetError(ERR_RUN_OUT_OF_MEM_HDRS);
return NULL_HANDLE;
}
/* Make new block point @ spare mem of alloced block */
SplitBlock->Mem=(void *) ((U32)(Block->Mem)+PhysSize);
SplitBlock->Size=Block->Size-PhysSize;
SplitBlock->Type=(u16) M->Type;
/* And put it into empty list in MEM_INIT_INFO */
MergeToEmptyList(M,SplitBlock);
/* Adjust alloced Block so that it is same size as memory wanted */
Block->Size=PhysSize;
}
/* Detach block from memory pool from Empty list & add to Used List*/
AttachHdrToList(&M->Used,Block);
/* Initialise the block */
Block->Owners = 0; /* Say no one owns this block */
Block->Type= (u16)M->Type;
Block->TimeStamp=TimeStamp;
/* Do Some reporting */
if (VerbLev >= GAL_NOISY)
{
DBG_SendMessage("Succesfully alloced block of %d",(int)Size);
GAL_MemDump(M->Type);
}
/* Set the blocks name */
SetBlockName(Block,Name);
/* return Block's handle */
return Block->Handle;
}
/* ---------------------------------------------------------------------------
Function: static MEM_HDR *FindBlockInTheseBounds(MEM_INIT_INFO *MI,void *Addr,U32 Size)
Purpose: Find a free block that fully covers from Addr to Addr[Size-1]
Parms: Head = First block in link list to search
Addr = Address needed at
Size = Size of block
Returns: A -> to mem block if found else
NULL
--------------------------------------------------------------------------- */
static MEM_HDR *FindBlockInTheseBounds(MEM_HDR *Head,void *Addr,U32 Size)
{
MEM_HDR * Index;
BOOL Done;
U32 ThisStart,ThisEnd;
U32 Start,End;
Start=(U32) Addr;
End=Start+Size;;
Done=FALSE;
Index=Head;
while (Index && !Done)
{
ThisStart=(U32) (Index->Mem);
ThisEnd=ThisStart+Index->Size;
if ((Start >= ThisStart) && (End <= ThisEnd))
Done=TRUE;
else
Index=Index->Next;
}
if (Done)
return Index;
else
return NULL;
}
/* ---------------------------------------------------------------------------
Function: static MEM_HDR *GetFreeMemHdrBlock(void)
Purpose: Get a mem hdr block from the list of free ones
Returns: A -> to mem block if found else
NULL
--------------------------------------------------------------------------- */
static MEM_HDR *GetFreeMemHdrBlock(void)
{
MEM_HDR *RetBlock;
RetBlock=NULL;
if (FreeBlocks)
{
NumOfFreeHdrs--;
if (VerbLev >= GAL_AVERAGE && NumOfFreeHdrs == 9)
DBG_SendMessage("GAL: Warning Number of free headers < 10");
RetBlock=FreeBlocks;
DetachHdrFromList(&FreeBlocks,FreeBlocks);
}
return RetBlock;
}
/* ---------------------------------------------------------------------------
Function: static void ReleaseMemHdrBlock(MEM_HDR * Index)
Purpose: Puts a block back onto the list and does some
auditing
Params: Index -> block to be put back on unused blocks list
--------------------------------------------------------------------------- */
static void ReleaseMemHdrBlock(MEM_HDR * Index)
{
NumOfFreeHdrs++;
AttachHdrToList(&FreeBlocks,Index);
}
/* ---------------------------------------------------------------------------
Function: void GAL_IterateEmptyMem(U32 MemType,void (*Func)(void *Addr,U32 Size,const char *Name))
Purpose: Iterate Through empry mem blocks of a mem type with a callback
Params: MemType = Type of mem to iterate through
--------------------------------------------------------------------------- */
void GAL_IterateEmptyMem(U32 MemType,void (*Func)(void *Addr,U32 Size,const char *Name))
{
MEM_INIT_INFO * M;
MemType&=~GAL_FLAGS;
if ((M=GetMemInitInfoBlockFromType(MemType)))
{
MEM_HDR * Block;
Block=M->Empty;
while (Block)
{
Func(Block->Mem,Block->Size,GetBlockName(Block));
Block=Block->Next;
}
}
else
GSetError(ERR_GAL_INVALID_MEM_TYPE);
}
/* ---------------------------------------------------------------------------
Function: void GAL_IterateUsedMem(U32 MemType,void (*Func)(MHANDLE hnd,void *Addr,U32 Size,const char *Name,int Users,int TimeStamp))
Purpose: Iterate Through empry mem blocks of a mem type with a callback
Params: MemType = Type of mem to iterate through
--------------------------------------------------------------------------- */
void GAL_IterateUsedMem(U32 MemType,void (*Func)(MHANDLE hnd,void *Addr,U32 Size,const char *Name,int Users,int TimeStamp))
{
MEM_INIT_INFO * M;
MemType&=~GAL_FLAGS;
if ((M=GetMemInitInfoBlockFromType(MemType)))
{
MEM_HDR * Block;
Block = M->Used;
while (Block)
{
Func(Block->Handle,Block->Mem, Block->Size, GetBlockName(Block), Block->Owners,Block->TimeStamp);
Block=Block->Next;
}
}
else
GSetError(ERR_GAL_INVALID_MEM_TYPE);
}
/* ---------------------------------------------------------------------------
Function: BOOL GAL_SetMemName(MHANDLE Hnd,const char *Text);
Purpose: Set this mem's name
Params: Hnd = handle of block to set name of
Text -> text to set it to
--------------------------------------------------------------------------- */
BOOL GAL_SetMemName(MHANDLE Hnd,const char *Text)
{
if (!IsActiveValidHandle(Hnd))
{
GSetError(ERR_GAL_INVALID_MEM_HANDLE);
return(FALSE);
}
SetBlockName(&MemHdrBlocks[Hnd],Text);
return(TRUE);
}
/* ---------------------------------------------------------------------------
Function: U32 GAL_TotalMem(U32 Type)
Purpose: Tells how much mem in total this mem block has
Params: Type = Type of mem you want to know about
Returns: Amount of mem, 0 if an erroneous type is passed
--------------------------------------------------------------------------- */
U32 GAL_TotalMem(U32 Type)
{
U32 TotalMem;
MEM_INIT_INFO * M;
Type&=~GAL_FLAGS;
TotalMem=0;
if ((M=GetMemInitInfoBlockFromType(Type)))
TotalMem=M->Size;
else
GSetError(ERR_GAL_INVALID_MEM_TYPE);
return(TotalMem);
}
/* ---------------------------------------------------------------------------
Function: void *GAL_MemBase(U32 Type)
Purpose: Says where the base of this mem type is
Params: Type = Type of mem you want to know about
Returns: Amount of mem, 0 if an erroneous type is passed
--------------------------------------------------------------------------- */
void *GAL_MemBase(U32 Type)
{
void * Ret;
MEM_INIT_INFO * M;
Ret=NULL;
Type&=~GAL_FLAGS;
if ((M=GetMemInitInfoBlockFromType(Type)))
Ret=M->Mem;
else
GSetError(ERR_GAL_INVALID_MEM_TYPE);
return(Ret);
}
/* ---------------------------------------------------------------------------
Function: BOOL GAL_DefragMem(U32 type)
Purpose: Defrag a mem type
Params: Type = Type of mem you want to defrag
Returns: TRUE if AOK
--------------------------------------------------------------------------- */
BOOL GAL_DefragMem(U32 type)
{
BOOL GalRet;
if (VerbLev >= GAL_AVERAGE)
DBG_SendMessage("GAL: Attempting defrag");
GalRet=GazDefragMem(type);
if (FullErrorChecking)
{
if (!GAL_CheckMem(type))
return FALSE;
}
NumOfFreeHdrs=CountFreeBlocks();
return(TRUE);
}
/* ---------------------------------------------------------------------------
Function: static BOOL GSetError(GAL_ERROR_CODE Err)
Purpose: Set's the internal error code to a vale
Params: Error code to set internal var to
Returns: FALSE
--------------------------------------------------------------------------- */
static BOOL GSetError(GAL_ERROR_CODE Err)
{
if (VerbLev >= GAL_AVERAGE)
DBG_SendMessage("GAL Error: %s ",GalErrors[Err]);
if (HaltOnError)
DBG_Halt();
LastError=Err;
return(FALSE);
}
/* ---------------------------------------------------------------------------
Function: BOOL GAL_CheckMem(U32 Type)
Purpose: Checks a memory types internal records for consistency
Params: Type = type of mem to check
Returns: False if there's some internal inconsistency
--------------------------------------------------------------------------- */
BOOL GAL_CheckMem(U32 Type)
{
MEM_INIT_INFO * M;
MEM_HDR * MemHdr;
u32 TotalMem;
Type&=~GAL_FLAGS;
TotalMem=0;
if (!(M=GetMemInitInfoBlockFromType(Type)))
{
GSetError(ERR_GAL_INVALID_MEM_TYPE);
return FALSE;
}
/* Check all of the empty blocks for collisions with any others */
MemHdr=M->Empty;
while (MemHdr)
{
if (CheckCollisions(M,MemHdr))
return(GSetError(ERR_GAL_MEM_BLOCK_COLLISION));
TotalMem+=MemHdr->Size;
MemHdr=MemHdr->Next;
}
/* Check all of the used blocks for collisions with any others */
MemHdr=M->Used;
while (MemHdr)
{
if (CheckCollisions(M,MemHdr))
return(GSetError(ERR_GAL_MEM_BLOCK_COLLISION));
TotalMem+=MemHdr->Size;
MemHdr=MemHdr->Next;
}
/* Check that the total mem is exactly the same as the mem info mem */
if (M->Size != TotalMem)
return(GSetError(ERR_GAL_MEM_AREA_NOT_COVERED));
return(TRUE);
}
/* ---------------------------------------------------------------------------
Function: static void CheckCollisions(MEM_INIT_INFO * M,MEM_HDR *MemHdr)
Purpose: Checks if this mem block overlaps with any other in this mem
types empty or used list
Params: M -> Header for type of mem
MemHdr -> Block to check
Returns: TRUE if it does
--------------------------------------------------------------------------- */
static BOOL CheckCollisions(MEM_INIT_INFO * M,MEM_HDR *MemHdr)
{
MEM_HDR * CheckHdr;
CheckHdr=M->Used;
while (CheckHdr)
{
if ((CheckHdr != MemHdr) && AreBlocksColliding(MemHdr,CheckHdr))
return(TRUE);
CheckHdr=CheckHdr->Next;
}
CheckHdr=M->Empty;
while (CheckHdr)
{
if ((CheckHdr != MemHdr) && AreBlocksColliding(MemHdr,CheckHdr))
return(TRUE);
CheckHdr=CheckHdr->Next;
}
return(FALSE);
}
/* ---------------------------------------------------------------------------
Function: static BOOL AreBlocksColliding(MEM_HDR *Hdr1,MEM_HDR *Hdr1)
Purpose: Do this two blocks overlap
Params: Hdr1 -> First block
Hdr2 -> Second block
Returns: TRUE if it does
--------------------------------------------------------------------------- */
static BOOL AreBlocksColliding(MEM_HDR *Hdr1,MEM_HDR *Hdr2)
{
U32 Addr1;
U32 Addr2;
Addr1=(U32) Hdr1->Mem;
Addr2=(U32) Hdr2->Mem;
if ((Addr1< Addr2+Hdr2->Size) && (Addr1 >= Addr2))
return(TRUE);
if ((Addr2< Addr1+Hdr1->Size) && (Addr2 >= Addr1))
return(TRUE);
return(FALSE);
}
/* ---------------------------------------------------------------------------
Function: const char *GAL_GetErrorText(GAL_ERROR_CODE Err)
Purpose: Converts a GAL error to
Params: Err = Error to get code for
Returns: NULL if no error || -> error text
--------------------------------------------------------------------------- */
char *GAL_GetErrorText(GAL_ERROR_CODE Err)
{
if (Err>= NUM_OF_ERROR_MESSAGES)
return("Invalid error code");
else
return(GalErrors[Err]);
}
/* ---------------------------------------------------------------------------
Function: GAL_ERROR_CODE GAL_GetLastErrorCode(void)
Purpose: Get's last error gal had
Returns: Last error code
--------------------------------------------------------------------------- */
GAL_ERROR_CODE GAL_GetLastErrorCode(void)
{
return(LastError);
}
/* ---------------------------------------------------------------------------
Function: char *GAL_GetLastErrorText(void)
Purpose: Get's text for last error gal had
Returns: NULL if no error || -> error text
--------------------------------------------------------------------------- */
char *GAL_GetLastErrorText(void)
{
return(GAL_GetErrorText(LastError));
}
/* ---------------------------------------------------------------------------
Function: int GAL_HowManyFreeBlocksUsed(U32 Type)
Purpose: Find's out how many free blocks are used by this mem type
Returns: Blocks used
--------------------------------------------------------------------------- */
int GAL_HowManyEmptyRegions(U32 Type)
{
MEM_INIT_INFO * m;
int Count;
Type&=~GAL_FLAGS;
if ((m = GetMemInitInfoBlockFromType(Type)))
{
MEM_HDR * mh;
Count=0;
mh=m->Empty;
while (mh)
{
Count++;
mh=mh->Next;
}
}
else
{
GSetError(ERR_GAL_INVALID_MEM_TYPE);
Count=-1;
}
return Count;
}
/* ---------------------------------------------------------------------------
Function: int GAL_HowManyFreeBlocksUsed(U32 Type)
Purpose: Find's out how many free blocks are used by this mem type
Returns: Blocks used
--------------------------------------------------------------------------- */
int GAL_HowManyUsedRegions(U32 Type)
{
MEM_INIT_INFO * m;
int Count;
Type&=~GAL_FLAGS;
if ((m = GetMemInitInfoBlockFromType(Type)))
{
MEM_HDR * mh;
mh=m->Used;
Count=0;
while (mh)
{
Count++;
mh=mh->Next;
}
}
else
{
GSetError(ERR_GAL_INVALID_MEM_TYPE);
Count=-1;
}
return Count;
}
/* ---------------------------------------------------------------------------
Function: void GAL_SetTimeStamp(int Time)
Purpose: All blocks alloced will be of this time stamp
--------------------------------------------------------------------------- */
void GAL_SetTimeStamp(int Time)
{
TimeStamp=Time;
}
/* ---------------------------------------------------------------------------
Function: void GAL_SetTimeStamp(int Time)
Purpose: All blocks alloced will be of this time stamp
--------------------------------------------------------------------------- */
void GAL_IncTimeStamp(void)
{
TimeStamp++;
}
/* ---------------------------------------------------------------------------
Function: void GAL_SetTimeStamp(int Time)
Purpose: All blocks alloced will be of this time stamp
--------------------------------------------------------------------------- */
int GAL_GetTimeStamp(void)
{
return TimeStamp;
}
/* ---------------------------------------------------------------------------
Function: S32 GAL_AlignSizeToType(U32 Size,U32 MemType)
Purpose: Align a size to the alignment specified by a mem type
Params: Size = Size to align
MemType = Mem type
Returns: Aligned size or -1 if an error
--------------------------------------------------------------------------- */
S32 GAL_AlignSizeToType(U32 Size,U32 MemType)
{
MEM_INIT_INFO * Mi;
MemType&=~GAL_FLAGS;
Mi=GetMemInitInfoBlockFromType(MemType);
if (Mi)
return(AlignSize(Size,Mi->Alignment));
else
return(-1);
}
/* ---------------------------------------------------------------------------
Function: MHANDLE GAL_AllocMultiStruct(GAL_STRUCT * G,U32 Type,const char *Name)
Purpose: Alloc a load of structures back to back all aligned to correct
boundaries for the mem type. Then store the offset into the mem
mem alloced for each struct back into the GAL_STRUC_ALLOC array.
The array should be terminated by an element with an original size
entry of -1. See TASKER.C TSK_AddTask for an example
Params: G -> Array of GAL_STRUC_ALLOC
Type = Mem to put it into
Name = Name of this block
Returns: HND to mem the mem if ok || NULL_HANDLE if not
--------------------------------------------------------------------------- */
MHANDLE GAL_AllocMultiStruct(GAL_STRUCT * G,U32 Type,const char *Name)
{
int TotalMem;
TotalMem=GAL_ProcessMultiStruct(G,Type&~GAL_FLAGS);
return(GAL_Alloc(TotalMem,Type,Name));
}
/* ---------------------------------------------------------------------------
Function: UINT GAL_ProcessMultiStruct(GAL_STRUCT * G,U32 Type)
Purpose: Works out the offsets for this multi struc in a particular mem
type and stores em back into the Offset stuff
Params: G -> Array of GAL_STRUC_ALLOC
Type = Mem to put it into
Returns: How big the alloced block would be
--------------------------------------------------------------------------- */
UINT GAL_ProcessMultiStruct(GAL_STRUCT * G,U32 Type)
{
UINT TotalMem;
int f;
Type&=~GAL_FLAGS;
TotalMem=0;
for (f=0;G[f].OriginalSize != -1;f++)
{
G[f].Offset=TotalMem;
TotalMem+=GAL_AlignSizeToType((UINT) G[f].OriginalSize,Type);
}
G[f].Offset=TotalMem;
return(TotalMem);
}
/* ---------------------------------------------------------------------------
Function: static BOOL GazDefragMem(U32 MemType)
Purpose: Defrag the memory of this mem type
Returns: If there was a problem or not
--------------------------------------------------------------------------- */
s32 GAL_GetSize(MHANDLE hnd)
{
MEM_HDR * MemHdr;
if (!IsActiveValidHandle(hnd))
{
GSetError(ERR_GAL_INVALID_MEM_HANDLE);
return -1;
}
MemHdr=&MemHdrBlocks[hnd];
return(MemHdr->Size);
}
/* ---------------------------------------------------------------------------
Function: static BOOL GazDefragMem(U32 MemType)
Purpose: Defrag the memory of this mem type
Returns: If there was a problem or not
--------------------------------------------------------------------------- */
static BOOL GazDefragMem(U32 MemType)
{
MEM_HDR * LockedBlocks;
MEM_INIT_INFO * M;
MEM_REG Reg;
MemType&=~GAL_FLAGS;
if (!(M=GetMemInitInfoBlockFromType(MemType)))
{
GSetError(ERR_GAL_INVALID_MEM_TYPE);
return (FALSE);
}
/* Only defrag if a memove defined in memory profile */
if (!M->MemMove)
{
GSetError(ERR_GAL_NO_MEM_MOVE);
return (FALSE);
}
/* Take all the locked blocks off the used list and chuck then onto our local list */
LockedBlocks=NULL;
PutAllLockedBlocksOntoList(&LockedBlocks,&M->Used);
/* Sort our brand new list by size */
/* Sort remaining used but unlocked blocks into addr order */
SortMemHdrListByAddr(&LockedBlocks);
/* Get Rid of all Empty blocks in MemType */
DeleteEmptyBlocks(M);
/* Now loop through sorted empty blocks */
Reg.Mem=NULL;
while (GetRegion(&Reg,LockedBlocks,M))
{
/* If there was a region and it has a size the do the business */
if (Reg.Size)
{
MEM_HDR * NewEmptyBlock;
MEM_HDR * ListOfBlocksInRegion;
U32 ShuffledSize;
int GapSize;
ListOfBlocksInRegion=NULL;
PutBlocksInRegionIntoList(&Reg,&ListOfBlocksInRegion,&M->Used);
SortMemHdrListByAddr(&ListOfBlocksInRegion);
ShuffledSize=ShuffleBlocks(ListOfBlocksInRegion,&Reg,M);
/* Create the empty block for the rest of the region */
GapSize=Reg.Size-ShuffledSize;
if (GapSize)
{
if (!(NewEmptyBlock=GetFreeMemHdrBlock()))
{
GSetError(ERR_RUN_OUT_OF_MEM_HDRS);
return FALSE;
}
NewEmptyBlock->Mem=(void *)((U32)Reg.Mem+ShuffledSize);
NewEmptyBlock->Size= GapSize;
NewEmptyBlock->Type=(u16)MemType;
/* And put it into the list */
MergeToEmptyList(M,NewEmptyBlock);
}
GraftMemHdrList(&M->Used,&ListOfBlocksInRegion);
}
}
/* Now add locked blocks back onto list */
PutAllLockedBlocksOntoList(&M->Used,&LockedBlocks);
return(TRUE);
}
/* ---------------------------------------------------------------------------
Function: void PutBlocksInRegionIntoList(MEM_REG *Reg,MEM_HDR **ToList,MEM_HDR **FromList)
Purpose: Go through From list and take out all the blocks in the
region and put it into ToList
Params: Reg -> Struct describing region
ToList -> Head of list to put them into
FromList -> Head of list to take them from
--------------------------------------------------------------------------- */
static void PutBlocksInRegionIntoList(MEM_REG *Reg,MEM_HDR **ToList,MEM_HDR **FromList)
{
MEM_HDR * ThisBlock;
ThisBlock=*FromList;
while (ThisBlock)
{
MEM_HDR * NextBlock;
MEM_REG MemReg;
NextBlock=ThisBlock->Next;
MemReg.Mem=ThisBlock->Mem;
MemReg.Size=ThisBlock->Size;
if (CollideRegions(Reg,&MemReg))
{
DetachHdrFromList(FromList,ThisBlock);
AttachHdrToList(ToList,ThisBlock);
}
ThisBlock=NextBlock;
}
}
/* ---------------------------------------------------------------------------
Function: BOOL CollideRegions(MEM_REG *Reg1,MEM_REG *Reg2)
Purpose: Do these regions collide
Params: Reg1 -> Region descriptor 1
Reg2 -> Region descriptor 2
Return: TRUE if so
--------------------------------------------------------------------------- */
static BOOL CollideRegions(MEM_REG *Reg1,MEM_REG *Reg2)
{
if (((U32) Reg1->Mem + Reg1->Size) <= (U32) Reg2->Mem)
return(FALSE);
if ((U32) Reg1->Mem >= ((U32) Reg2->Mem + Reg2->Size))
return(FALSE);
return(TRUE);
}
/* ---------------------------------------------------------------------------
Function: static void DeleteEmptyBlocks(MEM_INIT_INFO *M)
Purpose: Go through this mem type and delete all empty blocks
Params: M -> Information about this mem type
--------------------------------------------------------------------------- */
static void DeleteEmptyBlocks(MEM_INIT_INFO *M)
{
while (M->Empty)
{
MEM_HDR * ThisBlock;
ThisBlock=M->Empty;
DetachHdrFromList(&M->Empty,ThisBlock);
AttachHdrToList(&FreeBlocks,ThisBlock);
}
}
/* ---------------------------------------------------------------------------
Function: void BOOL GetRegion(MEM_REG *Reg,MEM_HDR * LockedBlocks,MEM_INIT_INFO *M)
Purpose: Find the next region of memory after Region that has no locked blocks
a new list
Params: Reg -> Description of previous region (If base is NULL will
from beggining
LockedBlocks -> List of locked blocks sorted by addr
M -> Information about this mem type
Returns: TRUE if there was another region and info about it in Reg
FALSE if not another region
--------------------------------------------------------------------------- */
static BOOL GetRegion(MEM_REG *Reg,MEM_HDR * LockedBlocks,MEM_INIT_INFO *M)
{
MEM_HDR * FirstBlock;
MEM_HDR * SecondBlock;
MEM_REG NewReg;
U32 FirstSize;
FirstBlock=FindNextBlock(Reg->Mem,LockedBlocks);
FirstSize=0;
if (FirstBlock)
NewReg.Mem=(void *)((U32)FirstBlock->Mem+FirstBlock->Size);
else
{
if (Reg->Mem)
return(FALSE);
else
NewReg.Mem=M->Mem;
}
SecondBlock=FindNextBlock(NewReg.Mem,LockedBlocks);
if (SecondBlock)
NewReg.Size=(U32) SecondBlock->Mem - (U32) NewReg.Mem;
else
NewReg.Size=(U32) M->Mem +M->Size - (U32) NewReg.Mem;
if (CollideRegions(Reg,&NewReg) && Reg->Mem)
return(FALSE);
else
{
Reg->Mem=NewReg.Mem;
Reg->Size=NewReg.Size;
return(TRUE);
}
}
/* ---------------------------------------------------------------------------
Function: static MEM_HDR *FindStartBlock(void *Addr,MEM_HDR * Blocks)
Purpose: Find the first block in this list that Sits addres this addr
Params: Addr = addr to look from
Blocks -> List of blocks to look in
Returns: -> Block || Null if none
--------------------------------------------------------------------------- */
/*
static MEM_HDR *FindStartBlock(void *Addr,MEM_HDR * Blocks)
{
while (Blocks)
{
if (Blocks->Mem==Addr)
return(Blocks);
else
Blocks=Blocks->Next;
}
return(NULL);
}
*/
/* ---------------------------------------------------------------------------
Function: static MEM_HDR *FindNextBlock(void *Addr,MEM_HDR * Blocks)
Purpose: Find the first block that is at >= Addr
Params: Addr = addr to look from
Blocks -> List of blocks to look in
Returns: -> Block || Null if none
--------------------------------------------------------------------------- */
static MEM_HDR *FindNextBlock(void *Addr,MEM_HDR * Blocks)
{
if (Addr)
{
while (Blocks)
{
U32 BlockAddr;
U32 AddrU32;
AddrU32=(U32) Addr;
BlockAddr=(U32) Blocks->Mem;
if (BlockAddr >= AddrU32)
return(Blocks);
else
Blocks=Blocks->Next;
}
}
return(NULL);
}
/* ---------------------------------------------------------------------------
Function: static U32 ShuffleBlocks(MEM_HDR *Blocks,MEM_REG *Reg,MEM_INIT_INFO *M)
Purpose: Compact a linked list of sorted by addr blocks in mem
Params: Blocks -> First in list of blocks
Reg -> Region the blocks should compact themselves in
M -> Description of mem region
Returns: Size all blocks take up in memory
--------------------------------------------------------------------------- */
static U32 ShuffleBlocks(MEM_HDR *Blocks,MEM_REG *Reg,MEM_INIT_INFO *M)
{
U32 NewSize;
void * MemBase;
MEM_HDR * ThisBlock;
NewSize=0;
MemBase=Reg->Mem;
ThisBlock=Blocks;
while (ThisBlock)
{
NewSize+=ThisBlock->Size;
if (MemBase != ThisBlock->Mem)
{
M->MemMove(MemBase,ThisBlock->Mem,ThisBlock->Size);
ThisBlock->Mem=MemBase;
}
MemBase=(void *)((U32) ThisBlock->Mem+ThisBlock->Size);
ThisBlock=ThisBlock->Next;
}
return(NewSize);
}
/* ---------------------------------------------------------------------------
Function: void PutAllLockedBlocksOntoList(MEM_HDR **ToHead,MEM_HDR **FromHead)
Purpose: Take all the locked blocks from a list and chuck them onto
a new list
Params: ToHead -> Head of list to put stuff onto
FromHead -> Head of list to take blocks off
--------------------------------------------------------------------------- */
static void PutAllLockedBlocksOntoList(MEM_HDR **ToHead,MEM_HDR **FromHead)
{
MEM_HDR * CurHdr;
CurHdr = *FromHead;
while (CurHdr)
{
MEM_HDR * NextCurHdr;
NextCurHdr=CurHdr->Next;
if (CurHdr->Owners)
{
DetachHdrFromList(FromHead,CurHdr);
AttachHdrToList(ToHead,CurHdr);
}
CurHdr=NextCurHdr;
}
}
/* ---------------------------------------------------------------------------
Function: void SortMemHdrListByAddr(MEM_HDR **Head)
Purpose: Sort all the memhdr blocks in a list in descending
order by base Address and yes, it's a bubble sort
Params: Head -> Head of list to sort
--------------------------------------------------------------------------- */
void SortMemHdrListByAddr(MEM_HDR **Head)
{
BOOL DidASwap;
MEM_HDR * CurHdr;
MEM_HDR * NextHdr;
if (*Head && (*Head)->Next)
{
do
{
DidASwap=FALSE;
CurHdr=*Head;
do
{
NextHdr=CurHdr->Next;
if ((U32) CurHdr->Mem > (U32) NextHdr->Mem)
{
MEM_HDR * OldPrev;
OldPrev=CurHdr->Prev;
/* Swap them in the link list */
CurHdr->Next = NextHdr->Next;
CurHdr->Prev = NextHdr;
NextHdr->Next= CurHdr;
if (CurHdr->Next)
CurHdr->Next->Prev=CurHdr;
NextHdr->Next=CurHdr;
NextHdr->Prev=OldPrev;
if (NextHdr->Prev)
NextHdr->Prev->Next=NextHdr;
else
*Head=NextHdr;
DidASwap=TRUE;
}
else
CurHdr=CurHdr->Next;
}
while(CurHdr->Next);
}
while(DidASwap);
}
}
/* ---------------------------------------------------------------------------
Function: void GraftMemHdrList(MEM_HDR ** ToList,MEM_HDR ** FromList)
Purpose: Graft one list to another
Params: ToList -> Head of list to graft to
FromList -> Head of list to graft
--------------------------------------------------------------------------- */
static void GraftMemHdrList(MEM_HDR ** ToList,MEM_HDR ** FromList)
{
MEM_HDR * OldFirst;
OldFirst=*ToList;
if (*FromList)
{
MEM_HDR * LastHdr;
*ToList=*FromList;
LastHdr=*FromList;
while (LastHdr->Next)
LastHdr=LastHdr->Next;
LastHdr->Next=OldFirst;
if (OldFirst)
OldFirst->Prev=LastHdr;
*FromList=NULL;
}
}
/* ---------------------------------------------------------------------------
Function: void GAL_MemDump(U32 Type)
Purpose: Do a dump of this type to the debug messager
Params: Type = type to dump
--------------------------------------------------------------------------- */
void GAL_MemDump(U32 Type)
{
Type&=~GAL_FLAGS;
DBG_SendMessage("%d : mem left",(int)GAL_GetFreeMem(Type));
DBG_SendMessage("%d : largest block",(int)GAL_GetFreeMem(Type));
DBG_SendMessage("%d : Last attempted alloc",(int)LastAttemptedAlloc);
}
/* ---------------------------------------------------------------------------
Function: void GAL_SetVerbosity(GAL_VERB_LEV G)
Purpose: Say how noisy gal should be
Params: Type = type to dump
--------------------------------------------------------------------------- */
void GAL_SetVerbosity(GAL_VERB_LEV G)
{
VerbLev=G;
}
/* ---------------------------------------------------------------------------
Function: void GAL_SetVerbosity(GAL_VERB_LEV G)
Purpose: Say how noisy gal should be
Params: Type = type to dump
--------------------------------------------------------------------------- */
int CountFreeBlocks(void)
{
MEM_HDR * RetBlock;
int Count;
RetBlock=FreeBlocks;
Count=0;
while (RetBlock)
{
Count++;
RetBlock=RetBlock->Next;
}
return(Count);
}
/* ---------------------------------------------------------------------------
Function: void SetBlockName(MEM_HDR * MemHdr,const char * NewName)
Purpose: Set the name of this block
Params: MemHdr - > Block to set name of
NewName -> New name of block
--------------------------------------------------------------------------- */
void SetBlockName(MEM_HDR * MemHdr,const char * NewName)
{
#ifdef __GL_DEBUG__
int IndexSoFar;
IndexSoFar=0;
if (NewName)
{
while ((IndexSoFar != MAX_NAME_SIZE-1) && *NewName)
MemHdr->Name[IndexSoFar++]=*NewName++;
}
MemHdr->Name[IndexSoFar]=0;
#endif
}
/* ---------------------------------------------------------------------------
Function: void SetBlockName(MEM_HDR * MemHdr,const char * NewName)
Purpose: Set the name of this block
Params: MemHdr - > Block to set name of
NewName -> New name of block
--------------------------------------------------------------------------- */
char const * GetBlockName(MEM_HDR * MemHdr)
{
#ifdef __GL_DEBUG__
return(MemHdr->Name);
#else
return("NO NAME");
#endif
}
/* ---------------------------------------------------------------------------
Function: int GAL_GetNumFreeHeaders(void)
Purpose: Find out how many more free hdrs there are
Returns: Info we want
--------------------------------------------------------------------------- */
int GAL_GetNumFreeHeaders(void)
{
return(NumOfFreeHdrs);
}
u32 GAL_GetLastTypeAlloced(void)
{
return(LastTypeAlloced);
}
/* ---------------------------------------------------------------------------
Function: int GAL_GetAlignment(u32 MemType)
Purpose: Get the allocation boundary alignment for this memory type
Returns: Info we want or -1 if an error
--------------------------------------------------------------------------- */
u32 GAL_GetAlignment(u32 MemType)
{
MEM_INIT_INFO * M;
if (!(M=GetMemInitInfoBlockFromType(MemType)))
{
GSetError(ERR_GAL_INVALID_MEM_TYPE);
return -1;
}
else
return(M->Alignment);
}
/* ---------------------------------------------------------------------------
Function: void GAL_HaltOnError(void)
Purpose: Say that gal will halt on an error
--------------------------------------------------------------------------- */
void GAL_HaltOnError(void)
{
HaltOnError=TRUE;
}
/* ---------------------------------------------------------------------------
Function: int GAL_GetAlignment(u32 MemType)
Purpose: Say that gal WONT will halt on an error (Default behaviour)
--------------------------------------------------------------------------- */
void GAL_ReturnOnError(void)
{
HaltOnError=FALSE;
}
/* ---------------------------------------------------------------------------
Function: GAL_FILTER GAL_SetAllocFilter(GAL_FILTER NewFilter)
Purpose: Set a callback to be executed b4 every alloc
Params: NewFilter -> Filter func (NULL means no filtering)
Returns: Old filter
--------------------------------------------------------------------------- */
GAL_FILTER GAL_SetAllocFilter(GAL_FILTER NewFilter)
{
GAL_FILTER OldFilter;
OldFilter=AllocFilter;
AllocFilter=NewFilter;
return(OldFilter);
}
/* ---------------------------------------------------------------------------
Function: void GAL_SortUsedRegionsBySize(U32 Type)
Purpose: Sort the order of the used regions by size (descending)
Params: MemType=type of mem to sort
--------------------------------------------------------------------------- */
GLIB_API BOOL GAL_SortUsedRegionsBySize(U32 MemType)
{
MEM_INIT_INFO * M;
MemType&=~GAL_FLAGS;
if (!(M=GetMemInitInfoBlockFromType(MemType)))
{
GSetError(ERR_GAL_INVALID_MEM_TYPE);
return (FALSE);
}
SortMemHdrList(&M->Used,SortSize);
return(TRUE);
}
BOOL SortSize(MEM_HDR *B1,MEM_HDR * B2)
{
if (B1->Size<B2->Size)
return(TRUE);
else
return(FALSE);
}
/* ---------------------------------------------------------------------------
Function: void GAL_SortUsedRegionsBySize(U32 Type)
Purpose: Sort the order of the used regions by size (descending)
Params: MemType=type of mem to sort
--------------------------------------------------------------------------- */
GLIB_API BOOL GAL_SortUsedRegionsByAddress(U32 MemType)
{
MEM_INIT_INFO * M;
MemType&=~GAL_FLAGS;
if (!(M=GetMemInitInfoBlockFromType(MemType)))
{
GSetError(ERR_GAL_INVALID_MEM_TYPE);
return (FALSE);
}
SortMemHdrList(&M->Used,SortAddr);
return(TRUE);
}
BOOL SortAddr(MEM_HDR *B1,MEM_HDR * B2)
{
if ((u32)B1->Mem<(u32)B2->Mem)
return(TRUE);
else
return(FALSE);
}
/* ---------------------------------------------------------------------------
Function: void SortMemHdrList(MEM_HDR **Head,bool (*CompFunc)(MEM_HDR *B1,MEM_HDR * B2))
Purpose: Sort a list of memhdr blocks
Params: Head->-> Head of list to be sorted
CompFunc Should I swap routine
--------------------------------------------------------------------------- */
void SortMemHdrList(MEM_HDR **Head,BOOL (*CompFunc)(MEM_HDR *B1,MEM_HDR * B2))
{
BOOL DidASwap;
MEM_HDR * CurHdr;
MEM_HDR * NextHdr;
if (*Head && (*Head)->Next)
{
do
{
DidASwap=FALSE;
CurHdr=*Head;
do
{
NextHdr=CurHdr->Next;
if (CompFunc(CurHdr,NextHdr))
{
MEM_HDR * OldPrev;
OldPrev=CurHdr->Prev;
/* Swap them in the link list */
CurHdr->Next = NextHdr->Next;
CurHdr->Prev = NextHdr;
NextHdr->Next= CurHdr;
if (CurHdr->Next)
CurHdr->Next->Prev=CurHdr;
NextHdr->Next=CurHdr;
NextHdr->Prev=OldPrev;
if (NextHdr->Prev)
NextHdr->Prev->Next=NextHdr;
else
*Head=NextHdr;
DidASwap=TRUE;
}
else
CurHdr=CurHdr->Next;
}
while(CurHdr->Next);
}
while(DidASwap);
}
}
/* ---------------------------------------------------------------------------
ends
---- */