www.pudn.com > MessageQueue.zip > memmgr.c
/*
Copyright (C) 2004 Liu Ge
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "memmgr.h"
#define MEM_CONTROL_BLOCK_USED 'US'
#define MEM_CONTROL_BLOCK_UNUSED 'UN'
#define memset( p, c, n )
typedef struct St_MemControlBlock
{
struct St_MemControlBlock * pNext;
unsigned nLimit;
unsigned uSignature;
}St_MemControlBlock;
typedef St_MemControlBlock * P_MemControlBlock;
static P_MemControlBlock s_pFirst;
static P_MemControlBlock s_pTop;
static unsigned s_nAvailMem;
static unsigned s_nUsedMem;
void MemHeap_Init( unsigned char * pBase, unsigned nLimit )
{
P_MemControlBlock pFirst = (P_MemControlBlock)pBase;
#ifndef NDEBUG
memset( pBase, DEBUG_GARBAGE_BYTE, nLimit );
#endif
s_pFirst = pFirst;
s_pTop = pFirst;
s_nAvailMem = nLimit - sizeof(St_MemControlBlock);
s_nUsedMem = 0;
// Initialize the first memory control block
pFirst->pNext = NULL;
pFirst->nLimit = nLimit - sizeof(St_MemControlBlock);
pFirst->uSignature = MEM_CONTROL_BLOCK_UNUSED;
}
void * malloc( unsigned nSize )
{
P_MemControlBlock pTop = s_pTop;
unsigned nAvailOnTop = 0;
P_MemControlBlock p;
unsigned nSizeOfAllocated;
if( nSize == 0 )
{
return NULL;
}
nSizeOfAllocated = nSize + sizeof(St_MemControlBlock);
if( pTop->nLimit > sizeof(St_MemControlBlock) )
{
nAvailOnTop = pTop->nLimit - sizeof(St_MemControlBlock);
}
if( nSize <= nAvailOnTop )
{
PBYTE pBase = (PBYTE)(pTop + 1);
P_MemControlBlock pNext = (P_MemControlBlock)(pBase + nSize);
// Split a memory block
ASSERT( s_nAvailMem >= nSizeOfAllocated );
pNext->pNext = pTop->pNext;
pNext->nLimit = nAvailOnTop - nSize;
pNext->uSignature = MEM_CONTROL_BLOCK_UNUSED;
pTop->pNext = pNext;
pTop->uSignature = MEM_CONTROL_BLOCK_USED;
pTop->nLimit = nSize;
s_pTop = pNext;
s_nAvailMem -= nSizeOfAllocated;
s_nUsedMem += nSizeOfAllocated;
return pBase;
}
// Travel the MCB link for finding a block that is large enough
p = s_pFirst;
while( p != NULL )
{
PBYTE pBase = (PBYTE)(p + 1);
if( p->uSignature == MEM_CONTROL_BLOCK_UNUSED )
{
if( p == pTop )
{
return NULL;
}
if( p->nLimit == nSize )
{
ASSERT( s_nAvailMem >= nSizeOfAllocated );
p->uSignature = MEM_CONTROL_BLOCK_USED;
#ifndef NDEBUG
memset( pBase, DEBUG_GARBAGE_BYTE, nSize );
#endif
s_nAvailMem -= nSizeOfAllocated;
s_nUsedMem += nSizeOfAllocated;
return pBase;
}
if( p->nLimit > nSizeOfAllocated )
{ // Split this block
P_MemControlBlock pNext = (P_MemControlBlock)( pBase + nSize );
ASSERT( s_nAvailMem >= nSizeOfAllocated );
pNext->pNext = p->pNext;
pNext->nLimit = p->nLimit - nSizeOfAllocated;
pNext->uSignature = MEM_CONTROL_BLOCK_UNUSED;
p->pNext = pNext;
p->uSignature = MEM_CONTROL_BLOCK_USED;
p->nLimit = nSize;
#ifndef NDEBUG
memset( pBase, DEBUG_GARBAGE_BYTE, nSize );
#endif
s_nAvailMem -= nSizeOfAllocated;
s_nUsedMem += nSizeOfAllocated;
return pBase;
}
}
else if( p->uSignature != MEM_CONTROL_BLOCK_USED )
{
// This node is not a valid MCB, the memory list is corrupted
return NULL;
}
p = p->pNext;
}
return NULL;
}
void free( void * p )
{
unsigned nToFree;
P_MemControlBlock pTop = s_pTop;
P_MemControlBlock pMcb = (P_MemControlBlock)( (P_MemControlBlock)p - 1 );
P_MemControlBlock pNext = pMcb->pNext;
if( pMcb->uSignature != MEM_CONTROL_BLOCK_USED )
{ // An invalid memory block, which may be corrupted.
ASSERT( pMcb->uSignature == MEM_CONTROL_BLOCK_USED );
}
pMcb->uSignature = MEM_CONTROL_BLOCK_UNUSED;
#ifndef NDEBUG
memset( pMcb+1, DEBUG_GARBAGE_BYTE, pMcb->nLimit );
#endif
nToFree = pMcb->nLimit + sizeof(St_MemControlBlock);
// Merges two unused blocks if the two blocks are adjacent
if( (PBYTE)pNext == ( (PBYTE)(pMcb + 1) + pMcb->nLimit ) &&
pNext->uSignature == MEM_CONTROL_BLOCK_UNUSED )
{
ASSERT( s_nUsedMem >= nToFree );
pMcb->pNext = pNext->pNext;
pMcb->nLimit += pNext->nLimit + sizeof(St_MemControlBlock);
pNext->uSignature = 0;
pNext->pNext = NULL;
// Clear this signature
if( pNext == pTop )
{
s_pTop = pMcb;
}
s_nAvailMem += nToFree;
s_nUsedMem -= nToFree;
}
else
{
ASSERT( s_nUsedMem >= nToFree );
s_nAvailMem += nToFree;
s_nUsedMem -= nToFree;
}
pMcb->uSignature = MEM_CONTROL_BLOCK_UNUSED;
}