summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/clock.c99
-rw-r--r--src/device.c277
-rw-r--r--src/idle.c112
-rw-r--r--src/ipc.c2200
-rw-r--r--src/irq.c69
-rw-r--r--src/kservice.c922
-rw-r--r--src/kservice.h100
-rw-r--r--src/mem.c504
-rw-r--r--src/mempool.c410
-rw-r--r--src/object.c401
-rw-r--r--src/scheduler.c414
-rw-r--r--src/slab.c815
-rw-r--r--src/thread.c625
-rw-r--r--src/timer.c384
14 files changed, 7332 insertions, 0 deletions
diff --git a/src/clock.c b/src/clock.c
new file mode 100644
index 0000000000..b45ca8d24f
--- /dev/null
+++ b/src/clock.c
@@ -0,0 +1,99 @@
+/*
+ * File : clock.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-03-12 Bernard first version
+ * 2006-05-27 Bernard add support for same priority thread schedule
+ * 2006-08-10 Bernard remove the last rt_schedule in rt_tick_increase
+ */
+
+#include <rtthread.h>
+
+static rt_tick_t rt_tick;
+static rt_time_t rt_passed_second;
+
+extern void rt_timer_check(void);
+
+/**
+ * This function will init system tick and set it to zero.
+ * @ingroup SystemInit
+ *
+ */
+void rt_system_tick_init()
+{
+ rt_tick = 0;
+ rt_passed_second = 0;
+}
+
+/**
+ * @addtogroup Clock
+ */
+
+/*@{*/
+
+/**
+ * This function will return current tick from operating system startup
+ *
+ * @return current tick
+ */
+rt_tick_t rt_tick_get()
+{
+ /* return the global tick */
+ return rt_tick;
+}
+
+/**
+ * This function will notify kernel there is one tick passed. Normally,
+ * this function is invoked by clock ISR.
+ */
+void rt_tick_increase()
+{
+ struct rt_thread* thread;
+
+ /* increase the global tick */
+ ++ rt_tick;
+
+ if (rt_tick % RT_TICK_PER_SECOND == 0)
+ {
+ ++rt_passed_second;
+ }
+
+ /* check timer */
+ rt_timer_check();
+
+ /* check time slice */
+ thread = rt_thread_self();
+
+ -- thread->remaining_tick;
+ if (thread->remaining_tick == 0)
+ {
+ /* change to initialized tick */
+ thread->remaining_tick = thread->init_tick;
+
+ /* yield */
+ rt_thread_yield();
+ }
+}
+
+/**
+ * This function will calculate the tick from millisecond.
+ *
+ * @param ms the specified millisecond
+ *
+ * @return the calculated tick
+ */
+rt_tick_t rt_tick_from_millisecond(rt_uint32_t ms)
+{
+ /* return the calculated tick */
+ return RT_TICK_PER_SECOND * (ms / 1000);
+}
+
+/*@}*/
+
diff --git a/src/device.c b/src/device.c
new file mode 100644
index 0000000000..cbd42cf103
--- /dev/null
+++ b/src/device.c
@@ -0,0 +1,277 @@
+/*
+ * File : device.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
+ * 2007-01-21 Bernard the first version
+ */
+
+#include <rtthread.h>
+#include "kservice.h"
+
+#ifdef RT_USING_DEVICE
+
+/**
+ * This function registers a device driver with specified name.
+ *
+ * @param dev the pointer of device driver structure
+ * @param name the device driver's name
+ * @param flags the flag of device
+ *
+ * @return the error code, RT_EOK on initialization successfully.
+ */
+rt_err_t rt_device_register(rt_device_t dev, const char* name, rt_uint16_t flags)
+{
+ if (dev == RT_NULL) return -RT_ERROR;
+
+ rt_object_init(&(dev->parent), RT_Object_Class_Device, name);
+ dev->flag = flags;
+
+ return RT_EOK;
+}
+
+/**
+ * This function removes a previouly registered device driver
+ *
+ * @param dev the pointer of device driver structure
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_device_unregister(rt_device_t dev)
+{
+ RT_ASSERT(dev != RT_NULL);
+
+ rt_object_detach(&(dev->parent));
+
+ return RT_EOK;
+}
+
+/**
+ * This function initializes all registered device driver
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_device_init_all()
+{
+ struct rt_device* device;
+ struct rt_list_node* node;
+ struct rt_object_information *information;
+ register rt_err_t result;
+
+ extern struct rt_object_information rt_object_container[];
+
+ information = &rt_object_container[RT_Object_Class_Device];
+
+ /* for each device */
+ for (node = information->object_list.next; node != &(information->object_list); node = node->next)
+ {
+ rt_err_t (*init)(rt_device_t dev);
+ device = (struct rt_device*)rt_list_entry(node, struct rt_object, list);
+
+ /* get device init handler */
+ init = device->init;
+ if (init != RT_NULL && !(device->flag & RT_DEVICE_FLAG_ACTIVATED))
+ {
+ result = init(device);
+ if (result != RT_EOK)
+ {
+ rt_kprintf("init device:%s error:\n", device->parent.name);
+ rt_kprintf("error code:%d\n", result);
+ }
+ }
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function finds a device driver by specified name.
+ *
+ * @param name the device driver's name
+ *
+ * @return the registered device driver on successful, or RT_NULL on failure.
+ */
+rt_device_t rt_device_find(const char* name)
+{
+ /* try to find device object */
+ return (struct rt_device*) rt_object_find (RT_Object_Class_Device,
+ name);
+}
+
+/**
+ * This function will open a device
+ *
+ * @param dev the pointer of device driver structure
+ *
+ * @return the result
+ */
+rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag)
+{
+ rt_err_t result;
+ rt_err_t (*open) (rt_device_t dev, rt_uint16_t oflag);
+
+ RT_ASSERT(dev != RT_NULL);
+
+ result = RT_EOK;
+
+ /* device is a standalone device and opened */
+ if ((dev->flag & RT_DEVICE_FLAG_STANDALONE) &&
+ (dev->open_flag & RT_DEVICE_OFLAG_OPEN))
+ return -RT_EBUSY;
+
+ /* call device open interface */
+ open = dev->open;
+ if (open != RT_NULL)
+ {
+ result = open(dev, oflag);
+ }
+ else
+ {
+ /* no this interface in device driver */
+ result = -RT_ENOSYS;
+ }
+
+ /* set open flag */
+ if (result == RT_EOK || result == -RT_ENOSYS)
+ dev->open_flag = oflag | RT_DEVICE_OFLAG_OPEN;
+
+ return result;
+}
+
+/**
+ * This function will close a device
+ *
+ * @param dev the pointer of device driver structure
+ *
+ * @return the result
+ */
+rt_err_t rt_device_close(rt_device_t dev)
+{
+ rt_err_t result;
+ rt_err_t (*close)(rt_device_t dev);
+
+ RT_ASSERT(dev != RT_NULL);
+
+ /* call device close interface */
+ close = dev->close;
+ if (close != RT_NULL)
+ {
+ result = close(dev);
+ }
+ else
+ {
+ /* no this interface in device driver */
+ result = -RT_ENOSYS;
+ }
+
+ /* set open flag */
+ if (result == RT_EOK || result == -RT_ENOSYS)
+ dev->open_flag = RT_DEVICE_OFLAG_CLOSE;
+
+ return result;
+}
+
+/**
+ * This function will read some data from a device.
+ *
+ * @param dev the pointer of device driver structure
+ * @param pos the position of reading
+ * @param buffer the data buffer to save read data
+ * @param size the size of buffer
+ *
+ * @return the actually read size on successful, otherwise negative returned.
+ */
+rt_size_t rt_device_read (rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ rt_size_t (*read)(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size);
+
+ RT_ASSERT(dev != RT_NULL);
+
+ /* call device read interface */
+ read = dev->read;
+ if (read != RT_NULL)
+ {
+ return read(dev, pos, buffer, size);
+ }
+
+ /* set error code */
+ rt_set_errno(-RT_ENOSYS);
+ return 0;
+}
+
+/**
+ * This function will write some data to a device.
+ *
+ * @param dev the pointer of device driver structure
+ * @param pos the position of written
+ * @param buffer the data buffer to be written to device
+ * @param size the size of buffer
+ *
+ * @return the actually written size on successful, otherwise negative returned.
+ */
+rt_size_t rt_device_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ rt_size_t (*write)(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size);
+
+ RT_ASSERT(dev != RT_NULL);
+
+ /* call device write interface */
+ write = dev->write;
+ if (write != RT_NULL)
+ {
+ return write(dev, pos, buffer, size);
+ }
+
+ /* set error code */
+ rt_set_errno(-RT_ENOSYS);
+ return 0;
+}
+
+/**
+ * This function will perform a variety of control functions on devices.
+ *
+ * @param dev the pointer of device driver structure
+ * @param cmd the command sent to device
+ * @param arg the argument of command
+ *
+ * @return the result
+ */
+rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg)
+{
+ rt_err_t (*control)(rt_device_t dev, rt_uint8_t cmd, void* arg);
+
+ RT_ASSERT(dev != RT_NULL);
+
+ /* call device write interface */
+ control = dev->control;
+ if (control != RT_NULL)
+ {
+ return control(dev, cmd, arg);
+ }
+
+ return -RT_ENOSYS;
+}
+
+rt_err_t rt_device_set_rx_indicate(rt_device_t dev, rt_err_t (*rx_ind )(rt_device_t dev, rt_size_t size))
+{
+ RT_ASSERT(dev != RT_NULL);
+
+ dev->rx_indicate = rx_ind;
+ return RT_EOK;
+}
+
+rt_err_t rt_device_set_tx_complete(rt_device_t dev, rt_err_t (*tx_done)(rt_device_t dev, void *buffer))
+{
+ RT_ASSERT(dev != RT_NULL);
+
+ dev->tx_complete = tx_done;
+ return RT_EOK;
+}
+
+#endif
diff --git a/src/idle.c b/src/idle.c
new file mode 100644
index 0000000000..f7da5e2c81
--- /dev/null
+++ b/src/idle.c
@@ -0,0 +1,112 @@
+/*
+ * File : idle.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-03-23 Bernard the first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include "kservice.h"
+
+#if defined (RT_USING_HOOK) || defined(RT_USING_HEAP)
+#define IDLE_THREAD_STACK_SIZE 256
+#else
+#define IDLE_THREAD_STACK_SIZE 128
+#endif
+
+static struct rt_thread idle;
+static rt_uint8_t rt_thread_stack[IDLE_THREAD_STACK_SIZE];
+
+#ifdef RT_USING_HEAP
+extern rt_list_t rt_thread_defunct;
+#endif
+
+#ifdef RT_USING_HOOK
+/**
+ * @addtogroup Hook
+ */
+/*@{*/
+
+static void (*rt_thread_idle_hook)();
+
+/**
+ * This function will set a hook function to idle thread loop.
+ *
+ * @param hook the specified hook function
+ *
+ * @note the hook function must be simple and never be blocked or suspend.
+ */
+void rt_thread_idle_sethook(void (*hook)())
+{
+ rt_thread_idle_hook = hook;
+}
+/*@}*/
+#endif
+
+static void rt_thread_idle_entry(void* parameter)
+{
+ while (1)
+ {
+#ifdef RT_USING_HOOK
+ /* if there is an idle thread hook */
+ if (rt_thread_idle_hook != RT_NULL) rt_thread_idle_hook();
+#endif
+
+#ifdef RT_USING_HEAP
+ /* check the defunct thread list */
+ if (!rt_list_isempty(&rt_thread_defunct))
+ {
+ rt_base_t lock;
+
+ struct rt_thread* thread = rt_list_entry(rt_thread_defunct.next, struct rt_thread, tlist);
+
+ /* disable interrupt */
+ lock = rt_hw_interrupt_disable();
+
+ rt_list_remove(&(thread->tlist));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(lock);
+
+ /* release thread's stack */
+ rt_free(thread->stack_addr);
+
+ /* delete thread object */
+ rt_object_delete((rt_object_t)thread);
+ }
+#endif
+ }
+}
+
+/**
+ * @addtogroup SystemInit
+ */
+/*@{*/
+
+/**
+ * This function will initialize idle thread, then start it.
+ *
+ * @note this function must be invoked when system init.
+ */
+void rt_thread_idle_init()
+{
+ /* init thread */
+ rt_thread_init(&idle,
+ "tidle",
+ rt_thread_idle_entry, RT_NULL,
+ &rt_thread_stack[0], sizeof(rt_thread_stack),
+ RT_THREAD_PRIORITY_MAX - 1, 32);
+
+ /* startup */
+ rt_thread_startup(&idle);
+}
+
+/*@}*/
diff --git a/src/ipc.c b/src/ipc.c
new file mode 100644
index 0000000000..b5d7cd3b86
--- /dev/null
+++ b/src/ipc.c
@@ -0,0 +1,2200 @@
+/*
+ * File : ipc.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-03-14 Bernard the first version
+ * 2006-04-25 Bernard implement semaphore
+ * 2006-05-03 Bernard add IPC_DEBUG
+ * modify the type of IPC waiting time to rt_int32_t
+ * 2006-05-10 Bernard fix the semaphore take bug and add IPC object
+ * 2006-05-12 Bernard implement mailbox and message queue
+ * 2006-05-20 Bernard implement mutex
+ * 2006-05-23 Bernard implement fast event
+ * 2006-05-24 Bernard implement event
+ * 2006-06-03 Bernard fix the thread timer init bug
+ * 2006-06-05 Bernard fix the mutex release bug
+ * 2006-06-07 Bernard fix the message queue send bug
+ * 2006-08-04 Bernard add hook support
+ * 2009-05-21 Yi.qiu fix the sem release bug
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+
+#include "kservice.h"
+
+/* #define IPC_DEBUG */
+
+#ifdef RT_USING_HOOK
+extern void (*rt_object_trytake_hook)(struct rt_object* object);
+extern void (*rt_object_take_hook)(struct rt_object* object);
+extern void (*rt_object_put_hook)(struct rt_object* object);
+#endif
+
+/**
+ * @addtogroup IPC
+ */
+
+/*@{*/
+
+/**
+ * This function will initialize an IPC object
+ *
+ * @param ipc the IPC object
+ *
+ * @return the operation status, RT_EOK on successful
+ */
+rt_inline rt_err_t rt_ipc_object_init(struct rt_ipc_object *ipc)
+{
+ /* init ipc object */
+ rt_list_init(&(ipc->suspend_thread));
+ ipc->suspend_thread_count = 0;
+
+ return RT_EOK;
+}
+
+/**
+ * This function will suspend a thread for a specified IPC object and put the
+ * thread into suspend queue of IPC object
+ *
+ * @param ipc the IPC object
+ * @param thread the thread object to be suspended
+ *
+ * @return the operation status, RT_EOK on successful
+ */
+rt_inline rt_err_t rt_ipc_object_suspend(struct rt_ipc_object *ipc, struct rt_thread *thread)
+{
+ /* suspend thread */
+ rt_thread_suspend(thread);
+ ipc->suspend_thread_count ++;
+
+ switch (ipc->parent.flag)
+ {
+ case RT_IPC_FLAG_FIFO:
+ rt_list_insert_before(&(ipc->suspend_thread), &(thread->tlist));
+ break;
+
+ case RT_IPC_FLAG_PRIO:
+ {
+ struct rt_list_node* n;
+ struct rt_thread* sthread;
+
+ /* find a suitable position */
+ for (n = ipc->suspend_thread.next; n != &(ipc->suspend_thread);
+ n = n->next)
+ {
+ sthread = rt_list_entry(n, struct rt_thread, tlist);
+
+ /* find out */
+ if (thread->current_priority < sthread->current_priority) break;
+ }
+
+ rt_list_insert_before(&(ipc->suspend_thread), &(thread->tlist));
+ }
+ break;
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will resume a thread from an IPC object:
+ * - remove the thread from suspend queue of IPC object
+ * - put the thread into system ready queue
+ *
+ * @param ipc the IPC object
+ *
+ * @return the operation status, RT_EOK on successful
+ */
+rt_inline rt_err_t rt_ipc_object_resume(struct rt_ipc_object* ipc)
+{
+ struct rt_thread *thread;
+
+ /* get thread entry */
+ thread = rt_list_entry(ipc->suspend_thread.next, struct rt_thread, tlist);
+
+#ifdef IPC_DEBUG
+ rt_kprintf("resume thread:%s\n", thread->name);
+#endif
+
+ /* resume it */
+ rt_thread_resume(thread);
+
+ /* decrease suspended thread count */
+ ipc->suspend_thread_count --;
+
+ return RT_EOK;
+}
+
+/**
+ * This function will resume all suspended threads in an IPC object.
+ *
+ * @param ipc the IPC object
+ *
+ * @return the operation status, RT_EOK on successful
+ */
+rt_inline rt_err_t rt_ipc_object_resume_all(struct rt_ipc_object* ipc)
+{
+ struct rt_thread* thread;
+ register rt_ubase_t temp;
+
+ /* wakeup all suspend threads */
+ while (!rt_list_isempty(&(ipc->suspend_thread)))
+ {
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* get next suspend thread */
+ thread = rt_list_entry(ipc->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 */
+ ipc->suspend_thread_count --;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+ }
+
+ return RT_EOK;
+}
+
+/* decrease ipc suspended thread number when thread can not take resource successfully */
+rt_inline void rt_ipc_object_decrease(struct rt_ipc_object* ipc)
+{
+ register rt_ubase_t level;
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* decrease suspended thread count */
+ ipc->suspend_thread_count --;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+}
+#ifdef RT_USING_SEMAPHORE
+
+/**
+ * This function will initialize a semaphore and put it under control of resource
+ * management.
+ *
+ * @param sem the semaphore object
+ * @param name the name of semaphore
+ * @param value the init value of semaphore
+ * @param flag the flag of semaphore
+ *
+ * @return the operation status, RT_EOK on successful
+ */
+rt_err_t rt_sem_init (rt_sem_t sem, const char* name, rt_uint32_t value, rt_uint8_t flag)
+{
+ RT_ASSERT(sem != RT_NULL);
+
+ /* init object */
+ rt_object_init(&(sem->parent.parent), RT_Object_Class_Semaphore, name);
+
+ /* init ipc object */
+ rt_ipc_object_init(&(sem->parent));
+
+ /* set init value */
+ sem->value = value;
+
+ /* set parent */
+ sem->parent.parent.flag = flag;
+
+ return RT_EOK;
+}
+
+/**
+ * This function will detach a semaphore from resource management
+ *
+ * @param sem the semaphore object
+ *
+ * @return the operation status, RT_EOK on successful
+ *
+ * @see rt_sem_delete
+ */
+rt_err_t rt_sem_detach (rt_sem_t sem)
+{
+ RT_ASSERT(sem != RT_NULL);
+
+ /* wakeup all suspend threads */
+ rt_ipc_object_resume_all(&(sem->parent));
+
+ /* detach semaphore object */
+ rt_object_detach(&(sem->parent.parent));
+
+ return RT_EOK;
+}
+
+#ifdef RT_USING_HEAP
+/**
+ * This function will create a semaphore from system resource
+ *
+ * @param name the name of semaphore
+ * @param value the init value of semaphore
+ * @param flag the flag of semaphore
+ *
+ * @return the created semaphore, RT_NULL on error happen
+ *
+ * @see rt_sem_init
+ */
+rt_sem_t rt_sem_create (const char* name, rt_uint32_t value, rt_uint8_t flag)
+{
+ rt_sem_t sem;
+
+ /* allocate object */
+ sem = (rt_sem_t) rt_object_allocate(RT_Object_Class_Semaphore, name);
+ if (sem == RT_NULL) return sem;
+
+ /* init ipc object */
+ rt_ipc_object_init(&(sem->parent));
+
+ /* set init value */
+ sem->value = value;
+
+ /* set parent */
+ sem->parent.parent.flag = flag;
+
+ return sem;
+}
+
+/**
+ * This function will delete a semaphore object and release the memory
+ *
+ * @param sem the semaphore object
+ *
+ * @return the error code
+ *
+ * @see rt_sem_detach
+ */
+rt_err_t rt_sem_delete (rt_sem_t sem)
+{
+ RT_ASSERT(sem != RT_NULL);
+
+ /* wakeup all suspend threads */
+ rt_ipc_object_resume_all(&(sem->parent));
+
+ /* delete semaphore object */
+ rt_object_delete(&(sem->parent.parent));
+
+ return RT_EOK;
+}
+#endif
+
+/**
+ * This function will take a semaphore, if the semaphore is unavailable, the
+ * thread shall wait for a specified time.
+ *
+ * @param sem the semaphore object
+ * @param time the waiting time
+ *
+ * @return the error code
+ */
+rt_err_t rt_sem_take (rt_sem_t sem, rt_int32_t time)
+{
+ register rt_base_t temp;
+ struct rt_thread* thread;
+
+ RT_ASSERT(sem != RT_NULL);
+
+#ifdef RT_USING_HOOK
+ if (rt_object_trytake_hook != RT_NULL) rt_object_trytake_hook(&(sem->parent.parent));
+#endif
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+#ifdef IPC_DEBUG
+ rt_kprintf("thread %s take sem:%s, which value is: %d\n", rt_thread_self()->name,
+ ((struct rt_object*)sem)->name, sem->value);
+#endif
+ if (sem->value > 0)
+ {
+ /* semaphore is available */
+ sem->value --;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+ }
+ else
+ {
+ /* no waiting, return with timeout */
+ if (time == 0 )
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_ETIMEOUT;
+ }
+ else
+ {
+ /* semaphore is unavailable, push to suspend list */
+ sem->value --;
+
+ /* get current thread */
+ thread = rt_thread_self();
+
+ /* reset thread error number */
+ thread->error = RT_EOK;
+
+#ifdef IPC_DEBUG
+ rt_kprintf("sem take: suspend thread - %s\n", thread->name);
+#endif
+
+ /* suspend thread */
+ rt_ipc_object_suspend(&(sem->parent), thread);
+
+ /* has waiting time, start thread timer */
+ if (time > 0)
+ {
+#ifdef IPC_DEBUG
+ rt_kprintf("set thread:%s to timer list\n", thread->name);
+#endif
+ /* reset the timeout of 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(temp);
+
+ /* do schedule */
+ rt_schedule();
+
+ if (thread->error != RT_EOK)
+ {
+ /* decrease suspended thread count */
+ rt_ipc_object_decrease(&(sem->parent));
+ return thread->error;
+ }
+ }
+ }
+
+#ifdef RT_USING_HOOK
+ if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(sem->parent.parent));
+#endif
+
+ return RT_EOK;
+}
+
+/**
+ * This function will try to take a semaphore and immediately return
+ *
+ * @param sem the semaphore object
+ *
+ * @return the error code
+ */
+rt_err_t rt_sem_trytake(rt_sem_t sem)
+{
+ return rt_sem_take(sem, 0);
+}
+
+/**
+ * This function will release a semaphore, if there are threads suspended on
+ * semaphore, it will be waked up.
+ *
+ * @param sem the semaphore object
+ *
+ * @return the error code
+ */
+rt_err_t rt_sem_release(rt_sem_t sem)
+{
+ register rt_base_t temp;
+
+#ifdef RT_USING_HOOK
+ if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(sem->parent.parent));
+#endif
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+#ifdef IPC_DEBUG
+ rt_kprintf("thread %s releases sem:%s, which value is: %d\n", rt_thread_self()->name,
+ ((struct rt_object*)sem)->name, sem->value);
+#endif
+ /* increase value */
+ sem->value ++;
+
+ if (sem->value <= 0 && sem->parent.suspend_thread_count > 0)
+ {
+ rt_ipc_object_resume(&(sem->parent));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ /* resume a thread, re-schedule */
+ rt_schedule();
+ return RT_EOK;
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ return RT_EOK;
+}
+
+/**
+ * This function can get or set some extra attributions of a semaphore object.
+ *
+ * @param sem the semaphore object
+ * @param cmd the execution command
+ * @param arg the execution argument
+ *
+ * @return the error code
+ */
+rt_err_t rt_sem_control(rt_sem_t sem, rt_uint8_t cmd, void* arg)
+{
+ return RT_EOK;
+}
+
+#endif /* end of RT_USING_SEMAPHORE */
+
+#ifdef RT_USING_MUTEX
+
+/**
+ * This function will initialize a mutex and put it under control of resource
+ * management.
+ *
+ * @param mutex the mutex object
+ * @param name the name of mutex
+ * @param flag the flag of mutex
+ *
+ * @return the operation status, RT_EOK on successful
+ */
+rt_err_t rt_mutex_init (rt_mutex_t mutex, const char* name, rt_uint8_t flag)
+{
+ RT_ASSERT(mutex != RT_NULL);
+
+ /* init object */
+ rt_object_init(&(mutex->parent.parent), RT_Object_Class_Mutex, name);
+
+ /* init ipc object */
+ rt_ipc_object_init(&(mutex->parent));
+
+ mutex->value = 1;
+ mutex->owner = RT_NULL;
+ mutex->original_priority = 0xFF;
+ mutex->hold = 0;
+
+ /* set flag */
+ mutex->parent.parent.flag = flag;
+
+ return RT_EOK;
+}
+
+/**
+ * This function will detach a mutex from resource management
+ *
+ * @param mutex the mutex object
+ *
+ * @return the operation status, RT_EOK on successful
+ *
+ * @see rt_mutex_delete
+ */
+rt_err_t rt_mutex_detach (rt_mutex_t mutex)
+{
+ RT_ASSERT(mutex != RT_NULL);
+
+ /* wakeup all suspend threads */
+ rt_ipc_object_resume_all(&(mutex->parent));
+
+ /* detach semaphore object */
+ rt_object_detach(&(mutex->parent.parent));
+
+ return RT_EOK;
+}
+
+#ifdef RT_USING_HEAP
+/**
+ * This function will create a mutex from system resource
+ *
+ * @param name the name of mutex
+ * @param flag the flag of mutex
+ *
+ * @return the created mutex, RT_NULL on error happen
+ *
+ * @see rt_mutex_init
+ */
+rt_mutex_t rt_mutex_create (const char* name, rt_uint8_t flag)
+{
+ struct rt_mutex *mutex;
+
+ /* allocate object */
+ mutex = (rt_mutex_t) rt_object_allocate(RT_Object_Class_Mutex, name);
+ if (mutex == RT_NULL) return mutex;
+
+ /* init ipc object */
+ rt_ipc_object_init(&(mutex->parent));
+
+ mutex->value = 1;
+ mutex->owner = RT_NULL;
+ mutex->original_priority = 0xFF;
+ mutex->hold = 0;
+
+ /* set flag */
+ mutex->parent.parent.flag = flag;
+
+ return mutex;
+}
+
+/**
+ * This function will delete a mutex object and release the memory
+ *
+ * @param mutex the mutex object
+ *
+ * @return the error code
+ *
+ * @see rt_mutex_detach
+ */
+rt_err_t rt_mutex_delete (rt_mutex_t mutex)
+{
+ RT_ASSERT(mutex != RT_NULL);
+
+ /* wakeup all suspend threads */
+ rt_ipc_object_resume_all(&(mutex->parent));
+
+ /* delete semaphore object */
+ rt_object_delete(&(mutex->parent.parent));
+
+ return RT_EOK;
+}
+#endif
+
+/**
+ * This function will take a mutex, if the mutex is unavailable, the
+ * thread shall wait for a specified time.
+ *
+ * @param mutex the mutex object
+ * @param time the waiting time
+ *
+ * @return the error code
+ */
+rt_err_t rt_mutex_take (rt_mutex_t mutex, rt_int32_t time)
+{
+ register rt_base_t temp;
+ struct rt_thread* thread;
+
+ RT_ASSERT(mutex != RT_NULL);
+
+#ifdef RT_USING_HOOK
+ if (rt_object_trytake_hook != RT_NULL) rt_object_trytake_hook(&(mutex->parent.parent));
+#endif
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+#ifdef IPC_DEBUG
+ rt_kprintf("mutex_take:mutex value: %d, hold: %d\n", mutex->value, mutex->hold);
+#endif
+
+ /* get current thread */
+ thread = rt_thread_self();
+
+ /* reset thread error */
+ thread->error = RT_EOK;
+
+ if (mutex->owner == thread)
+ {
+ /* it's the same thread */
+ mutex->hold ++;
+ }
+ else
+ {
+ if (mutex->value > 0)
+ {
+ /* mutex is available */
+ mutex->value --;
+
+ /* set mutex owner and original priority */
+ mutex->owner = thread;
+ mutex->original_priority = thread->current_priority;
+ mutex->hold ++;
+ }
+ else
+ {
+ /* no waiting, return with timeout */
+ if (time == 0 )
+ {
+ /* set error as timeout */
+ thread->error = -RT_ETIMEOUT;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ return -RT_ETIMEOUT;
+ }
+ else
+ {
+ /* mutex is unavailable, push to suspend list */
+ mutex->value --;
+
+#ifdef IPC_DEBUG
+ rt_kprintf("sem take: suspend thread: %s\n", thread->name);
+#endif
+ /* change the owner thread priority of mutex */
+ if (thread->current_priority < mutex->owner->current_priority)
+ {
+ /* change the owner thread priority */
+ rt_thread_control(mutex->owner, RT_THREAD_CTRL_CHANGE_PRIORITY,
+ &thread->current_priority);
+ }
+
+ /* suspend current thread */
+ rt_ipc_object_suspend(&(mutex->parent), thread);
+
+ /* has waiting time, start thread timer */
+ if (time > 0)
+ {
+#ifdef IPC_DEBUG
+ rt_kprintf("set thread:%s to timer list\n", thread->name);
+#endif
+ /* reset the timeout of 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(temp);
+
+ /* do schedule */
+ rt_schedule();
+
+ if (thread->error != RT_EOK)
+ {
+ /* decrease suspended thread count */
+ rt_ipc_object_decrease(&(mutex->parent));
+
+ /* return error */
+ return thread->error;
+ }
+ else
+ {
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* take mutex */
+ mutex->owner = thread;
+ mutex->hold ++;
+
+ /* set thread error */
+ thread->error = RT_EOK;
+ }
+ }
+ }
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+#ifdef RT_USING_HOOK
+ if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(mutex->parent.parent));
+#endif
+
+ return RT_EOK;
+}
+
+/**
+ * This function will release a mutex, if there are threads suspended on mutex,
+ * it will be waked up.
+ *
+ * @param mutex the mutex object
+ *
+ * @return the error code
+ */
+rt_err_t rt_mutex_release(rt_mutex_t mutex)
+{
+ register rt_base_t temp;
+ struct rt_thread* thread;
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+#ifdef IPC_DEBUG
+ rt_kprintf("mutex_release:mutex value: %d, hold: %d\n", mutex->value, mutex->hold);
+#endif
+
+#ifdef RT_USING_HOOK
+ if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(mutex->parent.parent));
+#endif
+
+ /* get current thread */
+ thread = rt_thread_self();
+
+ /* mutex is only released by owner */
+ if (thread != mutex->owner)
+ {
+ thread->error = -RT_ERROR;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ return -RT_ERROR;
+ }
+
+ /* decrease hold */
+ mutex->hold --;
+
+ /* if no hold */
+ if (mutex->hold == 0)
+ {
+ /* change the owner thread to original priority */
+ if (mutex->owner->init_priority != mutex->owner->current_priority)
+ {
+ rt_thread_control(mutex->owner, RT_THREAD_CTRL_CHANGE_PRIORITY,
+ &(mutex->owner->init_priority));
+ }
+
+ /* wakeup suspended thread */
+ if (mutex->value <= 0 && mutex->parent.suspend_thread_count > 0)
+ {
+#ifdef IPC_DEBUG
+ rt_kprintf("mutex release: resume thread: %s\n", thread->name);
+#endif
+
+ /* resume thread */
+ rt_ipc_object_resume(&(mutex->parent));
+ }
+
+ /* increase value */
+ mutex->value ++;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ rt_schedule();
+ return RT_EOK;
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ return RT_EOK;
+}
+
+/**
+ * This function can get or set some extra attributions of a mutex object.
+ *
+ * @param mutex the mutex object
+ * @param cmd the execution command
+ * @param arg the execution argument
+ *
+ * @return the error code
+ */
+rt_err_t rt_mutex_control(rt_mutex_t mutex, rt_uint8_t cmd, void* arg)
+{
+ return RT_EOK;
+}
+
+#endif /* end of RT_USING_MUTEX */
+
+#ifdef RT_USING_FASTEVENT
+
+/**
+ * This function will initialize a fast event and put it under control of resource
+ * management.
+ *
+ * @param event the fast event object
+ * @param name the name of fast event
+ * @param flag the flag of fast event
+ *
+ * @return the operation status, RT_EOK on successful
+ */
+rt_err_t rt_fast_event_init(rt_fast_event_t event, const char* name, rt_uint8_t flag)
+{
+ register rt_base_t offset;
+ RT_ASSERT(event != RT_NULL);
+
+ /* init object */
+ rt_object_init(&(event->parent), RT_Object_Class_FastEvent, name);
+
+ /* set parent */
+ event->parent.flag = flag;
+
+ /* clear event set */
+ event->set = 0x00;
+
+ /* init thread list */
+ for (offset = 0; offset < 32; offset ++)
+ {
+ rt_list_init(&(event->thread_list[offset]));
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will detach a fast event from resource management
+ *
+ * @param event the fast event object
+ *
+ * @return the operation status, RT_EOK on successful
+ */
+rt_err_t rt_fast_event_detach(rt_fast_event_t event)
+{
+ register rt_base_t bit;
+ struct rt_thread* thread;
+ register rt_ubase_t level;
+
+ RT_ASSERT(event != RT_NULL);
+
+ for (bit = 0; bit < RT_EVENT_LENGTH; bit ++)
+ {
+ /* resume all suspend thread */
+ if (!rt_list_isempty(&(event->thread_list[bit])))
+ {
+ /* wakeup all suspend threads */
+ while (!rt_list_isempty(&(event->thread_list[bit])))
+ {
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* get next suspend thread */
+ thread = rt_list_entry(event->thread_list[bit].next, struct rt_thread, tlist);
+ /* set error code to RT_ERROR */
+ thread->error = -RT_ERROR;
+
+ /* resume thread */
+ rt_thread_resume(thread);
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+ }
+
+ }
+ }
+
+ /* detach event object */
+ rt_object_detach(&(event->parent));
+
+ return RT_EOK;
+}
+
+#ifdef RT_USING_HEAP
+/**
+ * This function will create a fast event object from system resource
+ *
+ * @param name the name of fast event
+ * @param flag the flag of fast event
+ *
+ * @return the created fast event, RT_NULL on error happen
+ */
+rt_fast_event_t rt_fast_event_create (const char* name, rt_uint8_t flag)
+{
+ rt_fast_event_t event;
+ register rt_base_t offset;
+
+ /* allocate object */
+ event = (rt_fast_event_t) rt_object_allocate(RT_Object_Class_FastEvent, name);
+ if (event == RT_NULL) return event;
+
+ /* set parent */
+ event->parent.flag = flag;
+
+ /* clear event set */
+ event->set = 0x00;
+
+ /* init thread list */
+ for (offset = 0; offset < 32; offset ++)
+ {
+ rt_list_init(&(event->thread_list[offset]));
+ }
+
+ return event;
+}
+
+/**
+ * This function will delete a fast event object and release the memory
+ *
+ * @param event the fast event object
+ *
+ * @return the error code
+ */
+rt_err_t rt_fast_event_delete (rt_fast_event_t event)
+{
+ register rt_base_t bit;
+ struct rt_thread* thread;
+ register rt_ubase_t level;
+
+ RT_ASSERT(event != RT_NULL);
+
+ for (bit = 0; bit < RT_EVENT_LENGTH; bit ++)
+ {
+ /* resume all suspend thread */
+ if (!rt_list_isempty(&(event->thread_list[bit])))
+ {
+ /* wakeup all suspend threads */
+ while (!rt_list_isempty(&(event->thread_list[bit])))
+ {
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* get next suspend thread */
+ thread = rt_list_entry(event->thread_list[bit].next, struct rt_thread, tlist);
+ /* set error code to RT_ERROR */
+ thread->error = -RT_ERROR;
+
+ /* resume thread */
+ rt_thread_resume(thread);
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+ }
+
+ }
+ }
+
+ /* detach semaphore object */
+ rt_object_delete(&(event->parent));
+
+ return RT_EOK;
+}
+#endif
+
+/**
+ * This function will send an event to the fast event object, if there are threads
+ * suspended on fast event object, it will be waked up.
+ *
+ * @param event the fast event object
+ * @param bit the event bit
+ *
+ * @return the error code
+ */
+rt_err_t rt_fast_event_send(rt_fast_event_t event, rt_uint8_t bit)
+{
+ rt_uint32_t offset;
+ register rt_ubase_t level;
+ struct rt_thread *thread;
+ struct rt_list_node *n;
+
+ /* parameter check */
+ RT_ASSERT(event != RT_NULL);
+ RT_ASSERT(bit < RT_EVENT_LENGTH);
+
+ offset = 1 << bit;
+
+#ifdef RT_USING_HOOK
+ if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(event->parent));
+#endif
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ event->set |= offset;
+
+ /* if thread list at offset is not empty */
+ n = event->thread_list[bit].next;
+ while (n != &(event->thread_list[bit]))
+ {
+ /* get thread */
+ thread = rt_list_entry(n, struct rt_thread, tlist);
+
+ /* move to next node */
+ n = n->next;
+
+ /* clear bit or not */
+ if (thread->event_info & RT_EVENT_FLAG_CLEAR)
+ event->set &= ~offset;
+
+ /* resume thread */
+ rt_thread_resume(thread);
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ /* do a schedule */
+ rt_schedule();
+
+ return RT_EOK;
+}
+
+/**
+ * This function will receive an event from fast event object, if the event is
+ * unavailable, the thread shall wait for a specified time.
+ *
+ * @param event the fast event object
+ * @param bit the interested event
+ * @param option the receive option
+ * @param timeout the waiting time
+ *
+ * @return the error code
+ */
+rt_err_t rt_fast_event_recv(rt_fast_event_t event, rt_uint8_t bit, rt_uint8_t option, rt_int32_t timeout)
+{
+ rt_base_t offset;
+ struct rt_thread* thread;
+ register rt_ubase_t level;
+
+ /* parameter check */
+ RT_ASSERT(event != RT_NULL);
+ RT_ASSERT(bit < RT_EVENT_LENGTH);
+
+ offset = 1 << bit;
+
+#ifdef RT_USING_HOOK
+ if (rt_object_trytake_hook != RT_NULL) rt_object_trytake_hook(&(event->parent));
+#endif
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* get current thread */
+ thread = rt_thread_self();
+ thread->error = RT_EOK;
+
+ /* get event successfully */
+ if (event->set & offset)
+ {
+ if (option & RT_EVENT_FLAG_CLEAR)
+ event->set &= ~ offset;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ return RT_EOK;
+ }
+
+ /* no event happen */
+
+ /* check waiting time */
+ if (timeout == 0)
+ {
+ /* no waiting */
+ thread->error = -RT_ETIMEOUT;
+ }
+ else
+ {
+ /* there are no event, suspend thread */
+ rt_thread_suspend(thread);
+
+ /* set event info in thread */
+ thread->event_info = option;
+
+ switch (event->parent.flag)
+ {
+ case RT_IPC_FLAG_FIFO:
+ rt_list_insert_after(&(event->thread_list[bit]), &(thread->tlist));
+ break;
+
+ case RT_IPC_FLAG_PRIO:
+ {
+ struct rt_list_node* n;
+ struct rt_thread* sthread;
+
+ /* find a suitable position */
+ for (n = event->thread_list[bit].next; n != &(event->thread_list[bit]); n = n->next)
+ {
+ sthread = rt_list_entry(n, struct rt_thread, tlist);
+
+ /* find out */
+ if (thread->current_priority < sthread->current_priority) break;
+ }
+
+ /* insert thread */
+ rt_list_insert_before(&(event->thread_list[bit]), &(thread->tlist));
+ }
+ break;
+ }
+
+ /* if there is timeout, active thread timer */
+ if (timeout > 0)
+ {
+ /* reset the timeout of thread timer and start it */
+ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout);
+ rt_timer_start(&(thread->thread_timer));
+ }
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+#ifdef RT_USING_HOOK
+ if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(event->parent));
+#endif
+
+ return thread->error;
+}
+
+/**
+ * This function can get or set some extra attributions of a fast event object.
+ *
+ * @param event the event object
+ * @param cmd the execution command
+ * @param arg the execution argument
+ *
+ * @return the error code
+ */
+rt_err_t rt_fast_event_control (rt_fast_event_t event, rt_uint8_t cmd, void* arg)
+{
+ return RT_EOK;
+}
+#endif
+
+#ifdef RT_USING_EVENT
+
+/**
+ * This function will initialize an event and put it under control of resource
+ * management.
+ *
+ * @param event the event object
+ * @param name the name of event
+ * @param flag the flag of event
+ *
+ * @return the operation status, RT_EOK on successful
+ */
+rt_err_t rt_event_init(rt_event_t event, const char* name, rt_uint8_t flag)
+{
+ RT_ASSERT(event != RT_NULL);
+
+ /* init object */
+ rt_object_init(&(event->parent.parent), RT_Object_Class_Event, name);
+
+ /* set parent flag */
+ event->parent.parent.flag = flag;
+
+ /* init ipc object */
+ rt_ipc_object_init(&(event->parent));
+
+ /* init event */
+ event->set = 0;
+
+ return RT_EOK;
+}
+
+/**
+ * This function will detach an event object from resource management
+ *
+ * @param event the event object
+ *
+ * @return the operation status, RT_EOK on successful
+ */
+rt_err_t rt_event_detach(rt_event_t event)
+{
+ /* parameter check */
+ RT_ASSERT(event != RT_NULL);
+
+ /* resume all suspended thread */
+ rt_ipc_object_resume_all(&(event->parent));
+
+ /* detach event object */
+ rt_object_detach(&(event->parent.parent));
+
+ return RT_EOK;
+}
+
+#ifdef RT_USING_HEAP
+/**
+ * This function will create an event object from system resource
+ *
+ * @param name the name of event
+ * @param flag the flag of event
+ *
+ * @return the created event, RT_NULL on error happen
+ */
+rt_event_t rt_event_create (const char* name, rt_uint8_t flag)
+{
+ rt_event_t event;
+
+ /* allocate object */
+ event = (rt_event_t) rt_object_allocate(RT_Object_Class_Event, name);
+ if (event == RT_NULL) return event;
+
+ /* set parent */
+ event->parent.parent.flag = flag;
+
+ /* init ipc object */
+ rt_ipc_object_init(&(event->parent));
+
+ /* init event */
+ event->set = 0;
+
+ return event;
+}
+
+/**
+ * This function will delete an event object and release the memory
+ *
+ * @param event the event object
+ *
+ * @return the error code
+ */
+rt_err_t rt_event_delete (rt_event_t event)
+{
+ /* parameter check */
+ RT_ASSERT(event != RT_NULL);
+
+ /* resume all suspended thread */
+ rt_ipc_object_resume_all(&(event->parent));
+
+ /* delete event object */
+ rt_object_delete(&(event->parent.parent));
+
+ return RT_EOK;
+}
+#endif
+
+/**
+ * This function will send an event to the event object, if there are threads
+ * suspended on event object, it will be waked up.
+ *
+ * @param event the event object
+ * @param set the event set
+ *
+ * @return the error code
+ */
+rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set)
+{
+ struct rt_list_node *n;
+ struct rt_thread *thread;
+ register rt_ubase_t level;
+ register rt_base_t status;
+
+ /* parameter check */
+ RT_ASSERT(event != RT_NULL);
+ if (set == 0) return -RT_ERROR;
+
+#ifdef RT_USING_HOOK
+ if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(event->parent.parent));
+#endif
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* set event */
+ event->set |= set;
+
+ if (event->parent.suspend_thread_count > 0)
+ {
+ /* search thread list to resume thread */
+ n = event->parent.suspend_thread.next;
+ while (n != &(event->parent.suspend_thread))
+ {
+ /* get thread */
+ thread = rt_list_entry(n, struct rt_thread, tlist);
+
+ status = -RT_ERROR;
+ if (thread->event_info & RT_EVENT_FLAG_AND)
+ {
+ if ((thread->event_set & event->set) == thread->event_set)
+ {
+ status = RT_EOK;
+ }
+ }
+ else if (thread->event_info & RT_EVENT_FLAG_OR)
+ {
+ if (thread->event_set & event->set)
+ {
+ status = RT_EOK;
+ }
+ }
+
+ /* move node to the nexe */
+ n = n->next;
+
+ /* condition is satisfied, resume thread */
+ if (status == RT_EOK)
+ {
+ /* resume thread, and thread list breaks out */
+ rt_thread_resume(thread);
+
+ /* decrease suspended thread count */
+ event->parent.suspend_thread_count--;
+
+ if (thread->event_info & RT_EVENT_FLAG_CLEAR)
+ event->set &= ~thread->event_set;
+ }
+ }
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ /* do a schedule */
+ rt_schedule();
+
+ return RT_EOK;
+}
+
+/**
+ * This function will receive an event from event object, if the event is unavailable,
+ * the thread shall wait for a specified time.
+ *
+ * @param event the fast event object
+ * @param set the interested event set
+ * @param option the receive option
+ * @param timeout the waiting time
+ * @param recved the received event
+ *
+ * @return the error code
+ */
+rt_err_t rt_event_recv(rt_event_t event, rt_uint32_t set, rt_uint8_t option, rt_int32_t timeout, rt_uint32_t* recved)
+{
+ struct rt_thread *thread;
+ register rt_ubase_t level;
+ register rt_base_t status;
+
+ /* parameter check */
+ RT_ASSERT(event != RT_NULL);
+ if (set == 0) return -RT_ERROR;
+
+ /* init status */
+ status = -RT_ERROR;
+
+#ifdef RT_USING_HOOK
+ if (rt_object_trytake_hook != RT_NULL) rt_object_trytake_hook(&(event->parent.parent));
+#endif
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* check event set */
+ if (option & RT_EVENT_FLAG_AND)
+ {
+ if ((event->set & set) == set) status = RT_EOK;
+ }
+ else if (option & RT_EVENT_FLAG_OR)
+ {
+ if (event->set & set) status = RT_EOK;
+ }
+
+ /* get current thread */
+ thread = rt_thread_self();
+ /* reset thread error */
+ thread->error = RT_EOK;
+
+ if (status == RT_EOK)
+ {
+ /* set received event */
+ *recved = event->set;
+
+ /* received event */
+ if (option & RT_EVENT_FLAG_CLEAR) event->set &= ~set;
+ }
+ else if (timeout == 0)
+ {
+ /* no waiting */
+ thread->error = -RT_ETIMEOUT;
+ }
+ else
+ {
+ /* fill thread event info */
+ thread->event_set = set;
+ thread->event_info = option;
+
+ /* put thread to suspended thread list */
+ rt_ipc_object_suspend(&(event->parent), thread);
+
+ /* if there is a waiting timeout, active thread timer */
+ if (timeout > 0)
+ {
+ /* reset the timeout of thread timer and start it */
+ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout);
+ rt_timer_start(&(thread->thread_timer));
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ /* do a schedule */
+ rt_schedule();
+
+ if (thread->error != RT_EOK)
+ {
+ /* decrease suspended thread count */
+ rt_ipc_object_decrease(&(event->parent));
+ return thread->error;
+ }
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* get received event */
+ *recved = event->set;
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+#ifdef RT_USING_HOOK
+ if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(event->parent.parent));
+#endif
+
+ return thread->error;
+}
+
+/**
+ * This function can get or set some extra attributions of an event object.
+ *
+ * @param event the event object
+ * @param cmd the execution command
+ * @param arg the execution argument
+ *
+ * @return the error code
+ */
+rt_err_t rt_event_control (rt_event_t event, rt_uint8_t cmd, void* arg)
+{
+ return RT_EOK;
+}
+
+#endif /* end of RT_USING_EVENT */
+
+#ifdef RT_USING_MAILBOX
+
+/**
+ * This function will initialize a mailbox and put it under control of resource
+ * management.
+ *
+ * @param mb the mailbox object
+ * @param name the name of mailbox
+ * @param msgpool the begin address of buffer to save received mail
+ * @param size the size of mailbox
+ * @param flag the flag of mailbox
+ *
+ * @return the operation status, RT_EOK on successful
+ */
+rt_err_t rt_mb_init(rt_mailbox_t mb, const char* name, void* msgpool, rt_size_t size, rt_uint8_t flag)
+{
+ RT_ASSERT(mb != RT_NULL);
+
+ /* init object */
+ rt_object_init(&(mb->parent.parent), RT_Object_Class_MailBox, name);
+
+ /* set parent flag */
+ mb->parent.parent.flag = flag;
+
+ /* init ipc object */
+ rt_ipc_object_init(&(mb->parent));
+
+ /* init mailbox */
+ mb->msg_pool = msgpool;
+ mb->size = size;
+ mb->entry = 0;
+ mb->in_offset = 0;
+ mb->out_offset = 0;
+
+ return RT_EOK;
+}
+
+/**
+ * This function will detach a mailbox from resource management
+ *
+ * @param mb the mailbox object
+ *
+ * @return the operation status, RT_EOK on successful
+ */
+rt_err_t rt_mb_detach(rt_mailbox_t mb)
+{
+ /* parameter check */
+ RT_ASSERT(mb != RT_NULL);
+
+ /* resume all suspended thread */
+ rt_ipc_object_resume_all(&(mb->parent));
+
+ /* detach mailbox object */
+ rt_object_detach(&(mb->parent.parent));
+
+ return RT_EOK;
+}
+
+#ifdef RT_USING_HEAP
+/**
+ * This function will create a mailbox object from system resource
+ *
+ * @param name the name of mailbox
+ * @param size the size of mailbox
+ * @param flag the flag of mailbox
+ *
+ * @return the created mailbox, RT_NULL on error happen
+ */
+rt_mailbox_t rt_mb_create (const char* name, rt_size_t size, rt_uint8_t flag)
+{
+ rt_mailbox_t mb;
+
+ /* allocate object */
+ mb = (rt_mailbox_t) rt_object_allocate(RT_Object_Class_MailBox, name);
+ if (mb == RT_NULL) return mb;
+
+ /* set parent */
+ mb->parent.parent.flag = flag;
+
+ /* init ipc object */
+ rt_ipc_object_init(&(mb->parent));
+
+ /* init mailbox */
+ mb->size = size;
+ mb->msg_pool = rt_malloc(mb->size * sizeof(rt_uint32_t));
+ if (mb->msg_pool == RT_NULL)
+ {
+ /* delete mailbox object */
+ rt_object_delete(&(mb->parent.parent));
+
+ return RT_NULL;
+ }
+ mb->entry = 0;
+ mb->in_offset = 0;
+ mb->out_offset = 0;
+
+ return mb;
+}
+
+/**
+ * This function will delete a mailbox object and release the memory
+ *
+ * @param mb the mailbox object
+ *
+ * @return the error code
+ */
+rt_err_t rt_mb_delete (rt_mailbox_t mb)
+{
+ /* parameter check */
+ RT_ASSERT(mb != RT_NULL);
+
+ /* resume all suspended thread */
+ rt_ipc_object_resume_all(&(mb->parent));
+
+ /* free mailbox pool */
+ rt_free(mb->msg_pool);
+
+ /* delete mailbox object */
+ rt_object_delete(&(mb->parent.parent));
+
+ return RT_EOK;
+}
+#endif
+
+/**
+ * This function will send a mail to mailbox object, if there are threads suspended
+ * on mailbox object, it will be waked up.
+ *
+ * @param mb the mailbox object
+ * @param value the mail
+ *
+ * @return the error code
+ */
+rt_err_t rt_mb_send (rt_mailbox_t mb, rt_uint32_t value)
+{
+ register rt_ubase_t temp;
+
+ /* parameter check */
+ RT_ASSERT(mb != RT_NULL);
+
+#ifdef RT_USING_HOOK
+ if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(mb->parent.parent));
+#endif
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* mailbox is full */
+ if (mb->entry == mb->size)
+ {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ return -RT_EFULL;
+ }
+
+ /* set ptr */
+ mb->msg_pool[mb->in_offset] = value;
+ /* increase input offset */
+ ++ mb->in_offset;
+ mb->in_offset %= mb->size;
+ /* increase message entry */
+ mb->entry ++;
+
+ /* resume suspended thread */
+ if (mb->parent.suspend_thread_count > 0)
+ {
+ rt_ipc_object_resume(&(mb->parent));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ rt_schedule();
+ return RT_EOK;
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will receive a mail from mailbox object, if there is no mail in
+ * mailbox object, the thread shall wait for a specified time.
+ *
+ * @param mb the mailbox object
+ * @param value the received mail will be saved in
+ * @param timeout the waiting time
+ *
+ * @return the error code
+ */
+rt_err_t rt_mb_recv (rt_mailbox_t mb, rt_uint32_t* value, rt_int32_t timeout)
+{
+ struct rt_thread *thread;
+ register rt_ubase_t temp;
+
+ /* parameter check */
+ RT_ASSERT(mb != RT_NULL);
+
+#ifdef RT_USING_HOOK
+ if (rt_object_trytake_hook != RT_NULL) rt_object_trytake_hook(&(mb->parent.parent));
+#endif
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* mailbox is empty */
+ if (mb->entry == 0)
+ {
+ /* get current thread */
+ thread = rt_thread_self();
+
+ /* reset error number in thread */
+ thread->error = RT_EOK;
+
+ /* no waiting, return timeout */
+ if (timeout == 0)
+ {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ thread->error = -RT_ETIMEOUT;
+ return -RT_ETIMEOUT;
+ }
+
+ /* suspend current thread */
+ rt_ipc_object_suspend(&(mb->parent), thread);
+
+ /* has waiting time, start thread timer */
+ if (timeout > 0)
+ {
+#ifdef IPC_DEBUG
+ rt_kprintf("set thread:%s to timer list\n", thread->name);
+#endif
+ /* reset the timeout of thread timer and start it */
+ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout);
+ rt_timer_start(&(thread->thread_timer));
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ /* re-schedule */
+ rt_schedule();
+
+ /* recv message */
+ if (thread->error != RT_EOK)
+ {
+ /* decrease suspended thread count */
+ rt_ipc_object_decrease(&(mb->parent));
+ return thread->error;
+ }
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+ }
+
+ /* fill ptr */
+ *value = mb->msg_pool[mb->out_offset];
+
+ /* increase output offset */
+ ++mb->out_offset;
+ mb->out_offset %= mb->size;
+ /* decrease message entry */
+ mb->entry --;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+#ifdef RT_USING_HOOK
+ if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(mb->parent.parent));
+#endif
+
+ return RT_EOK;
+}
+
+/**
+ * This function can get or set some extra attributions of a mailbox object.
+ *
+ * @param mb the mailbox object
+ * @param cmd the execution command
+ * @param arg the execution argument
+ *
+ * @return the error code
+ */
+rt_err_t rt_mb_control(rt_mailbox_t mb, rt_uint8_t cmd, void* arg)
+{
+ return RT_EOK;
+}
+
+#endif /* end of RT_USING_MAILBOX */
+
+#ifdef RT_USING_MESSAGEQUEUE
+
+struct rt_mq_message
+{
+ struct rt_mq_message* next;
+};
+
+/**
+ * This function will initialize a message queue and put it under control of resource
+ * management.
+ *
+ * @param mq the message object
+ * @param name the name of message queue
+ * @param msgpool the beginning address of buffer to save messages
+ * @param msg_size the maximum size of message
+ * @param pool_size the size of buffer to save messages
+ * @param flag the flag of message queue
+ *
+ * @return the operation status, RT_EOK on successful
+ */
+rt_err_t rt_mq_init(rt_mq_t mq, const char* name, void *msgpool, rt_size_t msg_size, rt_size_t pool_size, rt_uint8_t flag)
+{
+ struct rt_mq_message* head;
+ register rt_base_t temp;
+
+ /* parameter check */
+ RT_ASSERT(mq != RT_NULL);
+
+ /* init object */
+ rt_object_init(&(mq->parent.parent), RT_Object_Class_MessageQueue, name);
+
+ /* set parent flag */
+ mq->parent.parent.flag = flag;
+
+ /* init ipc object */
+ rt_ipc_object_init(&(mq->parent));
+
+ /* set messasge pool */
+ mq->msg_pool = msgpool;
+
+ /* get correct message size */
+ mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE);
+ mq->max_msgs = pool_size / (mq->msg_size + sizeof(struct rt_mq_message));
+
+ /* init message list */
+ mq->msg_queue_head = RT_NULL;
+ mq->msg_queue_tail = RT_NULL;
+
+ /* init message empty list */
+ mq->msg_queue_free = RT_NULL;
+ for (temp = 0; temp < mq->max_msgs; temp ++)
+ {
+ head = (struct rt_mq_message*)((rt_uint8_t*)mq->msg_pool +
+ temp * (mq->msg_size + sizeof(struct rt_mq_message)));
+ head->next = mq->msg_queue_free;
+ mq->msg_queue_free = head;
+ }
+
+ /* the initial entry is zero */
+ mq->entry = 0;
+
+ return RT_EOK;
+}
+
+/**
+ * This function will detach a message queue object from resource management
+ *
+ * @param mq the message queue object
+ *
+ * @return the operation status, RT_EOK on successful
+ */
+rt_err_t rt_mq_detach(rt_mq_t mq)
+{
+ /* parameter check */
+ RT_ASSERT(mq != RT_NULL);
+
+ /* resume all suspended thread */
+ rt_ipc_object_resume_all((struct rt_ipc_object*)mq);
+
+ /* detach message queue object */
+ rt_object_detach(&(mq->parent.parent));
+
+ return RT_EOK;
+}
+
+#ifdef RT_USING_HEAP
+/**
+ * This function will create a message queue object from system resource
+ *
+ * @param name the name of message queue
+ * @param msg_size the size of message
+ * @param max_msgs the maximum number of message in queue
+ * @param flag the flag of message queue
+ *
+ * @return the created message queue, RT_NULL on error happen
+ */
+rt_mq_t rt_mq_create (const char* name, rt_size_t msg_size, rt_size_t max_msgs, rt_uint8_t flag)
+{
+ struct rt_messagequeue* mq;
+ struct rt_mq_message* head;
+ register rt_base_t temp;
+
+ /* allocate object */
+ mq = (rt_mq_t) rt_object_allocate(RT_Object_Class_MessageQueue, name);
+ if (mq == RT_NULL) return mq;
+
+ /* set parent */
+ mq->parent.parent.flag = flag;
+
+ /* init ipc object */
+ rt_ipc_object_init(&(mq->parent));
+
+ /* init message queue */
+
+ /* get correct message size */
+ mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE);
+ mq->max_msgs = max_msgs;
+
+ /* allocate message pool */
+ mq->msg_pool = rt_malloc((mq->msg_size + sizeof(struct rt_mq_message))* mq->max_msgs);
+ if (mq->msg_pool == RT_NULL)
+ {
+ rt_mq_delete(mq);
+ return RT_NULL;
+ }
+
+ /* init message list */
+ mq->msg_queue_head = RT_NULL;
+ mq->msg_queue_tail = RT_NULL;
+
+ /* init message empty list */
+ mq->msg_queue_free = RT_NULL;
+ for (temp = 0; temp < mq->max_msgs; temp ++)
+ {
+ head = (struct rt_mq_message*)((rt_uint8_t*)mq->msg_pool +
+ temp * (mq->msg_size + sizeof(struct rt_mq_message)));
+ head->next = mq->msg_queue_free;
+ mq->msg_queue_free = head;
+ }
+
+ /* the initial entry is zero */
+ mq->entry = 0;
+
+ return mq;
+}
+
+/**
+ * This function will delete a message queue object and release the memory
+ *
+ * @param mq the message queue object
+ *
+ * @return the error code
+ */
+rt_err_t rt_mq_delete (rt_mq_t mq)
+{
+ /* parameter check */
+ RT_ASSERT(mq != RT_NULL);
+
+ /* resume all suspended thread */
+ rt_ipc_object_resume_all(&(mq->parent));
+
+ /* free mailbox pool */
+ rt_free(mq->msg_pool);
+
+ /* delete mailbox object */
+ rt_object_delete(&(mq->parent.parent));
+
+ return RT_EOK;
+}
+#endif
+
+/**
+ * This function will send a message to message queue object, if there are threads
+ * suspended on message queue object, it will be waked up.
+ *
+ * @param mq the message queue object
+ * @param buffer the message
+ * @param size the size of buffer
+ *
+ * @return the error code
+ */
+rt_err_t rt_mq_send (rt_mq_t mq, void* buffer, rt_size_t size)
+{
+ register rt_ubase_t temp;
+ struct rt_mq_message *msg;
+
+ /* greater than one message size */
+ if (size > mq->msg_size) return -RT_ERROR;
+
+#ifdef RT_USING_HOOK
+ if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(mq->parent.parent));
+#endif
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* get a free list, there must be an empty item */
+ msg = (struct rt_mq_message*)mq->msg_queue_free;
+
+ /* message queue is full */
+ if (msg == RT_NULL)
+ {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ return -RT_EFULL;
+ }
+
+ /* move free list pointer */
+ mq->msg_queue_free = msg->next;
+
+ /* copy buffer */
+ rt_memcpy(msg + 1, buffer, size);
+
+ /* link msg to message queue */
+ if (mq->msg_queue_tail != RT_NULL)
+ {
+ /* if the tail exists, */
+ ((struct rt_mq_message*)mq->msg_queue_tail)->next = msg;
+ }
+ /* the msg is the new tail of list, the next shall be NULL */
+ msg->next = RT_NULL;
+
+ /* set new tail */
+ mq->msg_queue_tail = msg;
+
+ /* if the head is empty, set head */
+ if (mq->msg_queue_head == RT_NULL)mq->msg_queue_head = msg;
+
+ /* increase message entry */
+ mq->entry ++;
+
+ /* resume suspended thread */
+ if (mq->parent.suspend_thread_count > 0)
+ {
+ rt_ipc_object_resume(&(mq->parent));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ rt_schedule();
+ return RT_EOK;
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will send urgently a message to message queue object, which means
+ * the message will be inserted to the head of message queue. If there are threads
+ * suspended on message queue object, it will be waked up.
+ *
+ * @param mq the message queue object
+ * @param buffer the message
+ * @param size the size of buffer
+ *
+ * @return the error code
+ */
+rt_err_t rt_mq_urgent(rt_mq_t mq, void* buffer, rt_size_t size)
+{
+ register rt_ubase_t temp;
+ struct rt_mq_message *msg;
+
+ /* greater than one message size */
+ if (size > mq->msg_size) return -RT_ERROR;
+
+#ifdef RT_USING_HOOK
+ if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(mq->parent.parent));
+#endif
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* get a free list, there must be an empty item */
+ msg = (struct rt_mq_message*)mq->msg_queue_free;
+
+ /* message queue is full */
+ if (msg == RT_NULL)
+ {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ return -RT_EFULL;
+ }
+
+ /* move free list pointer */
+ mq->msg_queue_free = msg->next;
+
+ /* copy buffer */
+ rt_memcpy(msg + 1, buffer, size);
+
+ /* link msg to the beginning of message queue */
+ msg->next = mq->msg_queue_head;
+ mq->msg_queue_head = msg;
+
+ /* if there is no tail */
+ if (mq->msg_queue_tail == RT_NULL) mq->msg_queue_tail = msg;
+
+ /* increase message entry */
+ mq->entry ++;
+
+ /* resume suspended thread */
+ if (mq->parent.suspend_thread_count > 0)
+ {
+ rt_ipc_object_resume(&(mq->parent));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ rt_schedule();
+
+ return RT_EOK;
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will receive a message from message queue object, if there is no
+ * message in message queue object, the thread shall wait for a specified time.
+ *
+ * @param mq the message queue object
+ * @param buffer the received message will be saved in
+ * @param size the size of buffer
+ * @param timeout the waiting time
+ *
+ * @return the error code
+ */
+rt_err_t rt_mq_recv (rt_mq_t mq, void* buffer, rt_size_t size, rt_int32_t timeout)
+{
+ struct rt_thread *thread;
+ register rt_ubase_t temp;
+ struct rt_mq_message *msg;
+
+#ifdef RT_USING_HOOK
+ if (rt_object_trytake_hook != RT_NULL) rt_object_trytake_hook(&(mq->parent.parent));
+#endif
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* mailbox is empty */
+ if (mq->entry == 0)
+ {
+ /* get current thread */
+ thread = rt_thread_self();
+
+ /* reset error number in thread */
+ thread->error = RT_EOK;
+
+ /* no waiting, return timeout */
+ if (timeout == 0)
+ {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ thread->error = -RT_ETIMEOUT;
+ return -RT_ETIMEOUT;
+ }
+
+ /* suspend current thread */
+ rt_ipc_object_suspend(&(mq->parent), thread);
+
+ /* has waiting time, start thread timer */
+ if (timeout > 0)
+ {
+#ifdef IPC_DEBUG
+ rt_kprintf("set thread:%s to timer list\n", thread->name);
+#endif
+ /* reset the timeout of thread timer and start it */
+ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout);
+ rt_timer_start(&(thread->thread_timer));
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ /* re-schedule */
+ rt_schedule();
+
+ /* recv message */
+ if (thread->error != RT_EOK)
+ {
+ /* decrease suspended thread count */
+ rt_ipc_object_decrease(&(mq->parent));
+ return thread->error;
+ }
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+ }
+
+ /* get message from queue */
+ msg = (struct rt_mq_message*) mq->msg_queue_head;
+
+ /* move message queue head */
+ mq->msg_queue_head = msg->next;
+
+ /* reach queue tail, set to NULL */
+ if (mq->msg_queue_tail == msg) mq->msg_queue_tail = RT_NULL;
+
+ /* copy message */
+ rt_memcpy(buffer, msg + 1,
+ size > mq->msg_size? mq->msg_size : size);
+
+ /* put message to free list */
+ msg->next = (struct rt_mq_message*)mq->msg_queue_free;
+ mq->msg_queue_free = msg;
+
+ /* decrease message entry */
+ mq->entry --;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+#ifdef RT_USING_HOOK
+ if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(mq->parent.parent));
+#endif
+
+ return RT_EOK;
+}
+
+/**
+ * This function can get or set some extra attributions of a message queue object.
+ *
+ * @param mq the message queue object
+ * @param cmd the execution command
+ * @param arg the execution argument
+ *
+ * @return the error code
+ */
+rt_err_t rt_mq_control(rt_mq_t mq, rt_uint8_t cmd, void* arg)
+{
+ return RT_EOK;
+}
+
+#endif /* end of RT_USING_MESSAGEQUEUE */
+
+/**
+ * @ingroup SystemInit
+ * This function will init IPC module.
+ */
+void rt_system_ipc_init()
+{
+ /* nothing to be done */
+}
+
+/*@}*/
diff --git a/src/irq.c b/src/irq.c
new file mode 100644
index 0000000000..cdad403976
--- /dev/null
+++ b/src/irq.c
@@ -0,0 +1,69 @@
+/*
+ * File : irq.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-02-24 Bernard first version
+ * 2006-05-03 Bernard add IRQ_DEBUG
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+/* #define IRQ_DEBUG */
+
+/**
+ * @addtogroup Kernel
+ */
+
+/*@{*/
+
+volatile rt_uint32_t rt_interrupt_nest;
+
+/**
+ * This function will be invoked by BSP, when enter interrupt service routine
+ *
+ * @note please don't invoke this routine in application
+ *
+ * @see rt_interrupt_leave
+ */
+void rt_interrupt_enter()
+{
+ rt_base_t level;
+
+#ifdef IRQ_DEBUG
+ rt_kprintf("irq comming..., irq nest:%d\n", rt_interrupt_nest);
+#endif
+
+ level = rt_hw_interrupt_disable();
+ rt_interrupt_nest ++;
+ rt_hw_interrupt_enable(level);
+}
+
+/**
+ * This function will be invoked by BSP, when leave interrupt service routine
+ *
+ * @note please don't invoke this routine in application
+ *
+ * @see rt_interrupt_enter
+ */
+void rt_interrupt_leave()
+{
+ rt_base_t level;
+
+#ifdef IRQ_DEBUG
+ rt_kprintf("irq leave, irq nest:%d\n", rt_interrupt_nest);
+#endif
+
+ level = rt_hw_interrupt_disable();
+ rt_interrupt_nest --;
+ rt_hw_interrupt_enable(level);
+}
+
+/*@}*/
diff --git a/src/kservice.c b/src/kservice.c
new file mode 100644
index 0000000000..af2c4e5caa
--- /dev/null
+++ b/src/kservice.c
@@ -0,0 +1,922 @@
+/*
+ * File : kservice.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-03-16 Bernard the first version
+ * 2006-05-25 Bernard rewrite vsprintf
+ * 2006-08-10 Bernard add rt_show_version
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+
+/**
+ * @addtogroup KernelService
+ */
+/*@{*/
+
+#ifndef RT_USING_NEWLIB
+/* global errno in RT-Thread*/
+int errno;
+#else
+#include <errno.h>
+#endif
+
+/*
+ * This function will get errno
+ *
+ * @return errno
+ */
+rt_err_t rt_get_errno(void)
+{
+ rt_thread_t tid;
+
+ tid = rt_thread_self();
+ if (tid == RT_NULL) return errno;
+
+ return tid->error;
+}
+
+/*
+ * This function will set errno
+ *
+ * @param error the errno shall be set
+ */
+void rt_set_errno(rt_err_t error)
+{
+ rt_thread_t tid;
+
+ tid = rt_thread_self();
+ if (tid == RT_NULL) { errno = error; return; }
+
+ tid->error = error;
+}
+
+/**
+ * This function will set the content of memory to specified value
+ *
+ * @param s the address of source memory
+ * @param c the value shall be set in content
+ * @param count the copied length
+ *
+ * @return the address of source memory
+ *
+ */
+void *rt_memset(void * s, int c, rt_ubase_t count)
+{
+#ifdef RT_TINY_SIZE
+ char *xs = (char *) s;
+
+ while (count--)
+ *xs++ = c;
+
+ return s;
+#else
+#define LBLOCKSIZE (sizeof(rt_int32_t))
+#define UNALIGNED(X) ((rt_int32_t)X & (LBLOCKSIZE - 1))
+#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE)
+
+ int i;
+ char *m = (char *)s;
+ rt_uint32_t buffer;
+ rt_uint32_t *aligned_addr;
+ rt_uint32_t d = c & 0xff;
+
+ if (!TOO_SMALL (count) && !UNALIGNED (s))
+ {
+ /* If we get this far, we know that n is large and m is word-aligned. */
+ aligned_addr = (rt_uint32_t*)s;
+
+ /* Store D into each char sized location in BUFFER so that
+ * we can set large blocks quickly.
+ */
+ if (LBLOCKSIZE == 4)
+ {
+ buffer = (d << 8) | d;
+ buffer |= (buffer << 16);
+ }
+ else
+ {
+ buffer = 0;
+ for (i = 0; i < LBLOCKSIZE; i++)
+ buffer = (buffer << 8) | d;
+ }
+
+ while (count >= LBLOCKSIZE*4)
+ {
+ *aligned_addr++ = buffer;
+ *aligned_addr++ = buffer;
+ *aligned_addr++ = buffer;
+ *aligned_addr++ = buffer;
+ count -= 4*LBLOCKSIZE;
+ }
+
+ while (count >= LBLOCKSIZE)
+ {
+ *aligned_addr++ = buffer;
+ count -= LBLOCKSIZE;
+ }
+
+ /* Pick up the remainder with a bytewise loop. */
+ m = (char*)aligned_addr;
+ }
+
+ while (count--)
+ {
+ *m++ = (char)d;
+ }
+
+ return s;
+
+#undef LBLOCKSIZE
+#undef UNALIGNED
+#undef TOO_SMALL
+#endif
+}
+
+/**
+ * This function will copy memory content from source address to destination
+ * address.
+ *
+ * @param dst the address of destination memory
+ * @param src the address of source memory
+ * @param count the copied length
+ *
+ * @return the address of destination memory
+ *
+ */
+void *rt_memcpy(void * dst, const void *src, rt_ubase_t count)
+{
+#ifdef RT_TINY_SIZE
+ char *tmp = (char *) dst, *s = (char *) src;
+
+ while (count--)
+ *tmp++ = *s++;
+
+ return dst;
+#else
+
+#define UNALIGNED(X, Y) \
+ (((rt_int32_t)X & (sizeof (rt_int32_t) - 1)) | ((rt_int32_t)Y & (sizeof (rt_int32_t) - 1)))
+#define BIGBLOCKSIZE (sizeof (rt_int32_t) << 2)
+#define LITTLEBLOCKSIZE (sizeof (rt_int32_t))
+#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE)
+
+ char *dst_ptr = (char*)dst;
+ char *src_ptr = (char*)src;
+ rt_int32_t *aligned_dst;
+ rt_int32_t *aligned_src;
+ int len = count;
+
+ /* If the size is small, or either SRC or DST is unaligned,
+ then punt into the byte copy loop. This should be rare. */
+ if (!TOO_SMALL(len) && !UNALIGNED (src_ptr, dst_ptr))
+ {
+ aligned_dst = (rt_int32_t*)dst_ptr;
+ aligned_src = (rt_int32_t*)src_ptr;
+
+ /* Copy 4X long words at a time if possible. */
+ while (len >= BIGBLOCKSIZE)
+ {
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ len -= BIGBLOCKSIZE;
+ }
+
+ /* Copy one long word at a time if possible. */
+ while (len >= LITTLEBLOCKSIZE)
+ {
+ *aligned_dst++ = *aligned_src++;
+ len -= LITTLEBLOCKSIZE;
+ }
+
+ /* Pick up any residual with a byte copier. */
+ dst_ptr = (char*)aligned_dst;
+ src_ptr = (char*)aligned_src;
+ }
+
+ while (len--)
+ *dst_ptr++ = *src_ptr++;
+
+ return dst;
+#undef UNALIGNED
+#undef BIGBLOCKSIZE
+#undef LITTLEBLOCKSIZE
+#undef TOO_SMALL
+#endif
+}
+
+/**
+ * This function will move memory content from source address to destination
+ * address.
+ *
+ * @param dest the address of destination memory
+ * @param src the address of source memory
+ * @param n the copied length
+ *
+ * @return the address of destination memory
+ *
+ */
+void* rt_memmove(void *dest, const void *src, rt_ubase_t n)
+{
+ char *tmp = (char *) dest, *s = (char *) src;
+
+ if (s < tmp && tmp < s + n)
+ {
+ tmp+=n;
+ s+=n;
+
+ while (n--)
+ *tmp-- = *s--;
+ }
+ else
+ {
+ while (n--)
+ *tmp++ = *s++;
+ }
+
+ return dest;
+}
+
+/**
+ * memcmp - Compare two areas of memory
+ * @param cs: One area of memory
+ * @param ct: Another area of memory
+ * @param count: The size of the area.
+ */
+rt_int32_t rt_memcmp(const void * cs,const void * ct, rt_ubase_t count)
+{
+ const unsigned char *su1, *su2;
+ int res = 0;
+
+ for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+ if ((res = *su1 - *su2) != 0)
+ break;
+ return res;
+}
+
+/**
+ * This function will return the first occurrence of a string.
+ *
+ * @param s1 the source string
+ * @param s2 the find string
+ *
+ * @return the first occurrence of a s2 in s1, or RT_NULL if no found.
+ */
+char * rt_strstr(const char * s1,const char * s2)
+{
+ int l1, l2;
+
+ l2 = rt_strlen(s2);
+ if (!l2)
+ return (char *) s1;
+ l1 = rt_strlen(s1);
+ while (l1 >= l2)
+ {
+ l1--;
+ if (!rt_memcmp(s1,s2,l2))
+ return (char *) s1;
+ s1++;
+ }
+ return RT_NULL;
+}
+
+/**
+ * This function will compare two strings while ignoring differences in case
+ *
+ * @param a the string to be compared
+ * @param b the string to be compared
+ *
+ * @return the result
+ */
+rt_uint32_t rt_strcasecmp(const char *a, const char *b)
+{
+ int ca, cb;
+
+ do
+ {
+ ca = *a++ & 0xff;
+ cb = *b++ & 0xff;
+ if (ca >= 'A' && ca <= 'Z')
+ ca += 'a' - 'A';
+ if (cb >= 'A' && cb <= 'Z')
+ cb += 'a' - 'A';
+ }
+ while (ca == cb && ca != '\0');
+
+ return ca - cb;
+}
+
+/**
+ * This function will copy string no more than n bytes.
+ *
+ * @param dest the string to copy
+ * @param src the string to be copied
+ * @param n the maximum copied length
+ *
+ * @return the result
+ */
+char *rt_strncpy(char *dest, const char *src, rt_ubase_t n)
+{
+ char *tmp = (char *) dest, *s = (char *) src;
+
+ while(n--)
+ *tmp++ = *s++;
+
+ return dest;
+}
+
+/**
+ * This function will compare two strings with specified maximum length
+ *
+ * @param cs the string to be compared
+ * @param ct the string to be compared
+ * @param count the maximum compare length
+ *
+ * @return the result
+ */
+rt_ubase_t rt_strncmp(const char * cs, const char * ct, rt_ubase_t count)
+{
+ register signed char __res = 0;
+
+ while (count)
+ {
+ if ((__res = *cs - *ct++) != 0 || !*cs++)
+ break;
+ count--;
+ }
+
+ return __res;
+}
+
+/**
+ * This function will return the length of a string, which terminate will
+ * null character.
+ *
+ * @param s the string
+ *
+ * @return the length of string
+ */
+rt_ubase_t rt_strlen(const char *s)
+{
+ const char *sc;
+
+ for (sc = s; *sc != '\0'; ++sc) /* nothing */
+ ;
+
+ return sc - s;
+}
+
+#ifdef RT_USING_HEAP
+/**
+ * This function will duplicate a string.
+ *
+ * @param s the string to be duplicated
+ *
+ * @return the duplicated string pointer
+ */
+char *rt_strdup(const char *s)
+{
+ rt_size_t len = rt_strlen(s) + 1;
+ char *tmp = (char *)rt_malloc(len);
+
+ if(!tmp) return RT_NULL;
+
+ rt_memcpy(tmp, s, len);
+ return tmp;
+}
+#endif
+
+/**
+ * This function will show the version of rt-thread rtos
+ */
+void rt_show_version()
+{
+ rt_kprintf("\n \\ | /\n");
+ rt_kprintf("- RT - Thread Operating System\n");
+ rt_kprintf(" / | \\ 0.%d.%d build %s\n", RT_VERSION, RT_SUBVERSION, __DATE__);
+ rt_kprintf(" 2006 - 2009 Copyright by rt-thread team\n");
+}
+
+static char rt_log_buf[RT_CONSOLEBUF_SIZE]; /* Message log buffer */
+
+/* private function */
+#define isdigit(c) ((unsigned)((c) - '0') < 10)
+
+rt_inline rt_int32_t divide(rt_int32_t *n, rt_int32_t base)
+{
+ rt_int32_t res;
+
+ /* optimized for processor which does not support divide instructions. */
+ if (base == 10)
+ {
+ res = ((rt_uint32_t)*n) % 10U;
+ *n = ((rt_uint32_t)*n) / 10U;
+ }
+ else
+ {
+ res = ((rt_uint32_t)*n) % 16U;
+ *n = ((rt_uint32_t)*n) / 16U;
+ }
+
+ return res;
+}
+
+rt_inline int skip_atoi(const char **s)
+{
+ register int i=0;
+ while (isdigit(**s)) i = i*10 + *((*s)++) - '0';
+
+ return i;
+}
+
+#define ZEROPAD (1 << 0) /* pad with zero */
+#define SIGN (1 << 1) /* unsigned/signed long */
+#define PLUS (1 << 2) /* show plus */
+#define SPACE (1 << 3) /* space if plus */
+#define LEFT (1 << 4) /* left justified */
+#define SPECIAL (1 << 5) /* 0x */
+#define LARGE (1 << 6) /* use 'ABCDEF' instead of 'abcdef' */
+
+#ifdef RT_PRINTF_PRECISION
+static char *print_number(char * buf, char * end, long num, int base, int s, int precision, int type)
+#else
+static char *print_number(char * buf, char * end, long num, int base, int s, int type)
+#endif
+{
+ char c, sign;
+#ifdef RT_PRINTF_LONGLONG
+ char tmp[32];
+#else
+ char tmp[16];
+#endif
+ const char *digits;
+ static const char small_digits[] = "0123456789abcdef";
+ static const char large_digits[] = "0123456789ABCDEF";
+ register int i;
+ register int size;
+
+ size = s;
+
+ digits = (type & LARGE) ? large_digits : small_digits;
+ if (type & LEFT) type &= ~ZEROPAD;
+
+ c = (type & ZEROPAD) ? '0' : ' ';
+
+ /* get sign */
+ sign = 0;
+ if (type & SIGN)
+ {
+ if (num < 0)
+ {
+ sign = '-';
+ num = -num;
+ }
+ else if (type & PLUS) sign = '+';
+ else if (type & SPACE) sign = ' ';
+ }
+
+#ifdef RT_PRINTF_SPECIAL
+ if (type & SPECIAL)
+ {
+ if (base == 16) size -= 2;
+ else if (base == 8) size--;
+ }
+#endif
+
+ i = 0;
+ if (num == 0) tmp[i++]='0';
+ else
+ {
+ while (num != 0) tmp[i++] = digits[divide(&num, base)];
+ }
+
+#ifdef RT_PRINTF_PRECISION
+ if (i > precision) precision = i;
+ size -= precision;
+#else
+ size -= i;
+#endif
+
+ if (!(type&(ZEROPAD | LEFT)))
+ {
+ while(size-->0)
+ {
+ if (buf <= end) *buf = ' ';
+ ++buf;
+ }
+ }
+
+ if (sign)
+ {
+ if (buf <= end)
+ {
+ *buf = sign;
+ --size;
+ }
+ ++buf;
+ }
+
+#ifdef RT_PRINTF_SPECIAL
+ if (type & SPECIAL)
+ {
+ if (base==8)
+ {
+ if (buf <= end) *buf = '0';
+ ++buf;
+ }
+ else if (base==16)
+ {
+ if (buf <= end) *buf = '0';
+ ++buf;
+ if (buf <= end)
+ {
+ *buf = type & LARGE? 'X' : 'x';
+ }
+ ++buf;
+ }
+ }
+#endif
+
+ /* no align to the left */
+ if (!(type & LEFT))
+ {
+ while (size-- > 0)
+ {
+ if (buf <= end) *buf = c;
+ ++buf;
+ }
+ }
+
+#ifdef RT_PRINTF_PRECISION
+ while (i < precision--)
+ {
+ if (buf <= end) *buf = '0';
+ ++buf;
+ }
+#endif
+
+ /* put number in the temporary buffer */
+ while (i-- > 0)
+ {
+ if (buf <= end) *buf = tmp[i];
+ ++buf;
+ }
+
+ while (size-- > 0)
+ {
+ if (buf <= end) *buf = ' ';
+ ++buf;
+ }
+
+ return buf;
+}
+
+static rt_int32_t vsnprintf(char *buf, rt_size_t size, const char *fmt, va_list args)
+{
+#ifdef RT_PRINTF_LONGLONG
+ unsigned long long num;
+#else
+ rt_uint32_t num;
+#endif
+ int i, len;
+ char *str, *end, c;
+ const char *s;
+
+ rt_uint8_t base; /* the base of number */
+ rt_uint8_t flags; /* flags to print number */
+ rt_uint8_t qualifier; /* 'h', 'l', or 'L' for integer fields */
+ rt_int32_t field_width; /* width of output field */
+
+#ifdef RT_PRINTF_PRECISION
+ int precision; /* min. # of digits for integers and max for a string */
+#endif
+
+ str = buf;
+ end = buf + size - 1;
+
+ /* Make sure end is always >= buf */
+ if (end < buf)
+ {
+ end = ((char *)-1);
+ size = end - buf;
+ }
+
+ for (; *fmt ; ++fmt)
+ {
+ if (*fmt != '%')
+ {
+ if (str <= end) *str = *fmt;
+ ++str;
+ continue;
+ }
+
+ /* process flags */
+ flags = 0;
+
+ while(1)
+ {
+ /* skips the first '%' also */
+ ++fmt;
+ if (*fmt == '-') flags |= LEFT;
+ else if (*fmt == '+') flags |= PLUS;
+ else if (*fmt == ' ') flags |= SPACE;
+ else if (*fmt == '#') flags |= SPECIAL;
+ else if (*fmt == '0') flags |= ZEROPAD;
+ else break;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (isdigit(*fmt)) field_width = skip_atoi(&fmt);
+ else if (*fmt == '*')
+ {
+ ++fmt;
+ /* it's the next argument */
+ field_width = va_arg(args, int);
+ if (field_width < 0)
+ {
+ field_width = -field_width;
+ flags |= LEFT;
+ }
+ }
+
+#ifdef RT_PRINTF_PRECISION
+ /* get the precision */
+ precision = -1;
+ if (*fmt == '.')
+ {
+ ++fmt;
+ if (isdigit(*fmt)) precision = skip_atoi(&fmt);
+ else if (*fmt == '*')
+ {
+ ++fmt;
+ /* it's the next argument */
+ precision = va_arg(args, int);
+ }
+ if (precision < 0) precision = 0;
+ }
+#endif
+ /* get the conversion qualifier */
+ qualifier = 0;
+ if (*fmt == 'h' || *fmt == 'l'
+#ifdef RT_PRINTF_LONGLONG
+ || *fmt == 'L'
+#endif
+ )
+ {
+ qualifier = *fmt;
+ ++fmt;
+#ifdef RT_PRINTF_LONGLONG
+ if (qualifier == 'l' && *fmt == 'l')
+ {
+ qualifier = 'L';
+ ++fmt;
+ }
+#endif
+ }
+
+ /* the default base */
+ base = 10;
+
+ switch (*fmt)
+ {
+ case 'c':
+ if (!(flags & LEFT))
+ {
+ while (--field_width > 0)
+ {
+ if (str <= end) *str = ' ';
+ ++str;
+ }
+ }
+
+ /* get character */
+ c = (rt_uint8_t) va_arg(args, int);
+ if (str <= end) *str = c;
+ ++str;
+
+ /* put width */
+ while (--field_width > 0)
+ {
+ if (str <= end) *str = ' ';
+ ++str;
+ }
+ continue;
+
+ case 's':
+ s = va_arg(args, char *);
+ if (!s) s = "(NULL)";
+
+ len = rt_strlen(s);
+#ifdef RT_PRINTF_PRECISION
+ if (precision > 0 && len > precision) len = precision;
+#endif
+
+ if (!(flags & LEFT))
+ {
+ while (len < field_width--)
+ {
+ if (str <= end) *str = ' ';
+ ++str;
+ }
+ }
+
+ for (i = 0; i < len; ++i)
+ {
+ if (str <= end) *str = *s;
+ ++str;
+ ++s;
+ }
+
+ while (len < field_width--)
+ {
+ if (str <= end) *str = ' ';
+ ++str;
+ }
+ continue;
+
+ case 'p':
+ if (field_width == -1)
+ {
+ field_width = sizeof(void *) << 1;
+ flags |= ZEROPAD;
+ }
+#ifdef RT_PRINTF_PRECISION
+ str = print_number(str, end,
+ (long) va_arg(args, void *),
+ 16, field_width, precision, flags);
+#else
+ str = print_number(str, end,
+ (long) va_arg(args, void *),
+ 16, field_width, flags);
+#endif
+ continue;
+
+ case '%':
+ if (str <= end) *str = '%';
+ ++str;
+ continue;
+
+ /* integer number formats - set up the flags and "break" */
+ case 'o':
+ base = 8;
+ break;
+
+ case 'X':
+ flags |= LARGE;
+ case 'x':
+ base = 16;
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= SIGN;
+ case 'u':
+ break;
+
+ default:
+ if (str <= end) *str = '%';
+ ++str;
+
+ if (*fmt)
+ {
+ if (str <= end) *str = *fmt;
+ ++str;
+ }
+ else
+ {
+ --fmt;
+ }
+ continue;
+ }
+
+#ifdef RT_PRINTF_LONGLONG
+ if (qualifier == 'L') num = va_arg(args, long long);
+ else if (qualifier == 'l')
+#else
+ if (qualifier == 'l')
+#endif
+ {
+ num = va_arg(args, rt_uint32_t);
+ if (flags & SIGN) num = (rt_int32_t) num;
+ }
+ else if (qualifier == 'h')
+ {
+ num = (rt_uint16_t) va_arg(args, rt_int32_t);
+ if (flags & SIGN) num = (rt_int16_t) num;
+ }
+ else
+ {
+ num = va_arg(args, rt_uint32_t);
+ if (flags & SIGN) num = (rt_int32_t) num;
+ }
+#ifdef RT_PRINTF_PRECISION
+ str = print_number(str, end, num, base, field_width, precision, flags);
+#else
+ str = print_number(str, end, num, base, field_width, flags);
+#endif
+ }
+
+ if (str <= end) *str = '\0';
+ else *end = '\0';
+
+ /* the trailing null byte doesn't count towards the total
+ * ++str;
+ */
+ return str-buf;
+}
+
+/**
+ * This function will fill a formatted string to buffer
+ *
+ * @param buf the buffer to save formatted string
+ * @param size the size of buffer
+ * @param fmt the format
+ */
+rt_int32_t rt_snprintf(char *buf, rt_size_t size, const char *fmt, ...)
+{
+ rt_int32_t n;
+ va_list args;
+
+ va_start(args, fmt);
+ n = vsnprintf(buf, size, fmt, args);
+ va_end(args);
+
+ return n;
+}
+
+/**
+ * This function will fill a formatted string to buffer
+ *
+ * @param buf the buffer to save formatted string
+ * @param arg_ptr the arg_ptr
+ * @param format the format
+ */
+rt_int32_t rt_vsprintf(char *buf, const char *format, va_list arg_ptr)
+{
+ return vsnprintf(buf, (rt_size_t) -1, format, arg_ptr);
+}
+
+/**
+ * This function will fill a formatted string to buffer
+ *
+ * @param buf the buffer to save formatted string
+ * @param format the format
+ */
+rt_int32_t rt_sprintf(char *buf ,const char *format,...)
+{
+ rt_int32_t n;
+ va_list arg_ptr;
+
+ va_start(arg_ptr, format);
+ n = rt_vsprintf(buf ,format,arg_ptr);
+ va_end (arg_ptr);
+
+ return n;
+}
+
+
+/**
+ * This function will print a formatted string on system console
+ *
+ * @param fmt the format
+ */
+void rt_kprintf(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ vsnprintf(rt_log_buf, sizeof(rt_log_buf), fmt, args);
+ rt_hw_console_output(rt_log_buf);
+
+ va_end(args);
+}
+
+#if !defined (RT_USING_NEWLIB) && defined (RT_USING_MINILIBC) && defined (__GNUC__)
+#include <sys/types.h>
+void* memcpy(void *dest, const void *src, size_t n) __attribute__((weak, alias("rt_memcpy")));
+void* memset(void *s, int c, size_t n) __attribute__((weak, alias("rt_memset")));
+void* memmove(void *dest, const void *src, size_t n) __attribute__((weak, alias("rt_memmove")));
+int memcmp(const void *s1, const void *s2, size_t n) __attribute__((weak, alias("rt_memcmp")));
+
+size_t strlen(const char *s) __attribute__((weak, alias("rt_strlen")));
+char * strstr(const char * s1,const char * s2) __attribute__((weak, alias("rt_strstr")));
+int strcasecmp(const char *a, const char *b) __attribute__((weak, alias("rt_strcasecmp")));
+char *strncpy(char *dest, const char *src, size_t n) __attribute__((weak, alias("rt_strncpy")));
+int strncmp(const char * cs, const char * ct, size_t count) __attribute__((weak, alias("rt_strncmp")));
+#ifdef RT_USING_HEAP
+char* strdup(const char* s) __attribute__((weak, alias("rt_strdup")));
+#endif
+#endif
+
+/*@}*/
diff --git a/src/kservice.h b/src/kservice.h
new file mode 100644
index 0000000000..2b82cbe9b8
--- /dev/null
+++ b/src/kservice.h
@@ -0,0 +1,100 @@
+/*
+ * File : kservice.h
+ * 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-03-16 Bernard the first version
+ * 2006-09-07 Bernard move the kservice APIs to rtthread.h
+ * 2007-06-27 Bernard fix the rt_list_remove bug
+ */
+
+#ifndef __RT_SERVICE_H__
+#define __RT_SERVICE_H__
+
+#include <rtthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief initialize a list
+ *
+ * @param l list to be initialized
+ */
+rt_inline void rt_list_init(rt_list_t *l)
+{
+ l->next = l->prev = l;
+}
+
+/**
+ * @brief insert a node after a list
+ *
+ * @param l list to insert it
+ * @param n new node to be inserted
+ */
+rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n)
+{
+ l->next->prev = n;
+ n->next = l->next;
+
+ l->next = n;
+ n->prev = l;
+}
+
+/**
+ * @brief insert a node before a list
+ *
+ * @param n new node to be inserted
+ * @param l list to insert it
+ */
+rt_inline void rt_list_insert_before(rt_list_t *l, rt_list_t *n)
+{
+ l->prev->next = n;
+ n->prev = l->prev;
+
+ l->prev = n;
+ n->next = l;
+}
+
+/**
+ * @brief remove node from list.
+ * @param n the node to remove from the list.
+ */
+rt_inline void rt_list_remove(rt_list_t *n)
+{
+ n->next->prev = n->prev;
+ n->prev->next = n->next;
+
+ n->next = n->prev = n;
+}
+
+/**
+ * @brief tests whether a list is empty
+ * @param l the list to test.
+ */
+rt_inline int rt_list_isempty(const rt_list_t *l)
+{
+ return l->next == l;
+}
+
+/**
+ * @brief get the struct for this entry
+ * @param node the entry point
+ * @param type the type of structure
+ * @param member the name of list in structure
+ */
+#define rt_list_entry(node, type, member) \
+ ((type *)((char *)(node) - (unsigned long)(&((type *)0)->member)))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/mem.c b/src/mem.c
new file mode 100644
index 0000000000..ba080a5bcb
--- /dev/null
+++ b/src/mem.c
@@ -0,0 +1,504 @@
+/*
+ * File : kservice.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2008, 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://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2008-7-12 Bernard the first version
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <[email protected]>
+ * Simon Goldschmidt
+ *
+ */
+
+#include <rtthread.h>
+
+/* #define RT_MEM_DEBUG */
+#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
+ */
+/*@{*/
+
+/**
+ * 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;
+}
+
+/**
+ * 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
+
+#define HEAP_MAGIC 0x1ea0
+struct heap_mem
+{
+ /* magic and used flag */
+ rt_uint16_t magic;
+ rt_uint16_t used;
+
+ rt_size_t next, prev;
+};
+
+/** pointer to the heap: for alignment, heap_ptr is now a pointer instead of an array */
+static rt_uint8_t *heap_ptr;
+
+/** the last entry, always unused! */
+static struct heap_mem *heap_end;
+
+#define MIN_SIZE 12
+#define MIN_SIZE_ALIGNED RT_ALIGN(MIN_SIZE, RT_ALIGN_SIZE)
+#define SIZEOF_STRUCT_MEM RT_ALIGN(sizeof(struct heap_mem), 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
+
+static void plug_holes(struct heap_mem *mem)
+{
+ struct heap_mem *nmem;
+ struct heap_mem *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);
+
+ /* 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)
+ {
+ /* if mem->next is unused and not end of heap_ptr, combine mem and mem->next */
+ if (lfree == nmem)
+ {
+ lfree = mem;
+ }
+ mem->next = nmem->next;
+ ((struct heap_mem *)&heap_ptr[nmem->next])->prev = (rt_uint8_t *)mem - heap_ptr;
+ }
+
+ /* plug hole backward */
+ pmem = (struct heap_mem *)&heap_ptr[mem->prev];
+ if (pmem != mem && pmem->used == 0)
+ {
+ /* if mem->prev is unused, combine mem and mem->prev */
+ if (lfree == mem)
+ {
+ lfree = pmem;
+ }
+ pmem->next = mem->next;
+ ((struct heap_mem *)&heap_ptr[mem->next])->prev = (rt_uint8_t *)pmem - heap_ptr;
+ }
+}
+
+/**
+ * @ingroup SystemInit
+ *
+ * This function will init system heap
+ *
+ * @param begin_addr the beginning address of system page
+ * @param end_addr the end address of system page
+ *
+ */
+void rt_system_heap_init(void* begin_addr, void* end_addr)
+{
+ struct heap_mem *mem;
+
+ /* alignment addr */
+ begin_addr = (void*)RT_ALIGN((rt_uint32_t)begin_addr, RT_ALIGN_SIZE);
+
+ /* calculate the aligned memory size */
+ mem_size_aligned = RT_ALIGN((rt_uint32_t)end_addr - (rt_uint32_t)begin_addr, RT_ALIGN_SIZE) - 2 * sizeof(struct heap_mem);
+
+ /* point to begin address of heap */
+ heap_ptr = begin_addr;
+
+#ifdef RT_MEM_DEBUG
+ rt_kprintf("mem init, heap begin address 0x%x, size %d\n", (rt_uint32_t)heap_ptr, mem_size_aligned);
+#endif
+
+ /* initialize the start of the heap */
+ mem = (struct heap_mem *)heap_ptr;
+ mem->magic= HEAP_MAGIC;
+ mem->next = mem_size_aligned;
+ mem->prev = 0;
+ mem->used = 0;
+
+ /* initialize the end of the heap */
+ heap_end = (struct heap_mem *)&heap_ptr[mem_size_aligned];
+ heap_end->magic= HEAP_MAGIC;
+ heap_end->used = 1;
+ heap_end->next = mem_size_aligned;
+ heap_end->prev = mem_size_aligned;
+
+ rt_sem_init(&heap_sem, "heap", 1, RT_IPC_FLAG_FIFO);
+
+ /* initialize the lowest-free pointer to the start of the heap */
+ lfree = (struct heap_mem *)heap_ptr;
+}
+
+/**
+ * @addtogroup MM
+ */
+
+/*@{*/
+
+/**
+ * Allocate a block of memory with a minimum of 'size' bytes.
+ *
+ * @param size is the minimum size of the requested block in bytes.
+ *
+ * @return pointer to allocated memory or NULL if no free memory was found.
+ */
+void *rt_malloc(rt_size_t size)
+{
+ rt_size_t ptr, ptr2;
+ struct heap_mem *mem, *mem2;
+
+ if (size == 0) return RT_NULL;
+
+#ifdef RT_MEM_DEBUG
+ rt_kprintf("malloc size %d, but align to %d\n", size, RT_ALIGN(size, RT_ALIGN_SIZE));
+#endif
+
+ /* alignment size */
+ size = RT_ALIGN(size, RT_ALIGN_SIZE);
+
+ if (size > mem_size_aligned)
+ {
+#ifdef RT_MEM_DEBUG
+ rt_kprintf("no memory\n");
+#endif
+ return RT_NULL;
+ }
+
+ /* every data block must be at least MIN_SIZE_ALIGNED long */
+ 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)
+ {
+ mem = (struct heap_mem *)&heap_ptr[ptr];
+
+ if ((!mem->used) &&
+ (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 */
+
+ 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
+ * 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
+ * @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
+ */
+ ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
+
+ /* create mem2 struct */
+ mem2 = (struct heap_mem *)&heap_ptr[ptr2];
+ mem2->magic = HEAP_MAGIC;
+ mem2->used = 0;
+ mem2->next = mem->next;
+ mem2->prev = ptr;
+
+ /* and insert it between mem and mem->next */
+ mem->next = ptr2;
+ mem->used = 1;
+
+ if (mem2->next != mem_size_aligned)
+ {
+ ((struct heap_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
+ }
+ else
+ {
+ /* (a mem2 struct does no fit into the user data space of mem and mem->next will always
+ * be used at this point: if not we have 2 unused structs in a row, plug_holes should have
+ * take care of this).
+ * -> near fit or excact fit: do not split, no mem2 creation
+ * 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
+ }
+
+ if (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];
+
+ RT_ASSERT(((lfree == heap_end) || (!lfree->used)));
+ }
+
+ rt_sem_release(&heap_sem);
+ RT_ASSERT((rt_uint32_t)mem + SIZEOF_STRUCT_MEM + size <= (rt_uint32_t)heap_end);
+ RT_ASSERT((rt_uint32_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM) % RT_ALIGN_SIZE == 0);
+ RT_ASSERT((((rt_uint32_t)mem) & (RT_ALIGN_SIZE-1)) == 0);
+
+#ifdef RT_MEM_DEBUG
+ rt_kprintf("allocate memory at 0x%x\n", (rt_uint32_t)((rt_uint8_t*)mem + SIZEOF_STRUCT_MEM));
+#endif
+
+#ifdef RT_USING_HOOK
+ if (rt_malloc_hook != RT_NULL)
+ rt_malloc_hook((rt_uint8_t*)mem, size);
+#endif
+ /* return the memory data except mem struct */
+ return (rt_uint8_t *)mem + SIZEOF_STRUCT_MEM;
+ }
+ }
+
+ rt_sem_release(&heap_sem);
+ return RT_NULL;
+}
+
+/**
+ * This function will change the previously allocated memory block.
+ *
+ * @param rmem pointer to memory allocated by rt_malloc
+ * @param newsize the required new size
+ *
+ * @return the changed memory block address
+ */
+void *rt_realloc(void *rmem, rt_size_t newsize)
+{
+ rt_size_t size;
+ rt_size_t ptr, ptr2;
+ struct heap_mem *mem, *mem2;
+
+ /* alignment size */
+ newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE);
+ if (newsize > mem_size_aligned)
+ {
+#ifdef RT_MEM_DEBUG
+ rt_kprintf("no memory\n");
+#endif
+ return RT_NULL;
+ }
+
+ rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
+
+ 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;
+ }
+
+ mem = (struct heap_mem *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM);
+
+ ptr = (rt_uint8_t *)mem - heap_ptr;
+ size = mem->next - ptr - SIZEOF_STRUCT_MEM;
+
+ if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size)
+ {
+#if MEM_STATS
+ used_mem -= (size - newsize);
+#endif /* MEM_STATS */
+
+ ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
+ mem2 = (struct heap_mem *)&heap_ptr[ptr2];
+ mem2->magic= HEAP_MAGIC;
+ mem2->used = 0;
+ mem2->next = mem->next;
+ mem2->prev = ptr;
+ mem->next = ptr2;
+ if (mem2->next != mem_size_aligned)
+ {
+ ((struct heap_mem *)&heap_ptr[mem2->next])->prev = ptr2;
+ }
+
+ plug_holes(mem2);
+
+ rt_sem_release(&heap_sem);
+ return rmem;
+ }
+ rt_sem_release(&heap_sem);
+
+ /* expand memory */
+ mem2 = rt_malloc(newsize);
+ rt_memcpy(mem2, mem, size);
+
+ rt_free(mem);
+
+ return mem2;
+}
+
+/**
+ * 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.
+ *
+ * The allocated memory is filled with bytes of value zero.
+ *
+ * @param count number of objects to allocate
+ * @param size 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;
+}
+
+/**
+ * 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)
+{
+ struct heap_mem *mem;
+
+ if (rmem == RT_NULL) return;
+ RT_ASSERT((((rt_uint32_t)rmem) & (RT_ALIGN_SIZE-1)) == 0);
+
+#ifdef RT_USING_HOOK
+ if (rt_free_hook != RT_NULL) rt_free_hook(rmem);
+#endif
+
+#ifdef RT_MEM_DEBUG
+ rt_kprintf("release memory 0x%x\n", (rt_uint32_t)rmem);
+#endif
+
+ /* protect the heap from concurrent access */
+ rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
+
+ RT_ASSERT((rt_uint8_t *)rmem >= (rt_uint8_t *)heap_ptr &&
+ (rt_uint8_t *)rmem < (rt_uint8_t *)heap_end);
+
+ if ((rt_uint8_t *)rmem < (rt_uint8_t *)heap_ptr || (rt_uint8_t *)rmem >= (rt_uint8_t *)heap_end)
+ {
+#ifdef RT_MEM_DEBUG
+ rt_kprintf("illegal memory\n");
+#endif
+ /* illegal memory */
+ rt_sem_release(&heap_sem);
+ return;
+ }
+
+ /* Get the corresponding struct heap_mem ... */
+ mem = (struct heap_mem *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM);
+ /* ... which has to be in a used state ... */
+ RT_ASSERT(mem->used);
+ /* ... and is now unused. */
+ mem->used = 0;
+
+ if (mem < lfree)
+ {
+ /* the newly freed struct is now the lowest */
+ lfree = mem;
+ }
+
+#ifdef RT_MEM_STATS
+ used_mem -= (mem->next - ((rt_uint8_t*)mem - heap_ptr));
+#endif
+
+ /* finally, see if prev or next are free also */
+ plug_holes(mem);
+ rt_sem_release(&heap_sem);
+}
+
+#ifdef RT_MEM_STATS
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+void list_mem()
+{
+ 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)
+#endif
+#endif
+
+/*@}*/
+
+#endif
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
+
+/*@}*/
+
diff --git a/src/object.c b/src/object.c
new file mode 100644
index 0000000000..d3c6828bd8
--- /dev/null
+++ b/src/object.c
@@ -0,0 +1,401 @@
+/*
+ * File : object.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-03-14 Bernard the first version
+ * 2006-04-21 Bernard change the scheduler lock to interrupt lock
+ * 2006-05-18 Bernard fix the object init bug
+ * 2006-08-03 Bernard add hook support
+ * 2007-01-28 Bernard rename RT_OBJECT_Class_Static to RT_Object_Class_Static
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+
+#include "kservice.h"
+
+struct rt_object_information rt_object_container[RT_Object_Class_Unknown];
+
+#ifdef RT_USING_HOOK
+static void (*rt_object_attach_hook)(struct rt_object* object);
+static void (*rt_object_detach_hook)(struct rt_object* object);
+void (*rt_object_trytake_hook)(struct rt_object* object);
+void (*rt_object_take_hook)(struct rt_object* object);
+void (*rt_object_put_hook)(struct rt_object* object);
+
+/**
+ * @addtogroup Hook
+ */
+/*@{*/
+
+/**
+ * This function will set a hook function, which will be invoked when object
+ * attaches to kernel object system.
+ *
+ * @param hook the hook function
+ */
+void rt_object_attach_sethook(void (*hook)(struct rt_object* object))
+{
+ rt_object_attach_hook = hook;
+}
+
+/**
+ * This function will set a hook function, which will be invoked when object
+ * detaches from kernel object system.
+ *
+ * @param hook the hook function
+ */
+void rt_object_detach_sethook(void (*hook)(struct rt_object* object))
+{
+ rt_object_detach_hook = hook;
+}
+
+/**
+ * This function will set a hook function, which will be invoked when object
+ * is taken from kernel object system.
+ *
+ * The object is taken means that
+ * semaphore - semaphore is taken by thread
+ * mutex - mutex is taken by thread
+ * event/fast event - event/fast event is received by thread
+ * mailbox - mail is received by thread
+ * message queue - message is received by thread
+ *
+ * @param hook the hook function
+ */
+void rt_object_trytake_sethook(void (*hook)(struct rt_object* object))
+{
+ rt_object_trytake_hook = hook;
+}
+
+/**
+ * This function will set a hook function, which will be invoked when object
+ * have been taken from kernel object system.
+ *
+ * The object have been taken means that
+ * semaphore - semaphore have been taken by thread
+ * mutex - mutex have been taken by thread
+ * event/fast event - event/fast event have been received by thread
+ * mailbox - mail have been received by thread
+ * message queue - message have been received by thread
+ * timer - timer is started
+ *
+ * @param hook the hook function
+ */
+void rt_object_take_sethook(void (*hook)(struct rt_object* object))
+{
+ rt_object_take_hook = hook;
+}
+
+/**
+ * This function will set a hook function, which will be invoked when object
+ * is put to kernel object system.
+ *
+ * @param hook the hook function
+ */
+void rt_object_put_sethook(void (*hook)(struct rt_object* object))
+{
+ rt_object_put_hook = hook;
+}
+
+/*@}*/
+#endif
+
+/**
+ * @ingroup SystemInit
+ *
+ * This function will initialize system object management
+ *
+ */
+void rt_system_object_init(void)
+{
+ /* init object container - thread */
+ rt_list_init(&(rt_object_container[RT_Object_Class_Thread].object_list));
+ rt_object_container[RT_Object_Class_Thread].object_size = sizeof(struct rt_thread);
+ rt_object_container[RT_Object_Class_Thread].type = RT_Object_Class_Thread;
+
+#ifdef RT_USING_MODULE
+ /* init object container - module */
+ rt_list_init(&(rt_object_container[RT_Object_Class_Module].object_list));
+ rt_object_container[RT_Object_Class_Module].object_size = sizeof(struct rt_module);
+ rt_object_container[RT_Object_Class_Module].type = RT_Object_Class_Module;
+#endif
+
+#ifdef RT_USING_SEMAPHORE
+ /* init object container - semaphore */
+ rt_list_init(&(rt_object_container[RT_Object_Class_Semaphore].object_list));
+ rt_object_container[RT_Object_Class_Semaphore].object_size = sizeof(struct rt_semaphore);
+ rt_object_container[RT_Object_Class_Semaphore].type = RT_Object_Class_Semaphore;
+#endif
+
+#ifdef RT_USING_MUTEX
+ /* init object container - mutex */
+ rt_list_init(&(rt_object_container[RT_Object_Class_Mutex].object_list));
+ rt_object_container[RT_Object_Class_Mutex].object_size = sizeof(struct rt_mutex);
+ rt_object_container[RT_Object_Class_Mutex].type = RT_Object_Class_Mutex;
+#endif
+
+#ifdef RT_USING_FASTEVENT
+ /* init object container - fast event */
+ rt_list_init(&(rt_object_container[RT_Object_Class_FastEvent].object_list));
+ rt_object_container[RT_Object_Class_FastEvent].object_size = sizeof(struct rt_fast_event);
+ rt_object_container[RT_Object_Class_FastEvent].type = RT_Object_Class_FastEvent;
+#endif
+
+#ifdef RT_USING_EVENT
+ /* init object container - event */
+ rt_list_init(&(rt_object_container[RT_Object_Class_Event].object_list));
+ rt_object_container[RT_Object_Class_Event].object_size = sizeof(struct rt_event);
+ rt_object_container[RT_Object_Class_Event].type = RT_Object_Class_Event;
+#endif
+
+#ifdef RT_USING_MAILBOX
+ /* init object container - mailbox */
+ rt_list_init(&(rt_object_container[RT_Object_Class_MailBox].object_list));
+ rt_object_container[RT_Object_Class_MailBox].object_size = sizeof(struct rt_mailbox);
+ rt_object_container[RT_Object_Class_MailBox].type = RT_Object_Class_MailBox;
+#endif
+
+#ifdef RT_USING_MESSAGEQUEUE
+ /* init object container - message queue */
+ rt_list_init(&(rt_object_container[RT_Object_Class_MessageQueue].object_list));
+ rt_object_container[RT_Object_Class_MessageQueue].object_size = sizeof(struct rt_messagequeue);
+ rt_object_container[RT_Object_Class_MessageQueue].type = RT_Object_Class_MessageQueue;
+#endif
+
+#ifdef RT_USING_MEMPOOL
+ /* init object container - memory pool */
+ rt_list_init(&(rt_object_container[RT_Object_Class_MemPool].object_list));
+ rt_object_container[RT_Object_Class_MemPool].object_size = sizeof(struct rt_mempool);
+ rt_object_container[RT_Object_Class_MemPool].type = RT_Object_Class_MemPool;
+#endif
+
+#ifdef RT_USING_DEVICE
+ /* init object container - device */
+ rt_list_init(&(rt_object_container[RT_Object_Class_Device].object_list));
+ rt_object_container[RT_Object_Class_Device].object_size = sizeof(struct rt_device);
+ rt_object_container[RT_Object_Class_Device].type = RT_Object_Class_Device;
+#endif
+
+ /* init object container - timer */
+ rt_list_init(&(rt_object_container[RT_Object_Class_Timer].object_list));
+ rt_object_container[RT_Object_Class_Timer].object_size = sizeof(struct rt_timer);
+ rt_object_container[RT_Object_Class_Timer].type = RT_Object_Class_Timer;
+}
+
+/**
+ * @addtogroup KernelObject
+ */
+/*@{*/
+
+/**
+ * This function will init an object and add it to object system management.
+ *
+ * @param object the specified object to be initialized.
+ * @param type the object type.
+ * @param name the object name. In system, the object's name must
+ * be unique.
+ */
+void rt_object_init(struct rt_object* object, enum rt_object_class_type type, const char* name)
+{
+ register rt_base_t temp;
+ struct rt_object_information* information;
+
+ /* get object information */
+ information = &rt_object_container[type];
+
+ /* init object's parameters */
+
+ /* set object type to static */
+ object->type = type | RT_Object_Class_Static;
+
+ /* copy name */
+ for (temp = 0; temp < RT_NAME_MAX; temp ++)
+ {
+ object->name[temp] = name[temp];
+ }
+
+#ifdef RT_USING_HOOK
+ if (rt_object_attach_hook != RT_NULL)
+ {
+ rt_object_attach_hook(object);
+ }
+#endif
+
+ /* lock interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* insert object into information object list */
+ rt_list_insert_after(&(information->object_list), &(object->list));
+
+ /* unlock interrupt */
+ rt_hw_interrupt_enable(temp);
+}
+
+/**
+ * This function will detach a static object from object system,
+ * and the memory of static object is not freed.
+ *
+ * @param object the specified object to be detached.
+ */
+void rt_object_detach(rt_object_t object)
+{
+ register rt_base_t temp;
+
+ /* object check */
+ RT_ASSERT(object != RT_NULL);
+
+#ifdef RT_USING_HOOK
+ if (rt_object_detach_hook != RT_NULL) rt_object_detach_hook(object);
+#endif
+
+ /* lock interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* remove from old list */
+ rt_list_remove(&(object->list));
+
+ /* unlock interrupt */
+ rt_hw_interrupt_enable(temp);
+}
+
+#ifdef RT_USING_HEAP
+/**
+ * This function will allocate an object from object system
+ *
+ * @param type the type of object
+ * @param name the object name. In system, the object's name must be unique.
+ *
+ * @return object
+ */
+rt_object_t rt_object_allocate(enum rt_object_class_type type, const char* name)
+{
+ struct rt_object* object;
+ register rt_base_t temp;
+ struct rt_object_information* information;
+
+ /* get object information */
+ information = &rt_object_container[type];
+
+ object = (struct rt_object*)rt_malloc(information->object_size);
+ if (object == RT_NULL)
+ {
+ /* no memory can be allocated */
+ return RT_NULL;
+ }
+
+ /* init object's parameters */
+
+ /* set object type */
+ object->type = type;
+
+ /* copy name */
+ for (temp = 0; temp < RT_NAME_MAX; temp ++)
+ {
+ object->name[temp] = name[temp];
+ }
+
+#ifdef RT_USING_HOOK
+ if (rt_object_attach_hook != RT_NULL) rt_object_attach_hook(object);
+#endif
+
+ /* lock interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* insert object into information object list */
+ rt_list_insert_after(&(information->object_list), &(object->list));
+
+ /* unlock interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ /* return object */
+ return object;
+}
+
+/**
+ * This function will delete an object and release object memory.
+ *
+ * @param object the specified object to be deleted.
+ */
+void rt_object_delete(rt_object_t object)
+{
+ register rt_base_t temp;
+
+ /* object check */
+ RT_ASSERT(object != RT_NULL);
+ RT_ASSERT(!(object->type & RT_Object_Class_Static));
+
+#ifdef RT_USING_HOOK
+ if (rt_object_detach_hook != RT_NULL) rt_object_detach_hook(object);
+#endif
+
+ /* lock interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* remove from old list */
+ rt_list_remove(&(object->list));
+
+ /* unlock interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ /* free the memory of object */
+ rt_free(object);
+}
+#endif
+
+/**
+ * This fucntion will find the object id by specified object name
+ *
+ * @param type the type of object
+ * @param name the specified object name
+ *
+ * @return object id for successful
+ */
+rt_object_t rt_object_find(enum rt_object_class_type type, const char* name)
+{
+ struct rt_object_information *information;
+ struct rt_object* object;
+ struct rt_list_node* node;
+
+ information = &rt_object_container[type];
+
+ for (node = information->object_list.next; node != &(information->object_list); node = node->next)
+ {
+ object = rt_list_entry(node, struct rt_object, list);
+ if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
+ {
+ return object;
+ }
+ }
+
+ /* not found */
+ return RT_NULL;
+}
+
+/**
+ * This function will judge the object is system object or not.
+ * Normally, the system object is a static object and the type
+ * of object set to RT_Object_Class_Static.
+ *
+ * @param object the specified object to be judged.
+ *
+ * @return RT_EOK if a system object, RT_ERROR for others.
+ */
+rt_err_t rt_object_is_systemobject(rt_object_t object)
+{
+ /* object check */
+ RT_ASSERT(object != RT_NULL);
+
+ if (object->type & RT_Object_Class_Static) return RT_EOK;
+
+ return -RT_ERROR;
+}
+
+/*@}*/
diff --git a/src/scheduler.c b/src/scheduler.c
new file mode 100644
index 0000000000..907d0cdeba
--- /dev/null
+++ b/src/scheduler.c
@@ -0,0 +1,414 @@
+/*
+ * File : scheduler.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-03-17 Bernard the first version
+ * 2006-04-28 Bernard fix the scheduler algorthm
+ * 2006-04-30 Bernard add SCHEDULER_DEBUG
+ * 2006-05-27 Bernard fix the scheduler algorthm for same priority thread
+ * schedule
+ * 2006-06-04 Bernard rewrite the scheduler algorithm
+ * 2006-08-03 Bernard add hook support
+ * 2006-09-05 Bernard add 32 priority level support
+ * 2006-09-24 Bernard add rt_system_scheduler_start function
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+
+#include "kservice.h"
+
+/* #define SCHEDULER_DEBUG */
+
+static rt_int16_t rt_scheduler_lock_nest;
+extern rt_uint32_t rt_interrupt_nest;
+
+rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
+struct rt_thread* rt_current_thread;
+
+rt_uint8_t rt_current_priority;
+
+#if RT_THREAD_PRIORITY_MAX > 32
+/* maximun priority level, 256 */
+rt_uint32_t rt_thread_ready_priority_group;
+rt_uint8_t rt_thread_ready_table[32];
+#else
+/* maximun priority level, 32 */
+rt_uint32_t rt_thread_ready_priority_group;
+#endif
+
+#ifdef RT_USING_HEAP
+rt_list_t rt_thread_defunct;
+#endif
+
+const rt_uint8_t rt_lowest_bitmap[] =
+{
+ /* 00 */ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* 10 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* 20 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* 30 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* 40 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* 50 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* 60 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* 70 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* 80 */ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* 90 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* A0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* B0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* C0 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* D0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* E0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ /* F0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+};
+
+#ifdef RT_USING_HOOK
+static void (*rt_scheduler_hook)(struct rt_thread* from, struct rt_thread* to);
+
+/**
+ * @addtogroup Hook
+ */
+/*@{*/
+
+/**
+ * This function will set a hook function, which will be invoked when thread
+ * switch happens.
+ *
+ * @param hook the hook function
+ */
+void rt_scheduler_sethook(void (*hook)(struct rt_thread* from, struct rt_thread* to))
+{
+ rt_scheduler_hook = hook;
+}
+
+/*@}*/
+#endif
+
+#ifdef RT_USING_OVERFLOW_CHECK
+static void _rt_scheduler_stack_check(struct rt_thread* thread)
+{
+ RT_ASSERT(thread != RT_NULL);
+
+ if ((rt_uint32_t)thread->sp <= (rt_uint32_t)thread->stack_addr)
+ {
+ rt_uint32_t level;
+
+ rt_kprintf("thread:%s stack overflow\n", thread->name);
+ level = rt_hw_interrupt_disable();
+ while (level);
+ }
+ else if ((rt_uint32_t)thread->sp <= ((rt_uint32_t)thread->stack_addr + 32))
+ {
+ rt_kprintf("warning: %s stack is close to end of stack address.\n",
+ thread->name);
+ }
+}
+#endif
+
+/**
+ * @ingroup SystemInit
+ * This function will init the system scheduler
+ *
+ */
+void rt_system_scheduler_init(void)
+{
+ register rt_base_t offset;
+
+ rt_scheduler_lock_nest = 0;
+
+ for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)
+ {
+ rt_list_init(&rt_thread_priority_table[offset]);
+ }
+
+ rt_current_priority = RT_THREAD_PRIORITY_MAX - 1;
+ rt_current_thread = RT_NULL;
+
+ /* init ready priority group */
+ rt_thread_ready_priority_group = 0;
+
+#if RT_THREAD_PRIORITY_MAX > 32
+ /* init ready table */
+ rt_memset(rt_thread_ready_table, 0, sizeof(rt_thread_ready_table));
+#endif
+
+#ifdef RT_USING_HEAP
+ /* init thread defunct */
+ rt_list_init(&rt_thread_defunct);
+#endif
+}
+
+/**
+ * This function will startup scheduler. It will select one thread
+ * with the highest priority level, then switch to it.
+ */
+void rt_system_scheduler_start()
+{
+ register rt_uint8_t number;
+ register rt_uint8_t highest_ready_priority;
+
+ struct rt_thread *to_thread;
+
+ /* find out the highest priority task */
+ if (rt_thread_ready_priority_group & 0xff)
+ {
+ number = rt_lowest_bitmap[rt_thread_ready_priority_group & 0xff];
+ }
+ else if (rt_thread_ready_priority_group & 0xff00)
+ {
+ number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 8) & 0xff] + 8;
+ }
+ else if (rt_thread_ready_priority_group & 0xff0000)
+ {
+ number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 16) & 0xff] + 16;
+ }
+ else
+ {
+ number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 24) & 0xff] + 24;
+ }
+
+#if RT_THREAD_PRIORITY_MAX > 32
+ highest_ready_priority = (number << 3) + rt_lowest_bitmap[rt_thread_ready_table[number]];
+#else
+ highest_ready_priority = number;
+#endif
+
+ /* get switch to thread */
+ to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
+ struct rt_thread, tlist);
+
+ rt_current_thread = to_thread;
+
+ /* switch to new thread */
+ rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);
+
+ /* never come back */
+}
+
+/**
+ * @addtogroup Thread
+ */
+/*@{*/
+
+/**
+ * This function will perform one schedule. It will select one thread
+ * with the highest priority level, then switch to it.
+ */
+void rt_schedule()
+{
+ register rt_uint8_t number;
+ register rt_base_t level;
+ register rt_uint8_t highest_ready_priority;
+
+ struct rt_thread *to_thread;
+ struct rt_thread *from_thread;
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* check the scheduler is enabled or not */
+ if(rt_scheduler_lock_nest == 0)
+ {
+ /* find out the highest priority task */
+ if (rt_thread_ready_priority_group & 0xff)
+ {
+ number = rt_lowest_bitmap[rt_thread_ready_priority_group & 0xff];
+ }
+ else if (rt_thread_ready_priority_group & 0xff00)
+ {
+ number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 8) & 0xff] + 8;
+ }
+ else if (rt_thread_ready_priority_group & 0xff0000)
+ {
+ number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 16) & 0xff] + 16;
+ }
+ else
+ {
+ number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 24) & 0xff] + 24;
+ }
+
+#if RT_THREAD_PRIORITY_MAX > 32
+ highest_ready_priority = (number << 3) + rt_lowest_bitmap[rt_thread_ready_table[number]];
+#else
+ highest_ready_priority = number;
+#endif
+ /* get switch to thread */
+ to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
+ struct rt_thread, tlist);
+
+ /* if the destination thread is not the same as current thread */
+ if (to_thread != rt_current_thread)
+ {
+ rt_current_priority = highest_ready_priority;
+ from_thread = rt_current_thread;
+ rt_current_thread = to_thread;
+
+#ifdef RT_USING_HOOK
+ if (rt_scheduler_hook != RT_NULL) rt_scheduler_hook(from_thread, to_thread);
+#endif
+
+ /* switch to new thread */
+#ifdef SCHEDULER_DEBUG
+ rt_kprintf("[%d]switch to priority#%d thread:%s\n", rt_interrupt_nest,
+ highest_ready_priority, to_thread->name);
+#endif
+#ifdef RT_USING_OVERFLOW_CHECK
+ _rt_scheduler_stack_check(to_thread);
+#endif
+
+ if (rt_interrupt_nest == 0)
+ {
+ rt_hw_context_switch((rt_uint32_t)&from_thread->sp, (rt_uint32_t)&to_thread->sp);
+ }
+ else
+ {
+#ifdef SCHEDULER_DEBUG
+ rt_kprintf("switch in interrupt\n");
+#endif
+ rt_hw_context_switch_interrupt((rt_uint32_t)&from_thread->sp,
+ (rt_uint32_t)&to_thread->sp);
+ }
+ }
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+}
+
+/**
+ * This function will insert a thread to system ready queue. The state of
+ * thread will be set as READY and remove from suspend queue.
+ *
+ * @param thread the thread to be inserted
+ * @note Please do not invoke this function in user application.
+ */
+void rt_schedule_insert_thread(struct rt_thread* thread)
+{
+ register rt_base_t temp;
+
+ RT_ASSERT(thread != RT_NULL);
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* change stat */
+ thread->stat = RT_THREAD_READY;
+
+ /* insert thread to ready list */
+ rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
+ &(thread->tlist));
+
+ /* set priority mask */
+#ifdef SCHEDULER_DEBUG
+#if RT_THREAD_PRIORITY_MAX == 32
+ rt_kprintf("insert thread, the priority: %d\n", thread->current_priority);
+#else
+ rt_kprintf("insert thread, the priority: %d 0x%x %d\n", thread->number, thread->number_mask, thread->high_mask);
+#endif
+#endif
+
+#if RT_THREAD_PRIORITY_MAX > 32
+ rt_thread_ready_table[thread->number] |= thread->high_mask;
+#endif
+ rt_thread_ready_priority_group |= thread->number_mask;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+}
+
+/**
+ * This function will remove a thread from system ready queue.
+ *
+ * @param thread the thread to be removed
+ *
+ * @note Please do not invoke this function in user application.
+ */
+void rt_schedule_remove_thread(struct rt_thread* thread)
+{
+ register rt_base_t temp;
+
+ RT_ASSERT(thread != RT_NULL);
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+#ifdef SCHEDULER_DEBUG
+#if RT_THREAD_PRIORITY_MAX == 32
+ rt_kprintf("remove thread, the priority: %d\n", thread->current_priority);
+#else
+ rt_kprintf("remove thread, the priority: %d 0x%x %d\n", thread->number,
+ thread->number_mask, thread->high_mask);
+#endif
+#endif
+
+ /* remove thread from ready list */
+ rt_list_remove(&(thread->tlist));
+ if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
+ {
+#if RT_THREAD_PRIORITY_MAX > 32
+ rt_thread_ready_table[thread->number] &= ~thread->high_mask;
+ if (rt_thread_ready_table[thread->number] == 0)
+ {
+ rt_thread_ready_priority_group &= ~thread->number_mask;
+ }
+#else
+ rt_thread_ready_priority_group &= ~thread->number_mask;
+#endif
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+}
+
+/**
+ * This function will lock the thread scheduler.
+ */
+void rt_enter_critical()
+{
+ register rt_base_t level;
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ if (rt_scheduler_lock_nest < 255u)
+ rt_scheduler_lock_nest++;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+}
+
+/**
+ * This function will unlock the thread scheduler.
+ */
+void rt_exit_critical()
+{
+ register rt_base_t level;
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ rt_scheduler_lock_nest --;
+
+ if (rt_scheduler_lock_nest <= 0)
+ {
+ rt_scheduler_lock_nest = 0;
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ rt_schedule();
+ }
+ else
+ {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+ }
+}
+
+/*@}*/
+
diff --git a/src/slab.c b/src/slab.c
new file mode 100644
index 0000000000..59a1db7aa1
--- /dev/null
+++ b/src/slab.c
@@ -0,0 +1,815 @@
+/*
+ * File : slab.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2008, 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://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2008-07-12 Bernard the first version
+ */
+
+/*
+ * KERN_SLABALLOC.C - Kernel SLAB memory allocator
+ *
+ * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+/* #define RT_SLAB_DEBUG */
+
+#if defined (RT_USING_HEAP) && defined (RT_USING_SLAB)
+#ifdef RT_USING_HOOK
+static void (*rt_malloc_hook)(void *ptr, rt_size_t size);
+static void (*rt_free_hook)(void *ptr);
+
+/**
+ * @addtogroup Hook
+ */
+/*@{*/
+
+/**
+ * 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;
+}
+
+/**
+ * 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
+
+/*
+ * slab allocator implementation
+ *
+ * A slab allocator reserves a ZONE for each chunk size, then lays the
+ * chunks out in an array within the zone. Allocation and deallocation
+ * is nearly instantanious, and fragmentation/overhead losses are limited
+ * to a fixed worst-case amount.
+ *
+ * The downside of this slab implementation is in the chunk size
+ * multiplied by the number of zones. ~80 zones * 128K = 10MB of VM per cpu.
+ * In a kernel implementation all this memory will be physical so
+ * the zone size is adjusted downward on machines with less physical
+ * memory. The upside is that overhead is bounded... this is the *worst*
+ * case overhead.
+ *
+ * Slab management is done on a per-cpu basis and no locking or mutexes
+ * are required, only a critical section. When one cpu frees memory
+ * belonging to another cpu's slab manager an asynchronous IPI message
+ * will be queued to execute the operation. In addition, both the
+ * high level slab allocator and the low level zone allocator optimize
+ * M_ZERO requests, and the slab allocator does not have to pre initialize
+ * the linked list of chunks.
+ *
+ * XXX Balancing is needed between cpus. Balance will be handled through
+ * asynchronous IPIs primarily by reassigning the z_Cpu ownership of chunks.
+ *
+ * XXX If we have to allocate a new zone and M_USE_RESERVE is set, use of
+ * the new zone should be restricted to M_USE_RESERVE requests only.
+ *
+ * Alloc Size Chunking Number of zones
+ * 0-127 8 16
+ * 128-255 16 8
+ * 256-511 32 8
+ * 512-1023 64 8
+ * 1024-2047 128 8
+ * 2048-4095 256 8
+ * 4096-8191 512 8
+ * 8192-16383 1024 8
+ * 16384-32767 2048 8
+ * (if RT_MM_PAGE_SIZE is 4K the maximum zone allocation is 16383)
+ *
+ * Allocations >= zone_limit go directly to kmem.
+ *
+ * API REQUIREMENTS AND SIDE EFFECTS
+ *
+ * To operate as a drop-in replacement to the FreeBSD-4.x malloc() we
+ * have remained compatible with the following API requirements:
+ *
+ * + small power-of-2 sized allocations are power-of-2 aligned (kern_tty)
+ * + all power-of-2 sized allocations are power-of-2 aligned (twe)
+ * + malloc(0) is allowed and returns non-RT_NULL (ahc driver)
+ * + 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;
+
+#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.
+ */
+#define MIN_CHUNK_SIZE 8 /* in bytes */
+#define MIN_CHUNK_MASK (MIN_CHUNK_SIZE - 1)
+
+/*
+ * Array of descriptors that describe the contents of each page
+ */
+#define PAGE_TYPE_FREE 0x00
+#define PAGE_TYPE_SMALL 0x01
+#define PAGE_TYPE_LARGE 0x02
+struct memusage {
+ rt_uint32_t type:2 ; /* page type */
+ rt_uint32_t size:30; /* pages allocated or offset from zone */
+};
+static struct memusage *memusage = RT_NULL;
+#define btokup(addr) (&memusage[((rt_uint32_t)(addr) - heap_start) >> RT_MM_PAGE_BITS])
+
+static rt_uint32_t heap_start, heap_end;
+
+/* page allocator */
+struct rt_page_head
+{
+ struct rt_page_head *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))];
+};
+static struct rt_page_head *rt_page_list;
+
+static void *rt_page_alloc(rt_size_t npages)
+{
+ struct rt_page_head *b, *n;
+ struct rt_page_head **prev;
+
+ RT_ASSERT(npages != 0);
+
+ for (prev = &rt_page_list; (b = *prev) != RT_NULL; prev = &(b->next))
+ {
+ if (b->page > npages)
+ {
+ /* splite pages */
+ n = b + npages;
+ n->next = b->next;
+ n->page = b->page - npages;
+ *prev = n;
+ break;
+ }
+
+ if (b->page == npages)
+ {
+ /* this node fit, remove this node */
+ *prev = b->next;
+ break;
+ }
+ }
+
+ return b;
+}
+
+static void rt_page_free(void *addr, rt_size_t npages)
+{
+ struct rt_page_head *b, *n;
+ struct rt_page_head **prev;
+
+ RT_ASSERT(addr != RT_NULL);
+ RT_ASSERT((rt_uint32_t)addr % RT_MM_PAGE_SIZE == 0);
+ RT_ASSERT(npages != 0);
+
+ n = (struct rt_page_head *)addr;
+
+ for (prev = &rt_page_list; (b = *prev) != RT_NULL; prev = &(b->next))
+ {
+ RT_ASSERT(b->page > 0);
+ RT_ASSERT(b > n || b + b->page <= n);
+
+ if (b + b->page == n)
+ {
+ if (b + (b->page += npages) == b->next)
+ {
+ b->page += b->next->page;
+ b->next = b->next->next;
+ }
+
+ return;
+ }
+
+ if (b == n + npages)
+ {
+ n->page = b->page + npages;
+ n->next = b->next;
+ *prev = n;
+
+ return;
+ }
+
+ if (b > n + npages) break;
+ }
+
+ n->page = npages;
+ n->next = b;
+ *prev = n;
+}
+
+/*
+ * Initialize the page allocator
+ */
+static void rt_page_init(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);
+}
+
+/**
+ * @ingroup SystemInit
+ *
+ * This function will init system heap
+ *
+ * @param begin_addr the beginning address of system page
+ * @param end_addr the end address of system page
+ *
+ */
+void rt_system_heap_init(void *begin_addr, void* end_addr)
+{
+ rt_uint32_t limsize, npages;
+
+ /* align begin and end addr to page */
+ heap_start = RT_ALIGN((rt_uint32_t)begin_addr, RT_MM_PAGE_SIZE);
+ heap_end = RT_ALIGN((rt_uint32_t)end_addr, RT_MM_PAGE_SIZE);
+
+ limsize = heap_end - heap_start;
+ npages = limsize / RT_MM_PAGE_SIZE;
+
+#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
+
+ /* init pages */
+ rt_page_init((void*)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;
+
+ zone_limit = zone_size / 4;
+ if (zone_limit > ZALLOC_ZONE_LIMIT) zone_limit = ZALLOC_ZONE_LIMIT;
+
+ zone_page_cnt = zone_size / RT_MM_PAGE_SIZE;
+
+#ifdef RT_SLAB_DEBUG
+ rt_kprintf("zone size 0x%x, zone page count 0x%x\n", zone_size, zone_page_cnt);
+#endif
+
+ /* allocate memusage array */
+ limsize = npages * sizeof(struct memusage);
+ limsize = RT_ALIGN(limsize, RT_MM_PAGE_SIZE);
+ memusage = rt_page_alloc(limsize/RT_MM_PAGE_SIZE);
+
+#ifdef RT_SLAB_DEBUG
+ rt_kprintf("memusage 0x%x, size 0x%x\n", (rt_uint32_t)memusage, limsize);
+#endif
+}
+
+/*
+ * Calculate the zone index for the allocation request size and set the
+ * allocation request size to that particular zone's chunk size.
+ */
+rt_inline int zoneindex(rt_uint32_t *bytes)
+{
+ rt_uint32_t n = (rt_uint32_t)*bytes; /* unsigned for shift opt */
+
+ if (n < 128)
+ {
+ *bytes = n = (n + 7) & ~7;
+ return(n / 8 - 1); /* 8 byte chunks, 16 zones */
+ }
+ if (n < 256)
+ {
+ *bytes = n = (n + 15) & ~15;
+ return(n / 16 + 7);
+ }
+ if (n < 8192)
+ {
+ if (n < 512)
+ {
+ *bytes = n = (n + 31) & ~31;
+ return(n / 32 + 15);
+ }
+ if (n < 1024)
+ {
+ *bytes = n = (n + 63) & ~63;
+ return(n / 64 + 23);
+ }
+ if (n < 2048)
+ {
+ *bytes = n = (n + 127) & ~127;
+ return(n / 128 + 31);
+ }
+ if (n < 4096)
+ {
+ *bytes = n = (n + 255) & ~255;
+ return(n / 256 + 39);
+ }
+ *bytes = n = (n + 511) & ~511;
+ return(n / 512 + 47);
+ }
+ if (n < 16384)
+ {
+ *bytes = n = (n + 1023) & ~1023;
+ return(n / 1024 + 55);
+ }
+
+ rt_kprintf("Unexpected byte count %d", n);
+ return 0;
+}
+
+/**
+ * @addtogroup MM
+ */
+
+/*@{*/
+
+/**
+ * This function will allocate a block from system heap memory.
+ * - If the nbytes is less than zero,
+ * or
+ * - If there is no nbytes sized memory valid in system,
+ * the RT_NULL is returned.
+ *
+ * @param size the size of memory to be allocated
+ *
+ * @return the allocated memory
+ *
+ */
+void *rt_malloc(rt_size_t size)
+{
+ slab_zone *z;
+ rt_int32_t zi;
+ slab_chunk *chunk;
+ rt_base_t interrupt_level;
+ struct memusage *kup;
+
+ /* zero size, return RT_NULL */
+ if (size == 0) return RT_NULL;
+
+ /*
+ * Handle large allocations directly. There should not be very many of
+ * these so performance is not a big issue.
+ */
+ if (size >= zone_limit)
+ {
+ size = RT_ALIGN(size, RT_MM_PAGE_SIZE);
+
+ chunk = rt_page_alloc(size >> RT_MM_PAGE_BITS);
+ if (chunk == RT_NULL) return RT_NULL;
+
+ /* set kup */
+ kup = btokup(chunk);
+ kup->type = PAGE_TYPE_LARGE;
+ kup->size = size >> RT_MM_PAGE_BITS;
+
+#ifdef RT_SLAB_DEBUG
+ rt_kprintf("malloc a large memory 0x%x, page cnt %d, kup %d\n",
+ size,
+ size >> RT_MM_PAGE_BITS,
+ ((rt_uint32_t)chunk - heap_start) >> RT_MM_PAGE_BITS);
+#endif
+
+ /* lock interrupt */
+ interrupt_level = rt_hw_interrupt_disable();
+ goto done;
+ }
+
+ /*
+ * 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
+ * it to the head of the list so later allocations find it quickly
+ * (we might have thousands of zones in the list).
+ *
+ * Note: zoneindex() will panic of size is too large.
+ */
+ zi = zoneindex(&size);
+ RT_ASSERT(zi < NZONES);
+
+#ifdef RT_SLAB_DEBUG
+ 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);
+
+ /* Remove us from the zone_array[] when we become empty */
+ if (--z->z_nfree == 0)
+ {
+ zone_array[zi] = z->z_next;
+ z->z_next = RT_NULL;
+ }
+
+ /*
+ * No chunks are available but nfree said we had some memory, so
+ * it must be available in the never-before-used-memory area
+ * governed by uindex. The consequences are very serious if our zone
+ * got corrupted so we use an explicit rt_kprintf rather then a KASSERT.
+ */
+ 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);
+ }
+ else
+ {
+ /* find on free chunk list */
+ chunk = z->z_freechunk;
+
+ /* remove this chunk from list */
+ z->z_freechunk = z->z_freechunk->c_next;
+ }
+
+ goto done;
+ }
+
+ /*
+ * If all zones are exhausted we need to allocate a new zone for this
+ * index.
+ *
+ * At least one subsystem, the tty code (see CROUND) expects power-of-2
+ * allocations to be power-of-2 aligned. We maintain compatibility by
+ * adjusting the base offset below.
+ */
+ {
+ rt_int32_t off;
+
+ if ((z = zone_free) != RT_NULL)
+ {
+ /* remove zone from free zone list */
+ zone_free = z->z_next;
+ --zone_free_cnt;
+ }
+ else
+ {
+ /* allocate a zone from page */
+ z = rt_page_alloc(zone_size / RT_MM_PAGE_SIZE);
+ if (z == RT_NULL) goto fail;
+
+#ifdef RT_SLAB_DEBUG
+ rt_kprintf("alloc a new zone: 0x%x\n", (rt_uint32_t)z);
+#endif
+
+ /* set message usage */
+ for (off = 0, kup = btokup(z); off < zone_page_cnt; off ++)
+ {
+ kup->type = PAGE_TYPE_SMALL;
+ kup->size = off;
+
+ kup ++;
+ }
+ }
+
+ /* clear to zero */
+ rt_memset(z, 0, sizeof(slab_zone));
+
+ /* offset of slab zone struct in zone */
+ off = sizeof(slab_zone);
+
+ /*
+ * Guarentee power-of-2 alignment for power-of-2-sized chunks.
+ * Otherwise just 8-byte align the data.
+ */
+ if ((size | (size - 1)) + 1 == (size << 1))
+ off = (off + size - 1) & ~(size - 1);
+ else
+ off = (off + MIN_CHUNK_MASK) & ~MIN_CHUNK_MASK;
+
+ z->z_magic = ZALLOC_SLAB_MAGIC;
+ z->z_zoneindex = zi;
+ z->z_nmax = (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);
+
+ /* link to zone array */
+ z->z_next = zone_array[zi];
+ zone_array[zi] = z;
+ }
+
+done:
+ rt_hw_interrupt_enable(interrupt_level);
+
+#ifdef RT_USING_HOOK
+ if (rt_malloc_hook != RT_NULL) rt_malloc_hook((char*)chunk, size);
+#endif
+
+ return chunk;
+
+fail:
+ rt_hw_interrupt_enable(interrupt_level);
+ return RT_NULL;
+}
+
+/**
+ * This function will change the size of previously allocated memory block.
+ *
+ * @param ptr the previously allocated memory block
+ * @param size the new size of memory block
+ *
+ * @return the allocated memory
+ */
+void *rt_realloc(void *ptr, rt_size_t size)
+{
+ void *nptr;
+ slab_zone *z;
+ struct memusage *kup;
+
+ if (ptr == RT_NULL) return rt_malloc(size);
+ if (size == 0)
+ {
+ rt_free(ptr);
+ return RT_NULL;
+ }
+
+ /*
+ * Get the original allocation's zone. If the new request winds up
+ * using the same chunk size we do not have to do anything.
+ */
+ kup = btokup((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK);
+ if (kup->type == PAGE_TYPE_LARGE)
+ {
+ rt_size_t osize;
+
+ osize = kup->size << RT_MM_PAGE_BITS;
+ if ((nptr = rt_malloc(size)) == RT_NULL) return RT_NULL;
+ rt_memcpy(nptr, ptr, size > osize? osize : size);
+ rt_free(ptr);
+
+ return nptr;
+ }
+ else if (kup->type == PAGE_TYPE_SMALL)
+ {
+ 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);
+
+ zoneindex(&size);
+ if (z->z_chunksize == size) return(ptr); /* same chunk */
+
+ /*
+ * Allocate memory for the new request size. Note that zoneindex has
+ * 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) return RT_NULL;
+
+ rt_memcpy(nptr, ptr, size > z->z_chunksize? z->z_chunksize : size);
+ rt_free(ptr);
+
+ return nptr;
+ }
+
+ return RT_NULL;
+}
+
+/**
+ * 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.
+ *
+ * The allocated memory is filled with bytes of value zero.
+ *
+ * @param count number of objects to allocate
+ * @param size 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;
+}
+
+/**
+ * This function will release the previously allocated memory block by rt_malloc.
+ * The released memory block is taken back to system heap.
+ *
+ * @param ptr the address of memory which will be released
+ */
+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 ;
+
+#ifdef RT_USING_HOOK
+ if (rt_free_hook != RT_NULL) rt_free_hook(ptr);
+#endif
+
+ /* 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);
+#endif
+
+ kup = btokup((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK);
+ /* release large allocation */
+ if (kup->type == PAGE_TYPE_LARGE)
+ {
+ rt_uint32_t size;
+
+ /* clear page counter */
+ interrupt_level = rt_hw_interrupt_disable();
+ size = kup->size;
+ kup->size = 0;
+ rt_hw_interrupt_enable(interrupt_level);
+
+#ifdef RT_SLAB_DEBUG
+ rt_kprintf("free large memory block 0x%x, page count %d\n", (rt_uint32_t)ptr, size);
+#endif
+
+ /* free this page */
+ rt_page_free(ptr, size);
+ return;
+ }
+
+ /* 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;
+
+ /*
+ * Bump the number of free chunks. If it becomes non-zero the zone
+ * must be added back onto the appropriate list.
+ */
+ if (z->z_nfree++ == 0)
+ {
+ z->z_next = zone_array[z->z_zoneindex];
+ zone_array[z->z_zoneindex] = z;
+ }
+
+ /*
+ * If the zone becomes totally free, and there are other zones we
+ * can allocate from, move this zone to the FreeZones list. Since
+ * this code can be called from an IPI callback, do *NOT* try to mess
+ * 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))
+ {
+ slab_zone **pz;
+
+#ifdef RT_SLAB_DEBUG
+ rt_kprintf("free zone 0x%x\n", (rt_uint32_t)z, z->z_zoneindex);
+#endif
+
+ /* remove zone from zone array list */
+ for (pz = &zone_array[z->z_zoneindex]; z != *pz; pz = &(*pz)->z_next) ;
+ *pz = z->z_next;
+
+ /* reset zone */
+ z->z_magic = -1;
+
+ /* insert to free zone list */
+ z->z_next = zone_free;
+ zone_free = z;
+
+ ++zone_free_cnt;
+
+ /* release zone to page allocator */
+ if (zone_free_cnt > ZONE_RELEASE_THRESH)
+ {
+ register rt_base_t i;
+
+ z = zone_free;
+ zone_free = z->z_next;
+ --zone_free_cnt;
+
+ /* set message usage */
+ for (i = 0, kup = btokup(z); i < zone_page_cnt; i ++)
+ {
+ kup->type = PAGE_TYPE_FREE;
+ kup->size = 0;
+ kup ++;
+ }
+
+ /* release pages */
+ rt_page_free(z, zone_size);
+ }
+ }
+ rt_hw_interrupt_enable(interrupt_level);
+}
+
+/*@}*/
+
+#endif
diff --git a/src/thread.c b/src/thread.c
new file mode 100644
index 0000000000..b8ab0fb641
--- /dev/null
+++ b/src/thread.c
@@ -0,0 +1,625 @@
+/*
+ * File : thread.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-03-28 Bernard first version
+ * 2006-04-29 Bernard implement thread timer
+ * 2006-04-30 Bernard add THREAD_DEBUG
+ * 2006-05-27 Bernard fix the rt_thread_yield bug
+ * 2006-06-03 Bernard fix the thread timer init bug
+ * 2006-08-10 Bernard fix the timer bug in thread_sleep
+ * 2006-09-03 Bernard change rt_timer_delete to rt_timer_detach
+ * 2006-09-03 Bernard implement rt_thread_detach
+ * 2008-02-16 Bernard fix the rt_thread_timeout bug
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+#include "kservice.h"
+
+/*#define THREAD_DEBUG */
+
+extern rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
+extern struct rt_thread* rt_current_thread;
+extern rt_uint8_t rt_current_priority;
+
+#ifdef RT_USING_HEAP
+extern rt_list_t rt_thread_defunct;
+#endif
+
+static void rt_thread_exit(void);
+void rt_thread_timeout(void* parameter);
+
+static rt_err_t _rt_thread_init(struct rt_thread* thread,
+ const char* name,
+ void (*entry)(void* parameter), void* parameter,
+ void* stack_start, rt_uint32_t stack_size,
+ rt_uint8_t priority, rt_uint32_t tick)
+{
+ /* set thread id and init thread list */
+ thread->tid = thread;
+ rt_list_init(&(thread->tlist));
+
+ thread->entry = (void*)entry;
+ thread->parameter = parameter;
+
+ /* stack init */
+ thread->stack_addr = stack_start;
+ thread->stack_size = stack_size;
+
+ /* init thread stack */
+ rt_memset(thread->stack_addr, '#', thread->stack_size);
+ thread->sp = (void*)rt_hw_stack_init(thread->entry, thread->parameter,
+ (void *) ((char *)thread->stack_addr + thread->stack_size - 4),
+ (void*)rt_thread_exit);
+
+ /* priority init */
+ RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
+ thread->init_priority = priority;
+ thread->current_priority = priority;
+
+ /* tick init */
+ thread->init_tick = tick;
+ thread->remaining_tick = tick;
+
+ /* error and flags */
+ thread->error = RT_EOK;
+ thread->stat = RT_THREAD_INIT;
+ thread->flags = 0;
+
+#ifdef RT_USING_MODULE
+ /* init module parent */
+ thread->module_parent = RT_NULL;
+#endif
+
+ /* init user data */
+ thread->user_data = 0;
+
+ /* init thread timer */
+ rt_timer_init(&(thread->thread_timer),
+ thread->name,
+ rt_thread_timeout,
+ thread,
+ 0,
+ RT_TIMER_FLAG_ONE_SHOT);
+
+ return RT_EOK;
+}
+
+/**
+ * @addtogroup Thread
+ */
+
+/*@{*/
+
+/**
+ * This function will init a thread, normally it's used to initialize a static thread object.
+ *
+ * @param thread the static thread object
+ * @param name the name of thread, which shall be unique
+ * @param entry the entry function of thread
+ * @param parameter the parameter of thread enter function
+ * @param stack_start the start address of thread stack
+ * @param stack_size the size of thread stack
+ * @param priority the priority of thread
+ * @param tick the time slice if there are same priority thread
+ *
+ * @return the operation status, RT_EOK on OK; -RT_ERROR on error
+ *
+ */
+rt_err_t rt_thread_init(struct rt_thread* thread,
+ const char* name,
+ void (*entry)(void* parameter), void* parameter,
+ void* stack_start, rt_uint32_t stack_size,
+ rt_uint8_t priority, rt_uint32_t tick)
+{
+ /* thread check */
+ RT_ASSERT(thread != RT_NULL);
+ RT_ASSERT(stack_start != RT_NULL);
+
+ /* init thread object */
+ rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
+
+ return _rt_thread_init(thread, name, entry, parameter,
+ stack_start, stack_size,
+ priority, tick);
+}
+
+#ifdef RT_USING_HEAP
+/**
+ * This function will create a thread object and allocate thread object memory and stack.
+ *
+ * @param name the name of thread, which shall be unique
+ * @param entry the entry function of thread
+ * @param parameter the parameter of thread enter function
+ * @param stack_size the size of thread stack
+ * @param priority the priority of thread
+ * @param tick the time slice if there are same priority thread
+ *
+ * @return the created thread object
+ *
+ */
+rt_thread_t rt_thread_create (const char* name,
+ void (*entry)(void* parameter), void* parameter,
+ rt_uint32_t stack_size,
+ rt_uint8_t priority,
+ rt_uint32_t tick)
+{
+ struct rt_thread* thread;
+ void* stack_start;
+
+ thread = (struct rt_thread*) rt_object_allocate(RT_Object_Class_Thread, name);
+ if (thread == RT_NULL) return RT_NULL;
+
+ stack_start = (void*)rt_malloc(stack_size);
+ if (stack_start == RT_NULL)
+ {
+ /* allocate stack failure */
+ rt_object_delete((rt_object_t)thread);
+ return RT_NULL;
+ }
+
+ _rt_thread_init(thread, name, entry, parameter,
+ stack_start, stack_size,
+ priority, tick);
+
+ return thread;
+}
+#endif
+
+/**
+ * This function will return self thread object
+ *
+ * @return the self thread object
+ *
+ */
+rt_thread_t rt_thread_self (void)
+{
+ return rt_current_thread;
+}
+
+/**
+ * This function will start a thread and put it to system ready queue
+ *
+ * @param thread the thread to be started
+ *
+ * @return the operation status, RT_EOK on OK; -RT_ERROR on error
+ *
+ */
+rt_err_t rt_thread_startup (rt_thread_t thread)
+{
+ /* thread check */
+ RT_ASSERT(thread != RT_NULL);
+ RT_ASSERT(thread->stat == RT_THREAD_INIT);
+
+ /* set current priority to init priority */
+ thread->current_priority = thread->init_priority;
+
+ /* calculate priority attribute */
+#if RT_THREAD_PRIORITY_MAX > 32
+ thread->number = thread->current_priority >> 3; /* 5bit */
+ thread->number_mask = 1 << thread->number;
+ thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
+#else
+ thread->number_mask = 1 << thread->current_priority;
+#endif
+
+#ifdef THREAD_DEBUG
+ rt_kprintf("startup a thread:%s with priority:%d\n", thread->name, thread->init_priority);
+#endif
+
+ /* change thread stat */
+ thread->stat = RT_THREAD_SUSPEND;
+ /* then resume it */
+ rt_thread_resume(thread);
+
+ return RT_EOK;
+}
+
+static void rt_thread_exit()
+{
+ struct rt_thread* thread;
+ register rt_base_t temp;
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* get current thread */
+ thread = rt_current_thread;
+
+ /* remove from schedule */
+ rt_schedule_remove_thread(thread);
+
+ /* change stat */
+ thread->stat = RT_THREAD_CLOSE;
+
+ /* release thread timer */
+ rt_timer_detach(&(thread->thread_timer));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ if (rt_object_is_systemobject((rt_object_t)thread) == RT_EOK)
+ {
+ rt_object_detach((rt_object_t)thread);
+ }
+#ifdef RT_USING_HEAP
+ else
+ {
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* insert to defunct thread list */
+ rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+ }
+#endif
+
+ /* switch to next task */
+ rt_schedule();
+}
+
+/**
+ * This function will detach a thread. The thread object will be remove from thread
+ * queue and detached/deleted from system object management.
+ *
+ * @param thread the thread to be deleted
+ *
+ * @return the operation status, RT_EOK on OK; -RT_ERROR on error
+ *
+ */
+rt_err_t rt_thread_detach (rt_thread_t thread)
+{
+ /* thread check */
+ RT_ASSERT(thread != RT_NULL);
+
+ /* remove from schedule */
+ rt_schedule_remove_thread(thread);
+
+ /* release thread timer */
+ rt_timer_detach(&(thread->thread_timer));
+
+ rt_object_detach((rt_object_t)thread);
+
+ return RT_EOK;
+}
+
+#ifdef RT_USING_HEAP
+/**
+ * This function will delete a thread. The thread object will be remove from thread
+ * queue and detached/deleted from system object management.
+ *
+ * @param thread the thread to be deleted
+ *
+ * @return the operation status, RT_EOK on OK; -RT_ERROR on error
+ *
+ */
+rt_err_t rt_thread_delete (rt_thread_t thread)
+{
+ rt_base_t lock;
+
+ /* thread check */
+ RT_ASSERT(thread != RT_NULL);
+
+ /* remove from schedule */
+ rt_schedule_remove_thread(thread);
+
+ /* release thread timer */
+ rt_timer_detach(&(thread->thread_timer));
+
+ /* change stat */
+ thread->stat = RT_THREAD_CLOSE;
+
+ /* disable interrupt */
+ lock = rt_hw_interrupt_disable();
+
+ /* insert to defunct thread list */
+ rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(lock);
+
+ return RT_EOK;
+}
+#endif
+
+/**
+ * This function will let current thread yield processor, and scheduler will get a highest thread to run.
+ * After yield processor, the current thread is still in READY state.
+ *
+ * @return the operation status, RT_EOK on OK; -RT_ERROR on error
+ *
+ */
+rt_err_t rt_thread_yield ()
+{
+ register rt_base_t level;
+ struct rt_thread *thread;
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* set to current thread */
+ thread = rt_current_thread;
+
+ /* if the thread stat is READY and on ready queue list */
+ if (thread->stat == RT_THREAD_READY && thread->tlist.next != thread->tlist.prev)
+ {
+ /* remove thread from thread list */
+ rt_list_remove(&(thread->tlist));
+
+ /* put thread to end of ready queue */
+ rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
+ &(thread->tlist));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ rt_schedule();
+
+ return RT_EOK;
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will let current thread sleep for some ticks.
+ *
+ * @param tick the sleep ticks
+ *
+ * @return the operation status, RT_EOK on OK; RT_ERROR on error
+ *
+ */
+rt_err_t rt_thread_sleep (rt_tick_t tick)
+{
+ register rt_base_t temp;
+ struct rt_thread *thread;
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+ /* set to current thread */
+ thread = rt_current_thread;
+ RT_ASSERT(thread != RT_NULL);
+
+ /* suspend thread */
+ rt_thread_suspend(thread);
+
+ /* reset the timeout of thread timer and start it */
+ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);
+ rt_timer_start(&(thread->thread_timer));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ rt_schedule();
+
+ return RT_EOK;
+}
+
+/**
+ * This function will let current thread delay for some ticks.
+ *
+ * @param tick the delay ticks
+ *
+ * @return the operation status, RT_EOK on OK; RT_ERROR on error
+ *
+ */
+rt_err_t rt_thread_delay(rt_tick_t tick)
+{
+ return rt_thread_sleep(tick);
+}
+
+rt_err_t rt_thread_control (rt_thread_t thread, rt_uint8_t cmd, void* arg)
+{
+ register rt_base_t temp;
+
+ /* thread check */
+ RT_ASSERT(thread != RT_NULL);
+
+ switch (cmd)
+ {
+ case RT_THREAD_CTRL_CHANGE_PRIORITY:
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* for ready thread, change queue */
+ if (thread->stat == RT_THREAD_READY)
+ {
+ /* remove thread from schedule queue first */
+ rt_schedule_remove_thread(thread);
+
+ /* change thread priority */
+ thread->current_priority = *(rt_uint8_t*) arg;
+
+ /* recalculate priority attribute */
+#if RT_THREAD_PRIORITY_MAX > 32
+ thread->number = thread->current_priority >> 3; /* 5bit */
+ thread->number_mask = 1 << thread->number;
+ thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
+#else
+ thread->number_mask = 1 << thread->current_priority;
+#endif
+
+ /* insert thread to schedule queue again */
+ rt_schedule_insert_thread(thread);
+ }
+ else
+ {
+ thread->current_priority = *(rt_uint8_t*) arg;
+
+ /* recalculate priority attribute */
+#if RT_THREAD_PRIORITY_MAX > 32
+ thread->number = thread->current_priority >> 3; /* 5bit */
+ thread->number_mask = 1 << thread->number;
+ thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
+#else
+ thread->number_mask = 1 << thread->current_priority;
+#endif
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+ break;
+
+ case RT_THREAD_CTRL_STARTUP:
+ return rt_thread_startup(thread);
+
+#ifdef RT_USING_HEAP
+ case RT_THREAD_CTRL_CLOSE:
+ return rt_thread_delete(thread);
+#endif
+
+ default:
+ break;
+ }
+
+ return - RT_EOK;
+}
+
+/**
+ * This function will suspend the specified thread.
+ *
+ * @param thread the thread to be suspended
+ *
+ * @return the operation status, RT_EOK on OK; -RT_ERROR on error
+ *
+ */
+rt_err_t rt_thread_suspend (rt_thread_t thread)
+{
+ register rt_base_t temp;
+
+ /* thread check */
+ RT_ASSERT(thread != RT_NULL);
+
+#ifdef THREAD_DEBUG
+ rt_kprintf("thread suspend: %s\n", thread->name);
+#endif
+
+ if (thread->stat != RT_THREAD_READY)
+ {
+#ifdef THREAD_DEBUG
+ rt_kprintf("thread suspend: thread disorder, %d\n", thread->stat);
+#endif
+ return -RT_ERROR;
+ }
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* change thread stat */
+ thread->stat = RT_THREAD_SUSPEND;
+ rt_schedule_remove_thread(thread);
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will resume a thread and put it to system ready queue.
+ *
+ * @param thread the thread to be resumed
+ *
+ * @return the operation status, RT_EOK on OK; -RT_ERROR on error
+ *
+ */
+rt_err_t rt_thread_resume (rt_thread_t thread)
+{
+ register rt_base_t temp;
+
+ /* thread check */
+ RT_ASSERT(thread != RT_NULL);
+
+#ifdef THREAD_DEBUG
+ rt_kprintf("thread resume: %s\n", thread->name);
+#endif
+
+ if (thread->stat != RT_THREAD_SUSPEND)
+ {
+#ifdef THREAD_DEBUG
+ rt_kprintf("thread resume: thread disorder, %d\n", thread->stat);
+#endif
+ return -RT_ERROR;
+ }
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* remove from suspend list */
+ rt_list_remove(&(thread->tlist));
+
+ /* remove thread timer */
+ rt_list_remove(&(thread->thread_timer.list));
+
+ /* change timer state */
+ thread->thread_timer.parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ /* insert to schedule ready list */
+ rt_schedule_insert_thread(thread);
+
+ return RT_EOK;
+}
+
+/**
+ * This function is the timeout function for thread, normally which will
+ * be invoked when thread is timeout to wait some recourse.
+ *
+ * @param parameter the parameter of thread timeout function
+ *
+ */
+void rt_thread_timeout(void* parameter)
+{
+ struct rt_thread* thread;
+
+ thread = (struct rt_thread*) parameter;
+
+ /* thread check */
+ RT_ASSERT(thread != RT_NULL);
+ RT_ASSERT(thread->stat == RT_THREAD_SUSPEND);
+
+ /* set error number */
+ thread->error = -RT_ETIMEOUT;
+
+ /* remove from suspend list */
+ rt_list_remove(&(thread->tlist));
+
+ /* insert to schedule ready list */
+ rt_schedule_insert_thread(thread);
+
+ /* do schedule */
+ rt_schedule();
+}
+
+/**
+ * This function will find the specified thread.
+ *
+ * @param name the name of thread finding
+ *
+ * @return the thread
+ */
+rt_thread_t rt_thread_find(char* name)
+{
+ struct rt_thread* thread;
+
+ thread = (struct rt_thread*)rt_object_find(RT_Object_Class_Thread, name);
+
+ return thread;
+}
+
+/*@}*/
diff --git a/src/timer.c b/src/timer.c
new file mode 100644
index 0000000000..558cbfac35
--- /dev/null
+++ b/src/timer.c
@@ -0,0 +1,384 @@
+/*
+ * File : timer.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-03-12 Bernard first version
+ * 2006-04-29 Bernard implement thread timer
+ * 2006-06-04 Bernard implement rt_timer_control
+ * 2006-08-10 Bernard fix the periodic timer bug
+ * 2006-09-03 Bernard implement rt_timer_detach
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+
+#include "kservice.h"
+
+/* #define TIMER_DEBUG */
+static rt_list_t rt_timer_list;
+
+#ifdef RT_USING_HOOK
+extern void (*rt_object_take_hook)(struct rt_object* object);
+extern void (*rt_object_put_hook)(struct rt_object* object);
+static void (*rt_timer_timeout_hook)(struct rt_timer* timer);
+
+/**
+ * @addtogroup Hook
+ */
+/*@{*/
+
+/**
+ * This function will set a hook function, which will be invoked when timer
+ * is timeout.
+ *
+ * @param hook the hook function
+ */
+void rt_timer_timeout_sethook(void (*hook)(struct rt_timer* timer))
+{
+ rt_timer_timeout_hook = hook;
+}
+
+/*@}*/
+#endif
+
+/**
+ * @ingroup SystemInit
+ *
+ * This function will init system timer
+ *
+ */
+void rt_system_timer_init()
+{
+ rt_list_init(&rt_timer_list);
+}
+
+static void _rt_timer_init(rt_timer_t timer,
+ void (*timeout)(void* parameter), void* parameter,
+ rt_tick_t time, rt_uint8_t flag)
+{
+ /* set flag */
+ timer->parent.flag = flag;
+
+ /* set deactivated */
+ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
+
+ timer->timeout_func = timeout;
+ timer->parameter = parameter;
+
+ timer->timeout_tick = 0;
+ timer->init_tick = time;
+
+ /* init timer list */
+ rt_list_init(&(timer->list));
+}
+
+/**
+ * @addtogroup Clock
+ */
+/*@{*/
+
+/**
+ * This function will init a timer, normally this function is used to initialize
+ * a static timer object.
+ *
+ * @param timer the static timer object
+ * @param name the name of timer
+ * @param timeout the timeout function
+ * @param parameter the parameter of timeout function
+ * @param time the tick of timer
+ * @param flag the flag of timer
+ */
+void rt_timer_init(rt_timer_t timer,
+ const char* name,
+ void (*timeout)(void* parameter), void* parameter,
+ rt_tick_t time, rt_uint8_t flag)
+{
+ /* timer check */
+ RT_ASSERT(timer != RT_NULL);
+
+ /* timer object init */
+ rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name);
+
+ _rt_timer_init(timer, timeout, parameter, time, flag);
+}
+
+/**
+ * This function will detach a timer from timer management.
+ *
+ * @param timer the static timer object
+ *
+ * @return the operation status, RT_EOK on OK; RT_ERROR on error
+ */
+rt_err_t rt_timer_detach(rt_timer_t timer)
+{
+ register rt_base_t level;
+
+ /* timer check */
+ RT_ASSERT(timer != RT_NULL);
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* remove it from timer list */
+ rt_list_remove(&(timer->list));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ rt_object_detach((rt_object_t)timer);
+
+ return -RT_EOK;
+}
+
+#ifdef RT_USING_HEAP
+/**
+ * This function will create a timer
+ *
+ * @param name the name of timer
+ * @param timeout the timeout function
+ * @param parameter the parameter of timeout function
+ * @param time the tick of timer
+ * @param flag the flag of timer
+ *
+ * @return the created timer object
+ */
+rt_timer_t rt_timer_create(const char* name, void (*timeout)(void* parameter), void* parameter, rt_tick_t time, rt_uint8_t flag)
+{
+ struct rt_timer* timer;
+
+ /* allocate a object */
+ timer = (struct rt_timer*)rt_object_allocate(RT_Object_Class_Timer, name);
+ if (timer == RT_NULL)
+ {
+ return RT_NULL;
+ }
+
+ _rt_timer_init(timer, timeout, parameter, time, flag);
+
+ return timer;
+}
+
+/**
+ * This function will delete a timer and release timer memory
+ *
+ * @param timer the timer to be deleted
+ *
+ * @return the operation status, RT_EOK on OK; RT_ERROR on error
+ *
+ */
+rt_err_t rt_timer_delete(rt_timer_t timer)
+{
+ register rt_base_t level;
+
+ /* timer check */
+ RT_ASSERT(timer != RT_NULL);
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* remove it from timer list */
+ rt_list_remove(&(timer->list));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ rt_object_delete((rt_object_t)timer);
+
+ return -RT_EOK;
+}
+#endif
+
+/**
+ * This function will start the timer
+ *
+ * @param timer the timer to be started
+ *
+ * @return the operation status, RT_EOK on OK; RT_ERROR on error
+ *
+ */
+rt_err_t rt_timer_start(rt_timer_t timer)
+{
+ rt_list_t *n;
+ struct rt_timer* t;
+ register rt_base_t level;
+
+ /* timer check */
+ RT_ASSERT(timer != RT_NULL);
+ if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) return -RT_ERROR;
+
+#ifdef RT_USING_HOOK
+ if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(timer->parent));
+#endif
+
+ timer->timeout_tick = rt_tick_get() + timer->init_tick;
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* insert timer to system timer list */
+ for (n = rt_timer_list.next; n != &rt_timer_list; n = n->next)
+ {
+ t = rt_list_entry(n, struct rt_timer, list);
+ if (t->timeout_tick > timer->timeout_tick)
+ {
+ rt_list_insert_before(n, &(timer->list));
+ break;
+ }
+ }
+
+ /* no found suitable position in timer list */
+ if (n == &rt_timer_list)
+ {
+ rt_list_insert_before(n, &(timer->list));
+ }
+
+ timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ return -RT_EOK;
+}
+
+/**
+ * This function will stop the timer
+ *
+ * @param timer the timer to be stopped
+ *
+ * @return the operation status, RT_EOK on OK; RT_ERROR on error
+ *
+ */
+rt_err_t rt_timer_stop(rt_timer_t timer)
+{
+ register rt_base_t level;
+
+ /* timer check */
+ RT_ASSERT(timer != RT_NULL);
+ if(!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)) return -RT_ERROR;
+
+#ifdef RT_USING_HOOK
+ if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(timer->parent));
+#endif
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* remove it from timer list */
+ rt_list_remove(&(timer->list));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will get or set some options of the timer
+ *
+ * @param timer the timer to be get or set
+ * @param cmd the control command
+ * @param arg the argument
+ *
+ * @return the operation status, RT_EOK on OK; RT_ERROR on error
+ *
+ */
+rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void* arg)
+{
+ /* timer check */
+ RT_ASSERT(timer != RT_NULL);
+
+ switch (cmd)
+ {
+ case RT_TIMER_CTRL_GET_TIME:
+ *(rt_tick_t*)arg = timer->init_tick;
+ break;
+
+ case RT_TIMER_CTRL_SET_TIME:
+ timer->init_tick = *(rt_tick_t*)arg;
+ break;
+
+ case RT_TIMER_CTRL_SET_ONESHOT:
+ timer->parent.flag &= ~(1 << RT_TIMER_FLAG_PERIODIC);
+ break;
+
+ case RT_TIMER_CTRL_SET_PERIODIC:
+ timer->parent.flag |= (1 << RT_TIMER_FLAG_PERIODIC);
+ break;
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will check timer list, if a timeout event happens, the
+ * corresponding timeout function will be invoked.
+ *
+ */
+void rt_timer_check()
+{
+ rt_tick_t current_tick;
+ rt_list_t *n;
+ struct rt_timer *t;
+ register rt_base_t level;
+
+#ifdef TIMER_DEBUG
+ rt_kprintf("timer check enter\n");
+#endif
+
+ current_tick = rt_tick_get();
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ for (n = rt_timer_list.next; n != &(rt_timer_list); )
+ {
+ t = rt_list_entry(n, struct rt_timer, list);
+ if (current_tick >= t->timeout_tick)
+ {
+#ifdef RT_USING_HOOK
+ if (rt_timer_timeout_hook != RT_NULL) rt_timer_timeout_hook(t);
+#endif
+ /* move node to the next */
+ n = n->next;
+
+ /* remove timer from timer list firstly */
+ rt_list_remove(&(t->list));
+
+ /* call timeout function */
+ t->timeout_func(t->parameter);
+
+ /* reget tick */
+ current_tick = rt_tick_get();
+
+#ifdef TIMER_DEBUG
+ rt_kprintf("current tick: %d\n", current_tick);
+#endif
+
+ /* change timer state */
+ t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
+
+ if (t->parent.flag & RT_TIMER_FLAG_PERIODIC)
+ {
+ /* start it */
+ rt_timer_start(t);
+ }
+ }
+ else break;
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+#ifdef TIMER_DEBUG
+ rt_kprintf("timer check leave\n");
+#endif
+}
+
+/*@}*/