577 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			577 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) 2006-2018, RT-Thread Development Team
 | 
						|
 *
 | 
						|
 * SPDX-License-Identifier: Apache-2.0
 | 
						|
 *
 | 
						|
 * Change Logs:
 | 
						|
 * Date           Author       Notes
 | 
						|
 * 2012-04-10     Bernard      first implementation
 | 
						|
 * 2012-10-16     Bernard      add the mutex lock for heap object.
 | 
						|
 * 2012-12-29     Bernard      memheap can be used as system heap.
 | 
						|
 *                             change mutex lock to semaphore lock.
 | 
						|
 * 2013-04-10     Bernard      add rt_lwp_memheap_realloc function.
 | 
						|
 * 2013-05-24     Bernard      fix the rt_lwp_memheap_realloc issue.
 | 
						|
 * 2013-07-11     Grissiom     fix the memory block splitting issue.
 | 
						|
 * 2013-07-15     Grissiom     optimize rt_lwp_memheap_realloc
 | 
						|
 */
 | 
						|
 | 
						|
#include <rthw.h>
 | 
						|
#include <rtthread.h>
 | 
						|
#include <lwp.h>
 | 
						|
 | 
						|
/* dynamic pool magic and mask */
 | 
						|
#define RT_MEMHEAP_MAGIC        0x1ea01ea0
 | 
						|
#define RT_MEMHEAP_MASK         0xfffffffe
 | 
						|
#define RT_MEMHEAP_USED         0x01
 | 
						|
#define RT_MEMHEAP_FREED        0x00
 | 
						|
 | 
						|
#define RT_MEMHEAP_IS_USED(i)   ((i)->magic & RT_MEMHEAP_USED)
 | 
						|
#define RT_MEMHEAP_MINIALLOC    12
 | 
						|
 | 
						|
#define RT_MEMHEAP_SIZE         RT_ALIGN(sizeof(struct rt_lwp_memheap_item), RT_ALIGN_SIZE)
 | 
						|
#define MEMITEM_SIZE(item)      ((rt_uint32_t)item->next - (rt_uint32_t)item - RT_MEMHEAP_SIZE)
 | 
						|
 | 
						|
/*
 | 
						|
 * The initialized memory pool will be:
 | 
						|
 * +-----------------------------------+--------------------------+
 | 
						|
 * | whole freed memory block          | Used Memory Block Tailer |
 | 
						|
 * +-----------------------------------+--------------------------+
 | 
						|
 *
 | 
						|
 * block_list --> whole freed memory block
 | 
						|
 *
 | 
						|
 * The length of Used Memory Block Tailer is 0,
 | 
						|
 * which is prevents block merging across list
 | 
						|
 */
 | 
						|
rt_err_t rt_lwp_memheap_init(struct rt_lwp_memheap *memheap,
 | 
						|
                         const char        *name,
 | 
						|
                         void              *start_addr,
 | 
						|
                         rt_uint32_t        size)
 | 
						|
{
 | 
						|
    struct rt_lwp_memheap_item *item;
 | 
						|
 | 
						|
    RT_ASSERT(memheap != RT_NULL);
 | 
						|
 | 
						|
    /* initialize pool object */
 | 
						|
    memheap->start_addr     = start_addr;
 | 
						|
    memheap->pool_size      = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
 | 
						|
    memheap->available_size = memheap->pool_size - (2 * RT_MEMHEAP_SIZE);
 | 
						|
    memheap->max_used_size  = memheap->pool_size - memheap->available_size;
 | 
						|
 | 
						|
    /* initialize the free list header */
 | 
						|
    item            = &(memheap->free_header);
 | 
						|
    item->magic     = RT_MEMHEAP_MAGIC;
 | 
						|
    item->pool_ptr  = memheap;
 | 
						|
    item->next      = RT_NULL;
 | 
						|
    item->prev      = RT_NULL;
 | 
						|
    item->next_free = item;
 | 
						|
    item->prev_free = item;
 | 
						|
 | 
						|
    /* set the free list to free list header */
 | 
						|
    memheap->free_list = item;
 | 
						|
 | 
						|
    /* initialize the first big memory block */
 | 
						|
    item            = (struct rt_lwp_memheap_item *)start_addr;
 | 
						|
    item->magic     = RT_MEMHEAP_MAGIC;
 | 
						|
    item->pool_ptr  = memheap;
 | 
						|
    item->next      = RT_NULL;
 | 
						|
    item->prev      = RT_NULL;
 | 
						|
    item->next_free = item;
 | 
						|
    item->prev_free = item;
 | 
						|
 | 
						|
    item->next = (struct rt_lwp_memheap_item *)
 | 
						|
                 ((rt_uint8_t *)item + memheap->available_size + RT_MEMHEAP_SIZE);
 | 
						|
    item->prev = item->next;
 | 
						|
 | 
						|
    /* block list header */
 | 
						|
    memheap->block_list = item;
 | 
						|
 | 
						|
    /* place the big memory block to free list */
 | 
						|
    item->next_free = memheap->free_list->next_free;
 | 
						|
    item->prev_free = memheap->free_list;
 | 
						|
    memheap->free_list->next_free->prev_free = item;
 | 
						|
    memheap->free_list->next_free            = item;
 | 
						|
 | 
						|
    /* move to the end of memory pool to build a small tailer block,
 | 
						|
     * which prevents block merging
 | 
						|
     */
 | 
						|
    item = item->next;
 | 
						|
    /* it's a used memory block */
 | 
						|
    item->magic     = RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED;
 | 
						|
    item->pool_ptr  = memheap;
 | 
						|
    item->next      = (struct rt_lwp_memheap_item *)start_addr;
 | 
						|
    item->prev      = (struct rt_lwp_memheap_item *)start_addr;
 | 
						|
    /* not in free list */
 | 
						|
    item->next_free = item->prev_free = RT_NULL;
 | 
						|
 | 
						|
    /* initialize semaphore lock */
 | 
						|
    rt_sem_init(&(memheap->lock), name, 1, RT_IPC_FLAG_FIFO);
 | 
						|
 | 
						|
    RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
 | 
						|
                 ("memory heap: start addr 0x%08x, size %d, free list header 0x%08x\n",
 | 
						|
                  start_addr, size, &(memheap->free_header)));
 | 
						|
 | 
						|
    return RT_EOK;
 | 
						|
}
 | 
						|
 | 
						|
void *rt_lwp_memheap_alloc(struct rt_lwp_memheap *heap, rt_uint32_t size)
 | 
						|
{
 | 
						|
    rt_err_t result;
 | 
						|
    rt_uint32_t free_size;
 | 
						|
    struct rt_lwp_memheap_item *header_ptr;
 | 
						|
 | 
						|
    RT_ASSERT(heap != RT_NULL);
 | 
						|
 | 
						|
    /* align allocated size */
 | 
						|
    size = RT_ALIGN(size, RT_ALIGN_SIZE);
 | 
						|
    if (size < RT_MEMHEAP_MINIALLOC)
 | 
						|
        size = RT_MEMHEAP_MINIALLOC;
 | 
						|
 | 
						|
    RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate %d on heap:%8.*s",
 | 
						|
                                    size, RT_NAME_MAX, heap->parent.name));
 | 
						|
 | 
						|
    if (size < heap->available_size)
 | 
						|
    {
 | 
						|
        /* search on free list */
 | 
						|
        free_size = 0;
 | 
						|
 | 
						|
        /* lock memheap */
 | 
						|
        result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
 | 
						|
        if (result != RT_EOK)
 | 
						|
        {
 | 
						|
            rt_set_errno(result);
 | 
						|
 | 
						|
            return RT_NULL;
 | 
						|
        }
 | 
						|
 | 
						|
        /* get the first free memory block */
 | 
						|
        header_ptr = heap->free_list->next_free;
 | 
						|
        while (header_ptr != heap->free_list && free_size < size)
 | 
						|
        {
 | 
						|
            /* get current freed memory block size */
 | 
						|
            free_size = MEMITEM_SIZE(header_ptr);
 | 
						|
            if (free_size < size)
 | 
						|
            {
 | 
						|
                /* move to next free memory block */
 | 
						|
                header_ptr = header_ptr->next_free;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        /* determine if the memory is available. */
 | 
						|
        if (free_size >= size)
 | 
						|
        {
 | 
						|
            /* a block that satisfies the request has been found. */
 | 
						|
 | 
						|
            /* determine if the block needs to be split. */
 | 
						|
            if (free_size >= (size + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC))
 | 
						|
            {
 | 
						|
                struct rt_lwp_memheap_item *new_ptr;
 | 
						|
 | 
						|
                /* split the block. */
 | 
						|
                new_ptr = (struct rt_lwp_memheap_item *)
 | 
						|
                          (((rt_uint8_t *)header_ptr) + size + RT_MEMHEAP_SIZE);
 | 
						|
 | 
						|
                RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
 | 
						|
                             ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n",
 | 
						|
                              header_ptr,
 | 
						|
                              header_ptr->next,
 | 
						|
                              header_ptr->prev,
 | 
						|
                              new_ptr));
 | 
						|
 | 
						|
                /* mark the new block as a memory block and freed. */
 | 
						|
                new_ptr->magic = RT_MEMHEAP_MAGIC;
 | 
						|
 | 
						|
                /* put the pool pointer into the new block. */
 | 
						|
                new_ptr->pool_ptr = heap;
 | 
						|
 | 
						|
                /* break down the block list */
 | 
						|
                new_ptr->prev          = header_ptr;
 | 
						|
                new_ptr->next          = header_ptr->next;
 | 
						|
                header_ptr->next->prev = new_ptr;
 | 
						|
                header_ptr->next       = new_ptr;
 | 
						|
 | 
						|
                /* remove header ptr from free list */
 | 
						|
                header_ptr->next_free->prev_free = header_ptr->prev_free;
 | 
						|
                header_ptr->prev_free->next_free = header_ptr->next_free;
 | 
						|
                header_ptr->next_free = RT_NULL;
 | 
						|
                header_ptr->prev_free = RT_NULL;
 | 
						|
 | 
						|
                /* insert new_ptr to free list */
 | 
						|
                new_ptr->next_free = heap->free_list->next_free;
 | 
						|
                new_ptr->prev_free = heap->free_list;
 | 
						|
                heap->free_list->next_free->prev_free = new_ptr;
 | 
						|
                heap->free_list->next_free            = new_ptr;
 | 
						|
                RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x\n",
 | 
						|
                                                new_ptr->next_free,
 | 
						|
                                                new_ptr->prev_free));
 | 
						|
 | 
						|
                /* decrement the available byte count.  */
 | 
						|
                heap->available_size = heap->available_size -
 | 
						|
                                       size -
 | 
						|
                                       RT_MEMHEAP_SIZE;
 | 
						|
                if (heap->pool_size - heap->available_size > heap->max_used_size)
 | 
						|
                    heap->max_used_size = heap->pool_size - heap->available_size;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                /* decrement the entire free size from the available bytes count. */
 | 
						|
                heap->available_size = heap->available_size - free_size;
 | 
						|
                if (heap->pool_size - heap->available_size > heap->max_used_size)
 | 
						|
                    heap->max_used_size = heap->pool_size - heap->available_size;
 | 
						|
 | 
						|
                /* remove header_ptr from free list */
 | 
						|
                RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
 | 
						|
                             ("one block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x\n",
 | 
						|
                              header_ptr,
 | 
						|
                              header_ptr->next_free,
 | 
						|
                              header_ptr->prev_free));
 | 
						|
 | 
						|
                header_ptr->next_free->prev_free = header_ptr->prev_free;
 | 
						|
                header_ptr->prev_free->next_free = header_ptr->next_free;
 | 
						|
                header_ptr->next_free = RT_NULL;
 | 
						|
                header_ptr->prev_free = RT_NULL;
 | 
						|
            }
 | 
						|
 | 
						|
            /* Mark the allocated block as not available. */
 | 
						|
            header_ptr->magic |= RT_MEMHEAP_USED;
 | 
						|
 | 
						|
            /* release lock */
 | 
						|
            rt_sem_release(&(heap->lock));
 | 
						|
 | 
						|
            /* Return a memory address to the caller.  */
 | 
						|
            RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
 | 
						|
                         ("alloc mem: memory[0x%08x], heap[0x%08x], size: %d\n",
 | 
						|
                          (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE),
 | 
						|
                          header_ptr,
 | 
						|
                          size));
 | 
						|
 | 
						|
            return (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE);
 | 
						|
        }
 | 
						|
 | 
						|
        /* release lock */
 | 
						|
        rt_sem_release(&(heap->lock));
 | 
						|
    }
 | 
						|
 | 
						|
    RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate memory: failed\n"));
 | 
						|
 | 
						|
    /* Return the completion status.  */
 | 
						|
    return RT_NULL;
 | 
						|
}
 | 
						|
 | 
						|
void *rt_lwp_memheap_realloc(struct rt_lwp_memheap *heap, void *ptr, rt_size_t newsize)
 | 
						|
{
 | 
						|
    rt_err_t result;
 | 
						|
    rt_size_t oldsize;
 | 
						|
    struct rt_lwp_memheap_item *header_ptr;
 | 
						|
    struct rt_lwp_memheap_item *new_ptr;
 | 
						|
 | 
						|
    if (newsize == 0)
 | 
						|
    {
 | 
						|
        rt_lwp_memheap_free(ptr);
 | 
						|
 | 
						|
        return RT_NULL;
 | 
						|
    }
 | 
						|
    /* align allocated size */
 | 
						|
    newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE);
 | 
						|
    if (newsize < RT_MEMHEAP_MINIALLOC)
 | 
						|
        newsize = RT_MEMHEAP_MINIALLOC;
 | 
						|
 | 
						|
    if (ptr == RT_NULL)
 | 
						|
    {
 | 
						|
        return rt_lwp_memheap_alloc(heap, newsize);
 | 
						|
    }
 | 
						|
 | 
						|
    /* get memory block header and get the size of memory block */
 | 
						|
    header_ptr = (struct rt_lwp_memheap_item *)
 | 
						|
                 ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE);
 | 
						|
    oldsize = MEMITEM_SIZE(header_ptr);
 | 
						|
    /* re-allocate memory */
 | 
						|
    if (newsize > oldsize)
 | 
						|
    {
 | 
						|
        void *new_ptr;
 | 
						|
        struct rt_lwp_memheap_item *next_ptr;
 | 
						|
 | 
						|
        /* lock memheap */
 | 
						|
        result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
 | 
						|
        if (result != RT_EOK)
 | 
						|
        {
 | 
						|
            rt_set_errno(result);
 | 
						|
            return RT_NULL;
 | 
						|
        }
 | 
						|
 | 
						|
        next_ptr = header_ptr->next;
 | 
						|
 | 
						|
        /* header_ptr should not be the tail */
 | 
						|
        RT_ASSERT(next_ptr > header_ptr);
 | 
						|
 | 
						|
        /* check whether the following free space is enough to expand */
 | 
						|
        if (!RT_MEMHEAP_IS_USED(next_ptr))
 | 
						|
        {
 | 
						|
            rt_int32_t nextsize;
 | 
						|
 | 
						|
            nextsize = MEMITEM_SIZE(next_ptr);
 | 
						|
            RT_ASSERT(next_ptr > 0);
 | 
						|
 | 
						|
            /* Here is the ASCII art of the situation that we can make use of
 | 
						|
             * the next free node without alloc/memcpy, |*| is the control
 | 
						|
             * block:
 | 
						|
             *
 | 
						|
             *      oldsize           free node
 | 
						|
             * |*|-----------|*|----------------------|*|
 | 
						|
             *         newsize          >= minialloc
 | 
						|
             * |*|----------------|*|-----------------|*|
 | 
						|
             */
 | 
						|
            if (nextsize + oldsize > newsize + RT_MEMHEAP_MINIALLOC)
 | 
						|
            {
 | 
						|
                /* decrement the entire free size from the available bytes count. */
 | 
						|
                heap->available_size = heap->available_size - (newsize - oldsize);
 | 
						|
                if (heap->pool_size - heap->available_size > heap->max_used_size)
 | 
						|
                    heap->max_used_size = heap->pool_size - heap->available_size;
 | 
						|
 | 
						|
                /* remove next_ptr from free list */
 | 
						|
                RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
 | 
						|
                             ("remove block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x",
 | 
						|
                              next_ptr,
 | 
						|
                              next_ptr->next_free,
 | 
						|
                              next_ptr->prev_free));
 | 
						|
 | 
						|
                next_ptr->next_free->prev_free = next_ptr->prev_free;
 | 
						|
                next_ptr->prev_free->next_free = next_ptr->next_free;
 | 
						|
                next_ptr->next->prev = next_ptr->prev;
 | 
						|
                next_ptr->prev->next = next_ptr->next;
 | 
						|
 | 
						|
                /* build a new one on the right place */
 | 
						|
                next_ptr = (struct rt_lwp_memheap_item *)((char *)ptr + newsize);
 | 
						|
 | 
						|
                RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
 | 
						|
                             ("new free block: block[0x%08x] nextm[0x%08x] prevm[0x%08x]",
 | 
						|
                              next_ptr,
 | 
						|
                              next_ptr->next,
 | 
						|
                              next_ptr->prev));
 | 
						|
 | 
						|
                /* mark the new block as a memory block and freed. */
 | 
						|
                next_ptr->magic = RT_MEMHEAP_MAGIC;
 | 
						|
 | 
						|
                /* put the pool pointer into the new block. */
 | 
						|
                next_ptr->pool_ptr = heap;
 | 
						|
 | 
						|
                next_ptr->prev          = header_ptr;
 | 
						|
                next_ptr->next          = header_ptr->next;
 | 
						|
                header_ptr->next->prev = next_ptr;
 | 
						|
                header_ptr->next       = next_ptr;
 | 
						|
 | 
						|
                /* insert next_ptr to free list */
 | 
						|
                next_ptr->next_free = heap->free_list->next_free;
 | 
						|
                next_ptr->prev_free = heap->free_list;
 | 
						|
                heap->free_list->next_free->prev_free = next_ptr;
 | 
						|
                heap->free_list->next_free            = next_ptr;
 | 
						|
                RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x",
 | 
						|
                                                next_ptr->next_free,
 | 
						|
                                                next_ptr->prev_free));
 | 
						|
 | 
						|
                /* release lock */
 | 
						|
                rt_sem_release(&(heap->lock));
 | 
						|
 | 
						|
                return ptr;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        /* release lock */
 | 
						|
        rt_sem_release(&(heap->lock));
 | 
						|
 | 
						|
        /* re-allocate a memory block */
 | 
						|
        new_ptr = (void *)rt_lwp_memheap_alloc(heap, newsize);
 | 
						|
        if (new_ptr != RT_NULL)
 | 
						|
        {
 | 
						|
            rt_memcpy(new_ptr, ptr, oldsize < newsize ? oldsize : newsize);
 | 
						|
            rt_lwp_memheap_free(ptr);
 | 
						|
        }
 | 
						|
 | 
						|
        return new_ptr;
 | 
						|
    }
 | 
						|
 | 
						|
    /* don't split when there is less than one node space left */
 | 
						|
    if (newsize + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC >= oldsize)
 | 
						|
        return ptr;
 | 
						|
 | 
						|
    /* lock memheap */
 | 
						|
    result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
 | 
						|
    if (result != RT_EOK)
 | 
						|
    {
 | 
						|
        rt_set_errno(result);
 | 
						|
 | 
						|
        return RT_NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    /* split the block. */
 | 
						|
    new_ptr = (struct rt_lwp_memheap_item *)
 | 
						|
              (((rt_uint8_t *)header_ptr) + newsize + RT_MEMHEAP_SIZE);
 | 
						|
 | 
						|
    RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
 | 
						|
                 ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n",
 | 
						|
                  header_ptr,
 | 
						|
                  header_ptr->next,
 | 
						|
                  header_ptr->prev,
 | 
						|
                  new_ptr));
 | 
						|
 | 
						|
    /* mark the new block as a memory block and freed. */
 | 
						|
    new_ptr->magic = RT_MEMHEAP_MAGIC;
 | 
						|
    /* put the pool pointer into the new block. */
 | 
						|
    new_ptr->pool_ptr = heap;
 | 
						|
 | 
						|
    /* break down the block list */
 | 
						|
    new_ptr->prev          = header_ptr;
 | 
						|
    new_ptr->next          = header_ptr->next;
 | 
						|
    header_ptr->next->prev = new_ptr;
 | 
						|
    header_ptr->next       = new_ptr;
 | 
						|
 | 
						|
    /* determine if the block can be merged with the next neighbor. */
 | 
						|
    if (!RT_MEMHEAP_IS_USED(new_ptr->next))
 | 
						|
    {
 | 
						|
        struct rt_lwp_memheap_item *free_ptr;
 | 
						|
 | 
						|
        /* merge block with next neighbor. */
 | 
						|
        free_ptr = new_ptr->next;
 | 
						|
        heap->available_size = heap->available_size - MEMITEM_SIZE(free_ptr);
 | 
						|
 | 
						|
        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
 | 
						|
                     ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n",
 | 
						|
                      header_ptr, header_ptr->next_free, header_ptr->prev_free));
 | 
						|
 | 
						|
        free_ptr->next->prev = new_ptr;
 | 
						|
        new_ptr->next   = free_ptr->next;
 | 
						|
 | 
						|
        /* remove free ptr from free list */
 | 
						|
        free_ptr->next_free->prev_free = free_ptr->prev_free;
 | 
						|
        free_ptr->prev_free->next_free = free_ptr->next_free;
 | 
						|
    }
 | 
						|
 | 
						|
    /* insert the split block to free list */
 | 
						|
    new_ptr->next_free = heap->free_list->next_free;
 | 
						|
    new_ptr->prev_free = heap->free_list;
 | 
						|
    heap->free_list->next_free->prev_free = new_ptr;
 | 
						|
    heap->free_list->next_free            = new_ptr;
 | 
						|
    RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new free ptr: next_free 0x%08x, prev_free 0x%08x\n",
 | 
						|
                                    new_ptr->next_free,
 | 
						|
                                    new_ptr->prev_free));
 | 
						|
 | 
						|
    /* increment the available byte count.  */
 | 
						|
    heap->available_size = heap->available_size + MEMITEM_SIZE(new_ptr);
 | 
						|
 | 
						|
    /* release lock */
 | 
						|
    rt_sem_release(&(heap->lock));
 | 
						|
 | 
						|
    /* return the old memory block */
 | 
						|
    return ptr;
 | 
						|
}
 | 
						|
 | 
						|
void rt_lwp_memheap_free(void *ptr)
 | 
						|
{
 | 
						|
    rt_err_t result;
 | 
						|
    struct rt_lwp_memheap *heap;
 | 
						|
    struct rt_lwp_memheap_item *header_ptr, *new_ptr;
 | 
						|
    rt_uint32_t insert_header;
 | 
						|
 | 
						|
    /* NULL check */
 | 
						|
    if (ptr == RT_NULL) return;
 | 
						|
 | 
						|
    /* set initial status as OK */
 | 
						|
    insert_header = 1;
 | 
						|
    new_ptr       = RT_NULL;
 | 
						|
    header_ptr    = (struct rt_lwp_memheap_item *)
 | 
						|
                    ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE);
 | 
						|
 | 
						|
    RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("free memory: memory[0x%08x], block[0x%08x]\n",
 | 
						|
                                    ptr, header_ptr));
 | 
						|
 | 
						|
    /* check magic */
 | 
						|
    RT_ASSERT((header_ptr->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC);
 | 
						|
    RT_ASSERT(header_ptr->magic & RT_MEMHEAP_USED);
 | 
						|
    /* check whether this block of memory has been over-written. */
 | 
						|
    RT_ASSERT((header_ptr->next->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC);
 | 
						|
 | 
						|
    /* get pool ptr */
 | 
						|
    heap = header_ptr->pool_ptr;
 | 
						|
 | 
						|
    /* lock memheap */
 | 
						|
    result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
 | 
						|
    if (result != RT_EOK)
 | 
						|
    {
 | 
						|
        rt_set_errno(result);
 | 
						|
 | 
						|
        return ;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Mark the memory as available. */
 | 
						|
    header_ptr->magic &= ~RT_MEMHEAP_USED;
 | 
						|
    /* Adjust the available number of bytes. */
 | 
						|
    heap->available_size = heap->available_size + MEMITEM_SIZE(header_ptr);
 | 
						|
 | 
						|
    /* Determine if the block can be merged with the previous neighbor. */
 | 
						|
    if (!RT_MEMHEAP_IS_USED(header_ptr->prev))
 | 
						|
    {
 | 
						|
        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("merge: left node 0x%08x\n",
 | 
						|
                                        header_ptr->prev));
 | 
						|
 | 
						|
        /* adjust the available number of bytes. */
 | 
						|
        heap->available_size = heap->available_size + RT_MEMHEAP_SIZE;
 | 
						|
 | 
						|
        /* yes, merge block with previous neighbor. */
 | 
						|
        (header_ptr->prev)->next = header_ptr->next;
 | 
						|
        (header_ptr->next)->prev = header_ptr->prev;
 | 
						|
 | 
						|
        /* move header pointer to previous. */
 | 
						|
        header_ptr = header_ptr->prev;
 | 
						|
        /* don't insert header to free list */
 | 
						|
        insert_header = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    /* determine if the block can be merged with the next neighbor. */
 | 
						|
    if (!RT_MEMHEAP_IS_USED(header_ptr->next))
 | 
						|
    {
 | 
						|
        /* adjust the available number of bytes. */
 | 
						|
        heap->available_size = heap->available_size + RT_MEMHEAP_SIZE;
 | 
						|
 | 
						|
        /* merge block with next neighbor. */
 | 
						|
        new_ptr = header_ptr->next;
 | 
						|
 | 
						|
        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
 | 
						|
                     ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n",
 | 
						|
                      new_ptr, new_ptr->next_free, new_ptr->prev_free));
 | 
						|
 | 
						|
        new_ptr->next->prev = header_ptr;
 | 
						|
        header_ptr->next    = new_ptr->next;
 | 
						|
 | 
						|
        /* remove new ptr from free list */
 | 
						|
        new_ptr->next_free->prev_free = new_ptr->prev_free;
 | 
						|
        new_ptr->prev_free->next_free = new_ptr->next_free;
 | 
						|
    }
 | 
						|
 | 
						|
    if (insert_header)
 | 
						|
    {
 | 
						|
        /* no left merge, insert to free list */
 | 
						|
        header_ptr->next_free = heap->free_list->next_free;
 | 
						|
        header_ptr->prev_free = heap->free_list;
 | 
						|
        heap->free_list->next_free->prev_free = header_ptr;
 | 
						|
        heap->free_list->next_free            = header_ptr;
 | 
						|
 | 
						|
        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
 | 
						|
                     ("insert to free list: next_free 0x%08x, prev_free 0x%08x\n",
 | 
						|
                      header_ptr->next_free, header_ptr->prev_free));
 | 
						|
    }
 | 
						|
 | 
						|
    /* release lock */
 | 
						|
    rt_sem_release(&(heap->lock));
 | 
						|
}
 | 
						|
 | 
						|
rt_bool_t rt_lwp_memheap_is_empty(struct rt_lwp_memheap *memheap)
 | 
						|
{
 | 
						|
    RT_ASSERT(memheap != RT_NULL);
 | 
						|
 | 
						|
    return (memheap->available_size + 2 * sizeof(struct rt_lwp_memheap_item)) == memheap->pool_size;
 | 
						|
}
 | 
						|
 | 
						|
rt_bool_t rt_lwp_memheap_unavailable_size_get(void)
 | 
						|
{
 | 
						|
    return 2 * RT_MEMHEAP_SIZE + 3;
 | 
						|
}
 |