summaryrefslogtreecommitdiff
path: root/src/mempool.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mempool.c')
-rw-r--r--src/mempool.c410
1 files changed, 410 insertions, 0 deletions
diff --git a/src/mempool.c b/src/mempool.c
new file mode 100644
index 0000000000..3c5637d20e
--- /dev/null
+++ b/src/mempool.c
@@ -0,0 +1,410 @@
+/*
+ * File : partition.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://openlab.rt-thread.com/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2006-05-27 Bernard implement memory pool
+ * 2006-06-03 Bernard fix the thread timer init bug
+ * 2006-06-30 Bernard fix the allocate/free block bug
+ * 2006-08-04 Bernard add hook support
+ * 2006-08-10 Bernard fix interrupt bug in rt_mp_alloc
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#include "kservice.h"
+
+#ifdef RT_USING_MEMPOOL
+
+#ifdef RT_USING_HOOK
+static void (*rt_mp_alloc_hook)(void *block);
+static void (*rt_mp_free_hook)(void *block);
+
+/**
+ * @addtogroup Hook
+ */
+/*@{*/
+
+/**
+ * This function will set a hook function, which will be invoked when a memory
+ * block is allocated from memory pool.
+ *
+ * @param hook the hook function
+ */
+void rt_mp_alloc_sethook(void (*hook)(void *block))
+{
+ rt_mp_alloc_hook = hook;
+}
+
+/**
+ * This function will set a hook function, which will be invoked when a memory
+ * block is released to memory pool.
+ *
+ * @param hook the hook function
+ */
+void rt_mp_free_sethook(void (*hook)(void *block))
+{
+ rt_mp_free_hook = hook;
+}
+
+/*@}*/
+#endif
+
+/**
+ * @addtogroup MM
+ */
+
+/*@{*/
+
+/**
+ * This function will initialize a mempool object, normally which is used for static object.
+ *
+ * @param mp the mempool object
+ * @param name the name of memory pool
+ * @param start the star address of memory pool
+ * @param size the total size of memory pool
+ * @param block_size the size for each block
+ *
+ * @return the operation status, RT_EOK on OK; RT_ERROR on error
+ *
+ */
+rt_err_t rt_mp_init(struct rt_mempool* mp, const char* name, void *start, rt_size_t size, rt_size_t block_size)
+{
+ rt_uint8_t *block_ptr;
+ register rt_base_t offset;
+
+ /* parameter check */
+ RT_ASSERT(mp != RT_NULL);
+
+ /* init object */
+ rt_object_init(&(mp->parent), RT_Object_Class_MemPool, name);
+
+ /* init memory pool */
+ mp->start_address = start;
+ mp->size = RT_ALIGN(size, RT_ALIGN_SIZE);
+
+ mp->block_size = block_size;
+
+ /* align to align size byte */
+ mp->block_total_count = mp->size / (mp->block_size + sizeof(rt_uint8_t*));
+ mp->block_free_count = mp->block_total_count;
+
+ /* init suspended thread list */
+ rt_list_init(&(mp->suspend_thread));
+ mp->suspend_thread_count = 0;
+
+ /* init free block list */
+ block_ptr = (rt_uint8_t*) mp->start_address;
+ for (offset = 0; offset < mp->block_total_count; offset ++)
+ {
+ *(rt_uint8_t**)(block_ptr + offset * (block_size + sizeof(rt_uint8_t*)))
+ = (rt_uint8_t*)(block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t*)));
+ }
+
+ *(rt_uint8_t**)(block_ptr + offset * (block_size + sizeof(rt_uint8_t*))) = RT_NULL;
+
+ mp->block_list = block_ptr;
+
+ return RT_EOK;
+}
+
+rt_err_t rt_mp_detach(struct rt_mempool* mp)
+{
+ struct rt_thread* thread;
+ register rt_ubase_t temp;
+
+ /* parameter check */
+ RT_ASSERT(mp != RT_NULL);
+
+ /* wakeup all suspended threads */
+ while (!rt_list_isempty(&(mp->suspend_thread)))
+ {
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* get next suspend thread */
+ thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
+ /* set error code to RT_ERROR */
+ thread->error = -RT_ERROR;
+
+ /*
+ * resume thread
+ * In rt_thread_resume function, it will remove current thread from suspend
+ * list
+ */
+ rt_thread_resume(thread);
+
+ /* decrease suspended thread count */
+ mp->suspend_thread_count --;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+ }
+
+ /* detach object */
+ rt_object_detach(&(mp->parent));
+
+ return RT_EOK;
+}
+
+#ifdef RT_USING_HEAP
+/**
+ * This function will create a mempool object and allocate the memory pool from heap.
+ *
+ * @param name the name of memory pool
+ * @param block_count the count of blocks in memory pool
+ * @param block_size the size for each block
+ *
+ * @return the created mempool object
+ *
+ */
+rt_mp_t rt_mp_create(const char* name, rt_size_t block_count, rt_size_t block_size)
+{
+ rt_uint8_t *block_ptr;
+ struct rt_mempool* mp;
+ register rt_base_t offset;
+
+ /* allocate object */
+ mp = (struct rt_mempool*)rt_object_allocate(RT_Object_Class_MemPool, name);
+
+ /* init memory pool */
+ mp->block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);
+ mp->size = (block_size + sizeof(rt_uint8_t*))* block_count;
+
+ /* allocate memory */
+ mp->start_address = rt_malloc((block_size + sizeof(rt_uint8_t*))* block_count);
+ if (mp->start_address == RT_NULL)
+ {
+ /* no memory, delete memory pool object */
+ rt_object_delete(&(mp->parent));
+
+ return RT_NULL;
+ }
+
+ mp->block_total_count = block_count;
+ mp->block_free_count = mp->block_total_count;
+
+ /* init suspended thread list */
+ rt_list_init(&(mp->suspend_thread));
+ mp->suspend_thread_count = 0;
+
+ /* init free block list */
+ block_ptr = (rt_uint8_t*) mp->start_address;
+ for (offset = 0; offset < mp->block_total_count; offset ++)
+ {
+ *(rt_uint8_t**)(block_ptr + offset * (block_size + sizeof(rt_uint8_t*)))
+ = block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t*));
+ }
+
+ *(rt_uint8_t**)(block_ptr + offset * (block_size + sizeof(rt_uint8_t*))) = RT_NULL;
+
+ mp->block_list = block_ptr;
+
+ return mp;
+}
+
+/**
+ * This function will delete a memory pool and release the object memory.
+ *
+ * @param mp the memory pool object
+ *
+ * @return the operation status, RT_EOK on OK; -RT_ERROR on error
+ *
+ */
+rt_err_t rt_mp_delete(rt_mp_t mp)
+{
+ struct rt_thread* thread;
+ register rt_ubase_t temp;
+
+ /* parameter check */
+ RT_ASSERT(mp != RT_NULL);
+
+ /* wakeup all suspended threads */
+ while (!rt_list_isempty(&(mp->suspend_thread)))
+ {
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* get next suspend thread */
+ thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
+ /* set error code to RT_ERROR */
+ thread->error = -RT_ERROR;
+
+ /*
+ * resume thread
+ * In rt_thread_resume function, it will remove current thread from suspend
+ * list
+ */
+ rt_thread_resume(thread);
+
+ /* decrease suspended thread count */
+ mp->suspend_thread_count --;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+ }
+
+ /* release allocated room */
+ rt_free(mp->start_address);
+
+ /* detach object */
+ rt_object_delete(&(mp->parent));
+
+ return RT_EOK;
+}
+#endif
+
+/**
+ * This function will allocate a block from memory pool
+ *
+ * @param mp the memory pool object
+ * @param time the waiting time
+ *
+ * @return the allocated memory block
+ *
+ */
+void *rt_mp_alloc (rt_mp_t mp, rt_int32_t time)
+{
+ rt_uint8_t* block_ptr;
+ register rt_base_t level;
+ struct rt_thread* thread;
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ if(mp->block_free_count)
+ {
+ /* memory block is available. decrease the free block counter */
+ mp->block_free_count--;
+
+ /* get block from block list */
+ block_ptr = mp->block_list;
+ mp->block_list = *(rt_uint8_t**)block_ptr;
+
+ /* point to memory pool */
+ *(rt_uint8_t**)block_ptr = (rt_uint8_t*)mp;
+ }
+ else
+ {
+ /* memory block is unavailable. */
+ if (time == 0) return RT_NULL;
+ else
+ {
+ /* get current thread */
+ thread = rt_thread_self();
+
+ /* need suspend thread */
+ rt_thread_suspend(thread);
+ rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist));
+ mp->suspend_thread_count++;
+
+ if (time > 0)
+ {
+ /* init thread timer and start it */
+ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &time);
+ rt_timer_start(&(thread->thread_timer));
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ /* do a schedule */
+ rt_schedule();
+
+ if (thread->error != RT_EOK) return RT_NULL;
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* decrease free block */
+ mp->block_free_count --;
+
+ /* get block from block list */
+ block_ptr = mp->block_list;
+ mp->block_list = *(rt_uint8_t**)block_ptr;
+
+ /* point to memory pool */
+ *(rt_uint8_t**)block_ptr = (rt_uint8_t*)mp;
+ }
+ }
+
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+#ifdef RT_USING_HOOK
+ if (rt_mp_alloc_hook != RT_NULL) rt_mp_alloc_hook((rt_uint8_t*)(block_ptr + sizeof(rt_uint8_t*)));
+#endif
+
+ return (rt_uint8_t*)(block_ptr + sizeof(rt_uint8_t*));
+}
+
+/**
+ * This function will release a memory block
+ *
+ * @param block the address of memory block to be released
+ *
+ */
+void rt_mp_free (void *block)
+{
+ rt_uint8_t **block_ptr;
+ struct rt_mempool *mp;
+ struct rt_thread *thread;
+ register rt_base_t level;
+
+ /* get the control block of pool which the block belongs to */
+ block_ptr = (rt_uint8_t**)((rt_uint8_t*)block - sizeof(rt_uint8_t*));
+ mp = (struct rt_mempool*) *block_ptr;
+
+#ifdef RT_USING_HOOK
+ if (rt_mp_free_hook != RT_NULL) rt_mp_free_hook(block);
+#endif
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* increase the free block count */
+ mp->block_free_count ++;
+
+ /* link the block into the block list */
+ *block_ptr = mp->block_list;
+ mp->block_list = (rt_uint8_t*)block_ptr;
+
+ if (mp->suspend_thread_count > 0)
+ {
+ /* get the suspended thread */
+ thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
+
+ /* set error */
+ thread->error = RT_EOK;
+
+ /* resume thread */
+ rt_thread_resume(thread);
+
+ /* decrease suspended thread count */
+ mp->suspend_thread_count --;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ /* do a schedule */
+ rt_schedule();
+
+ return;
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+}
+
+#endif
+
+/*@}*/
+