wangzheng3056 发表于 2013-7-26 10:17

malloc(内存分配)在嵌入式下的一种实现

想知道malloc是如何实现的吗?这里是一个简单版本,所有的功能都在这个文件实现了。如果你对malloc的原理有兴趣,可以通过这个代码窥视一二。实际上这个实现是著名的嵌入式操作系统vxworks5.5以前的内存分配版本。这里我已经把它实现的更简单易懂了。当然我还有移植到vc++下的版本,更方便调试。有需要请留言:)



*\file
*\brief               
*\details       
*
*\author        Janson
*\version       
*\date                04Jan12
*
*\warning       
*
*\history \arg        30Jan12, Janson, Create the file
*        modify from VxWorks source
*  Legal Declaration: it is for studying VxWorks only.
*/
#include "includes.h"

/* The memParLib.h file is hear:
https://code.google.com/p/vxworks-like-kernel/source/browse/trunk/inc/private/memPartLib.h
*/

/* optional check for bad blocks */

#define MEM_BLOCK_CHECK                        0x10

/* response to errors when allocating memory */

#define MEM_ALLOC_ERROR_LOG_FLAG        0x20
#define MEM_ALLOC_ERROR_SUSPEND_FLAG        0x40

/* response to errors when freeing memory */

#define MEM_BLOCK_ERROR_LOG_FLAG        0x80
#define MEM_BLOCK_ERROR_SUSPEND_FLAG        0x100

#define NEXT_HDR(pHdr)  ((BLOCK_HDR *) ((char *) (pHdr) + (2 * (pHdr)->nWords)))
#define PREV_HDR(pHdr)        ((pHdr)->prevHdr)

#define HDR_TO_BLOCK(pHdr)        ((char *) ((int) pHdr + sizeof (BLOCK_HDR)))
#define BLOCK_TO_HDR(pBlock)        ((BLOCK_HDR *) ((int) pBlock - \
                                                sizeof(BLOCK_HDR)))

#define HDR_TO_NODE(pHdr)        (& ((FREE_BLOCK *) pHdr)->node)
#define NODE_TO_HDR(pNode)        ((BLOCK_HDR *) ((int) pNode - \
                                                OFFSET (FREE_BLOCK, node)))

static BOOL memPartLibInstalled = FALSE;

static OBJ_CLASS memPartClass;
CLASS_ID memPartClassId = &memPartClass;

static PARTITION memSysPartition;
PART_ID memSysPartId = &memSysPartition;
U32 memDefaultAlign = _ALLOC_ALIGN_SIZE;

static SEMAPHORE semMemSysPartition;

static void memPartSemInit(PART_ID partId);

FUNCTION  memPartSemInitRtn        = (FUNCTION) memPartSemInit;

unsigned memPartDefaultOption = MEM_BLOCK_ERROR_SUSPEND_FLAG | MEM_BLOCK_CHECK;

static BOOL memPartBlockIsValid(PART_ID partId, FAST BLOCK_HDR* pHdr, BOOL isFree);
static BLOCK_HDR* memAlignedBlockSplit(PART_ID partId
        , FAST BLOCK_HDR* pHdr
        , FAST unsigned nWords
        , unsigned minWords
        , unsigned align);

static STATUS memPartAddToPool(PART_ID partId, char* pPool, unsigned poolSize);

STATUS memPartLibInit(char* pPool, unsigned poolSize)
{
        if((!memPartLibInstalled) &&
                (OK == classInit(memPartClassId, sizeof(PARTITION), OFFSET(PARTITION, objCore)
                , (FUNCTION)memPartCreate, (FUNCTION)memPartInit, (FUNCTION)memPartDestroy)))
        {
                memPartInit(&memSysPartition, pPool, poolSize);
                memPartLibInstalled = TRUE;
        }

        return ((memPartLibInstalled)? OK : ERROR);
}

PART_ID memPartCreate(char* pPool, unsigned poolSize)
{
        PART_ID pPart = (PART_ID)objAlloc(memPartClassId);

        if(NULL != pPart)
        {
                memPartInit(pPart, pPool, poolSize);
        }

        return pPart;
}

void memPartInit(PART_ID partId, char* pPool, unsigned poolSize)
{
        memset((void*)partId, 0, sizeof(*partId));

        partId->options = memPartDefaultOption;
        partId->minBlockWords = sizeof (FREE_BLOCK) >> 1;        /* word not byte */

        (* memPartSemInitRtn) (partId);
       
        dllInit(&partId->freeList);
       
        objCoreInit(&partId->objCore, memPartClassId);
       
        memPartAddToPool(partId, pPool, poolSize);
}

STATUS memPartDestroy(PART_ID partId)
{
        return (ERROR);
}

void memAddToPool(FAST char *pPool, FAST unsigned poolSize)
{
    (void)memPartAddToPool(&memSysPartition, pPool, poolSize);
}


static STATUS memPartAddToPool(PART_ID partId, char* pPool, unsigned poolSize)
{
        BLOCK_HDR* pHdrStart;
        BLOCK_HDR* pHdrMid;
        BLOCK_HDR* pHdrEnd;
        char* tmp;
        int reducePool;

        if(!(IS_CLASS(partId, memPartClassId)))        /* only memPartClass can call this function */
        {
                return (ERROR);
        }

        tmp = (char*) MEM_ROUND_UP(pPool);
        reducePool = tmp - pPool;

        /* adjust the lenght */
        if(poolSize >= reducePool)
        {
                poolSize -= reducePool;
        }
        else
        {
                poolSize = 0;
        }
        pPool = tmp;
       
        poolSize = MEM_ROUND_DOWN(poolSize);
       
        /* at least one valid free block and three header blocks */
        if((sizeof(BLOCK_HDR)*3 + (partId->minBlockWords*2)) > poolSize)
        {
                return (ERROR);
        }

        /* initialize three blocks */
        pHdrStart = (BLOCK_HDR*)pPool;
        pHdrStart->prevHdr = NULL;
        pHdrStart->free = FALSE;                /* never in use */
        pHdrStart->nWords = sizeof(BLOCK_HDR) >> 1;

        pHdrMid = NEXT_HDR(pHdrStart);
        pHdrMid->prevHdr = pHdrStart;
        pHdrMid->free = TRUE;                        /* the main block */
        pHdrMid->nWords = (poolSize - 2*sizeof(BLOCK_HDR)) >> 1;

        pHdrEnd = NEXT_HDR(pHdrMid);
        pHdrEnd->prevHdr = pHdrMid;
        pHdrEnd->free = FALSE;
        pHdrEnd->nWords = sizeof (BLOCK_HDR) >> 1;

        /* TODO take sem hear */
        semTake(partId->semPartId, WAIT_FOREVER);
       
        dllInsert(&partId->freeList, (DL_NODE*)NULL, HDR_TO_NODE(pHdrMid));
        partId->totalWords += (poolSize >> 1);

        /* TODO give sem hear */
        semGive(partId->semPartId);


        return (OK);
}

void* memPartAllignedAlloc(FAST PART_ID partId, unsigned nBytes, unsigned align)
{
        FAST unsigned nWords;
        FAST unsigned nWordsExtra;
        FAST DL_NODE* pNode;
        FAST BLOCK_HDR* pHdr;
        BLOCK_HDR* pNewHdr;
        BLOCK_HDR* origpHdr;

        if(!(IS_CLASS(partId, memPartClassId)))        /* only memPartClass can call this function */
        {
                return (NULL);
        }

        nWords = (MEM_ROUND_UP(nBytes)+sizeof(BLOCK_HDR)) >>1;

        if((nWords<<1) < nBytes)
        {
                /* TODO suspend the task */
                return (NULL);
        }

        if(nWords < partId->minBlockWords)
        {
                nWords = partId->minBlockWords;
        }

        /* TODO task the semaphore hear */
        semTake(partId->semPartId, WAIT_FOREVER);
        pNode = DLL_FIRST(&partId->freeList);
        nWordsExtra = nWords + align/2; /* why? */

        for(;;)
        {
                while(NULL != pNode)
                {
                        if((NODE_TO_HDR(pNode)->nWords > nWordsExtra) ||
                                ((NODE_TO_HDR(pNode)->nWords == nWords) &&
                                (ALIGNED(HDR_TO_BLOCK(NODE_TO_HDR(pNode)), align))))
                        {
                                break;
                        }

                        pNode = DLL_NEXT(pNode);
                }

                if(NULL == pNode)
                {
                        /*TODO give the semaphore */
                        semGive(partId->semPartId);
                        return NULL;
                }

                pHdr = NODE_TO_HDR(pNode);
                origpHdr = pHdr;

                pNewHdr = memAlignedBlockSplit(partId, pHdr, nWords, partId->minBlockWords, align);
                if(NULL != pNewHdr)
                {
                        pHdr = pNewHdr;
                        break;
                }

                pNode = DLL_NEXT(pNode);
        }

        pHdr->free = FALSE;
        partId->allBlocksAlloc++;
        partId->allWordsAlloc += pHdr->nWords;
        partId->curBlocksAlloc++;
        partId->curWordsAlloc += pHdr->nWords;

        /*TODO give the  semaphore hear */
        semGive(partId->semPartId);
        return (HDR_TO_BLOCK(pHdr));
       
}

void* memPartAlloc(FAST PART_ID partId, unsigned bytes)
{
        return memPartAllignedAlloc(partId, bytes, memDefaultAlign);
}

STATUS memPartFree(PART_ID partId, char* pBlock)
{
        FAST BLOCK_HDR *pHdr;
    FAST unsigned   nWords;
    FAST BLOCK_HDR *pNextHdr;

        if(!IS_CLASS(partId, memPartClassId))
        {
                return (ERROR);
        }

        if(NULL == pBlock)
        {
                return (OK);
        }

        pHdr =  BLOCK_TO_HDR(pBlock);

        semTake(partId->semPartId, WAIT_FOREVER);

        if((partId->options & MEM_BLOCK_CHECK)
                && !memPartBlockIsValid(partId, pHdr, FALSE))
        {
                semGive(partId->semPartId);
                return (ERROR);
        }

        nWords = pHdr->nWords;
        if(PREV_HDR(pHdr)->free)
        {/* the prev hdr is free and than coalesce with it */
                pHdr->free = FALSE;
                pHdr = PREV_HDR(pHdr);
                pHdr->nWords += nWords;
        }
        else
        {
                pHdr->free = TRUE;
                dllInsert(&partId->freeList, (DL_NODE*)NULL, HDR_TO_NODE(pHdr));
        }

        /* check to coalesce with the next */
        pNextHdr = NEXT_HDR(pHdr);
        if(pNextHdr->free)
        {
                pHdr->nWords += pNextHdr->nWords;
                dllRemove(&partId->freeList, HDR_TO_NODE(pNextHdr));
        }

        /* cannot use pNextHdr->prevHdr=pHdr hear */
        NEXT_HDR(pHdr)->prevHdr = pHdr;

        partId->curBlocksAlloc--;
        partId->curWordsAlloc -= nWords;

        /* TODO give sem hear */
        semGive(partId->semPartId);
       
        return (OK);
}

static BOOL memPartBlockIsValid(PART_ID partId, FAST BLOCK_HDR* pHdr, BOOL isFree)
{
        BOOL valid;

        TASK_LOCK();
        semGive(partId->semPartId);
       
        valid = MEM_ALIGNED(pHdr)
        && MEM_ALIGNED(pHdr->nWords*2)
        && (pHdr->nWords < partId->totalWords)
        && (pHdr->free == isFree)
        && (pHdr == PREV_HDR(NEXT_HDR(pHdr)))
        && (pHdr == NEXT_HDR(PREV_HDR(pHdr)));
       
        semTake(partId->semPartId, WAIT_FOREVER);
        TASK_UNLOCK();

        return valid;
}

static BLOCK_HDR* memAlignedBlockSplit(PART_ID partId
        , FAST BLOCK_HDR* pHdr
        , FAST unsigned nWords
        , unsigned minWords
        , unsigned align)
{
        FAST BLOCK_HDR *pNewHdr;
    FAST BLOCK_HDR *pNextHdr;
    FAST char *endOfBlock;
    FAST char *pNewBlock;
    int blockSize;

        endOfBlock = (char*)pHdr + (pHdr->nWords*2);

        pNewBlock = (char*)((unsigned)endOfBlock - ((nWords - sizeof(BLOCK_HDR)/2)*2));

        pNewBlock = (char*)((unsigned)pNewBlock & (~(align-1)));

        pNewHdr = BLOCK_TO_HDR(pNewBlock);

        blockSize = ((char*)pNewHdr - (char*)pHdr)/2;

        if(blockSize < minWords)
        {
                if(pNewHdr == pHdr)
                {
                        dllRemove(&partId->freeList, HDR_TO_NODE(pHdr));
                }
                else
                {
                        return NULL;
                }
        }
        else
        {        /* recaculate pHdr */
                pNewHdr->prevHdr = pHdr;
                pHdr->nWords = blockSize;
        }

        if(((U32)endOfBlock - (U32)pNewHdr - (nWords*2)) < (minWords*2))
        {
                pNewHdr->nWords = (endOfBlock - pNewBlock + sizeof(BLOCK_HDR))/2;
                pNewHdr->free = TRUE;

                NEXT_HDR(pNewHdr)->prevHdr = pNewHdr;
        }
        else
        {/* space left is enough to be a fragment on the free list then */
                pNewHdr->nWords = nWords;
                pNewHdr->free = TRUE;

                pNextHdr = NEXT_HDR(pNewHdr);
                /* words 包括BlockHdr */
                pNextHdr->nWords = ((U32)endOfBlock - (U32)pNextHdr) / 2;
                pNextHdr->prevHdr = pNewHdr;
                pNextHdr->free = TRUE;

                dllAdd(&partId->freeList, HDR_TO_NODE(pNextHdr));

                NEXT_HDR(pNextHdr)->prevHdr = pNewHdr;
        }

        return (pNewHdr);
}

static void memPartSemInit(PART_ID partId)
{
        semBInit(&semMemSysPartition, SEM_Q_FIFO, SEM_FULL);

        partId->semPartId = &semMemSysPartition;
}

void* malloc(unsigned bytes)
{
        return memPartAlloc(memSysPartId, bytes);
}

void free(void* p)
{
        memPartFree(memSysPartId, (char*)p);
}
页: [1]
查看完整版本: malloc(内存分配)在嵌入式下的一种实现