浏览代码

[Drivers] Add workqueue implementation.

bernard 10 年之前
父节点
当前提交
005014e7d0
共有 2 个文件被更改,包括 136 次插入0 次删除
  1. 34 0
      components/drivers/include/rtdevice.h
  2. 102 0
      components/drivers/src/workqueue.c

+ 34 - 0
components/drivers/include/rtdevice.h

@@ -20,6 +20,7 @@
  * Change Logs:
  * Date           Author       Notes
  * 2012-01-08     bernard      first version.
+ * 2014-07-12     bernard      Add workqueue implementation.
  */
 
 #ifndef __RT_DEVICE_H__
@@ -143,6 +144,21 @@ struct rt_data_queue
     void (*evt_notify)(struct rt_data_queue *queue, rt_uint32_t event);
 };
 
+/* workqueue implementation */
+struct rt_workqueue
+{
+	rt_list_t   work_list;
+	rt_thread_t work_thread;
+};
+
+struct rt_work
+{
+	rt_list_t list;
+
+	void (*work_func)(struct rt_work* work, void* work_data);
+	void *work_data;
+};
+
 /**
  * Completion
  */
@@ -274,6 +290,24 @@ rt_err_t rt_data_queue_peak(struct rt_data_queue *queue,
                             rt_size_t            *size);
 void rt_data_queue_reset(struct rt_data_queue *queue);
 
+#ifdef RT_USING_HEAP
+/**
+ * WorkQueue for DeviceDriver
+ */
+struct rt_workqueue *rt_workqueue_create(const char* name, rt_uint16_t stack_size, rt_uint8_t priority);
+rt_err_t rt_workqueue_destroy(struct rt_workqueue* queue);
+rt_err_t rt_workqueue_dowork(struct rt_workqueue* queue, struct rt_work* work);
+rt_err_t rt_workqueue_cancel_work(struct rt_workqueue* queue, struct rt_work* work);
+
+rt_inline void rt_work_init(struct rt_work* work, void (*work_func)(struct rt_work* work, void* work_data), 
+    void* work_data)
+{
+    rt_list_init(&(work->list));
+    work->work_func = work_func;
+    work->work_data = work_data;
+}
+#endif
+
 #ifdef RT_USING_RTC
 #include "drivers/rtc.h"
 #ifdef RT_USING_ALARM

+ 102 - 0
components/drivers/src/workqueue.c

@@ -0,0 +1,102 @@
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#ifdef RT_USING_HEAP
+static void _workqueue_thread_entry(void* parameter)
+{
+	struct rt_work* work;
+	struct rt_workqueue* queue;
+	
+	queue = (struct rt_workqueue*) parameter;
+	RT_ASSERT(queue != RT_NULL);
+
+	while (1)
+	{
+		if (rt_list_isempty(&(queue->work_list)))
+		{
+			/* no software timer exist, suspend self. */
+			rt_thread_suspend(rt_thread_self());
+			rt_schedule();
+		}
+
+		/* we have work to do with. */
+		rt_enter_critical();
+		work = rt_list_entry(queue->work_list.next, struct rt_work, list);
+		rt_list_remove(&(work->list));
+		rt_exit_critical();
+
+		/* do work */
+		work->work_func(work, work->work_data);
+	}
+}
+
+struct rt_workqueue *rt_workqueue_create(const char* name, rt_uint16_t stack_size, rt_uint8_t priority)
+{
+	struct rt_workqueue *queue = RT_NULL;
+
+	queue = (struct rt_workqueue*)RT_KERNEL_MALLOC(sizeof(struct rt_workqueue));
+	if (queue != RT_NULL)
+	{
+        /* initialize work list */
+        rt_list_init(&(queue->work_list));
+        
+		/* create the work thread */
+		queue->work_thread = rt_thread_create(name, _workqueue_thread_entry, queue, stack_size, priority, 10);
+		if (queue->work_thread == RT_NULL)
+		{
+			RT_KERNEL_FREE(queue);
+			return RT_NULL;
+		}
+
+		rt_thread_startup(queue->work_thread);
+	}
+
+	return queue;
+}
+
+rt_err_t rt_workqueue_destroy(struct rt_workqueue* queue)
+{
+	RT_ASSERT(queue != RT_NULL);
+
+	rt_thread_delete(queue->work_thread);
+	RT_KERNEL_FREE(queue);
+
+	return RT_EOK;
+}
+
+rt_err_t rt_workqueue_dowork(struct rt_workqueue* queue, struct rt_work* work)
+{
+	RT_ASSERT(queue != RT_NULL);
+	RT_ASSERT(work != RT_NULL);
+
+	rt_enter_critical();
+	/* NOTE: the work MUST be initialized firstly */
+	rt_list_remove(&(work->list));
+
+	rt_list_insert_after(queue->work_list.prev, &(work->list));
+	if (queue->work_thread->stat != RT_THREAD_READY)
+	{
+		rt_exit_critical();
+		/* resume work thread */
+		rt_thread_resume(queue->work_thread);
+		rt_schedule();
+	}
+	else rt_exit_critical();
+
+	return RT_EOK;
+}
+
+rt_err_t rt_workqueue_cancel_work(struct rt_workqueue* queue, struct rt_work* work)
+{
+	RT_ASSERT(queue != RT_NULL);
+	RT_ASSERT(work != RT_NULL);
+
+	rt_enter_critical();
+	rt_list_remove(&(work->list));
+	rt_exit_critical();
+
+	return RT_EOK;
+}
+
+#endif
+