www.pudn.com > ucosv2(GUI).rar > GUIAlloc.c


/*
*********************************************************************************************************
*                                                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     : emWin dynamic memory management 
---------------------------------------------------------------------- 
Version-Date---Author-Explanation 
---------------------------------------------------------------------- 
1.00    000107 RS     First version 
---------------------------------------------------------------------- 
Known problems: 
None. 
---------------------------------------------------------------------- 
Open issues: 
None. 
---------------------------------------------------------------------- 
Todo: 
Nothing. 
 
*/ 
 
 
#include            /* needed for definition of NULL */ 
#include            /* for memcpy, memset */ 
 
#include "GUI_Protected.H" 
#include "GUIDebug.h" 
 
#if GUI_ALLOC_SIZE==0 
  #error GUI_ALLOC_SIZE needs to be > 0 when using this module 
#endif 
/* 
  ***************************************************************** 
  * 
  *              Config defaults 
  * 
  ***************************************************************** 
*/ 
 
/* Permit automatic defragmentation when necessary */ 
#ifndef GUI_ALLOC_AUTDEFRAG 
  #define GUI_ALLOC_AUTDEFRAG 1 
#endif 
 
#ifndef GUI_BLOCK_ALIGN 
  #define GUI_BLOCK_ALIGN 2    /* 2 means 4 bytes, 1 means 2 bytes */ 
                              /* 1 can be used on 16-bit CPUs and 
                                 CPUs which do not require aligned 
                                 32-bit values (such as x86) */  
#endif 
 
#ifndef GUI_MAXBLOCKS 
  #define GUI_MAXBLOCKS (2+GUI_ALLOC_SIZE/32) 
#endif 
 
 
/* 
  ***************************************************************** 
  * 
  *              Internal types and declarations 
  * 
  ***************************************************************** 
*/ 
#if GUI_ALLOC_SIZE <32767 
  #define tALLOCINT I16 
#else 
  #define tALLOCINT I32 
#endif 
 
#if GUI_MAXBLOCKS >= 256 
  #define HANDLE U16 
#else 
  #define HANDLE U8 
#endif 
 
 
 
 
typedef struct { 
  tALLOCINT Off;       /* Offset of memory area */ 
  tALLOCINT Size;      /* usable size of allocated block */ 
  HANDLE Next;      /* next handle in linked list */ 
  HANDLE Prev; 
} tBlock; 
 
/**************************************************************** 
* 
*              Static data 
* 
***************************************************************** 
*/ 
 
GUI_HEAP GUI_Heap;       /* Public for debugging only */ 
static tBlock aBlock[GUI_MAXBLOCKS]; 
 
struct { 
  int       NumUsedBlocks, NumFreeBlocks, NumFreeBlocksMin;        /* For statistical purposes only */ 
  tALLOCINT NumUsedBytes,  NumFreeBytes,  NumFreeBytesMin; 
} GUI_ALLOC; 
 
static char   IsInitialized =0; 
 
/* 
  ******************************************************************** 
  * 
  *                 Macros for internal use 
  * 
  ******************************************************************** 
*/ 
 
#define Min(v0,v1) ((v0>v1) ? v1 : v0) 
#define Max(v0,v1) ((v0>v1) ? v0 : v1) 
#define ASSIGN_IF_LESS(v0,v1) if (v1=Size) 
      return i; 
  } 
/* Check last block */ 
  if (GUI_ALLOC_SIZE - (aBlock[i].Off+aBlock[i].Size) >= Size) 
    return i; 
  return -1; 
} 
 
/* 
  ************************************************* 
  * 
  *             Create hole in heap area 
  * 
  ************************************************* 
 
  returns: Offset to the memory hole (if available) 
           -1 if not available 
*/ 
static GUI_HMEM CreateHole(int Size) { 
  int i, iNext; 
  int r = -1; 
  for (i=0; (iNext =aBlock[i].Next) !=0; i= iNext) { 
    int NumFreeBytes = aBlock[iNext].Off- (aBlock[i].Off+aBlock[i].Size); 
    if (NumFreeBytes < Size) { 
      int 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; 
} 
 
static void CheckInit(void) { 
  if (!IsInitialized) 
    GUI_ALLOC_Init(); 
} 
 
/* 
  ******************************************************************** 
  * 
  *                  Exported routines 
  * 
  ******************************************************************** 
*/ 
 
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< 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; 
	} 
  { 
    int 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; 
  } 
/* In order to be on the safe side, zeroinit ! */ 
  memset(HMEM2PTR(hMemNew), 0, size); 
  return hMemNew; 
} 
 
GUI_HMEM GUI_ALLOC_Alloc(int size) { 
  GUI_HMEM hMem; 
 /* First make sure that init has been called */ 
  GUI_LOCK(); 
  GUI_DEBUG_LOG2("\nGUI_ALLOC_Alloc... requesting %d, %d avail", size, GUI_ALLOC.NumFreeBytes); 
  hMem = _Alloc(size); 
  GUI_DEBUG_LOG1("\nGUI_ALLOC_Alloc : Handle", hMem); 
  GUI_UNLOCK(); 
  return hMem; 
} 
 
void GUI_ALLOC_Free(GUI_HMEM hMem) { 
  int Size; 
  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); 
  /* 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 
    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--; 
  GUI_UNLOCK(); 
} 
 
void*       GUI_ALLOC_h2p   (GUI_HMEM  hMem) { 
  #if GUI_DEBUG_LEVEL>0 
    if (!hMem) { 
      GUI_DEBUG_ERROROUT("\n"__FILE__ " GUI_ALLOC_h2p: illegal argument (0 handle)"); 
      return 0; 
    } 
  #endif 
  return HMEM2PTR(hMem); 
} 
 
void GUI_ALLOC_FreePtr(GUI_HMEM *ph) { 
  GUI_LOCK(); 
  GUI_ALLOC_Free(*ph); 
  *ph =0; 
  GUI_UNLOCK(); 
} 
 
/* 
  ******************************************************************** 
  * 
  *                  Exported info routines 
  * 
  ******************************************************************** 
*/ 
 
int GUI_GetUsedMem(void) { 
  int NumUsedBytes=0; 
  int i; 
  GUI_LOCK(); 
  CheckInit(); 
  for (i=1; i; i = aBlock[i].Next) { 
    NumUsedBytes += aBlock[i].Size; 
  } 
  GUI_UNLOCK(); 
  return NumUsedBytes; 
} 
 
 
int GUI_ALLOC_GetNumFreeBytes(void) { 
  CheckInit(); 
  return GUI_ALLOC.NumFreeBytes;   
} 
/* 
  ************************************************* 
  * 
  *       GetMaxSize 
  * 
  ************************************************* 
 
  Returns the biggest available blocksize 
  (without relocation) 
 
*/ 
int GUI_ALLOC_GetMaxSize(void) { 
  int r=0; 
  int 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; 
}