|
| 1 | +/* |
| 2 | + * File : workqueue.c |
| 3 | + * This file is part of RT-Thread RTOS |
| 4 | + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team |
| 5 | + * |
| 6 | + * This program is free software; you can redistribute it and/or modify |
| 7 | + * it under the terms of the GNU General Public License as published by |
| 8 | + * the Free Software Foundation; either version 2 of the License, or |
| 9 | + * (at your option) any later version. |
| 10 | + * |
| 11 | + * This program is distributed in the hope that it will be useful, |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | + * GNU General Public License for more details. |
| 15 | + * |
| 16 | + * You should have received a copy of the GNU General Public License along |
| 17 | + * with this program; if not, write to the Free Software Foundation, Inc., |
| 18 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| 19 | + * |
| 20 | + * Change Logs: |
| 21 | + * Date Author Notes |
| 22 | + * 2017-02-27 bernard fix the re-work issue. |
| 23 | + */ |
| 24 | + |
| 25 | +#include <rthw.h> |
1 | 26 | #include <rtthread.h> |
2 | 27 | #include <rtdevice.h> |
3 | 28 |
|
4 | 29 | #ifdef RT_USING_HEAP |
5 | 30 | static void _workqueue_thread_entry(void* parameter) |
6 | 31 | { |
7 | | - struct rt_work* work; |
8 | | - struct rt_workqueue* queue; |
9 | | - |
10 | | - queue = (struct rt_workqueue*) parameter; |
11 | | - RT_ASSERT(queue != RT_NULL); |
12 | | - |
13 | | - while (1) |
14 | | - { |
15 | | - if (rt_list_isempty(&(queue->work_list))) |
16 | | - { |
17 | | - /* no software timer exist, suspend self. */ |
18 | | - rt_thread_suspend(rt_thread_self()); |
19 | | - rt_schedule(); |
20 | | - } |
21 | | - |
22 | | - /* we have work to do with. */ |
23 | | - rt_enter_critical(); |
24 | | - work = rt_list_entry(queue->work_list.next, struct rt_work, list); |
25 | | - rt_list_remove(&(work->list)); |
26 | | - rt_exit_critical(); |
27 | | - |
28 | | - /* do work */ |
29 | | - work->work_func(work, work->work_data); |
30 | | - } |
| 32 | + rt_base_t level; |
| 33 | + struct rt_work* work; |
| 34 | + struct rt_workqueue* queue; |
| 35 | + |
| 36 | + queue = (struct rt_workqueue*) parameter; |
| 37 | + RT_ASSERT(queue != RT_NULL); |
| 38 | + |
| 39 | + while (1) |
| 40 | + { |
| 41 | + if (rt_list_isempty(&(queue->work_list))) |
| 42 | + { |
| 43 | + /* no software timer exist, suspend self. */ |
| 44 | + rt_thread_suspend(rt_thread_self()); |
| 45 | + rt_schedule(); |
| 46 | + } |
| 47 | + |
| 48 | + /* we have work to do with. */ |
| 49 | + level = rt_hw_interrupt_disable(); |
| 50 | + work = rt_list_entry(queue->work_list.next, struct rt_work, list); |
| 51 | + rt_list_remove(&(work->list)); |
| 52 | + queue->work_current = work; |
| 53 | + rt_hw_interrupt_enable(level); |
| 54 | + |
| 55 | + /* do work */ |
| 56 | + work->work_func(work, work->work_data); |
| 57 | + level = rt_hw_interrupt_disable(); |
| 58 | + /* clean current work */ |
| 59 | + queue->work_current = RT_NULL; |
| 60 | + rt_hw_interrupt_enable(level); |
| 61 | + } |
31 | 62 | } |
32 | 63 |
|
33 | 64 | struct rt_workqueue *rt_workqueue_create(const char* name, rt_uint16_t stack_size, rt_uint8_t priority) |
34 | 65 | { |
35 | | - struct rt_workqueue *queue = RT_NULL; |
| 66 | + struct rt_workqueue *queue = RT_NULL; |
36 | 67 |
|
37 | | - queue = (struct rt_workqueue*)RT_KERNEL_MALLOC(sizeof(struct rt_workqueue)); |
38 | | - if (queue != RT_NULL) |
39 | | - { |
| 68 | + queue = (struct rt_workqueue*)RT_KERNEL_MALLOC(sizeof(struct rt_workqueue)); |
| 69 | + if (queue != RT_NULL) |
| 70 | + { |
40 | 71 | /* initialize work list */ |
41 | 72 | rt_list_init(&(queue->work_list)); |
42 | | - |
43 | | - /* create the work thread */ |
44 | | - queue->work_thread = rt_thread_create(name, _workqueue_thread_entry, queue, stack_size, priority, 10); |
45 | | - if (queue->work_thread == RT_NULL) |
46 | | - { |
47 | | - RT_KERNEL_FREE(queue); |
48 | | - return RT_NULL; |
49 | | - } |
50 | | - |
51 | | - rt_thread_startup(queue->work_thread); |
52 | | - } |
53 | | - |
54 | | - return queue; |
| 73 | + queue->work_current = RT_NULL; |
| 74 | + |
| 75 | + /* create the work thread */ |
| 76 | + queue->work_thread = rt_thread_create(name, _workqueue_thread_entry, queue, stack_size, priority, 10); |
| 77 | + if (queue->work_thread == RT_NULL) |
| 78 | + { |
| 79 | + RT_KERNEL_FREE(queue); |
| 80 | + return RT_NULL; |
| 81 | + } |
| 82 | + |
| 83 | + rt_thread_startup(queue->work_thread); |
| 84 | + } |
| 85 | + |
| 86 | + return queue; |
55 | 87 | } |
56 | 88 |
|
57 | 89 | rt_err_t rt_workqueue_destroy(struct rt_workqueue* queue) |
58 | 90 | { |
59 | | - RT_ASSERT(queue != RT_NULL); |
| 91 | + RT_ASSERT(queue != RT_NULL); |
60 | 92 |
|
61 | | - rt_thread_delete(queue->work_thread); |
62 | | - RT_KERNEL_FREE(queue); |
| 93 | + rt_thread_delete(queue->work_thread); |
| 94 | + RT_KERNEL_FREE(queue); |
63 | 95 |
|
64 | | - return RT_EOK; |
| 96 | + return RT_EOK; |
65 | 97 | } |
66 | 98 |
|
67 | 99 | rt_err_t rt_workqueue_dowork(struct rt_workqueue* queue, struct rt_work* work) |
68 | 100 | { |
69 | | - RT_ASSERT(queue != RT_NULL); |
70 | | - RT_ASSERT(work != RT_NULL); |
71 | | - |
72 | | - rt_enter_critical(); |
73 | | - /* NOTE: the work MUST be initialized firstly */ |
74 | | - rt_list_remove(&(work->list)); |
75 | | - |
76 | | - rt_list_insert_after(queue->work_list.prev, &(work->list)); |
77 | | - if (queue->work_thread->stat != RT_THREAD_READY) |
78 | | - { |
79 | | - rt_exit_critical(); |
80 | | - /* resume work thread */ |
81 | | - rt_thread_resume(queue->work_thread); |
82 | | - rt_schedule(); |
83 | | - } |
84 | | - else rt_exit_critical(); |
85 | | - |
86 | | - return RT_EOK; |
| 101 | + rt_base_t level; |
| 102 | + RT_ASSERT(queue != RT_NULL); |
| 103 | + RT_ASSERT(work != RT_NULL); |
| 104 | + |
| 105 | + level = rt_hw_interrupt_disable(); |
| 106 | + if (queue->work_current == work) |
| 107 | + { |
| 108 | + rt_hw_interrupt_enable(level); |
| 109 | + return -RT_EBUSY; |
| 110 | + } |
| 111 | + |
| 112 | + /* NOTE: the work MUST be initialized firstly */ |
| 113 | + rt_list_remove(&(work->list)); |
| 114 | + |
| 115 | + rt_list_insert_after(queue->work_list.prev, &(work->list)); |
| 116 | + /* whether the workqueue is doing work */ |
| 117 | + if (queue->work_current == RT_NULL) |
| 118 | + { |
| 119 | + rt_hw_interrupt_enable(level); |
| 120 | + /* resume work thread */ |
| 121 | + rt_thread_resume(queue->work_thread); |
| 122 | + rt_schedule(); |
| 123 | + } |
| 124 | + else rt_hw_interrupt_enable(level); |
| 125 | + |
| 126 | + return RT_EOK; |
87 | 127 | } |
88 | 128 |
|
89 | 129 | rt_err_t rt_workqueue_critical_work(struct rt_workqueue* queue, struct rt_work* work) |
90 | 130 | { |
91 | | - RT_ASSERT(queue != RT_NULL); |
92 | | - RT_ASSERT(work != RT_NULL); |
93 | | - |
94 | | - rt_enter_critical(); |
95 | | - /* NOTE: the work MUST be initialized firstly */ |
96 | | - rt_list_remove(&(work->list)); |
97 | | - |
98 | | - rt_list_insert_after(queue->work_list.prev, &(work->list)); |
99 | | - if (queue->work_thread->stat != RT_THREAD_READY) |
100 | | - { |
101 | | - rt_exit_critical(); |
102 | | - /* resume work thread */ |
103 | | - rt_thread_resume(queue->work_thread); |
104 | | - rt_schedule(); |
105 | | - } |
106 | | - else rt_exit_critical(); |
107 | | - |
108 | | - return RT_EOK; |
| 131 | + rt_base_t level; |
| 132 | + RT_ASSERT(queue != RT_NULL); |
| 133 | + RT_ASSERT(work != RT_NULL); |
| 134 | + |
| 135 | + level = rt_hw_interrupt_disable(); |
| 136 | + if (queue->work_current == work) |
| 137 | + { |
| 138 | + rt_hw_interrupt_enable(level); |
| 139 | + return -RT_EBUSY; |
| 140 | + } |
| 141 | + |
| 142 | + /* NOTE: the work MUST be initialized firstly */ |
| 143 | + rt_list_remove(&(work->list)); |
| 144 | + |
| 145 | + rt_list_insert_after(queue->work_list.prev, &(work->list)); |
| 146 | + if (queue->work_current == RT_NULL) |
| 147 | + { |
| 148 | + rt_hw_interrupt_enable(level); |
| 149 | + /* resume work thread */ |
| 150 | + rt_thread_resume(queue->work_thread); |
| 151 | + rt_schedule(); |
| 152 | + } |
| 153 | + else rt_hw_interrupt_enable(level); |
| 154 | + |
| 155 | + return RT_EOK; |
109 | 156 | } |
110 | 157 |
|
111 | 158 | rt_err_t rt_workqueue_cancel_work(struct rt_workqueue* queue, struct rt_work* work) |
112 | 159 | { |
113 | | - RT_ASSERT(queue != RT_NULL); |
114 | | - RT_ASSERT(work != RT_NULL); |
| 160 | + rt_base_t level; |
| 161 | + |
| 162 | + RT_ASSERT(queue != RT_NULL); |
| 163 | + RT_ASSERT(work != RT_NULL); |
115 | 164 |
|
116 | | - rt_enter_critical(); |
117 | | - rt_list_remove(&(work->list)); |
118 | | - rt_exit_critical(); |
| 165 | + level = rt_hw_interrupt_disable(); |
| 166 | + if (queue->work_current == work) |
| 167 | + { |
| 168 | + rt_hw_interrupt_enable(level); |
| 169 | + return -RT_EBUSY; |
| 170 | + } |
| 171 | + rt_list_remove(&(work->list)); |
| 172 | + rt_hw_interrupt_enable(level); |
119 | 173 |
|
120 | | - return RT_EOK; |
| 174 | + return RT_EOK; |
121 | 175 | } |
122 | 176 |
|
123 | 177 | rt_err_t rt_workqueue_cancel_all_work(struct rt_workqueue* queue) |
124 | 178 | { |
125 | | - struct rt_list_node *node, *next; |
126 | | - RT_ASSERT(queue != RT_NULL); |
127 | | - |
128 | | - rt_enter_critical(); |
129 | | - for (node = queue->work_list.next; node != &(queue->work_list); node = next) |
130 | | - { |
131 | | - next = node->next; |
132 | | - rt_list_remove(node); |
133 | | - } |
134 | | - rt_exit_critical(); |
135 | | - |
136 | | - return RT_EOK; |
| 179 | + struct rt_list_node *node, *next; |
| 180 | + RT_ASSERT(queue != RT_NULL); |
| 181 | + |
| 182 | + rt_enter_critical(); |
| 183 | + for (node = queue->work_list.next; node != &(queue->work_list); node = next) |
| 184 | + { |
| 185 | + next = node->next; |
| 186 | + rt_list_remove(node); |
| 187 | + } |
| 188 | + rt_exit_critical(); |
| 189 | + |
| 190 | + return RT_EOK; |
137 | 191 | } |
138 | 192 |
|
139 | 193 | #endif |
|
0 commit comments