summaryrefslogtreecommitdiff
path: root/src/slab.c
diff options
context:
space:
mode:
author[email protected] <[email protected]>2010-12-05 11:59:54 +0000
committer[email protected] <[email protected]>2010-12-05 11:59:54 +0000
commit1a8721ecdfa0c4036492a0e0f2c2beb9cec35642 (patch)
tree68bef2aaed29df006669642e6f688d72ae4b60b6 /src/slab.c
parent14a840b911701783687321fbc74ab43e1dc844b2 (diff)
add list_mem function in slab allocator.
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1178 bbd45198-f89e-11dd-88c7-29a3b14d5316
Diffstat (limited to 'src/slab.c')
-rw-r--r--src/slab.c122
1 files changed, 98 insertions, 24 deletions
diff --git a/src/slab.c b/src/slab.c
index ffcdcb9cb3..b8175482c5 100644
--- a/src/slab.c
+++ b/src/slab.c
@@ -56,8 +56,14 @@
#include "kservice.h"
/* #define RT_SLAB_DEBUG */
+#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
+
#ifdef RT_USING_HOOK
static void (*rt_malloc_hook)(void *ptr, rt_size_t size);
static void (*rt_free_hook)(void *ptr);
@@ -188,13 +194,6 @@ static int zone_size;
static int zone_limit;
static int zone_page_cnt;
-#ifdef RT_MEM_STATS
-/* some statistical variable */
-static rt_uint32_t rt_mem_allocated = 0;
-static rt_uint32_t rt_mem_zone = 0;
-static rt_uint32_t rt_mem_page_allocated = 0;
-#endif
-
/*
* 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.
@@ -227,6 +226,7 @@ struct rt_page_head
char dummy[RT_MM_PAGE_SIZE - (sizeof(struct rt_page_head*) + sizeof (rt_size_t))];
};
static struct rt_page_head *rt_page_list;
+static struct rt_semaphore heap_sem;
void *rt_page_alloc(rt_size_t npages)
{
@@ -235,6 +235,8 @@ void *rt_page_alloc(rt_size_t npages)
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))
{
if (b->page > npages)
@@ -254,6 +256,8 @@ void *rt_page_alloc(rt_size_t npages)
break;
}
}
+ /* unlock heap */
+ rt_sem_release(&heap_sem);
return b;
}
@@ -269,6 +273,8 @@ void rt_page_free(void *addr, rt_size_t npages)
n = (struct rt_page_head *)addr;
+ /* lock heap */
+ rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
for (prev = &rt_page_list; (b = *prev) != RT_NULL; prev = &(b->next))
{
RT_ASSERT(b->page > 0);
@@ -282,7 +288,7 @@ void rt_page_free(void *addr, rt_size_t npages)
b->next = b->next->next;
}
- return;
+ goto _return;
}
if (b == n + npages)
@@ -291,7 +297,7 @@ void rt_page_free(void *addr, rt_size_t npages)
n->next = b->next;
*prev = n;
- return;
+ goto _return;
}
if (b > n + npages) break;
@@ -300,6 +306,10 @@ 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);
}
/*
@@ -339,6 +349,9 @@ void rt_system_heap_init(void *begin_addr, void* end_addr)
limsize = heap_end - heap_start;
npages = limsize / RT_MM_PAGE_SIZE;
+ /* initialize heap semaphore */
+ rt_sem_init(&heap_sem, "heap", 1, RT_IPC_FLAG_FIFO);
+
#ifdef RT_SLAB_DEBUG
rt_kprintf("heap[0x%x - 0x%x], size 0x%x, 0x%x pages\n", heap_start, heap_end, limsize, npages);
#endif
@@ -478,12 +491,19 @@ void *rt_malloc(rt_size_t size)
size >> RT_MM_PAGE_BITS,
((rt_uint32_t)chunk - heap_start) >> RT_MM_PAGE_BITS);
#endif
+ /* lock heap */
+ rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
- /* lock interrupt */
- interrupt_level = rt_hw_interrupt_disable();
+#ifdef RT_MEM_STATS
+ used_mem += size;
+ if (used_mem > max_mem) max_mem = used_mem;
+#endif
goto done;
}
+ /* 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
@@ -499,7 +519,6 @@ void *rt_malloc(rt_size_t size)
rt_kprintf("try to malloc 0x%x on zone: %d\n", size, zi);
#endif
- interrupt_level = rt_hw_interrupt_disable();
if ((z = zone_array[zi]) != RT_NULL)
{
RT_ASSERT(z->z_nfree > 0);
@@ -531,6 +550,11 @@ void *rt_malloc(rt_size_t size)
z->z_freechunk = z->z_freechunk->c_next;
}
+#ifdef RT_MEM_STATS
+ used_mem += z->z_chunksize;
+ if (used_mem > max_mem) max_mem = used_mem;
+#endif
+
goto done;
}
@@ -553,10 +577,16 @@ void *rt_malloc(rt_size_t size)
}
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);
if (z == RT_NULL) goto fail;
+ /* lock heap */
+ rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
+
#ifdef RT_SLAB_DEBUG
rt_kprintf("alloc a new zone: 0x%x\n", (rt_uint32_t)z);
#endif
@@ -599,10 +629,15 @@ void *rt_malloc(rt_size_t 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
}
done:
- rt_hw_interrupt_enable(interrupt_level);
+ rt_sem_release(&heap_sem);
#ifdef RT_USING_HOOK
if (rt_malloc_hook != RT_NULL) rt_malloc_hook((char*)chunk, size);
@@ -611,7 +646,7 @@ done:
return chunk;
fail:
- rt_hw_interrupt_enable(interrupt_level);
+ rt_sem_release(&heap_sem);
return RT_NULL;
}
@@ -716,7 +751,6 @@ void rt_free(void *ptr)
slab_zone *z;
slab_chunk *chunk;
struct memusage *kup;
- rt_base_t interrupt_level;
/* free a RT_NULL pointer */
if (ptr == RT_NULL) return ;
@@ -735,11 +769,13 @@ void rt_free(void *ptr)
/* get memory usage */
#ifdef RT_SLAB_DEBUG
- rt_uint32 addr = ((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK);
- rt_kprintf("free a memory 0x%x and align to 0x%x, kup index %d\n",
- (rt_uint32_t)ptr,
- (rt_uint32_t)addr,
- ((rt_uint32_t)(addr) - heap_start) >> RT_MM_PAGE_BITS);
+ {
+ rt_uint32 addr = ((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK);
+ rt_kprintf("free a memory 0x%x and align to 0x%x, kup index %d\n",
+ (rt_uint32_t)ptr,
+ (rt_uint32_t)addr,
+ ((rt_uint32_t)(addr) - heap_start) >> RT_MM_PAGE_BITS);
+ }
#endif
kup = btokup((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK);
@@ -748,11 +784,16 @@ void rt_free(void *ptr)
{
rt_uint32_t size;
+ /* lock heap */
+ rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
/* clear page counter */
- interrupt_level = rt_hw_interrupt_disable();
size = kup->size;
kup->size = 0;
- rt_hw_interrupt_enable(interrupt_level);
+
+#ifdef RT_MEM_STATS
+ used_mem -= size;
+#endif
+ rt_sem_release(&heap_sem);
#ifdef RT_SLAB_DEBUG
rt_kprintf("free large memory block 0x%x, page count %d\n", (rt_uint32_t)ptr, size);
@@ -763,15 +804,21 @@ void rt_free(void *ptr)
return;
}
+ /* lock heap */
+ rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
+
/* zone case. get out zone. */
z = (slab_zone*)(((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK) - kup->size * RT_MM_PAGE_SIZE);
RT_ASSERT(z->z_magic == ZALLOC_SLAB_MAGIC);
- interrupt_level = rt_hw_interrupt_disable();
chunk = (slab_chunk*)ptr;
chunk->c_next = z->z_freechunk;
z->z_freechunk = chunk;
+#ifdef RT_MEM_STATS
+ used_mem -= z->z_chunksize;
+#endif
+
/*
* Bump the number of free chunks. If it becomes non-zero the zone
* must be added back onto the appropriate list.
@@ -827,13 +874,40 @@ void rt_free(void *ptr)
kup ++;
}
+ /* unlock heap */
+ rt_sem_release(&heap_sem);
+
/* release pages */
rt_page_free(z, zone_size);
+ return;
}
}
- rt_hw_interrupt_enable(interrupt_level);
+ /* unlock heap */
+ rt_sem_release(&heap_sem);
+}
+
+#ifdef RT_MEM_STATS
+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()
+{
+ 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
+#endif
+
/*@}*/
#endif