⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 heap.c

📁 HAL硬件抽象层源码
💻 C
字号:
/***************************************************************************
 * Copyright ? Intel Corporation, March 18th 1998.  All rights reserved.
 * Copyright ? ARM Limited 1998/1999.  All rights reserved.
 ***************************************************************************/
/*
 * This is a simple heap allocator.  It allocates memory in fixed "chunk" 
 * sizes.  The chunk size is a power of 2, for example 128.  It allocates
 * as many chunks as it takes to hold the memory size requested and a chunk
 * header which describes the block of chunks.  All blocks of chunks are kept
 * in the memory list pointed at by "first".  The header describes the number 
 * of chunks in this block, whether or not it is free and how much memory
 * the caller asked for.  It also contains a magic pattern that allows the
 * deallocation code to check for memory corruption.  The smaller the chunk
 * size the less wasted memory, however a chunk must be bigger than the chunk
 * header.
 *
 * The memory allocation algorithm is to find the first block of chunks big
 * enough.  If this block of chunks is too large, the block is broken into 
 * two blocks.  The first block of chunks is used for the memory and second
 * is made free.  This is a "first found" algorithm, it could be more efficient
 * but the search would take longer.
 *
 * When freeing memory we could check to see if the block of chunks being
 * freed could be merged with either the previous or next block of chunks (or
 * both) if they are already free.  This collects the memory back into larger
 * chunks and helps prevent excessive fragmentation.  Rather than do this 
 * every time memory is deallocated, we wait until either we cannot find a 
 * free block of chunks big enough or we are concerned that there is too much
 * fragmentation.
 *
 * The macros uHAL_HEAP_BASE and uHAL_HEAP_SIZE must be declared in the system
 * specific header files.
 *
 *****************************************************************************/

#include "uhal.h"

#if uHAL_HEAP != 0

/* memory chunk descriptor */
typedef struct chunkHeader
{
    unsigned int Magic;         // magic number

    unsigned int chunkSize;     // size of chunk in chunks

    unsigned int allocatedSize; // allocated size in bytes

    struct chunkHeader *next;   // next chunk in the list

}
chunkHeader_t;

struct chunkStatistics
{
    unsigned int totalMemory;
    unsigned int allocatedMemory;
    unsigned int maxChunks;
    unsigned int totalBlocks;
};

static struct chunkStatistics statistics;

#define HEADER_SIZE sizeof(chunkHeader_t)
#define CHUNK_MAGIC 0xDEADBEEF

/* minimum size of memory to be allocated */
#define CHUNK_SIZE_IN_BITS 7
#define CHUNK_SIZE (1 << CHUNK_SIZE_IN_BITS)

/* How many times to try and merge the chunks when freeing them */
#define MAX_MERGE_ATTEMPTS 2

/* How many times do we try to allocate memory when there are not any 
 * blocks of chunks big enough */
#define MAX_ALLOCATE_ATTEMPTS 5

/* first memory chunk pointers (held in ascending memory order) */
chunkHeader_t *first = NULL;

/* local (static) routines */
static int easyMergeChunks(chunkHeader_t * blockP);
static void mergeChunks(void);
static chunkHeader_t *firstFit(unsigned int chunks);

/* ----------------------- static source code ----------------------------- */
static void mergeChunks(void)
{
    chunkHeader_t *blockP;
    int i;
    int count;

    /* See if you can merge this freed chunk with another one */
    for (i = 0; i < MAX_MERGE_ATTEMPTS; i++)
    {

        count = 0;
        blockP = first;

        while (blockP)
        {
            count += easyMergeChunks(blockP);
            blockP = blockP->next;
        }

        /* if we didn't merge any chunks this pass, then give up */
        if (count == 0)
            return;
    }
}

static chunkHeader_t *firstFit(unsigned int chunks)
{
    chunkHeader_t *blockP = first;

    /* very, very simple algorithm, find the first chunk big enough */
    while (blockP)
    {
#ifdef DEBUG
        if (blockP->Magic != CHUNK_MAGIC)
        {
            uHALr_printf("ERROR: corrupt heap @ 0x%x\n", blockP);
            return NULL;
        }
#endif
        if ((blockP->chunkSize > chunks) && (blockP->allocatedSize == 0))
        {
            return blockP;
        }
        blockP = blockP->next;
    }
    return NULL;
}

/* merge this chunk and the next, if they are both free */
static int easyMergeChunks(chunkHeader_t * blockP)
{
    chunkHeader_t *nextP = blockP->next;

    if (nextP)
    {
        if ((blockP->allocatedSize == 0) && (nextP->allocatedSize == 0))
        {

            /* swallow (merge) the next chunk. */
            blockP->next = nextP->next;
            blockP->chunkSize += nextP->chunkSize;
            nextP->Magic = ~CHUNK_MAGIC;

            /* account for the death of a block of chunks */
            statistics.totalBlocks--;
            return 1;
        }
    }
    return 0;
}

/* ------------------ externally available routines ------------------------ */
int uHALr_HeapAvailable(void)
{
    return TRUE;
}

#ifdef USE_C_LIBRARY
extern void uHALir_InitCLibraryMalloc(void);

#endif
/* initialize the heap allocation scheme */
void uHALr_InitHeap(void)
{
#ifdef DEBUG
    uHALr_printf("uHALr_InitHeap() called, uHAL_HEAP_BASE = 0x%x\n",
                 uHAL_HEAP_BASE);
#endif

    /* if we're using the C library, init it's heap usage */
#ifdef USE_C_LIBRARY
    uHALir_InitCLibraryMalloc();
#endif

    /* set up the free block (one big one to start with) */
    first = (chunkHeader_t *) uHAL_HEAP_BASE;
    first->Magic = CHUNK_MAGIC;
    first->allocatedSize = 0;
    first->chunkSize = uHAL_HEAP_SIZE >> CHUNK_SIZE_IN_BITS;
    first->next = NULL;

    /* set up the statistics */
    statistics.totalMemory = uHAL_HEAP_SIZE;
    statistics.allocatedMemory = 0;
    statistics.maxChunks = uHAL_HEAP_SIZE >> CHUNK_SIZE_IN_BITS;
    statistics.totalBlocks = 1;
}

/* allocate memory, make this as quick as possible */
void *uHALr_malloc(unsigned int size)
{
    unsigned int chunks;
    chunkHeader_t *blockP;
    int tries;

    /* figure out the number of chunks we need */
    chunks = (~(CHUNK_SIZE - 1) &
           (CHUNK_SIZE + size + sizeof(chunkHeader_t))) >> CHUNK_SIZE_IN_BITS;

    /* find the best fit for this number of blocks (retry if neccessary) */
    for (tries = 0; tries < MAX_ALLOCATE_ATTEMPTS; tries++)
    {

        /* find the first block that fits */
        blockP = firstFit(chunks);

        /* if we got a chunk, do we need to break it into smaller chunks? */
        if (blockP)
        {
            if (blockP->chunkSize > chunks)
            {
                chunkHeader_t *newP;

                /* make a new chunk and thread it into the list, make sure that
                 * the allocator gets the chunk at the end,this tends to keep the free
                 * blocks of chunks at the start of the memory list. */
                newP = (chunkHeader_t *) ((char *)blockP
                                          + ((blockP->chunkSize - chunks)
                                             * CHUNK_SIZE));

                newP->Magic = CHUNK_MAGIC;
                newP->next = blockP->next;
                newP->allocatedSize = 0;
                newP->chunkSize = blockP->chunkSize - chunks;

                blockP->next = newP;
                blockP->chunkSize -= chunks;

                /* account for the birth of a chunk */
                statistics.totalBlocks++;

                /* Use the new block of chunks */
                blockP = newP;
            }

            /* account for this memory */
            statistics.allocatedMemory += (chunks * CHUNK_SIZE);

            /* mark this memory allocated */
            blockP->Magic = CHUNK_MAGIC;
            blockP->allocatedSize = size;
            blockP->chunkSize = chunks;

            /* return the caller a pointer to its memory */
            return (void *)((unsigned char *)blockP + sizeof(chunkHeader_t));
        }

        /* try and merge any free chunks that are next to each other 
         * and then retry the allocate */
        mergeChunks();

    }                           /* ran out of retries, give up */

    return NULL;
}

void uHALr_free(void *where)
{
    chunkHeader_t *blockP = (chunkHeader_t *) ((char *)where - sizeof(chunkHeader_t));

    /* check the magic header number */
    if (blockP->Magic != CHUNK_MAGIC)
    {
        return;
    }

    /* check that this block is indeed allocated */
    if (blockP->allocatedSize == 0)
    {
        return;
    }

    /* account for this memory */
    statistics.allocatedMemory -= (blockP->chunkSize * CHUNK_SIZE);

    /* mark this block of chunks as free, don't attempt to merge (yet) */
    blockP->allocatedSize = 0;
}

#else
/* ------------------ externally available routines ------------------------ */
int uHALr_HeapAvailable(void)
{
    return FALSE;
}

#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -