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; 
}