/* ********************************************************************************************************* * uC/GUI * Universal graphic software for embedded applications * * (c) Copyright 2002, Micrium Inc., Weston, FL * (c) Copyright 2002, SEGGER Microcontroller Systeme GmbH * * µC/GUI is protected by international copyright laws. Knowledge of the * source code may not be used to write a similar product. This file may * only be used in accordance with a license and should not be redistributed * in any way. We appreciate your understanding and fairness. * ---------------------------------------------------------------------- File : GUIAlloc.C Purpose : Dynamic memory management ---------------------------------------------------------------------- */ #include /* needed for definition of NULL */ #include /* for memcpy, memset */ #include "GUI_Protected.h" #include "GUIDebug.h" /********************************************************************* * * Internal memory management * ********************************************************************** */ #ifndef GUI_ALLOC_ALLOC #if GUI_ALLOC_SIZE==0 #error GUI_ALLOC_SIZE needs to be > 0 when using this module #endif /********************************************************************* * * Defines, config defaults * ********************************************************************** */ /* Permit automatic defragmentation when necessary */ #ifndef GUI_ALLOC_AUTDEFRAG #define GUI_ALLOC_AUTDEFRAG 1 #endif #ifndef GUI_BLOCK_ALIGN /* 2 means 4 bytes, 1 means 2 bytes */ #define GUI_BLOCK_ALIGN 2 /* 1 can be used on 16-bit CPUs and CPUs */ #endif /* which do not require aligned 32-bit */ /* values (such as x86) */ #ifndef GUI_MAXBLOCKS #define GUI_MAXBLOCKS (2 + GUI_ALLOC_SIZE / 32) #endif #ifndef GUI_ALLOC_LOCATION #define GUI_ALLOC_LOCATION #endif #ifndef GUI_MEM_ALLOC /* Allows us in some systems to place the GUI memory */ #define GUI_MEM_ALLOC /* in a different memory space ... eg "__far" */ #endif /********************************************************************* * * Defines * ********************************************************************** */ #define Min(v0,v1) ((v0>v1) ? v1 : v0) #define Max(v0,v1) ((v0>v1) ? v0 : v1) #define ASSIGN_IF_LESS(v0,v1) if (v1= 256 #define HANDLE U16 #else #define HANDLE U8 #endif /********************************************************************* * * Types * ********************************************************************** */ typedef union { int aintHeap[GUI_ALLOC_SIZE / 4]; /* required for proper alignement */ U8 abHeap[GUI_ALLOC_SIZE]; } GUI_HEAP; typedef struct { GUI_ALLOC_DATATYPE Off; /* Offset of memory area */ GUI_ALLOC_DATATYPE Size; /* usable size of allocated block */ HANDLE Next; /* next handle in linked list */ HANDLE Prev; } tBlock; /********************************************************************* * * Static data * ********************************************************************** */ GUI_MEM_ALLOC GUI_HEAP GUI_Heap GUI_ALLOC_LOCATION; /* Public for debugging only */ static tBlock aBlock[GUI_MAXBLOCKS]; struct { int NumUsedBlocks, NumFreeBlocks, NumFreeBlocksMin; /* For statistical purposes only */ GUI_ALLOC_DATATYPE NumUsedBytes, NumFreeBytes, NumFreeBytesMin; } GUI_ALLOC; static char IsInitialized =0; /********************************************************************* * * Static code * ********************************************************************** */ /********************************************************************* * * _Size2LegalSize * * Return value: * Legal allocation size */ static GUI_ALLOC_DATATYPE _Size2LegalSize(GUI_ALLOC_DATATYPE size) { return (size + ((1 << GUI_BLOCK_ALIGN) - 1)) & ~((1 << GUI_BLOCK_ALIGN) - 1); } /********************************************************************* * * _GetSize */ static GUI_ALLOC_DATATYPE _GetSize(GUI_HMEM hMem) { return aBlock[hMem].Size; } /********************************************************************* * * _Free */ static void _Free(GUI_HMEM hMem) { GUI_ALLOC_DATATYPE Size; GUI_DEBUG_LOG1("\nGUI_ALLOC_Free(%d)", hMem); /* Do some error checking ... */ #if GUI_DEBUG_LEVEL>0 /* Block not allocated ? */ if (aBlock[hMem].Size == 0) { GUI_DEBUG_ERROROUT("GUI_ALLOC_Free(): Invalid hMem"); return; } #endif Size = aBlock[hMem].Size; #ifdef WIN32 GUI_MEMSET(&GUI_Heap.abHeap[aBlock[hMem].Off], 0xcc, Size); #endif GUI_ALLOC.NumFreeBytes += Size; GUI_ALLOC.NumUsedBytes -= Size; aBlock[hMem].Size = 0; { int Next = aBlock[hMem].Next; int Prev = aBlock[hMem].Prev; aBlock[Prev].Next = Next; if (Next) { aBlock[Next].Prev = Prev; } } GUI_ALLOC.NumFreeBlocks++; GUI_ALLOC.NumUsedBlocks--; } /********************************************************************* * * _FindFreeHandle * * Return value: * Free handle */ static GUI_HMEM _FindFreeHandle(void) { int i; for (i=1; i< GUI_MAXBLOCKS; i++) { if (aBlock[i].Size ==0) return i; } GUI_DEBUG_ERROROUT1("Insufficient memory handles configured (GUI_MAXBLOCKS == %d (See GUIConf.h))", GUI_MAXBLOCKS); return GUI_HMEM_NULL; } /********************************************************************* * * _FindHole * * Return value: * Offset to the memory hole (if available) * -1 if not available */ static GUI_HMEM _FindHole(GUI_ALLOC_DATATYPE Size) { int i, iNext; for (i=0; (iNext = aBlock[i].Next) != 0; i = iNext) { int NumFreeBytes = aBlock[iNext].Off- (aBlock[i].Off+aBlock[i].Size); if (NumFreeBytes>=Size) { return i; } } /* Check last block */ if (GUI_ALLOC_SIZE - (aBlock[i].Off+aBlock[i].Size) >= Size) { return i; } return -1; } /********************************************************************* * * _CreateHole * * Return value: * Offset to the memory hole (if available) * -1 if not available */ static GUI_HMEM _CreateHole(GUI_ALLOC_DATATYPE Size) { int i, iNext; int r = -1; for (i=0; (iNext =aBlock[i].Next) !=0; i= iNext) { GUI_ALLOC_DATATYPE NumFreeBytes = aBlock[iNext].Off- (aBlock[i].Off+aBlock[i].Size); if (NumFreeBytes < Size) { GUI_ALLOC_DATATYPE NumBytesBeforeBlock = aBlock[iNext].Off - (aBlock[i].Off+aBlock[i].Size); if (NumBytesBeforeBlock) { U8* pData = &GUI_Heap.abHeap[aBlock[iNext].Off]; memmove(pData-NumBytesBeforeBlock, pData, aBlock[iNext].Size); aBlock[iNext].Off -=NumBytesBeforeBlock; } } } /* Check last block */ if (GUI_ALLOC_SIZE - (aBlock[i].Off+aBlock[i].Size) >= Size) { r = i; } return r; } /********************************************************************* * * _CheckInit */ static void _CheckInit(void) { if (!IsInitialized) { GUI_ALLOC_Init(); } } /********************************************************************* * * _Alloc */ static GUI_HMEM _Alloc(GUI_ALLOC_DATATYPE size) { GUI_HMEM hMemNew, hMemIns; _CheckInit(); size = _Size2LegalSize(size); /* Check if memory is available at all ...*/ if (size > GUI_ALLOC.NumFreeBytes) { GUI_DEBUG_WARN1("GUI_ALLOC_Alloc: Insufficient memory configured (Trying to alloc % bytes)", size); return 0; } /* Locate free handle */ if ((hMemNew = _FindFreeHandle()) == 0) return 0; /* Locate or Create hole of sufficient size */ hMemIns = _FindHole(size); #if GUI_ALLOC_AUTDEFRAG if (hMemIns == -1) { hMemIns = _CreateHole(size); } #endif /* Occupy hole */ if (hMemIns==-1) { GUI_DEBUG_ERROROUT1("GUI_ALLOC_Alloc: Could not allocate %d bytes",size); return 0; } { GUI_ALLOC_DATATYPE Off = aBlock[hMemIns].Off + aBlock[hMemIns].Size; int Next = aBlock[hMemIns].Next; aBlock[hMemNew].Size = size; aBlock[hMemNew].Off = Off; if ((aBlock[hMemNew].Next = Next) >0) { aBlock[Next].Prev = hMemNew; } aBlock[hMemNew].Prev = hMemIns; aBlock[hMemIns].Next = hMemNew; } /* Keep track of number of blocks and av. memory */ GUI_ALLOC.NumUsedBlocks++; GUI_ALLOC.NumFreeBlocks--; if (GUI_ALLOC.NumFreeBlocksMin > GUI_ALLOC.NumFreeBlocks) { GUI_ALLOC.NumFreeBlocksMin = GUI_ALLOC.NumFreeBlocks; } GUI_ALLOC.NumUsedBytes += size; GUI_ALLOC.NumFreeBytes -= size; if (GUI_ALLOC.NumFreeBytesMin > GUI_ALLOC.NumFreeBytes) { GUI_ALLOC.NumFreeBytesMin = GUI_ALLOC.NumFreeBytes; } return hMemNew; } /********************************************************************* * * Exported routines * ********************************************************************** */ /********************************************************************* * * GUI_ALLOC_Init */ void GUI_ALLOC_Init(void) { GUI_DEBUG_LOG("\nGUI_ALLOC_Init..."); GUI_ALLOC.NumFreeBlocksMin = GUI_ALLOC.NumFreeBlocks = GUI_MAXBLOCKS-1; GUI_ALLOC.NumFreeBytesMin = GUI_ALLOC.NumFreeBytes = GUI_ALLOC_SIZE; GUI_ALLOC.NumUsedBlocks = 0; GUI_ALLOC.NumUsedBytes = 0; aBlock[0].Size = (1< 0 if (!hMem) { GUI_DEBUG_ERROROUT("\n"__FILE__ " GUI_ALLOC_h2p: illegal argument (0 handle)"); return 0; } if (aBlock[hMem].Size == 0) { GUI_DEBUG_ERROROUT("Dereferencing free block"); } #endif return HMEM2PTR(hMem); } /********************************************************************* * * GUI_ALLOC_GetNumFreeBytes */ GUI_ALLOC_DATATYPE GUI_ALLOC_GetNumFreeBytes(void) { _CheckInit(); return GUI_ALLOC.NumFreeBytes; } /********************************************************************* * * GUI_ALLOC_GetMaxSize * * Purpose: * Returns the biggest available blocksize (without relocation). */ GUI_ALLOC_DATATYPE GUI_ALLOC_GetMaxSize(void) { GUI_ALLOC_DATATYPE r = 0; GUI_ALLOC_DATATYPE NumFreeBytes; int i, iNext; GUI_LOCK(); _CheckInit(); for (i=0; (iNext =aBlock[i].Next) !=0; i= iNext) { NumFreeBytes = aBlock[iNext].Off- (aBlock[i].Off+aBlock[i].Size); if (NumFreeBytes > r) { r = NumFreeBytes; } } /* Check last block */ NumFreeBytes = (GUI_ALLOC_SIZE - (aBlock[i].Off+aBlock[i].Size)); if (NumFreeBytes > r) { r = NumFreeBytes; } GUI_UNLOCK(); return r; } #else /********************************************************************* * * External memory management functions * * The functions below will generate code only if the GUI memory * management is not used (GUI_ALLOC_ALLOC defined). * * Note: * The memory block allocated is bigger than the requested one, as we * store some add. information (size of the memory block) there. * ********************************************************************** */ typedef struct { union { GUI_ALLOC_DATATYPE Size; int Dummy; /* Needed to guarantee alignment on 32 / 64 bit CPUs */ } Info; /* Unnamed would be best, but is not supported by all compilers */ } INFO; /********************************************************************* * * _GetSize */ static GUI_ALLOC_DATATYPE _GetSize(GUI_HMEM hMem) { INFO * pInfo; pInfo = (INFO *)GUI_ALLOC_H2P(hMem); return pInfo->Info.Size; } /********************************************************************* * * _Free */ static void _Free(GUI_HMEM hMem) { GUI_ALLOC_FREE(hMem); } /********************************************************************* * * GUI_ALLOC_AllocNoInit */ GUI_HMEM GUI_ALLOC_AllocNoInit(GUI_ALLOC_DATATYPE Size) { GUI_HMEM hMem; if (Size == 0) { return (GUI_HMEM)0; } hMem= GUI_ALLOC_ALLOC(Size + sizeof(INFO)); /* Init info structure */ if (hMem) { INFO * pInfo; pInfo = (INFO *)GUI_ALLOC_H2P(hMem); pInfo->Info.Size = Size; } return hMem; } /********************************************************************* * * GUI_ALLOC_h2p */ void* GUI_ALLOC_h2p(GUI_HMEM hMem) { U8* p = (U8*)GUI_ALLOC_H2P(hMem); /* Pointer to memory block from memory manager */ p += sizeof(INFO); /* Convert to pointer to usable area */ return p; } /********************************************************************* * * GUI_ALLOC_GetMaxSize */ GUI_ALLOC_DATATYPE GUI_ALLOC_GetMaxSize(void) { return GUI_ALLOC_GETMAXSIZE(); } /********************************************************************* * * GUI_ALLOC_Init */ void GUI_ALLOC_Init(void) { #ifdef GUI_ALLOC_INIT GUI_ALLOC_INIT(); #endif } #endif /********************************************************************* * * Public code, common memory management functions * ********************************************************************** */ /********************************************************************* * * GUI_ALLOC_GetSize */ GUI_ALLOC_DATATYPE GUI_ALLOC_GetSize(GUI_HMEM hMem) { /* Do the error checking first */ #if GUI_DEBUG_LEVEL>0 if (!hMem) { GUI_DEBUG_ERROROUT("\n"__FILE__ " GUI_ALLOC_h2p: illegal argument (0 handle)"); return 0; } #endif return _GetSize(hMem); } /********************************************************************* * * GUI_ALLOC_Free */ void GUI_ALLOC_Free(GUI_HMEM hMem) { if (hMem == GUI_HMEM_NULL) { /* Note: This is not an error, it is permitted */ return; } GUI_LOCK(); GUI_DEBUG_LOG1("\nGUI_ALLOC_Free(%d)", hMem); _Free(hMem); GUI_UNLOCK(); } /********************************************************************* * * GUI_ALLOC_FreePtr */ void GUI_ALLOC_FreePtr(GUI_HMEM *ph) { GUI_LOCK(); GUI_ALLOC_Free(*ph); *ph =0; GUI_UNLOCK(); } /*************************** End of file ****************************/