diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Kconfig | 76 | ||||
| -rw-r--r-- | src/SConscript | 9 | ||||
| -rw-r--r-- | src/kservice.c | 313 | ||||
| -rw-r--r-- | src/mem.c | 635 | ||||
| -rw-r--r-- | src/memheap.c | 636 | ||||
| -rw-r--r-- | src/object.c | 7 | ||||
| -rw-r--r-- | src/slab.c | 597 |
7 files changed, 1157 insertions, 1116 deletions
diff --git a/src/Kconfig b/src/Kconfig index 8647d35698..2bc37cf451 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -284,36 +284,67 @@ menu "Memory Management" help Using static memory fixed partition + config RT_USING_SMALL_MEM + bool "Using Small Memory Algorithm" + default n + help + Using Small Memory Algorithm + + config RT_USING_SLAB + bool "Using SLAB Memory Algorithm" + default n + help + The slab allocator of RT-Thread is a memory allocation algorithm + optimizedfor embedded systems based on the slab allocator + implemented by Matthew Dillon, founder of dragonfly BSD. + The original slab algorithm is an efficient kernel memory + allocation algorithm introduced by Jeff bonwick for + Solaris Operating System. + menuconfig RT_USING_MEMHEAP - bool "Using memory heap object" + bool "Using memheap Memory Algorithm" default n if RT_USING_MEMHEAP + choice + prompt "Memheap memory allocation mode" + default RT_MEMHEAP_FAST_MODE - if RT_USING_MEMHEAP_AS_HEAP - config RT_USING_MEMHEAP_AUTO_BINDING - bool "Use all of memheap objects as heap" - default y - endif + config RT_MEMHEAP_FAST_MODE + bool "fast mode" + help + Speed priority mode. + As long as the memory block size meets the requirements, the search ends immediately. + + config RT_MEMHEAP_BSET_MODE + bool "best mode" + help + Best size first. + The search does not end until the memory block of the most appropriate size is found + endchoice endif choice - prompt "Dynamic Memory Management" - default RT_USING_SMALL_MEM + prompt "System Heap Memory Management" + default RT_USING_SMALL_MEM_AS_HEAP - config RT_USING_NOHEAP - bool "Disable Heap" - - config RT_USING_SMALL_MEM + config RT_USING_SMALL_MEM_AS_HEAP bool "Small Memory Algorithm" + select RT_USING_SMALL_MEM - config RT_USING_SLAB - bool "SLAB Algorithm for large memory" - - if RT_USING_MEMHEAP config RT_USING_MEMHEAP_AS_HEAP bool "Use memheap objects as heap" - endif + select RT_USING_MEMHEAP + + if RT_USING_MEMHEAP_AS_HEAP + config RT_USING_MEMHEAP_AUTO_BINDING + bool "Use all of memheap objects as heap" + default y + endif + + config RT_USING_SLAB_AS_HEAP + bool "SLAB Algorithm for large memory" + select RT_USING_SLAB config RT_USING_USERHEAP bool "Use user heap" @@ -322,10 +353,11 @@ menu "Memory Management" rt_malloc(), rt_malloc_sethook() rt_free(), rt_free_sethook() rt_calloc(), rt_realloc() + rt_memory_info() rt_system_heap_init() - And if FinSH is used at the same time, please implement list_mem() - + config RT_USING_NOHEAP + bool "Disable Heap" endchoice config RT_USING_MEMTRACE @@ -342,6 +374,12 @@ menu "Memory Management" to check memory block to find which thread has wrongly modified memory. + config RT_USING_HEAP_ISR + bool "Using heap in ISR" + default n + help + When this option is enabled, the critical zone will be protected with disable interrupt. + config RT_USING_HEAP bool default n if RT_USING_NOHEAP diff --git a/src/SConscript b/src/SConscript index 68523978d6..3f014551f0 100644 --- a/src/SConscript +++ b/src/SConscript @@ -6,10 +6,10 @@ src = Glob('*.c') CPPPATH = [RTT_ROOT + '/include'] -if GetDepend('RT_USING_HEAP') == False or GetDepend('RT_USING_SMALL_MEM') == False: +if GetDepend('RT_USING_SMALL_MEM') == False: SrcRemove(src, ['mem.c']) -if GetDepend('RT_USING_HEAP') == False or GetDepend('RT_USING_SLAB') == False: +if GetDepend('RT_USING_SLAB') == False: SrcRemove(src, ['slab.c']) if GetDepend('RT_USING_MEMPOOL') == False: @@ -17,11 +17,6 @@ if GetDepend('RT_USING_MEMPOOL') == False: if GetDepend('RT_USING_MEMHEAP') == False: SrcRemove(src, ['memheap.c']) - if GetDepend('RT_USING_MEMHEAP_AS_HEAP'): - SrcRemove(src, ['mem.c']) - -if GetDepend('RT_USING_USERHEAP'): - SrcRemove(src, ['mem.c', 'slab.c']) if GetDepend('RT_USING_SIGNALS') == False: SrcRemove(src, ['signal.c']) diff --git a/src/kservice.c b/src/kservice.c index 8b959cbd68..5d4311507d 100644 --- a/src/kservice.c +++ b/src/kservice.c @@ -1276,7 +1276,318 @@ RT_WEAK int rt_kprintf(const char *fmt, ...) RTM_EXPORT(rt_kprintf); #endif /* RT_USING_CONSOLE */ -#ifdef RT_USING_HEAP +#if defined(RT_USING_HEAP) && !defined(RT_USING_USERHEAP) +#ifdef RT_USING_HOOK +static void (*rt_malloc_hook)(void *ptr, rt_size_t size); +static void (*rt_free_hook)(void *ptr); + +/** + * @addtogroup Hook + */ + +/**@{*/ + +/** + * @brief This function will set a hook function, which will be invoked when a memory + * block is allocated from heap memory. + * + * @param hook the hook function. + */ +void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size)) +{ + rt_malloc_hook = hook; +} + +/** + * @brief This function will set a hook function, which will be invoked when a memory + * block is released to heap memory. + * + * @param hook the hook function + */ +void rt_free_sethook(void (*hook)(void *ptr)) +{ + rt_free_hook = hook; +} + +/**@}*/ + +#endif /* RT_USING_HOOK */ + +#if defined(RT_USING_HEAP_ISR) +#elif defined(RT_USING_MUTEX) +static struct rt_mutex _lock; +#endif + +rt_inline void _heap_lock_init(void) +{ +#if defined(RT_USING_HEAP_ISR) +#elif defined(RT_USING_MUTEX) + rt_mutex_init(&_lock, "heap", RT_IPC_FLAG_PRIO); +#endif +} + +rt_inline rt_base_t _heap_lock(void) +{ +#if defined(RT_USING_HEAP_ISR) + return rt_hw_interrupt_disable(); +#elif defined(RT_USING_MUTEX) + if (rt_thread_self()) + return rt_mutex_take(&_lock, RT_WAITING_FOREVER); + else + return RT_EOK; +#else + rt_enter_critical(); + return RT_EOK; +#endif +} + +rt_inline void _heap_unlock(rt_base_t level) +{ +#if defined(RT_USING_HEAP_ISR) + rt_hw_interrupt_enable(level); +#elif defined(RT_USING_MUTEX) + RT_ASSERT(level == RT_EOK); + if (rt_thread_self()) + rt_mutex_release(&_lock); +#else + rt_exit_critical(); +#endif +} + +#if defined(RT_USING_SMALL_MEM_AS_HEAP) +static rt_smem_t system_heap; +rt_inline void _smem_info(rt_uint32_t *total, + rt_uint32_t *used, rt_uint32_t *max_used) +{ + if (total) + *total = system_heap->total; + if (used) + *used = system_heap->used; + if (max_used) + *max_used = system_heap->max; +} +#define _MEM_INIT(_name, _start, _size) \ + system_heap = rt_smem_init(_name, _start, _size) +#define _MEM_MALLOC(_size) \ + rt_smem_alloc(system_heap, _size) +#define _MEM_REALLOC(_ptr, _newsize)\ + rt_smem_realloc(system_heap, _ptr, _newsize) +#define _MEM_FREE(_ptr) \ + rt_smem_free(_ptr) +#define _MEM_INFO(_total, _used, _max) \ + _smem_info(_total, _used, _max) +#elif defined(RT_USING_MEMHEAP_AS_HEAP) +static struct rt_memheap system_heap; +void *_memheap_alloc(struct rt_memheap *heap, rt_size_t size); +void _memheap_free(void *rmem); +void *_memheap_realloc(struct rt_memheap *heap, void *rmem, rt_size_t newsize); +#define _MEM_INIT(_name, _start, _size) \ + rt_memheap_init(&system_heap, _name, _start, _size) +#define _MEM_MALLOC(_size) \ + _memheap_alloc(&system_heap, _size) +#define _MEM_REALLOC(_ptr, _newsize) \ + _memheap_realloc(&system_heap, _ptr, _newsize) +#define _MEM_FREE(_ptr) \ + _memheap_free(_ptr) +#define _MEM_INFO(_total, _used, _max) \ + rt_memheap_info(&system_heap, _total, _used, _max) +#elif defined(RT_USING_SLAB_AS_HEAP) +static rt_slab_t system_heap; +rt_inline void _slab_info(rt_uint32_t *total, + rt_uint32_t *used, rt_uint32_t *max_used) +{ + if (total) + *total = system_heap->total; + if (used) + *used = system_heap->used; + if (max_used) + *max_used = system_heap->max; +} +#define _MEM_INIT(_name, _start, _size) \ + system_heap = rt_slab_init(_name, _start, _size) +#define _MEM_MALLOC(_size) \ + rt_slab_alloc(system_heap, _size) +#define _MEM_REALLOC(_ptr, _newsize) \ + rt_slab_realloc(system_heap, _ptr, _newsize) +#define _MEM_FREE(_ptr) \ + rt_slab_free(system_heap, _ptr) +#define _MEM_INFO _slab_info +#else +#define _MEM_INIT(...) +#define _MEM_MALLOC(...) RT_NULL +#define _MEM_REALLOC(...) RT_NULL +#define _MEM_FREE(...) +#define _MEM_INFO(...) +#endif + +/** + * @brief This function will init system heap. + * + * @param begin_addr the beginning address of system page. + * + * @param end_addr the end address of system page. + */ +RT_WEAK void rt_system_heap_init(void *begin_addr, void *end_addr) +{ + rt_ubase_t begin_align = RT_ALIGN((rt_ubase_t)begin_addr, RT_ALIGN_SIZE); + rt_ubase_t end_align = RT_ALIGN_DOWN((rt_ubase_t)end_addr, RT_ALIGN_SIZE); + + RT_ASSERT(end_align > begin_align); + + /* Initialize system memory heap */ + _MEM_INIT("heap", begin_addr, end_align - begin_align); + /* Initialize multi thread contention lock */ + _heap_lock_init(); +} + +/** + * @brief Allocate a block of memory with a minimum of 'size' bytes. + * + * @param size is the minimum size of the requested block in bytes. + * + * @return the pointer to allocated memory or NULL if no free memory was found. + */ +RT_WEAK void *rt_malloc(rt_size_t size) +{ + rt_base_t level; + void *ptr; + + /* Enter critical zone */ + level = _heap_lock(); + /* allocate memory block from system heap */ + ptr = _MEM_MALLOC(size); + /* Exit critical zone */ + _heap_unlock(level); + /* call 'rt_malloc' hook */ + RT_OBJECT_HOOK_CALL(rt_malloc_hook, (ptr, size)); + return ptr; +} +RTM_EXPORT(rt_malloc); + +/** + * @brief This function will change the size of previously allocated memory block. + * + * @param rmem is the pointer to memory allocated by rt_malloc. + * + * @param newsize is the required new size. + * + * @return the changed memory block address. + */ +RT_WEAK void *rt_realloc(void *rmem, rt_size_t newsize) +{ + rt_base_t level; + void *nptr; + + /* Enter critical zone */ + level = _heap_lock(); + /* Change the size of previously allocated memory block */ + nptr = _MEM_REALLOC(rmem, newsize); + /* Exit critical zone */ + _heap_unlock(level); + return nptr; +} +RTM_EXPORT(rt_realloc); + +/** + * @brief This function will contiguously allocate enough space for count objects + * that are size bytes of memory each and returns a pointer to the allocated + * memory. + * + * @note The allocated memory is filled with bytes of value zero. + * + * @param count is the number of objects to allocate. + * + * @param size is the size of one object to allocate. + * + * @return pointer to allocated memory / NULL pointer if there is an error. + */ +RT_WEAK void *rt_calloc(rt_size_t count, rt_size_t size) +{ + void *p; + + /* allocate 'count' objects of size 'size' */ + p = rt_malloc(count * size); + /* zero the memory */ + if (p) + { + rt_memset(p, 0, count * size); + } + return p; +} +RTM_EXPORT(rt_calloc); + +/** + * @brief This function will release the previously allocated memory block by + * rt_malloc. The released memory block is taken back to system heap. + * + * @param rmem the address of memory which will be released. + */ +RT_WEAK void rt_free(void *rmem) +{ + rt_base_t level; + + /* call 'rt_free' hook */ + RT_OBJECT_HOOK_CALL(rt_free_hook, (rmem)); + /* Enter critical zone */ + level = _heap_lock(); + _MEM_FREE(rmem); + /* Exit critical zone */ + _heap_unlock(level); +} +RTM_EXPORT(rt_free); + +/** +* @brief This function will caculate the total memory, the used memory, and +* the max used memory. +* +* @param total is a pointer to get the total size of the memory. +* +* @param used is a pointer to get the size of memory used. +* +* @param max_used is a pointer to get the maximum memory used. +*/ +RT_WEAK void rt_memory_info(rt_uint32_t *total, + rt_uint32_t *used, + rt_uint32_t *max_used) +{ + rt_base_t level; + + /* Enter critical zone */ + level = _heap_lock(); + _MEM_INFO(total, used, max_used); + /* Exit critical zone */ + _heap_unlock(level); +} +RTM_EXPORT(rt_memory_info); + +#if defined(RT_USING_SLAB) && defined(RT_USING_SLAB_AS_HEAP) +void *rt_page_alloc(rt_size_t npages) +{ + rt_base_t level; + void *ptr; + + /* Enter critical zone */ + level = _heap_lock(); + /* alloc page */ + ptr = rt_slab_page_alloc(system_heap, npages); + /* Exit critical zone */ + _heap_unlock(level); + return ptr; +} + +void rt_page_free(void *addr, rt_size_t npages) +{ + rt_base_t level; + + /* Enter critical zone */ + level = _heap_lock(); + /* free page */ + rt_slab_page_free(system_heap, addr, npages); + /* Exit critical zone */ + _heap_unlock(level); +} +#endif + /** * This function allocates a memory block, which address is aligned to the * specified alignment size. @@ -50,73 +50,40 @@ #include <rthw.h> #include <rtthread.h> -#ifndef RT_USING_MEMHEAP_AS_HEAP - -#define RT_MEM_STATS - -#if defined (RT_USING_HEAP) && defined (RT_USING_SMALL_MEM) -#ifdef RT_USING_HOOK -static void (*rt_malloc_hook)(void *ptr, rt_size_t size); -static void (*rt_free_hook)(void *ptr); - -/** - * @addtogroup Hook - */ - -/**@{*/ - -/** - * @brief This function will set a hook function, which will be invoked when a memory - * block is allocated from heap memory. - * - * @param hook the hook function. - */ -void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size)) -{ - rt_malloc_hook = hook; -} - -/** - * @brief This function will set a hook function, which will be invoked when a memory - * block is released to heap memory. - * - * @param hook the hook function - */ -void rt_free_sethook(void (*hook)(void *ptr)) -{ - rt_free_hook = hook; -} - -/**@}*/ - -#endif /* RT_USING_HOOK */ - -#define HEAP_MAGIC 0x1ea0 -struct heap_mem +#if defined (RT_USING_SMALL_MEM) + /** + * memory item on the small mem + */ +struct rt_small_mem_item { - /* magic and used flag */ - rt_uint16_t magic; - rt_uint16_t used; + rt_ubase_t pool_ptr; /**< small memory object addr */ #ifdef ARCH_CPU_64BIT - rt_uint32_t resv; + rt_uint32_t resv; #endif /* ARCH_CPU_64BIT */ - - rt_size_t next, prev; - + rt_size_t next; /**< next free item */ + rt_size_t prev; /**< prev free item */ #ifdef RT_USING_MEMTRACE #ifdef ARCH_CPU_64BIT - rt_uint8_t thread[8]; + rt_uint8_t thread[8]; /**< thread name */ #else - rt_uint8_t thread[4]; /* thread name */ + rt_uint8_t thread[4]; /**< thread name */ #endif /* ARCH_CPU_64BIT */ #endif /* RT_USING_MEMTRACE */ }; -/** pointer to the heap: for alignment, heap_ptr is now a pointer instead of an array */ -static rt_uint8_t *heap_ptr; +/** + * Base structure of small memory object + */ +struct rt_small_mem +{ + struct rt_memory parent; /**< inherit from rt_memory */ + rt_uint8_t *heap_ptr; /**< pointer to the heap */ + struct rt_small_mem_item *heap_end; + struct rt_small_mem_item *lfree; + rt_size_t mem_size_aligned; /**< aligned memory size */ +}; -/** the last entry, always unused! */ -static struct heap_mem *heap_end; +#define HEAP_MAGIC 0x1ea0 #ifdef ARCH_CPU_64BIT #define MIN_SIZE 24 @@ -124,20 +91,22 @@ static struct heap_mem *heap_end; #define MIN_SIZE 12 #endif /* ARCH_CPU_64BIT */ -#define MIN_SIZE_ALIGNED RT_ALIGN(MIN_SIZE, RT_ALIGN_SIZE) -#define SIZEOF_STRUCT_MEM RT_ALIGN(sizeof(struct heap_mem), RT_ALIGN_SIZE) +#define MEM_MASK 0xfffffffe +#define MEM_USED() ((((rt_base_t)(small_mem)) & MEM_MASK) | 0x1) +#define MEM_FREED() ((((rt_base_t)(small_mem)) & MEM_MASK) | 0x0) +#define MEM_ISUSED(_mem) \ + (((rt_base_t)(((struct rt_small_mem_item *)(_mem))->pool_ptr)) & (~MEM_MASK)) +#define MEM_POOL(_mem) \ + ((struct rt_small_mem *)(((rt_base_t)(((struct rt_small_mem_item *)(_mem))->pool_ptr)) & (MEM_MASK))) +#define MEM_SIZE(_heap, _mem) \ + (((struct rt_small_mem_item *)(_mem))->next - ((rt_ubase_t)(_mem) - \ + (rt_ubase_t)((_heap)->heap_ptr)) - RT_ALIGN(sizeof(struct rt_small_mem_item), RT_ALIGN_SIZE)) -static struct heap_mem *lfree; /* pointer to the lowest free block */ - -static struct rt_semaphore heap_sem; -static rt_size_t mem_size_aligned; - -#ifdef RT_MEM_STATS -static rt_size_t used_mem, max_mem; -#endif /* RT_MEM_STATS */ +#define MIN_SIZE_ALIGNED RT_ALIGN(MIN_SIZE, RT_ALIGN_SIZE) +#define SIZEOF_STRUCT_MEM RT_ALIGN(sizeof(struct rt_small_mem_item), RT_ALIGN_SIZE) #ifdef RT_USING_MEMTRACE -rt_inline void rt_mem_setname(struct heap_mem *mem, const char *name) +rt_inline void rt_smem_setname(struct rt_small_mem_item *mem, const char *name) { int index; for (index = 0; index < sizeof(mem->thread); index ++) @@ -153,107 +122,144 @@ rt_inline void rt_mem_setname(struct heap_mem *mem, const char *name) } #endif /* RT_USING_MEMTRACE */ -static void plug_holes(struct heap_mem *mem) +static void plug_holes(struct rt_small_mem *m, struct rt_small_mem_item *mem) { - struct heap_mem *nmem; - struct heap_mem *pmem; + struct rt_small_mem_item *nmem; + struct rt_small_mem_item *pmem; - RT_ASSERT((rt_uint8_t *)mem >= heap_ptr); - RT_ASSERT((rt_uint8_t *)mem < (rt_uint8_t *)heap_end); - RT_ASSERT(mem->used == 0); + RT_ASSERT((rt_uint8_t *)mem >= m->heap_ptr); + RT_ASSERT((rt_uint8_t *)mem < (rt_uint8_t *)m->heap_end); /* plug hole forward */ - nmem = (struct heap_mem *)&heap_ptr[mem->next]; - if (mem != nmem && - nmem->used == 0 && - (rt_uint8_t *)nmem != (rt_uint8_t *)heap_end) + nmem = (struct rt_small_mem_item *)&m->heap_ptr[mem->next]; + if (mem != nmem && !MEM_ISUSED(nmem) && + (rt_uint8_t *)nmem != (rt_uint8_t *)m->heap_end) { - /* if mem->next is unused and not end of heap_ptr, + /* if mem->next is unused and not end of m->heap_ptr, * combine mem and mem->next */ - if (lfree == nmem) + if (m->lfree == nmem) { - lfree = mem; + m->lfree = mem; } + nmem->pool_ptr = 0; mem->next = nmem->next; - ((struct heap_mem *)&heap_ptr[nmem->next])->prev = (rt_uint8_t *)mem - heap_ptr; + ((struct rt_small_mem_item *)&m->heap_ptr[nmem->next])->prev = (rt_uint8_t *)mem - m->heap_ptr; } /* plug hole backward */ - pmem = (struct heap_mem *)&heap_ptr[mem->prev]; - if (pmem != mem && pmem->used == 0) + pmem = (struct rt_small_mem_item *)&m->heap_ptr[mem->prev]; + if (pmem != mem && !MEM_ISUSED(pmem)) { /* if mem->prev is unused, combine mem and mem->prev */ - if (lfree == mem) + if (m->lfree == mem) { - lfree = pmem; + m->lfree = pmem; } + mem->pool_ptr = 0; pmem->next = mem->next; - ((struct heap_mem *)&heap_ptr[mem->next])->prev = (rt_uint8_t *)pmem - heap_ptr; + ((struct rt_small_mem_item *)&m->heap_ptr[mem->next])->prev = (rt_uint8_t *)pmem - m->heap_ptr; } } /** - * @brief This function will initialize system heap memory. + * @brief This function will initialize small memory management algorithm. * - * @param begin_addr the beginning address of system heap memory. + * @param m the small memory management object. * - * @param end_addr the end address of system heap memory. + * @param name is the name of the small memory management object. + * + * @param begin_addr the beginning address of memory. + * + * @param size is the size of the memory. + * + * @return Return a pointer to the memory object. When the return value is RT_NULL, it means the init failed. */ -void rt_system_heap_init(void *begin_addr, void *end_addr) +rt_smem_t rt_smem_init(const char *name, + void *begin_addr, + rt_size_t size) { - struct heap_mem *mem; - rt_ubase_t begin_align = RT_ALIGN((rt_ubase_t)begin_addr, RT_ALIGN_SIZE); - rt_ubase_t end_align = RT_ALIGN_DOWN((rt_ubase_t)end_addr, RT_ALIGN_SIZE); + struct rt_small_mem_item *mem; + struct rt_small_mem *small_mem; + rt_ubase_t start_addr, begin_align, end_align, mem_size; - RT_DEBUG_NOT_IN_INTERRUPT; + small_mem = (struct rt_small_mem *)RT_ALIGN((rt_ubase_t)begin_addr, RT_ALIGN_SIZE); + start_addr = (rt_ubase_t)small_mem + sizeof(*small_mem); + begin_align = RT_ALIGN((rt_ubase_t)start_addr, RT_ALIGN_SIZE); + end_align = RT_ALIGN_DOWN((rt_ubase_t)begin_addr + size, RT_ALIGN_SIZE); /* alignment addr */ if ((end_align > (2 * SIZEOF_STRUCT_MEM)) && - ((end_align - 2 * SIZEOF_STRUCT_MEM) >= begin_align)) + ((end_align - 2 * SIZEOF_STRUCT_MEM) >= start_addr)) { /* calculate the aligned memory size */ - mem_size_aligned = end_align - begin_align - 2 * SIZEOF_STRUCT_MEM; + mem_size = end_align - begin_align - 2 * SIZEOF_STRUCT_MEM; } else { rt_kprintf("mem init, error begin address 0x%x, and end address 0x%x\n", - (rt_ubase_t)begin_addr, (rt_ubase_t)end_addr); + (rt_ubase_t)begin_addr, (rt_ubase_t)begin_addr + size); - return; + return RT_NULL; } + rt_memset(small_mem, 0, sizeof(*small_mem)); + /* initialize small memory object */ + rt_object_init(&(small_mem->parent.parent), RT_Object_Class_Memory, name); + small_mem->parent.algorithm = "small"; + small_mem->parent.address = begin_align; + small_mem->parent.total = mem_size; + small_mem->mem_size_aligned = mem_size; + /* point to begin address of heap */ - heap_ptr = (rt_uint8_t *)begin_align; + small_mem->heap_ptr = (rt_uint8_t *)begin_align; RT_DEBUG_LOG(RT_DEBUG_MEM, ("mem init, heap begin address 0x%x, size %d\n", - (rt_ubase_t)heap_ptr, mem_size_aligned)); + (rt_ubase_t)small_mem->heap_ptr, small_mem->mem_size_aligned)); /* initialize the start of the heap */ - mem = (struct heap_mem *)heap_ptr; - mem->magic = HEAP_MAGIC; - mem->next = mem_size_aligned + SIZEOF_STRUCT_MEM; + mem = (struct rt_small_mem_item *)small_mem->heap_ptr; + mem->pool_ptr = MEM_FREED(); + mem->next = small_mem->mem_size_aligned + SIZEOF_STRUCT_MEM; mem->prev = 0; - mem->used = 0; #ifdef RT_USING_MEMTRACE - rt_mem_setname(mem, "INIT"); + rt_smem_setname(mem, "INIT"); #endif /* RT_USING_MEMTRACE */ /* initialize the end of the heap */ - heap_end = (struct heap_mem *)&heap_ptr[mem->next]; - heap_end->magic = HEAP_MAGIC; - heap_end->used = 1; - heap_end->next = mem_size_aligned + SIZEOF_STRUCT_MEM; - heap_end->prev = mem_size_aligned + SIZEOF_STRUCT_MEM; + small_mem->heap_end = (struct rt_small_mem_item *)&small_mem->heap_ptr[mem->next]; + small_mem->heap_end->pool_ptr = MEM_USED(); + small_mem->heap_end->next = small_mem->mem_size_aligned + SIZEOF_STRUCT_MEM; + small_mem->heap_end->prev = small_mem->mem_size_aligned + SIZEOF_STRUCT_MEM; #ifdef RT_USING_MEMTRACE - rt_mem_setname(heap_end, "INIT"); + rt_smem_setname(small_mem->heap_end, "INIT"); #endif /* RT_USING_MEMTRACE */ - rt_sem_init(&heap_sem, "heap", 1, RT_IPC_FLAG_PRIO); - /* initialize the lowest-free pointer to the start of the heap */ - lfree = (struct heap_mem *)heap_ptr; + small_mem->lfree = (struct rt_small_mem_item *)small_mem->heap_ptr; + + return &small_mem->parent; } +RTM_EXPORT(rt_smem_init); + +/** + * @brief This function will remove a small mem from the system. + * + * @param m the small memory management object. + * + * @return RT_EOK + */ +rt_err_t rt_smem_detach(rt_smem_t m) +{ + RT_ASSERT(m != RT_NULL); + RT_ASSERT(rt_object_get_type(&m->parent) == RT_Object_Class_Memory); + RT_ASSERT(rt_object_is_systemobject(&m->parent)); + + rt_object_detach(&(m->parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_smem_detach); /** * @addtogroup MM @@ -264,19 +270,24 @@ void rt_system_heap_init(void *begin_addr, void *end_addr) /** * @brief Allocate a block of memory with a minimum of 'size' bytes. * + * @param m the small memory management object. + * * @param size is the minimum size of the requested block in bytes. * * @return the pointer to allocated memory or NULL if no free memory was found. */ -void *rt_malloc(rt_size_t size) +void *rt_smem_alloc(rt_smem_t m, rt_size_t size) { rt_size_t ptr, ptr2; - struct heap_mem *mem, *mem2; + struct rt_small_mem_item *mem, *mem2; + struct rt_small_mem *small_mem; if (size == 0) return RT_NULL; - RT_DEBUG_NOT_IN_INTERRUPT; + RT_ASSERT(m != RT_NULL); + RT_ASSERT(rt_object_get_type(&m->parent) == RT_Object_Class_Memory); + RT_ASSERT(rt_object_is_systemobject(&m->parent)); if (size != RT_ALIGN(size, RT_ALIGN_SIZE)) RT_DEBUG_LOG(RT_DEBUG_MEM, ("malloc size %d, but align to %d\n", @@ -284,10 +295,11 @@ void *rt_malloc(rt_size_t size) else RT_DEBUG_LOG(RT_DEBUG_MEM, ("malloc size %d\n", size)); + small_mem = (struct rt_small_mem *)m; /* alignment size */ size = RT_ALIGN(size, RT_ALIGN_SIZE); - if (size > mem_size_aligned) + if (size > small_mem->mem_size_aligned) { RT_DEBUG_LOG(RT_DEBUG_MEM, ("no memory\n")); @@ -298,16 +310,13 @@ void *rt_malloc(rt_size_t size) if (size < MIN_SIZE_ALIGNED) size = MIN_SIZE_ALIGNED; - /* take memory semaphore */ - rt_sem_take(&heap_sem, RT_WAITING_FOREVER); - - for (ptr = (rt_uint8_t *)lfree - heap_ptr; - ptr < mem_size_aligned - size; - ptr = ((struct heap_mem *)&heap_ptr[ptr])->next) + for (ptr = (rt_uint8_t *)small_mem->lfree - small_mem->heap_ptr; + ptr <= small_mem->mem_size_aligned - size; + ptr = ((struct rt_small_mem_item *)&small_mem->heap_ptr[ptr])->next) { - mem = (struct heap_mem *)&heap_ptr[ptr]; + mem = (struct rt_small_mem_item *)&small_mem->heap_ptr[ptr]; - if ((!mem->used) && (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) + if ((!MEM_ISUSED(mem)) && (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) { /* mem is not used and at least perfect fit is possible: * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ @@ -315,12 +324,12 @@ void *rt_malloc(rt_size_t size) if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { - /* (in addition to the above, we test if another struct heap_mem (SIZEOF_STRUCT_MEM) containing + /* (in addition to the above, we test if another struct rt_small_mem_item (SIZEOF_STRUCT_MEM) containing * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') * -> split large block, create empty remainder, * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, - * struct heap_mem would fit in but no data between mem2 and mem2->next + * struct rt_small_mem_item would fit in but no data between mem2 and mem2->next * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty * region that couldn't hold data, but when mem->next gets freed, * the 2 regions would be combined, resulting in more free memory @@ -328,28 +337,24 @@ void *rt_malloc(rt_size_t size) ptr2 = ptr + SIZEOF_STRUCT_MEM + size; /* create mem2 struct */ - mem2 = (struct heap_mem *)&heap_ptr[ptr2]; - mem2->magic = HEAP_MAGIC; - mem2->used = 0; + mem2 = (struct rt_small_mem_item *)&small_mem->heap_ptr[ptr2]; + mem2->pool_ptr = MEM_FREED(); mem2->next = mem->next; mem2->prev = ptr; #ifdef RT_USING_MEMTRACE - rt_mem_setname(mem2, " "); + rt_smem_setname(mem2, " "); #endif /* RT_USING_MEMTRACE */ /* and insert it between mem and mem->next */ mem->next = ptr2; - mem->used = 1; - if (mem2->next != mem_size_aligned + SIZEOF_STRUCT_MEM) + if (mem2->next != small_mem->mem_size_aligned + SIZEOF_STRUCT_MEM) { - ((struct heap_mem *)&heap_ptr[mem2->next])->prev = ptr2; + ((struct rt_small_mem_item *)&small_mem->heap_ptr[mem2->next])->prev = ptr2; } -#ifdef RT_MEM_STATS - used_mem += (size + SIZEOF_STRUCT_MEM); - if (max_mem < used_mem) - max_mem = used_mem; -#endif /* RT_MEM_STATS */ + small_mem->parent.used += (size + SIZEOF_STRUCT_MEM); + if (small_mem->parent.max < small_mem->parent.used) + small_mem->parent.max = small_mem->parent.used; } else { @@ -360,76 +365,72 @@ void *rt_malloc(rt_size_t size) * also can't move mem->next directly behind mem, since mem->next * will always be used at this point! */ - mem->used = 1; -#ifdef RT_MEM_STATS - used_mem += mem->next - ((rt_uint8_t *)mem - heap_ptr); - if (max_mem < used_mem) - max_mem = used_mem; -#endif /* RT_MEM_STATS */ + small_mem->parent.used += mem->next - ((rt_uint8_t *)mem - small_mem->heap_ptr); + if (small_mem->parent.max < small_mem->parent.used) + small_mem->parent.max = small_mem->parent.used; } - /* set memory block magic */ - mem->magic = HEAP_MAGIC; + /* set small memory object */ + mem->pool_ptr = MEM_USED(); #ifdef RT_USING_MEMTRACE if (rt_thread_self()) - rt_mem_setname(mem, rt_thread_self()->name); + rt_smem_setname(mem, rt_thread_self()->name); else - rt_mem_setname(mem, "NONE"); + rt_smem_setname(mem, "NONE"); #endif /* RT_USING_MEMTRACE */ - if (mem == lfree) + if (mem == small_mem->lfree) { /* Find next free block after mem and update lowest free pointer */ - while (lfree->used && lfree != heap_end) - lfree = (struct heap_mem *)&heap_ptr[lfree->next]; + while (MEM_ISUSED(small_mem->lfree) && small_mem->lfree != small_mem->heap_end) + small_mem->lfree = (struct rt_small_mem_item *)&small_mem->heap_ptr[small_mem->lfree->next]; - RT_ASSERT(((lfree == heap_end) || (!lfree->used))); + RT_ASSERT(((small_mem->lfree == small_mem->heap_end) || (!MEM_ISUSED(small_mem->lfree)))); } - - rt_sem_release(&heap_sem); - RT_ASSERT((rt_ubase_t)mem + SIZEOF_STRUCT_MEM + size <= (rt_ubase_t)heap_end); + RT_ASSERT((rt_ubase_t)mem + SIZEOF_STRUCT_MEM + size <= (rt_ubase_t)small_mem->heap_end); RT_ASSERT((rt_ubase_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM) % RT_ALIGN_SIZE == 0); RT_ASSERT((((rt_ubase_t)mem) & (RT_ALIGN_SIZE - 1)) == 0); RT_DEBUG_LOG(RT_DEBUG_MEM, ("allocate memory at 0x%x, size: %d\n", (rt_ubase_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM), - (rt_ubase_t)(mem->next - ((rt_uint8_t *)mem - heap_ptr)))); - - RT_OBJECT_HOOK_CALL(rt_malloc_hook, - (((void *)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM)), size)); + (rt_ubase_t)(mem->next - ((rt_uint8_t *)mem - small_mem->heap_ptr)))); /* return the memory data except mem struct */ return (rt_uint8_t *)mem + SIZEOF_STRUCT_MEM; } } - rt_sem_release(&heap_sem); - return RT_NULL; } -RTM_EXPORT(rt_malloc); +RTM_EXPORT(rt_smem_alloc); /** * @brief This function will change the size of previously allocated memory block. * - * @param rmem is the pointer to memory allocated by rt_malloc. + * @param m the small memory management object. + * + * @param rmem is the pointer to memory allocated by rt_mem_alloc. * * @param newsize is the required new size. * * @return the changed memory block address. */ -void *rt_realloc(void *rmem, rt_size_t newsize) +void *rt_smem_realloc(rt_smem_t m, void *rmem, rt_size_t newsize) { rt_size_t size; rt_size_t ptr, ptr2; - struct heap_mem *mem, *mem2; + struct rt_small_mem_item *mem, *mem2; + struct rt_small_mem *small_mem; void *nmem; - RT_DEBUG_NOT_IN_INTERRUPT; + RT_ASSERT(m != RT_NULL); + RT_ASSERT(rt_object_get_type(&m->parent) == RT_Object_Class_Memory); + RT_ASSERT(rt_object_is_systemobject(&m->parent)); + small_mem = (struct rt_small_mem *)m; /* alignment size */ newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE); - if (newsize > mem_size_aligned) + if (newsize > small_mem->mem_size_aligned) { RT_DEBUG_LOG(RT_DEBUG_MEM, ("realloc: out of memory\n")); @@ -437,243 +438,171 @@ void *rt_realloc(void *rmem, rt_size_t newsize) } else if (newsize == 0) { - rt_free(rmem); + rt_smem_free(rmem); return RT_NULL; } /* allocate a new memory block */ if (rmem == RT_NULL) - return rt_malloc(newsize); - - rt_sem_take(&heap_sem, RT_WAITING_FOREVER); + return rt_smem_alloc(&small_mem->parent, newsize); - if ((rt_uint8_t *)rmem < (rt_uint8_t *)heap_ptr || - (rt_uint8_t *)rmem >= (rt_uint8_t *)heap_end) - { - /* illegal memory */ - rt_sem_release(&heap_sem); - - return rmem; - } + RT_ASSERT((((rt_ubase_t)rmem) & (RT_ALIGN_SIZE - 1)) == 0); + RT_ASSERT((rt_uint8_t *)rmem >= (rt_uint8_t *)small_mem->heap_ptr); + RT_ASSERT((rt_uint8_t *)rmem < (rt_uint8_t *)small_mem->heap_end); - mem = (struct heap_mem *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM); + mem = (struct rt_small_mem_item *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM); - ptr = (rt_uint8_t *)mem - heap_ptr; + /* current memory block size */ + ptr = (rt_uint8_t *)mem - small_mem->heap_ptr; size = mem->next - ptr - SIZEOF_STRUCT_MEM; if (size == newsize) { /* the size is the same as */ - rt_sem_release(&heap_sem); - return rmem; } if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size) { /* split memory block */ -#ifdef RT_MEM_STATS - used_mem -= (size - newsize); -#endif /* RT_MEM_STATS */ + small_mem->parent.used -= (size - newsize); ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; - mem2 = (struct heap_mem *)&heap_ptr[ptr2]; - mem2->magic = HEAP_MAGIC; - mem2->used = 0; + mem2 = (struct rt_small_mem_item *)&small_mem->heap_ptr[ptr2]; + mem2->pool_ptr = MEM_FREED(); mem2->next = mem->next; mem2->prev = ptr; #ifdef RT_USING_MEMTRACE - rt_mem_setname(mem2, " "); + rt_smem_setname(mem2, " "); #endif /* RT_USING_MEMTRACE */ mem->next = ptr2; - if (mem2->next != mem_size_aligned + SIZEOF_STRUCT_MEM) + if (mem2->next != small_mem->mem_size_aligned + SIZEOF_STRUCT_MEM) { - ((struct heap_mem *)&heap_ptr[mem2->next])->prev = ptr2; + ((struct rt_small_mem_item *)&small_mem->heap_ptr[mem2->next])->prev = ptr2; } - if (mem2 < lfree) + if (mem2 < small_mem->lfree) { /* the splited struct is now the lowest */ - lfree = mem2; + small_mem->lfree = mem2; } - plug_holes(mem2); - - rt_sem_release(&heap_sem); + plug_holes(small_mem, mem2); return rmem; } - rt_sem_release(&heap_sem); /* expand memory */ - nmem = rt_malloc(newsize); + nmem = rt_smem_alloc(&small_mem->parent, newsize); if (nmem != RT_NULL) /* check memory */ { rt_memcpy(nmem, rmem, size < newsize ? size : newsize); - rt_free(rmem); + rt_smem_free(rmem); } return nmem; } -RTM_EXPORT(rt_realloc); - -/** - * @brief This function will contiguously allocate enough space for count objects - * that are size bytes of memory each and returns a pointer to the allocated - * memory. - * - * @note The allocated memory is filled with bytes of value zero. - * - * @param count is the number of objects to allocate. - * - * @param size is the size of one object to allocate. - * - * @return pointer to allocated memory / NULL pointer if there is an error. - */ -void *rt_calloc(rt_size_t count, rt_size_t size) -{ - void *p; - - /* allocate 'count' objects of size 'size' */ - p = rt_malloc(count * size); - - /* zero the memory */ - if (p) - rt_memset(p, 0, count * size); - - return p; -} -RTM_EXPORT(rt_calloc); +RTM_EXPORT(rt_smem_realloc); /** * @brief This function will release the previously allocated memory block by - * rt_malloc. The released memory block is taken back to system heap. + * rt_mem_alloc. The released memory block is taken back to system heap. * * @param rmem the address of memory which will be released. */ -void rt_free(void *rmem) +void rt_smem_free(void *rmem) { - struct heap_mem *mem; + struct rt_small_mem_item *mem; + struct rt_small_mem *small_mem; if (rmem == RT_NULL) return; - RT_DEBUG_NOT_IN_INTERRUPT; - RT_ASSERT((((rt_ubase_t)rmem) & (RT_ALIGN_SIZE - 1)) == 0); - RT_ASSERT((rt_uint8_t *)rmem >= (rt_uint8_t *)heap_ptr && - (rt_uint8_t *)rmem < (rt_uint8_t *)heap_end); - - RT_OBJECT_HOOK_CALL(rt_free_hook, (rmem)); - - if ((rt_uint8_t *)rmem < (rt_uint8_t *)heap_ptr || - (rt_uint8_t *)rmem >= (rt_uint8_t *)heap_end) - { - RT_DEBUG_LOG(RT_DEBUG_MEM, ("illegal memory\n")); - return; - } - - /* Get the corresponding struct heap_mem ... */ - mem = (struct heap_mem *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM); + /* Get the corresponding struct rt_small_mem_item ... */ + mem = (struct rt_small_mem_item *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM); RT_DEBUG_LOG(RT_DEBUG_MEM, ("release memory 0x%x, size: %d\n", (rt_ubase_t)rmem, - (rt_ubase_t)(mem->next - ((rt_uint8_t *)mem - heap_ptr)))); - - - /* protect the heap from concurrent access */ - rt_sem_take(&heap_sem, RT_WAITING_FOREVER); + (rt_ubase_t)(mem->next - ((rt_uint8_t *)mem - small_mem->heap_ptr)))); /* ... which has to be in a used state ... */ - if (!mem->used || mem->magic != HEAP_MAGIC) - { - rt_kprintf("to free a bad data block:\n"); - rt_kprintf("mem: 0x%08x, used flag: %d, magic code: 0x%04x\n", mem, mem->used, mem->magic); - } - RT_ASSERT(mem->used); - RT_ASSERT(mem->magic == HEAP_MAGIC); + small_mem = MEM_POOL(mem); + RT_ASSERT(small_mem != RT_NULL); + RT_ASSERT(MEM_ISUSED(mem)); + RT_ASSERT(rt_object_get_type(&small_mem->parent.parent) == RT_Object_Class_Memory); + RT_ASSERT(rt_object_is_systemobject(&small_mem->parent.parent)); + RT_ASSERT((rt_uint8_t *)rmem >= (rt_uint8_t *)small_mem->heap_ptr && + (rt_uint8_t *)rmem < (rt_uint8_t *)small_mem->heap_end); + RT_ASSERT(MEM_POOL(&small_mem->heap_ptr[mem->next]) == small_mem); + /* ... and is now unused. */ - mem->used = 0; - mem->magic = HEAP_MAGIC; + mem->pool_ptr = MEM_FREED(); #ifdef RT_USING_MEMTRACE - rt_mem_setname(mem, " "); + rt_smem_setname(mem, " "); #endif /* RT_USING_MEMTRACE */ - if (mem < lfree) + if (mem < small_mem->lfree) { /* the newly freed struct is now the lowest */ - lfree = mem; + small_mem->lfree = mem; } -#ifdef RT_MEM_STATS - used_mem -= (mem->next - ((rt_uint8_t *)mem - heap_ptr)); -#endif /* RT_MEM_STATS */ + small_mem->parent.used -= (mem->next - ((rt_uint8_t *)mem - small_mem->heap_ptr)); /* finally, see if prev or next are free also */ - plug_holes(mem); - rt_sem_release(&heap_sem); -} -RTM_EXPORT(rt_free); - -#ifdef RT_MEM_STATS -/** -* @brief This function will caculate the total memory, the used memory, and -* the max used memory. -* -* @param total is a pointer to get the total size of the memory. -* -* @param used is a pointer to get the size of memory used. -* -* @param max_used is a pointer to get the maximum memory used. -*/ -void rt_memory_info(rt_uint32_t *total, - rt_uint32_t *used, - rt_uint32_t *max_used) -{ - if (total != RT_NULL) - *total = mem_size_aligned; - if (used != RT_NULL) - *used = used_mem; - if (max_used != RT_NULL) - *max_used = max_mem; + plug_holes(small_mem, mem); } +RTM_EXPORT(rt_smem_free); #ifdef RT_USING_FINSH #include <finsh.h> -void list_mem(void) -{ - rt_kprintf("total memory: %d\n", mem_size_aligned); - rt_kprintf("used memory : %d\n", used_mem); - rt_kprintf("maximum allocated memory: %d\n", max_mem); -} -FINSH_FUNCTION_EXPORT(list_mem, list memory usage information) - #ifdef RT_USING_MEMTRACE -int memcheck(void) +int memcheck(int argc, char *argv[]) { int position; rt_ubase_t level; - struct heap_mem *mem; + struct rt_small_mem_item *mem; + struct rt_small_mem *m; + struct rt_object_information *information; + struct rt_list_node *node; + struct rt_object *object; + char *name; + + name = argc > 1 ? argv[1] : RT_NULL; level = rt_hw_interrupt_disable(); - for (mem = (struct heap_mem *)heap_ptr; mem != heap_end; mem = (struct heap_mem *)&heap_ptr[mem->next]) + /* get mem object */ + information = rt_object_get_information(RT_Object_Class_Memory); + for (node = information->object_list.next; + node != &(information->object_list); + node = node->next) { - position = (rt_ubase_t)mem - (rt_ubase_t)heap_ptr; - if (position < 0) goto __exit; - if (position > (int)mem_size_aligned) goto __exit; - if (mem->magic != HEAP_MAGIC) goto __exit; - if (mem->used != 0 && mem->used != 1) goto __exit; + object = rt_list_entry(node, struct rt_object, list); + /* find the specified object */ + if (name != RT_NULL && rt_strncmp(name, object->name, RT_NAME_MAX) != 0) + continue; + /* mem object */ + m = (struct rt_small_mem *)object; + /* check mem */ + for (mem = (struct rt_small_mem_item *)m->heap_ptr; mem != m->heap_end; mem = (struct rt_small_mem_item *)&m->heap_ptr[mem->next]) + { + position = (rt_ubase_t)mem - (rt_ubase_t)m->heap_ptr; + if (position < 0) goto __exit; + if (position > (int)m->mem_size_aligned) goto __exit; + if (MEM_POOL(mem) != m) goto __exit; + } } rt_hw_interrupt_enable(level); return 0; __exit: rt_kprintf("Memory block wrong:\n"); + rt_kprintf(" name: %s\n", m->parent.parent.name); rt_kprintf("address: 0x%08x\n", mem); - rt_kprintf(" magic: 0x%04x\n", mem->magic); - rt_kprintf(" used: %d\n", mem->used); - rt_kprintf(" size: %d\n", mem->next - position - SIZEOF_STRUCT_MEM); + rt_kprintf(" pool: 0x%04x\n", mem->pool_ptr); + rt_kprintf(" size: %d\n", mem->next - position - SIZEOF_STRUCT_MEM); rt_hw_interrupt_enable(level); return 0; @@ -682,47 +611,61 @@ MSH_CMD_EXPORT(memcheck, check memory data); int memtrace(int argc, char **argv) { - struct heap_mem *mem; + struct rt_small_mem_item *mem; + struct rt_small_mem *m; + struct rt_object_information *information; + struct rt_list_node *node; + struct rt_object *object; + char *name; - list_mem(); - - rt_kprintf("\nmemory heap address:\n"); - rt_kprintf("heap_ptr: 0x%08x\n", heap_ptr); - rt_kprintf("lfree : 0x%08x\n", lfree); - rt_kprintf("heap_end: 0x%08x\n", heap_end); - - rt_kprintf("\n--memory item information --\n"); - for (mem = (struct heap_mem *)heap_ptr; mem != heap_end; mem = (struct heap_mem *)&heap_ptr[mem->next]) + name = argc > 1 ? argv[1] : RT_NULL; + /* get mem object */ + information = rt_object_get_information(RT_Object_Class_Memory); + for (node = information->object_list.next; + node != &(information->object_list); + node = node->next) { - int position = (rt_ubase_t)mem - (rt_ubase_t)heap_ptr; - int size; - - rt_kprintf("[0x%08x - ", mem); + object = rt_list_entry(node, struct rt_object, list); + /* find the specified object */ + if (name != RT_NULL && rt_strncmp(name, object->name, RT_NAME_MAX) != 0) + continue; + /* mem object */ + m = (struct rt_small_mem *)object; + /* show memory information */ + rt_kprintf("\nmemory heap address:\n"); + rt_kprintf("name : %s\n", m->parent.parent.name); + rt_kprintf("total : 0x%d\n", m->parent.total); + rt_kprintf("used : 0x%d\n", m->parent.used); + rt_kprintf("max_used: 0x%d\n", m->parent.max); + rt_kprintf("heap_ptr: 0x%08x\n", m->heap_ptr); + rt_kprintf("lfree : 0x%08x\n", m->lfree); + rt_kprintf("heap_end: 0x%08x\n", m->heap_end); + rt_kprintf("\n--memory item information --\n"); + for (mem = (struct rt_small_mem_item *)m->heap_ptr; mem != m->heap_end; mem = (struct rt_small_mem_item *)&m->heap_ptr[mem->next]) + { + int size = MEM_SIZE(m, mem); - size = mem->next - position - SIZEOF_STRUCT_MEM; - if (size < 1024) - rt_kprintf("%5d", size); - else if (size < 1024 * 1024) - rt_kprintf("%4dK", size / 1024); - else - rt_kprintf("%4dM", size / (1024 * 1024)); + rt_kprintf("[0x%08x - ", mem); + if (size < 1024) + rt_kprintf("%5d", size); + else if (size < 1024 * 1024) + rt_kprintf("%4dK", size / 1024); + else + rt_kprintf("%4dM", size / (1024 * 1024)); - rt_kprintf("] %c%c%c%c", mem->thread[0], mem->thread[1], mem->thread[2], mem->thread[3]); - if (mem->magic != HEAP_MAGIC) - rt_kprintf(": ***\n"); - else - rt_kprintf("\n"); + rt_kprintf("] %c%c%c%c", mem->thread[0], mem->thread[1], mem->thread[2], mem->thread[3]); + if (MEM_POOL(mem) != m) + rt_kprintf(": ***\n"); + else + rt_kprintf("\n"); + } } - return 0; } MSH_CMD_EXPORT(memtrace, dump memory trace information); #endif /* RT_USING_MEMTRACE */ #endif /* RT_USING_FINSH */ -#endif /* defined (RT_USING_HEAP) && defined (RT_USING_SMALL_MEM) */ +#endif /* defined (RT_USING_SMALL_MEM) */ /**@}*/ - -#endif /* RT_MEM_STATS */ -#endif /* RT_USING_MEMHEAP_AS_HEAP */ diff --git a/src/memheap.c b/src/memheap.c index e96b402bcf..62b42f73ed 100644 --- a/src/memheap.c +++ b/src/memheap.c @@ -38,58 +38,6 @@ #define MEMITEM_SIZE(item) ((rt_ubase_t)item->next - (rt_ubase_t)item - RT_MEMHEAP_SIZE) #define MEMITEM(ptr) (struct rt_memheap_item*)((rt_uint8_t*)ptr - RT_MEMHEAP_SIZE) -#ifdef RT_USING_MEMTRACE -/** - * @brief This function will set a new name for memheap. - * - * @param item is a pointer point to a memheap object. - * - * @param name is the new name to be set. - */ -rt_inline void rt_memheap_setname(struct rt_memheap_item *item, const char *name) -{ - int index; - rt_uint8_t *ptr; - - ptr = (rt_uint8_t *) & (item->next_free); - for (index = 0; index < sizeof(void *); index ++) - { - if (name[index] == '\0') break; - ptr[index] = name[index]; - } - if (name[index] == '\0') ptr[index] = '\0'; - else - { - ptr = (rt_uint8_t *) & (item->prev_free); - for (index = 0; index < sizeof(void *) && (index + sizeof(void *)) < RT_NAME_MAX; index ++) - { - if (name[sizeof(void *) + index] == '\0') break; - ptr[index] = name[sizeof(void *) + index]; - } - - if (name[sizeof(void *) + index] == '\0') ptr[index] = '\0'; - } -} - -/** - * @brief This function will set a new name for memheap. - * - * @param ptr is a pointer point to a memheap object. - * - * @param name is the new name to be set. - */ -void rt_mem_set_tag(void *ptr, const char *name) -{ - struct rt_memheap_item *item; - - if (ptr && name) - { - item = MEMITEM(ptr); - rt_memheap_setname(item, name); - } -} -#endif /* RT_USING_MEMTRACE */ - /** * @brief This function initializes a piece of memory called memheap. * @@ -182,6 +130,7 @@ rt_err_t rt_memheap_init(struct rt_memheap *memheap, /* initialize semaphore lock */ rt_sem_init(&(memheap->lock), name, 1, RT_IPC_FLAG_PRIO); + memheap->locked = RT_FALSE; RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("memory heap: start addr 0x%08x, size %d, free list header 0x%08x\n", @@ -244,12 +193,15 @@ void *rt_memheap_alloc(struct rt_memheap *heap, rt_size_t size) free_size = 0; /* lock memheap */ - result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); - if (result != RT_EOK) + if (heap->locked == RT_FALSE) { - rt_set_errno(result); + result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); + if (result != RT_EOK) + { + rt_set_errno(result); - return RT_NULL; + return RT_NULL; + } } /* get the first free memory block */ @@ -354,8 +306,11 @@ void *rt_memheap_alloc(struct rt_memheap *heap, rt_size_t size) rt_memcpy(header_ptr->owner_thread_name, "NONE", sizeof(header_ptr->owner_thread_name)); #endif /* RT_USING_MEMTRACE */ - /* release lock */ - rt_sem_release(&(heap->lock)); + if (heap->locked == RT_FALSE) + { + /* release lock */ + rt_sem_release(&(heap->lock)); + } /* Return a memory address to the caller. */ RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, @@ -367,8 +322,11 @@ void *rt_memheap_alloc(struct rt_memheap *heap, rt_size_t size) return (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE); } - /* release lock */ - rt_sem_release(&(heap->lock)); + if (heap->locked == RT_FALSE) + { + /* release lock */ + rt_sem_release(&(heap->lock)); + } } RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate memory: failed\n")); @@ -427,12 +385,15 @@ void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize) /* Fix the crash problem after opening Oz optimization on ac6 */ volatile struct rt_memheap_item *next_ptr; - /* lock memheap */ - result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); - if (result != RT_EOK) + if (heap->locked == RT_FALSE) { - rt_set_errno(result); - return RT_NULL; + /* 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; @@ -508,16 +469,21 @@ void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize) 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)); + if (heap->locked == RT_FALSE) + { + /* release lock */ + rt_sem_release(&(heap->lock)); + } return ptr; } } - /* release lock */ - rt_sem_release(&(heap->lock)); + if (heap->locked == RT_FALSE) + { + /* release lock */ + rt_sem_release(&(heap->lock)); + } /* re-allocate a memory block */ new_ptr = (void *)rt_memheap_alloc(heap, newsize); @@ -534,13 +500,16 @@ void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize) 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) + if (heap->locked == RT_FALSE) { - rt_set_errno(result); + /* lock memheap */ + result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); + if (result != RT_EOK) + { + rt_set_errno(result); - return RT_NULL; + return RT_NULL; + } } /* split the block. */ @@ -602,8 +571,11 @@ void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize) /* increment the available byte count. */ heap->available_size = heap->available_size + MEMITEM_SIZE(new_ptr); - /* release lock */ - rt_sem_release(&(heap->lock)); + if (heap->locked == RT_FALSE) + { + /* release lock */ + rt_sem_release(&(heap->lock)); + } /* return the old memory block */ return ptr; @@ -636,14 +608,15 @@ void rt_memheap_free(void *ptr) ptr, header_ptr)); /* check magic */ - if (header_ptr->magic != (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED)) + if (header_ptr->magic != (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED) || + (header_ptr->next->magic & RT_MEMHEAP_MASK) != RT_MEMHEAP_MAGIC) { RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("bad magic:0x%08x @ memheap\n", header_ptr->magic)); + RT_ASSERT(header_ptr->magic == (RT_MEMHEAP_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); } - RT_ASSERT(header_ptr->magic == (RT_MEMHEAP_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; @@ -651,13 +624,16 @@ void rt_memheap_free(void *ptr) RT_ASSERT(heap); RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap); - /* lock memheap */ - result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); - if (result != RT_EOK) + if (heap->locked == RT_FALSE) { - rt_set_errno(result); + /* lock memheap */ + result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); + if (result != RT_EOK) + { + rt_set_errno(result); - return ; + return ; + } } /* Mark the memory as available. */ @@ -707,11 +683,23 @@ void rt_memheap_free(void *ptr) if (insert_header) { + struct rt_memheap_item *n = heap->free_list->next_free;; +#if defined(RT_MEMHEAP_BSET_MODE) + rt_uint32_t blk_size = MEMITEM_SIZE(header_ptr); + for (;n != heap->free_list; n = n->next_free) + { + rt_uint32_t m = MEMITEM_SIZE(n); + if (blk_size <= m) + { + break; + } + } +#endif /* 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; + header_ptr->next_free = n; + header_ptr->prev_free = n->prev_free; + n->prev_free->next_free = header_ptr; + n->prev_free = header_ptr; RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("insert to free list: next_free 0x%08x, prev_free 0x%08x\n", @@ -722,149 +710,77 @@ void rt_memheap_free(void *ptr) rt_memset(header_ptr->owner_thread_name, ' ', sizeof(header_ptr->owner_thread_name)); #endif /* RT_USING_MEMTRACE */ - /* release lock */ - rt_sem_release(&(heap->lock)); + if (heap->locked == RT_FALSE) + { + /* release lock */ + rt_sem_release(&(heap->lock)); + } } RTM_EXPORT(rt_memheap_free); -#ifdef RT_USING_FINSH -static void _memheap_dump_tag(struct rt_memheap_item *item) -{ - rt_uint8_t name[2 * sizeof(void *)]; - rt_uint8_t *ptr; - - ptr = (rt_uint8_t *) & (item->next_free); - rt_memcpy(name, ptr, sizeof(void *)); - ptr = (rt_uint8_t *) & (item->prev_free); - rt_memcpy(&name[sizeof(void *)], ptr, sizeof(void *)); - - rt_kprintf("%.*s", 2 * sizeof(void *), name); -} /** - * @brief This function will print the memheap infomation. - * - * @param heap is the pointer to the memheap to get information. - * - * @return 0 - */ -int rt_memheap_dump(struct rt_memheap *heap) +* @brief This function will caculate the total memory, the used memory, and +* the max used memory. +* +* @param heap is a pointer to the memheap object, which will reallocate +* memory from the block +* +* @param total is a pointer to get the total size of the memory. +* +* @param used is a pointer to get the size of memory used. +* +* @param max_used is a pointer to get the maximum memory used. +*/ +void rt_memheap_info(struct rt_memheap *heap, + rt_uint32_t *total, + rt_uint32_t *used, + rt_uint32_t *max_used) { - struct rt_memheap_item *item, *end; - - if (heap == RT_NULL) return 0; - RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap); - - rt_kprintf("\n[%.*s] [0x%08x - 0x%08x]->\n", RT_NAME_MAX, heap->parent.name, - (rt_ubase_t)heap->start_addr, (rt_ubase_t)heap->start_addr + heap->pool_size); - rt_kprintf("------------------------------\n"); - - /* lock memheap */ - rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); - item = heap->block_list; - - end = (struct rt_memheap_item *)((rt_uint8_t *)heap->start_addr + heap->pool_size - RT_MEMHEAP_SIZE); + rt_err_t result; - /* for each memory block */ - while ((rt_ubase_t)item < ((rt_ubase_t)end)) + if (heap->locked == RT_FALSE) { - if (RT_MEMHEAP_IS_USED(item) && ((item->magic & RT_MEMHEAP_MASK) != RT_MEMHEAP_MAGIC)) - rt_kprintf("0x%08x", item + 1); - - if (item->magic == (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED)) - { - rt_kprintf("0x%08x: %-8d ", item + 1, MEMITEM_SIZE(item)); - _memheap_dump_tag(item); - rt_kprintf("\n"); - } - else + /* lock memheap */ + result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); + if (result != RT_EOK) { - rt_kprintf("0x%08x: %-8d <F>\n", item + 1, MEMITEM_SIZE(item)); + rt_set_errno(result); + return; } - - item = item->next; } - rt_sem_release(&(heap->lock)); - return 0; -} - -int memheaptrace(void) -{ - int count = rt_object_get_length(RT_Object_Class_MemHeap); - struct rt_memheap **heaps; + if (total != RT_NULL) + *total = heap->pool_size; - if (count > 0) - { - int index; -#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS) - extern int list_memheap(void); -#endif + if (used != RT_NULL) + *used = heap->pool_size - heap->available_size; - heaps = (struct rt_memheap **)rt_malloc(sizeof(struct rt_memheap *) * count); - if (heaps == RT_NULL) return 0; -#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS) - list_memheap(); -#endif - rt_kprintf("memheap header size: %d\n", RT_MEMHEAP_SIZE); - count = rt_object_get_pointers(RT_Object_Class_MemHeap, (rt_object_t *)heaps, count); - for (index = 0; index < count; index++) - { - rt_memheap_dump(heaps[index]); - } + if (max_used != RT_NULL) + *max_used = heap->max_used_size; - rt_free(heaps); + if (heap->locked == RT_FALSE) + { + /* release lock */ + rt_sem_release(&(heap->lock)); } - - return 0; } -MSH_CMD_EXPORT(memheaptrace, dump memory trace information); -#endif /* RT_USING_FINSH */ #ifdef RT_USING_MEMHEAP_AS_HEAP -static struct rt_memheap _heap; - -/** - * @brief This function initializes a heap for system. - * - * @param begin_addr is the start address of the memory. - * - * @param end_addr is the end address of the memory. - */ -void rt_system_heap_init(void *begin_addr, void *end_addr) -{ - RT_ASSERT((rt_size_t)end_addr > (rt_size_t)begin_addr); - - rt_size_t begin_align = RT_ALIGN((rt_size_t)begin_addr, RT_ALIGN_SIZE); - rt_size_t end_align = RT_ALIGN_DOWN((rt_size_t)end_addr, RT_ALIGN_SIZE); - - /* initialize a default heap in the system */ - rt_memheap_init(&_heap, - "heap", - (void *)begin_align, - end_align - begin_align); -} - -/** - * @brief Allocate a block of memory with a minimum of 'size' bytes. - * - * @param size is the minimum size of the requested block in bytes. - */ -void *rt_malloc(rt_size_t size) +/* + * rt_malloc port function +*/ +void *_memheap_alloc(struct rt_memheap *heap, rt_size_t size) { void *ptr; - /* zero size, return RT_NULL */ - if (size == 0) - return RT_NULL; - /* try to allocate in system heap */ - ptr = rt_memheap_alloc(&_heap, size); + ptr = rt_memheap_alloc(heap, size); #ifdef RT_USING_MEMHEAP_AUTO_BINDING if (ptr == RT_NULL) { struct rt_object *object; struct rt_list_node *node; - struct rt_memheap *heap; + struct rt_memheap *_heap; struct rt_object_information *information; /* try to allocate on other memory heap */ @@ -875,75 +791,43 @@ void *rt_malloc(rt_size_t size) node = node->next) { object = rt_list_entry(node, struct rt_object, list); - heap = (struct rt_memheap *)object; - - RT_ASSERT(heap); - RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap); + _heap = (struct rt_memheap *)object; /* not allocate in the default system heap */ - if (heap == &_heap) + if (heap == _heap) continue; - ptr = rt_memheap_alloc(heap, size); + ptr = rt_memheap_alloc(_heap, size); if (ptr != RT_NULL) break; } } #endif /* RT_USING_MEMHEAP_AUTO_BINDING */ - -#ifdef RT_USING_MEMTRACE - if (ptr == RT_NULL) - { - RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("malloc[%d] => NULL", size)); - } - else - { - struct rt_memheap_item *item = MEMITEM(ptr); - if (rt_thread_self()) - rt_memheap_setname(item, rt_thread_self()->name); - else - rt_memheap_setname(item, "<null>"); - - RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("malloc => 0x%08x : %d", ptr, size)); - } -#endif /* RT_USING_MEMTRACE */ - return ptr; } -RTM_EXPORT(rt_malloc); -/** - * @brief This function will release the previously allocated memory block by - * rt_malloc. The released memory block is taken back to system heap. - * - * @param rmem the address of memory which will be released. - */ -void rt_free(void *rmem) +/* + * rt_free port function +*/ +void _memheap_free(void *rmem) { rt_memheap_free(rmem); } -RTM_EXPORT(rt_free); -/** - * @brief This function will change the size of previously allocated memory block. - * - * @param rmem is the pointer to memory allocated by rt_malloc. - * - * @param newsize is the required new size. - * - * @return the changed memory block address. - */ -void *rt_realloc(void *rmem, rt_size_t newsize) +/* + * rt_realloc port function +*/ +void *_memheap_realloc(struct rt_memheap *heap, void *rmem, rt_size_t newsize) { void *new_ptr; struct rt_memheap_item *header_ptr; if (rmem == RT_NULL) - return rt_malloc(newsize); + return _memheap_alloc(heap, newsize); if (newsize == 0) { - rt_free(rmem); + _memheap_free(rmem); return RT_NULL; } @@ -955,7 +839,7 @@ void *rt_realloc(void *rmem, rt_size_t newsize) if (new_ptr == RT_NULL && newsize != 0) { /* allocate memory block from other memheap */ - new_ptr = rt_malloc(newsize); + new_ptr = _memheap_alloc(heap, newsize); if (new_ptr != RT_NULL && rmem != RT_NULL) { rt_size_t oldsize; @@ -967,177 +851,145 @@ void *rt_realloc(void *rmem, rt_size_t newsize) else rt_memcpy(new_ptr, rmem, newsize); - rt_free(rmem); + _memheap_free(rmem); } } -#ifdef RT_USING_MEMTRACE - if (new_ptr == RT_NULL) - { - RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("realloc[%d] => NULL", newsize)); - } - else - { - struct rt_memheap_item *item = MEMITEM(new_ptr); - if (rt_thread_self()) - rt_memheap_setname(item, rt_thread_self()->name); - else - rt_memheap_setname(item, "<null>"); - - RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("realloc => 0x%08x : %d", - new_ptr, newsize)); - } -#endif /* RT_USING_MEMTRACE */ - return new_ptr; } -RTM_EXPORT(rt_realloc); - -/** - * @brief This function will contiguously allocate enough space for count objects - * that are size bytes of memory each and returns a pointer to the allocated - * memory. - * - * @note The allocated memory is filled with bytes of value zero. - * - * @param count is the number of objects to allocate. - * - * @param size is the size of one object to allocate. - * - * @return pointer to allocated memory pointer. - */ -void *rt_calloc(rt_size_t count, rt_size_t size) -{ - void *ptr; - rt_size_t total_size; - - total_size = count * size; - ptr = rt_malloc(total_size); - if (ptr != RT_NULL) - { - /* clean memory */ - rt_memset(ptr, 0, total_size); - } - -#ifdef RT_USING_MEMTRACE - if (ptr == RT_NULL) - { - RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("calloc[%d x %d] => NULL", - count, size)); - } - else - { - RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("calloc => 0x%08x : %d", - ptr, count * size)); - } -#endif /* RT_USING_MEMTRACE */ - - return ptr; -} -RTM_EXPORT(rt_calloc); - -/** -* @brief This function will caculate the total memory, the used memory, and -* the max used memory. -* -* @param total is a pointer to get the total size of the memory. -* -* @param used is a pointer to get the size of memory used. -* -* @param max_used is a pointer to get the maximum memory used. -*/ -void rt_memory_info(rt_uint32_t *total, - rt_uint32_t *used, - rt_uint32_t *max_used) -{ - if (total != RT_NULL) - *total = _heap.pool_size; - - if (used != RT_NULL) - *used = _heap.pool_size - _heap.available_size; - - if (max_used != RT_NULL) - *max_used = _heap.max_used_size; -} - -#endif /* RT_USING_MEMHEAP_AS_HEAP */ +#endif #ifdef RT_USING_MEMTRACE - -/** - * @brief This function will print the used memheap infomation. - * - * @param mh is a pointer of the memheap object. - */ -void dump_used_memheap(struct rt_memheap *mh) +int memheapcheck(int argc, char *argv[]) { - struct rt_memheap_item *header_ptr; - rt_uint32_t block_size; - - rt_kprintf("\nmemory heap address:\n"); - rt_kprintf("heap_ptr: 0x%08x\n", mh->start_addr); - rt_kprintf("free : 0x%08x\n", mh->available_size); - rt_kprintf("max_used: 0x%08x\n", mh->max_used_size); - rt_kprintf("size : 0x%08x\n", mh->pool_size); - - rt_kprintf("\n--memory used information --\n"); + struct rt_object_information *info; + struct rt_list_node *list; + struct rt_memheap *heap; + struct rt_list_node *node; + struct rt_memheap_item *item; + rt_bool_t has_bad = RT_FALSE; + rt_base_t level; + char *name; - header_ptr = mh->block_list; - while (header_ptr->next != mh->block_list) + name = argc > 1 ? argv[1] : RT_NULL; + level = rt_hw_interrupt_disable(); + info = rt_object_get_information(RT_Object_Class_MemHeap); + list = &info->object_list; + for (node = list->next; node != list; node = node->next) { - if ((header_ptr->magic & RT_MEMHEAP_MASK) != RT_MEMHEAP_MAGIC) + heap = (struct rt_memheap *)rt_list_entry(node, struct rt_object, list); + /* find the specified object */ + if (name != RT_NULL && rt_strncmp(name, heap->parent.name, RT_NAME_MAX) != 0) + continue; + /* check memheap */ + for (item = heap->block_list; item->next != heap->block_list; item = item->next) { - rt_kprintf("[0x%08x - incorrect magic: 0x%08x\n", header_ptr, header_ptr->magic); - break; - } - - /* get current memory block size */ - block_size = MEMITEM_SIZE(header_ptr); - if (block_size < 0) - break; - - if (RT_MEMHEAP_IS_USED(header_ptr)) - { - /* dump information */ - rt_kprintf("[0x%08x - %d - %c%c%c%c] used\n", header_ptr, block_size, - header_ptr->owner_thread_name[0], header_ptr->owner_thread_name[1], - header_ptr->owner_thread_name[2], header_ptr->owner_thread_name[3]); - } - else - { - /* dump information */ - rt_kprintf("[0x%08x - %d - %c%c%c%c] free\n", header_ptr, block_size, - header_ptr->owner_thread_name[0], header_ptr->owner_thread_name[1], - header_ptr->owner_thread_name[2], header_ptr->owner_thread_name[3]); + /* check magic */ + if (!((item->magic & (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED)) == (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED) || + (item->magic & (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED)) == (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED))) + { + has_bad = RT_TRUE; + break; + } + /* check pool_ptr */ + if (heap != item->pool_ptr) + { + has_bad = RT_TRUE; + break; + } + /* check next and prev */ + if (!((rt_uint32_t)item->next <= (rt_uint32_t)((rt_uint32_t)heap->start_addr + heap->pool_size) && + (rt_uint32_t)item->prev >= (rt_uint32_t)heap->start_addr) && + (rt_uint32_t)item->next == RT_ALIGN((rt_uint32_t)item->next, RT_ALIGN_SIZE) && + (rt_uint32_t)item->prev == RT_ALIGN((rt_uint32_t)item->prev, RT_ALIGN_SIZE)) + { + has_bad = RT_TRUE; + break; + } + /* check item */ + if (item->next == item->next->prev) + { + has_bad = RT_TRUE; + break; + } } - - /* move to next used memory block */ - header_ptr = header_ptr->next; } + rt_hw_interrupt_enable(level); + if (has_bad) + { + rt_kprintf("Memory block wrong:\n"); + rt_kprintf("name: %s\n", heap->parent.name); + rt_kprintf("item: 0x%08x\n", item); + } + return 0; } +MSH_CMD_EXPORT(memheapcheck, check memory for memheap); -void memtrace_heap() +int memheaptrace(int argc, char *argv[]) { struct rt_object_information *info; struct rt_list_node *list; struct rt_memheap *mh; struct rt_list_node *node; + char *name; + name = argc > 1 ? argv[1] : RT_NULL; info = rt_object_get_information(RT_Object_Class_MemHeap); list = &info->object_list; - for (node = list->next; node != list; node = node->next) { + struct rt_memheap_item *header_ptr; + long block_size; + mh = (struct rt_memheap *)rt_list_entry(node, struct rt_object, list); - dump_used_memheap(mh); + /* find the specified object */ + if (name != RT_NULL && rt_strncmp(name, mh->parent.name, RT_NAME_MAX) != 0) + continue; + /* memheap dump */ + rt_kprintf("\nmemory heap address:\n"); + rt_kprintf("name : %s\n", mh->parent.name); + rt_kprintf("heap_ptr: 0x%08x\n", mh->start_addr); + rt_kprintf("free : 0x%08x\n", mh->available_size); + rt_kprintf("max_used: 0x%08x\n", mh->max_used_size); + rt_kprintf("size : 0x%08x\n", mh->pool_size); + rt_kprintf("\n--memory used information --\n"); + /* memheap item */ + for (header_ptr = mh->block_list; + header_ptr->next != mh->block_list; + header_ptr = header_ptr->next) + { + if ((header_ptr->magic & RT_MEMHEAP_MASK) != RT_MEMHEAP_MAGIC) + { + rt_kprintf("[0x%08x - incorrect magic: 0x%08x\n", + header_ptr, header_ptr->magic); + break; + } + /* get current memory block size */ + block_size = MEMITEM_SIZE(header_ptr); + if (block_size < 0) + break; + + rt_kprintf("[0x%08x - ", header_ptr); + if (block_size < 1024) + rt_kprintf("%5d", block_size); + else if (block_size < 1024 * 1024) + rt_kprintf("%4dK", block_size / 1024); + else + rt_kprintf("%4dM", block_size / (1024 * 1024)); + /* dump thread name */ + rt_kprintf("] %c%c%c%c\n", + header_ptr->owner_thread_name[0], + header_ptr->owner_thread_name[1], + header_ptr->owner_thread_name[2], + header_ptr->owner_thread_name[3]); + } } + return 0; } #ifdef RT_USING_FINSH #include <finsh.h> -MSH_CMD_EXPORT(memtrace_heap, dump memory trace for heap); +MSH_CMD_EXPORT(memheaptrace, dump memory trace for memheap); #endif /* RT_USING_FINSH */ - #endif /* RT_USING_MEMTRACE */ - #endif /* RT_USING_MEMHEAP */ diff --git a/src/object.c b/src/object.c index 66d5775bd7..76534f4566 100644 --- a/src/object.c +++ b/src/object.c @@ -56,6 +56,9 @@ enum rt_object_info_type #ifdef RT_USING_MODULE RT_Object_Info_Module, /**< The object is a module. */ #endif +#ifdef RT_USING_HEAP + RT_Object_Info_Memory, /**< The object is a memory. */ +#endif RT_Object_Info_Unknown, /**< The object is unknown. */ }; @@ -104,6 +107,10 @@ static struct rt_object_information _object_container[RT_Object_Info_Unknown] = /* initialize object container - module */ {RT_Object_Class_Module, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Module), sizeof(struct rt_dlmodule)}, #endif +#ifdef RT_USING_HEAP + /* initialize object container - small memory */ + {RT_Object_Class_Memory, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Memory), sizeof(struct rt_memory)}, +#endif }; #ifdef RT_USING_HOOK diff --git a/src/slab.c b/src/slab.c index 8e0ce7bc83..f48179afaf 100644 --- a/src/slab.c +++ b/src/slab.c @@ -55,52 +55,7 @@ #include <rthw.h> #include <rtthread.h> -#define RT_MEM_STATS - -#if defined (RT_USING_HEAP) && defined (RT_USING_SLAB) -/* some statistical variable */ -#ifdef RT_MEM_STATS -static rt_size_t used_mem, max_mem; -#endif /* RT_MEM_STATS */ - -#ifdef RT_USING_HOOK -static void (*rt_malloc_hook)(void *ptr, rt_size_t size); -static void (*rt_free_hook)(void *ptr); - -/** - * @addtogroup Hook - */ - -/**@{*/ - -/** - * @brief This function will set a hook function, which will be invoked when a memory - * block is allocated from heap memory. - * - * @param hook the hook function. - */ -void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size)) -{ - rt_malloc_hook = hook; -} -RTM_EXPORT(rt_malloc_sethook); - -/** - * @brief This function will set a hook function, which will be invoked when a memory - * block is released to heap memory. - * - * @param hook the hook function - */ -void rt_free_sethook(void (*hook)(void *ptr)) -{ - rt_free_hook = hook; -} -RTM_EXPORT(rt_free_sethook); - -/**@}*/ - -#endif /* RT_USING_HOOK */ - +#if defined (RT_USING_SLAB) /* * slab allocator implementation * @@ -155,48 +110,12 @@ RTM_EXPORT(rt_free_sethook); * + ability to allocate arbitrarily large chunks of memory */ -/* - * Chunk structure for free elements - */ -typedef struct slab_chunk -{ - struct slab_chunk *c_next; -} slab_chunk; - -/* - * The IN-BAND zone header is placed at the beginning of each zone. - */ -typedef struct slab_zone -{ - rt_int32_t z_magic; /* magic number for sanity check */ - rt_int32_t z_nfree; /* total free chunks / ualloc space in zone */ - rt_int32_t z_nmax; /* maximum free chunks */ - - struct slab_zone *z_next; /* zoneary[] link if z_nfree non-zero */ - rt_uint8_t *z_baseptr; /* pointer to start of chunk array */ - - rt_int32_t z_uindex; /* current initial allocation index */ - rt_int32_t z_chunksize; /* chunk size for validation */ - - rt_int32_t z_zoneindex; /* zone index */ - slab_chunk *z_freechunk; /* free chunk list */ -} slab_zone; - #define ZALLOC_SLAB_MAGIC 0x51ab51ab #define ZALLOC_ZONE_LIMIT (16 * 1024) /* max slab-managed alloc */ #define ZALLOC_MIN_ZONE_SIZE (32 * 1024) /* minimum zone size */ #define ZALLOC_MAX_ZONE_SIZE (128 * 1024) /* maximum zone size */ -#define NZONES 72 /* number of zones */ #define ZONE_RELEASE_THRESH 2 /* threshold number of zones */ -static slab_zone *zone_array[NZONES]; /* linked list of zones NFree > 0 */ -static slab_zone *zone_free; /* whole zones that have become free */ - -static int zone_free_cnt; -static int zone_size; -static int zone_limit; -static int zone_page_cnt; - /* * Misc constants. Note that allocations that are exact multiples of * RT_MM_PAGE_SIZE, or exceed the zone limit, fall through to the kmem module. @@ -210,45 +129,95 @@ static int zone_page_cnt; #define PAGE_TYPE_FREE 0x00 #define PAGE_TYPE_SMALL 0x01 #define PAGE_TYPE_LARGE 0x02 -struct memusage + +#define btokup(addr) \ + (&slab->memusage[((rt_ubase_t)(addr) - slab->heap_start) >> RT_MM_PAGE_BITS]) + +/** + * Base structure of slab memory object + */ + +/* + * The IN-BAND zone header is placed at the beginning of each zone. + */ +struct rt_slab_zone { - rt_uint32_t type: 2 ; /* page type */ - rt_uint32_t size: 30; /* pages allocated or offset from zone */ + rt_uint32_t z_magic; /**< magic number for sanity check */ + rt_uint32_t z_nfree; /**< total free chunks / ualloc space in zone */ + rt_uint32_t z_nmax; /**< maximum free chunks */ + struct rt_slab_zone *z_next; /**< zoneary[] link if z_nfree non-zero */ + rt_uint8_t *z_baseptr; /**< pointer to start of chunk array */ + + rt_uint32_t z_uindex; /**< current initial allocation index */ + rt_uint32_t z_chunksize; /**< chunk size for validation */ + + rt_uint32_t z_zoneindex; /**< zone index */ + struct rt_slab_chunk *z_freechunk; /**< free chunk list */ +}; + +/* + * Chunk structure for free elements + */ +struct rt_slab_chunk +{ + struct rt_slab_chunk *c_next; }; -static struct memusage *memusage = RT_NULL; -#define btokup(addr) \ - (&memusage[((rt_ubase_t)(addr) - heap_start) >> RT_MM_PAGE_BITS]) -static rt_ubase_t heap_start, heap_end; +struct rt_slab_memusage +{ + rt_uint32_t type: 2 ; /**< page type */ + rt_uint32_t size: 30; /**< pages allocated or offset from zone */ +}; -/* page allocator */ -struct rt_page_head +/* + * slab page allocator + */ +struct rt_slab_page { - struct rt_page_head *next; /* next valid page */ - rt_size_t page; /* number of page */ + struct rt_slab_page *next; /**< next valid page */ + rt_size_t page; /**< number of page */ /* dummy */ - char dummy[RT_MM_PAGE_SIZE - (sizeof(struct rt_page_head *) + sizeof(rt_size_t))]; + char dummy[RT_MM_PAGE_SIZE - (sizeof(struct rt_slab_page *) + sizeof(rt_size_t))]; +}; + +#define RT_SLAB_NZONES 72 /* number of zones */ + +/* + * slab object + */ +struct rt_slab +{ + struct rt_memory parent; /**< inherit from rt_memory */ + rt_ubase_t heap_start; /**< memory start address */ + rt_ubase_t heap_end; /**< memory end address */ + struct rt_slab_memusage *memusage; + struct rt_slab_zone *zone_array[RT_SLAB_NZONES]; /* linked list of zones NFree > 0 */ + struct rt_slab_zone *zone_free; /* whole zones that have become free */ + rt_uint32_t zone_free_cnt; + rt_uint32_t zone_size; + rt_uint32_t zone_limit; + rt_uint32_t zone_page_cnt; + struct rt_slab_page *page_list; }; -static struct rt_page_head *rt_page_list; -static struct rt_semaphore heap_sem; /** * @brief Alloc memory size by page. * + * @param slab the slab memory management object. + * * @param npages the number of pages. */ -void *rt_page_alloc(rt_size_t npages) +void *rt_slab_page_alloc(rt_slab_t m, rt_size_t npages) { - struct rt_page_head *b, *n; - struct rt_page_head **prev; + struct rt_slab_page *b, *n; + struct rt_slab_page **prev; + struct rt_slab *slab = (struct rt_slab *)m; if (npages == 0) return RT_NULL; - /* lock heap */ - rt_sem_take(&heap_sem, RT_WAITING_FOREVER); - for (prev = &rt_page_list; (b = *prev) != RT_NULL; prev = &(b->next)) + for (prev = &slab->page_list; (b = *prev) != RT_NULL; prev = &(b->next)) { if (b->page > npages) { @@ -268,34 +237,31 @@ void *rt_page_alloc(rt_size_t npages) } } - /* unlock heap */ - rt_sem_release(&heap_sem); - return b; } /** * @brief Free memory by page. * + * @param slab the slab memory management object. + * * @param addr is the head address of first page. * * @param npages is the number of pages. */ -void rt_page_free(void *addr, rt_size_t npages) +void rt_slab_page_free(rt_slab_t m, void *addr, rt_size_t npages) { - struct rt_page_head *b, *n; - struct rt_page_head **prev; + struct rt_slab_page *b, *n; + struct rt_slab_page **prev; + struct rt_slab *slab = (struct rt_slab *)m; RT_ASSERT(addr != RT_NULL); RT_ASSERT((rt_ubase_t)addr % RT_MM_PAGE_SIZE == 0); RT_ASSERT(npages != 0); - n = (struct rt_page_head *)addr; + n = (struct rt_slab_page *)addr; - /* lock heap */ - rt_sem_take(&heap_sem, RT_WAITING_FOREVER); - - for (prev = &rt_page_list; (b = *prev) != RT_NULL; prev = &(b->next)) + for (prev = &slab->page_list; (b = *prev) != RT_NULL; prev = &(b->next)) { RT_ASSERT(b->page > 0); RT_ASSERT(b > n || b + b->page <= n); @@ -307,8 +273,7 @@ void rt_page_free(void *addr, rt_size_t npages) b->page += b->next->page; b->next = b->next->next; } - - goto _return; + return; } if (b == n + npages) @@ -316,8 +281,7 @@ void rt_page_free(void *addr, rt_size_t npages) n->page = b->page + npages; n->next = b->next; *prev = n; - - goto _return; + return; } if (b > n + npages) @@ -327,83 +291,115 @@ void rt_page_free(void *addr, rt_size_t npages) n->page = npages; n->next = b; *prev = n; - -_return: - /* unlock heap */ - rt_sem_release(&heap_sem); } /* * Initialize the page allocator */ -static void rt_page_init(void *addr, rt_size_t npages) +static void rt_slab_page_init(struct rt_slab *slab, void *addr, rt_size_t npages) { RT_ASSERT(addr != RT_NULL); RT_ASSERT(npages != 0); - rt_page_list = RT_NULL; - rt_page_free(addr, npages); + slab->page_list = RT_NULL; + rt_slab_page_free((rt_slab_t)(&slab->parent), addr, npages); } /** - * @brief This function will init system heap. + * @brief This function will init slab memory management algorithm + * + * @param slab the slab memory management object. + * + * @param name is the name of the slab memory management object. * * @param begin_addr the beginning address of system page. * - * @param end_addr the end address of system page. + * @param size is the size of the memory. + * + * @return Return a pointer to the slab memory object. */ -void rt_system_heap_init(void *begin_addr, void *end_addr) +rt_slab_t rt_slab_init(const char *name, void *begin_addr, rt_size_t size) { rt_uint32_t limsize, npages; + rt_ubase_t start_addr, begin_align, end_align; + struct rt_slab *slab; - RT_DEBUG_NOT_IN_INTERRUPT; - + slab = (struct rt_slab *)RT_ALIGN((rt_ubase_t)begin_addr, RT_ALIGN_SIZE); + start_addr = (rt_ubase_t)slab + sizeof(*slab); /* align begin and end addr to page */ - heap_start = RT_ALIGN((rt_ubase_t)begin_addr, RT_MM_PAGE_SIZE); - heap_end = RT_ALIGN_DOWN((rt_ubase_t)end_addr, RT_MM_PAGE_SIZE); - - if (heap_start >= heap_end) + begin_align = RT_ALIGN((rt_ubase_t)start_addr, RT_MM_PAGE_SIZE); + end_align = RT_ALIGN_DOWN((rt_ubase_t)begin_addr + size, RT_MM_PAGE_SIZE); + if (begin_align >= end_align) { - rt_kprintf("rt_system_heap_init, wrong address[0x%x - 0x%x]\n", - (rt_ubase_t)begin_addr, (rt_ubase_t)end_addr); - - return; + rt_kprintf("slab init errr. wrong address[0x%x - 0x%x]\n", + (rt_ubase_t)begin_addr, (rt_ubase_t)begin_addr + size); + return RT_NULL; } - limsize = heap_end - heap_start; + limsize = end_align - begin_align; npages = limsize / RT_MM_PAGE_SIZE; - - /* initialize heap semaphore */ - rt_sem_init(&heap_sem, "heap", 1, RT_IPC_FLAG_PRIO); - RT_DEBUG_LOG(RT_DEBUG_SLAB, ("heap[0x%x - 0x%x], size 0x%x, 0x%x pages\n", - heap_start, heap_end, limsize, npages)); + begin_align, end_align, limsize, npages)); + + rt_memset(slab, 0, sizeof(*slab)); + /* initialize slab memory object */ + rt_object_init(&(slab->parent.parent), RT_Object_Class_Memory, name); + slab->parent.algorithm = "slab"; + slab->parent.address = begin_align; + slab->parent.total = limsize; + slab->parent.used = 0; + slab->parent.max = 0; + slab->heap_start = begin_align; + slab->heap_end = end_align; /* init pages */ - rt_page_init((void *)heap_start, npages); + rt_slab_page_init(slab, (void *)slab->heap_start, npages); /* calculate zone size */ - zone_size = ZALLOC_MIN_ZONE_SIZE; - while (zone_size < ZALLOC_MAX_ZONE_SIZE && (zone_size << 1) < (limsize / 1024)) - zone_size <<= 1; + slab->zone_size = ZALLOC_MIN_ZONE_SIZE; + while (slab->zone_size < ZALLOC_MAX_ZONE_SIZE && (slab->zone_size << 1) < (limsize / 1024)) + slab->zone_size <<= 1; - zone_limit = zone_size / 4; - if (zone_limit > ZALLOC_ZONE_LIMIT) - zone_limit = ZALLOC_ZONE_LIMIT; + slab->zone_limit = slab->zone_size / 4; + if (slab->zone_limit > ZALLOC_ZONE_LIMIT) + slab->zone_limit = ZALLOC_ZONE_LIMIT; - zone_page_cnt = zone_size / RT_MM_PAGE_SIZE; + slab->zone_page_cnt = slab->zone_size / RT_MM_PAGE_SIZE; RT_DEBUG_LOG(RT_DEBUG_SLAB, ("zone size 0x%x, zone page count 0x%x\n", - zone_size, zone_page_cnt)); + slab->zone_size, slab->zone_page_cnt)); - /* allocate memusage array */ - limsize = npages * sizeof(struct memusage); + /* allocate slab->memusage array */ + limsize = npages * sizeof(struct rt_slab_memusage); limsize = RT_ALIGN(limsize, RT_MM_PAGE_SIZE); - memusage = rt_page_alloc(limsize / RT_MM_PAGE_SIZE); + slab->memusage = rt_slab_page_alloc((rt_slab_t)(&slab->parent), limsize / RT_MM_PAGE_SIZE); - RT_DEBUG_LOG(RT_DEBUG_SLAB, ("memusage 0x%x, size 0x%x\n", - (rt_ubase_t)memusage, limsize)); + RT_DEBUG_LOG(RT_DEBUG_SLAB, ("slab->memusage 0x%x, size 0x%x\n", + (rt_ubase_t)slab->memusage, limsize)); + return &slab->parent; } +RTM_EXPORT(rt_slab_init); + +/** + * @brief This function will remove a slab object from the system. + * + * @param m the slab memory management object. + * + * @return RT_EOK + */ +rt_err_t rt_slab_detach(rt_slab_t m) +{ + struct rt_slab *slab = (struct rt_slab *)m; + + RT_ASSERT(slab != RT_NULL); + RT_ASSERT(rt_object_get_type(&slab->parent.parent) == RT_Object_Class_Memory); + RT_ASSERT(rt_object_is_systemobject(&slab->parent.parent)); + + rt_object_detach(&(slab->parent.parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_slab_detach); /* * Calculate the zone index for the allocation request size and set the @@ -476,22 +472,25 @@ rt_inline int zoneindex(rt_size_t *bytes) /**@{*/ /** - * @brief This function will allocate a block from system heap memory. + * @brief This function will allocate a block from slab object. * * @note the RT_NULL is returned if * - the nbytes is less than zero. * - there is no nbytes sized memory valid in system. * + * @param m the slab memory management object. + * * @param size is the size of memory to be allocated. * * @return the allocated memory. */ -void *rt_malloc(rt_size_t size) +void *rt_slab_alloc(rt_slab_t m, rt_size_t size) { - slab_zone *z; + struct rt_slab_zone *z; rt_int32_t zi; - slab_chunk *chunk; - struct memusage *kup; + struct rt_slab_chunk *chunk; + struct rt_slab_memusage *kup; + struct rt_slab *slab = (struct rt_slab *)m; /* zero size, return RT_NULL */ if (size == 0) @@ -501,11 +500,11 @@ void *rt_malloc(rt_size_t size) * Handle large allocations directly. There should not be very many of * these so performance is not a big issue. */ - if (size >= zone_limit) + if (size >= slab->zone_limit) { size = RT_ALIGN(size, RT_MM_PAGE_SIZE); - chunk = rt_page_alloc(size >> RT_MM_PAGE_BITS); + chunk = rt_slab_page_alloc(m, size >> RT_MM_PAGE_BITS); if (chunk == RT_NULL) return RT_NULL; @@ -515,25 +514,17 @@ void *rt_malloc(rt_size_t size) kup->size = size >> RT_MM_PAGE_BITS; RT_DEBUG_LOG(RT_DEBUG_SLAB, - ("malloc a large memory 0x%x, page cnt %d, kup %d\n", + ("alloc a large memory 0x%x, page cnt %d, kup %d\n", size, size >> RT_MM_PAGE_BITS, - ((rt_ubase_t)chunk - heap_start) >> RT_MM_PAGE_BITS)); - - /* lock heap */ - rt_sem_take(&heap_sem, RT_WAITING_FOREVER); - -#ifdef RT_MEM_STATS - used_mem += size; - if (used_mem > max_mem) - max_mem = used_mem; -#endif /* RT_MEM_STATS */ - goto done; + ((rt_ubase_t)chunk - slab->heap_start) >> RT_MM_PAGE_BITS)); + /* mem stat */ + slab->parent.used += size; + if (slab->parent.used > slab->parent.max) + slab->parent.max = slab->parent.used; + return chunk; } - /* lock heap */ - rt_sem_take(&heap_sem, RT_WAITING_FOREVER); - /* * Attempt to allocate out of an existing zone. First try the free list, * then allocate out of unallocated space. If we find a good zone move @@ -543,18 +534,18 @@ void *rt_malloc(rt_size_t size) * Note: zoneindex() will panic of size is too large. */ zi = zoneindex(&size); - RT_ASSERT(zi < NZONES); + RT_ASSERT(zi < RT_SLAB_NZONES); - RT_DEBUG_LOG(RT_DEBUG_SLAB, ("try to malloc 0x%x on zone: %d\n", size, zi)); + RT_DEBUG_LOG(RT_DEBUG_SLAB, ("try to alloc 0x%x on zone: %d\n", size, zi)); - if ((z = zone_array[zi]) != RT_NULL) + if ((z = slab->zone_array[zi]) != RT_NULL) { RT_ASSERT(z->z_nfree > 0); /* Remove us from the zone_array[] when we become full */ if (--z->z_nfree == 0) { - zone_array[zi] = z->z_next; + slab->zone_array[zi] = z->z_next; z->z_next = RT_NULL; } @@ -567,7 +558,7 @@ void *rt_malloc(rt_size_t size) if (z->z_uindex + 1 != z->z_nmax) { z->z_uindex = z->z_uindex + 1; - chunk = (slab_chunk *)(z->z_baseptr + z->z_uindex * size); + chunk = (struct rt_slab_chunk *)(z->z_baseptr + z->z_uindex * size); } else { @@ -577,14 +568,12 @@ void *rt_malloc(rt_size_t size) /* remove this chunk from list */ z->z_freechunk = z->z_freechunk->c_next; } + /* mem stats */ + slab->parent.used += z->z_chunksize; + if (slab->parent.used > slab->parent.max) + slab->parent.max = slab->parent.used; -#ifdef RT_MEM_STATS - used_mem += z->z_chunksize; - if (used_mem > max_mem) - max_mem = used_mem; -#endif /* RT_MEM_STATS */ - - goto done; + return chunk; } /* @@ -596,35 +585,28 @@ void *rt_malloc(rt_size_t size) * adjusting the base offset below. */ { - rt_int32_t off; + rt_uint32_t off; - if ((z = zone_free) != RT_NULL) + if ((z = slab->zone_free) != RT_NULL) { /* remove zone from free zone list */ - zone_free = z->z_next; - -- zone_free_cnt; + slab->zone_free = z->z_next; + -- slab->zone_free_cnt; } else { - /* unlock heap, since page allocator will think about lock */ - rt_sem_release(&heap_sem); - /* allocate a zone from page */ - z = rt_page_alloc(zone_size / RT_MM_PAGE_SIZE); + z = rt_slab_page_alloc(m, slab->zone_size / RT_MM_PAGE_SIZE); if (z == RT_NULL) { - chunk = RT_NULL; - goto __exit; + return RT_NULL; } - /* lock heap */ - rt_sem_take(&heap_sem, RT_WAITING_FOREVER); - RT_DEBUG_LOG(RT_DEBUG_SLAB, ("alloc a new zone: 0x%x\n", (rt_ubase_t)z)); /* set message usage */ - for (off = 0, kup = btokup(z); off < zone_page_cnt; off ++) + for (off = 0, kup = btokup(z); off < slab->zone_page_cnt; off ++) { kup->type = PAGE_TYPE_SMALL; kup->size = off; @@ -634,10 +616,10 @@ void *rt_malloc(rt_size_t size) } /* clear to zero */ - rt_memset(z, 0, sizeof(slab_zone)); + rt_memset(z, 0, sizeof(struct rt_slab_zone)); /* offset of slab zone struct in zone */ - off = sizeof(slab_zone); + off = sizeof(struct rt_slab_zone); /* * Guarentee power-of-2 alignment for power-of-2-sized chunks. @@ -650,55 +632,51 @@ void *rt_malloc(rt_size_t size) z->z_magic = ZALLOC_SLAB_MAGIC; z->z_zoneindex = zi; - z->z_nmax = (zone_size - off) / size; + z->z_nmax = (slab->zone_size - off) / size; z->z_nfree = z->z_nmax - 1; z->z_baseptr = (rt_uint8_t *)z + off; z->z_uindex = 0; z->z_chunksize = size; - chunk = (slab_chunk *)(z->z_baseptr + z->z_uindex * size); + chunk = (struct rt_slab_chunk *)(z->z_baseptr + z->z_uindex * size); /* link to zone array */ - z->z_next = zone_array[zi]; - zone_array[zi] = z; - -#ifdef RT_MEM_STATS - used_mem += z->z_chunksize; - if (used_mem > max_mem) - max_mem = used_mem; -#endif /* RT_MEM_STATS */ + z->z_next = slab->zone_array[zi]; + slab->zone_array[zi] = z; + /* mem stats */ + slab->parent.used += z->z_chunksize; + if (slab->parent.used > slab->parent.max) + slab->parent.max = slab->parent.used; } -done: - rt_sem_release(&heap_sem); - RT_OBJECT_HOOK_CALL(rt_malloc_hook, ((char *)chunk, size)); - -__exit: return chunk; } -RTM_EXPORT(rt_malloc); +RTM_EXPORT(rt_slab_alloc); /** * @brief This function will change the size of previously allocated memory block. * + * @param m the slab memory management object. + * * @param ptr is the previously allocated memory block. * * @param size is the new size of memory block. * * @return the allocated memory. */ -void *rt_realloc(void *ptr, rt_size_t size) +void *rt_slab_realloc(rt_slab_t m, void *ptr, rt_size_t size) { void *nptr; - slab_zone *z; - struct memusage *kup; + struct rt_slab_zone *z; + struct rt_slab_memusage *kup; + struct rt_slab *slab = (struct rt_slab *)m; if (ptr == RT_NULL) - return rt_malloc(size); + return rt_slab_alloc(m, size); + if (size == 0) { - rt_free(ptr); - + rt_slab_free(m, ptr); return RT_NULL; } @@ -712,16 +690,16 @@ void *rt_realloc(void *ptr, rt_size_t size) rt_size_t osize; osize = kup->size << RT_MM_PAGE_BITS; - if ((nptr = rt_malloc(size)) == RT_NULL) + if ((nptr = rt_slab_alloc(m, size)) == RT_NULL) return RT_NULL; rt_memcpy(nptr, ptr, size > osize ? osize : size); - rt_free(ptr); + rt_slab_free(m, ptr); return nptr; } else if (kup->type == PAGE_TYPE_SMALL) { - z = (slab_zone *)(((rt_ubase_t)ptr & ~RT_MM_PAGE_MASK) - + z = (struct rt_slab_zone *)(((rt_ubase_t)ptr & ~RT_MM_PAGE_MASK) - kup->size * RT_MM_PAGE_SIZE); RT_ASSERT(z->z_magic == ZALLOC_SLAB_MAGIC); @@ -734,66 +712,38 @@ void *rt_realloc(void *ptr, rt_size_t size) * already adjusted the request size to the appropriate chunk size, which * should optimize our bcopy(). Then copy and return the new pointer. */ - if ((nptr = rt_malloc(size)) == RT_NULL) + if ((nptr = rt_slab_alloc(m, size)) == RT_NULL) return RT_NULL; rt_memcpy(nptr, ptr, size > z->z_chunksize ? z->z_chunksize : size); - rt_free(ptr); + rt_slab_free(m, ptr); return nptr; } return RT_NULL; } -RTM_EXPORT(rt_realloc); - -/** - * @brief This function will contiguously allocate enough space for count objects - * that are size bytes of memory each and returns a pointer to the allocated - * memory. - * - * @note The allocated memory is filled with bytes of value zero. - * - * @param count is the number of objects to allocate. - * - * @param size is the size of the objects to allocate. - * - * @return pointer to allocated memory / NULL pointer if there is an error. - */ -void *rt_calloc(rt_size_t count, rt_size_t size) -{ - void *p; - - /* allocate 'count' objects of size 'size' */ - p = rt_malloc(count * size); - - /* zero the memory */ - if (p) - rt_memset(p, 0, count * size); - - return p; -} -RTM_EXPORT(rt_calloc); +RTM_EXPORT(rt_slab_realloc); /** - * @brief This function will release the previous allocated memory block by rt_malloc. + * @brief This function will release the previous allocated memory block by rt_slab_alloc. * * @note The released memory block is taken back to system heap. * + * @param m the slab memory management object. * @param ptr is the address of memory which will be released */ -void rt_free(void *ptr) +void rt_slab_free(rt_slab_t m, void *ptr) { - slab_zone *z; - slab_chunk *chunk; - struct memusage *kup; + struct rt_slab_zone *z; + struct rt_slab_chunk *chunk; + struct rt_slab_memusage *kup; + struct rt_slab *slab = (struct rt_slab *)m; /* free a RT_NULL pointer */ if (ptr == RT_NULL) return ; - RT_OBJECT_HOOK_CALL(rt_free_hook, (ptr)); - /* get memory usage */ #if RT_DEBUG_SLAB { @@ -802,7 +752,7 @@ void rt_free(void *ptr) ("free a memory 0x%x and align to 0x%x, kup index %d\n", (rt_ubase_t)ptr, (rt_ubase_t)addr, - ((rt_ubase_t)(addr) - heap_start) >> RT_MM_PAGE_BITS)); + ((rt_ubase_t)(addr) - slab->heap_start) >> RT_MM_PAGE_BITS)); } #endif /* RT_DEBUG_SLAB */ @@ -812,42 +762,32 @@ void rt_free(void *ptr) { rt_ubase_t size; - /* lock heap */ - rt_sem_take(&heap_sem, RT_WAITING_FOREVER); /* clear page counter */ size = kup->size; kup->size = 0; - -#ifdef RT_MEM_STATS - used_mem -= size * RT_MM_PAGE_SIZE; -#endif /* RT_MEM_STATS */ - rt_sem_release(&heap_sem); + /* mem stats */ + slab->parent.used -= size * RT_MM_PAGE_SIZE; RT_DEBUG_LOG(RT_DEBUG_SLAB, ("free large memory block 0x%x, page count %d\n", (rt_ubase_t)ptr, size)); /* free this page */ - rt_page_free(ptr, size); + rt_slab_page_free(m, ptr, size); return; } - /* lock heap */ - rt_sem_take(&heap_sem, RT_WAITING_FOREVER); - /* zone case. get out zone. */ - z = (slab_zone *)(((rt_ubase_t)ptr & ~RT_MM_PAGE_MASK) - + z = (struct rt_slab_zone *)(((rt_ubase_t)ptr & ~RT_MM_PAGE_MASK) - kup->size * RT_MM_PAGE_SIZE); RT_ASSERT(z->z_magic == ZALLOC_SLAB_MAGIC); - chunk = (slab_chunk *)ptr; + chunk = (struct rt_slab_chunk *)ptr; chunk->c_next = z->z_freechunk; z->z_freechunk = chunk; - -#ifdef RT_MEM_STATS - used_mem -= z->z_chunksize; -#endif /* RT_MEM_STATS */ + /* mem stats */ + slab->parent.used -= z->z_chunksize; /* * Bump the number of free chunks. If it becomes non-zero the zone @@ -855,8 +795,8 @@ void rt_free(void *ptr) */ if (z->z_nfree++ == 0) { - z->z_next = zone_array[z->z_zoneindex]; - zone_array[z->z_zoneindex] = z; + z->z_next = slab->zone_array[z->z_zoneindex]; + slab->zone_array[z->z_zoneindex] = z; } /* @@ -866,96 +806,51 @@ void rt_free(void *ptr) * with kernel_map here. Hysteresis will be performed at malloc() time. */ if (z->z_nfree == z->z_nmax && - (z->z_next || zone_array[z->z_zoneindex] != z)) + (z->z_next || slab->zone_array[z->z_zoneindex] != z)) { - slab_zone **pz; + struct rt_slab_zone **pz; RT_DEBUG_LOG(RT_DEBUG_SLAB, ("free zone 0x%x\n", (rt_ubase_t)z, z->z_zoneindex)); /* remove zone from zone array list */ - for (pz = &zone_array[z->z_zoneindex]; z != *pz; pz = &(*pz)->z_next) + for (pz = &slab->zone_array[z->z_zoneindex]; z != *pz; pz = &(*pz)->z_next) ; *pz = z->z_next; /* reset zone */ - z->z_magic = -1; + z->z_magic = RT_UINT32_MAX; /* insert to free zone list */ - z->z_next = zone_free; - zone_free = z; + z->z_next = slab->zone_free; + slab->zone_free = z; - ++ zone_free_cnt; + ++ slab->zone_free_cnt; /* release zone to page allocator */ - if (zone_free_cnt > ZONE_RELEASE_THRESH) + if (slab->zone_free_cnt > ZONE_RELEASE_THRESH) { - register rt_base_t i; + register rt_uint32_t i; - z = zone_free; - zone_free = z->z_next; - -- zone_free_cnt; + z = slab->zone_free; + slab->zone_free = z->z_next; + -- slab->zone_free_cnt; /* set message usage */ - for (i = 0, kup = btokup(z); i < zone_page_cnt; i ++) + for (i = 0, kup = btokup(z); i < slab->zone_page_cnt; i ++) { kup->type = PAGE_TYPE_FREE; kup->size = 0; kup ++; } - /* unlock heap */ - rt_sem_release(&heap_sem); - /* release pages */ - rt_page_free(z, zone_size / RT_MM_PAGE_SIZE); + rt_slab_page_free(m, z, slab->zone_size / RT_MM_PAGE_SIZE); return; } } - /* unlock heap */ - rt_sem_release(&heap_sem); -} -RTM_EXPORT(rt_free); - -#ifdef RT_MEM_STATS -/** -* @brief This function will caculate the total memory, the used memory, and -* the max used memory. -* -* @param total is a pointer to get the total size of the memory. -* -* @param used is a pointer to get the size of memory used. -* -* @param max_used is a pointer to get the maximum memory used. -*/ -void rt_memory_info(rt_uint32_t *total, - rt_uint32_t *used, - rt_uint32_t *max_used) -{ - if (total != RT_NULL) - *total = heap_end - heap_start; - - if (used != RT_NULL) - *used = used_mem; - - if (max_used != RT_NULL) - *max_used = max_mem; -} - -#ifdef RT_USING_FINSH -#include <finsh.h> - -void list_mem(void) -{ - rt_kprintf("total memory: %d\n", heap_end - heap_start); - rt_kprintf("used memory : %d\n", used_mem); - rt_kprintf("maximum allocated memory: %d\n", max_mem); } -FINSH_FUNCTION_EXPORT(list_mem, list memory usage information) -#endif /* RT_USING_FINSH */ -#endif /* RT_MEM_STATS */ - -/**@}*/ +RTM_EXPORT(rt_slab_free); -#endif /* defined (RT_USING_HEAP) && defined (RT_USING_SLAB) */ +#endif /* defined (RT_USING_SLAB) */ |
