1 /*
2 * Copyright (C) 2015-2017 Alibaba Group Holding Limited
3 */
4
5 #include "k_api.h"
6
7 #if (RHINO_CONFIG_WORKQUEUE > 0)
workqueue_is_exist(kworkqueue_t * workqueue)8 static kstat_t workqueue_is_exist(kworkqueue_t *workqueue)
9 {
10 CPSR_ALLOC();
11 kworkqueue_t *pos;
12
13 RHINO_CRITICAL_ENTER();
14
15 for (pos = krhino_list_entry(g_workqueue_list_head.next, kworkqueue_t, workqueue_node);
16 &pos->workqueue_node != &g_workqueue_list_head;
17 pos = krhino_list_entry(pos->workqueue_node.next, kworkqueue_t, workqueue_node)) {
18 if (pos == workqueue) {
19 RHINO_CRITICAL_EXIT();
20 return RHINO_WORKQUEUE_EXIST;
21 }
22 }
23
24 RHINO_CRITICAL_EXIT();
25 return RHINO_WORKQUEUE_NOT_EXIST;
26 }
27
worker_task(void * arg)28 static void worker_task(void *arg)
29 {
30 CPSR_ALLOC();
31 kstat_t ret;
32 kwork_t *work = NULL;
33 kworkqueue_t *queue = (kworkqueue_t *)arg;
34
35 while (1) {
36
37 ret = krhino_sem_take(&(queue->sem), RHINO_WAIT_FOREVER);
38 if (ret != RHINO_SUCCESS) {
39 k_err_proc(ret);
40 }
41
42 RHINO_CRITICAL_ENTER();
43
44 /* have work to do. */
45 work = krhino_list_entry(queue->work_list.next, kwork_t, work_node);
46 klist_rm_init(&(work->work_node));
47 queue->work_current = work;
48 work->work_exit = 0;
49 RHINO_CRITICAL_EXIT();
50
51 /* do work */
52 work->handle(work->arg);
53 RHINO_CRITICAL_ENTER();
54 /* clean current work */
55 queue->work_current = NULL;
56
57 RHINO_CRITICAL_EXIT();
58 }
59 }
60
krhino_workqueue_create(kworkqueue_t * workqueue,const name_t * name,uint8_t pri,cpu_stack_t * stack_buf,size_t stack_size)61 kstat_t krhino_workqueue_create(kworkqueue_t *workqueue, const name_t *name,
62 uint8_t pri, cpu_stack_t *stack_buf, size_t stack_size)
63 {
64 CPSR_ALLOC();
65 kstat_t ret;
66
67 NULL_PARA_CHK(workqueue);
68 NULL_PARA_CHK(name);
69 NULL_PARA_CHK(stack_buf);
70
71 if (pri >= RHINO_CONFIG_PRI_MAX) {
72 return RHINO_BEYOND_MAX_PRI;
73 }
74
75 if (stack_size == 0u) {
76 return RHINO_TASK_INV_STACK_SIZE;
77 }
78
79 ret = workqueue_is_exist(workqueue);
80 if (ret == RHINO_WORKQUEUE_EXIST) {
81 return RHINO_WORKQUEUE_EXIST;
82 }
83
84 klist_init(&(workqueue->workqueue_node));
85 klist_init(&(workqueue->work_list));
86 workqueue->work_current = NULL;
87 workqueue->name = name;
88
89 ret = krhino_sem_create(&(workqueue->sem), "WORKQUEUE-SEM", 0);
90 if (ret != RHINO_SUCCESS) {
91 return ret;
92 }
93
94 RHINO_CRITICAL_ENTER();
95 klist_insert(&g_workqueue_list_head, &(workqueue->workqueue_node));
96 RHINO_CRITICAL_EXIT();
97
98 ret = krhino_task_create(&(workqueue->worker), name, (void *)workqueue, pri,
99 0, stack_buf, stack_size, worker_task, 1);
100 if (ret != RHINO_SUCCESS) {
101 RHINO_CRITICAL_ENTER();
102 klist_rm_init(&(workqueue->workqueue_node));
103 RHINO_CRITICAL_EXIT();
104 krhino_sem_del(&(workqueue->sem));
105 return ret;
106 }
107
108 TRACE_WORKQUEUE_CREATE(krhino_cur_task_get(), workqueue);
109
110 return RHINO_SUCCESS;
111 }
112
krhino_workqueue_del(kworkqueue_t * workqueue)113 kstat_t krhino_workqueue_del(kworkqueue_t *workqueue)
114 {
115 CPSR_ALLOC();
116 kstat_t ret;
117
118 NULL_PARA_CHK(workqueue);
119
120 ret = workqueue_is_exist(workqueue);
121 if (ret == RHINO_WORKQUEUE_NOT_EXIST) {
122 return RHINO_WORKQUEUE_NOT_EXIST;
123 }
124
125 RHINO_CRITICAL_ENTER();
126
127 if (!is_klist_empty(&(workqueue->work_list))) {
128 RHINO_CRITICAL_EXIT();
129 return RHINO_WORKQUEUE_BUSY;
130 }
131
132 if (workqueue->work_current != NULL) {
133 RHINO_CRITICAL_EXIT();
134 return RHINO_WORKQUEUE_BUSY;
135 }
136
137 RHINO_CRITICAL_EXIT();
138
139 ret = krhino_task_del(&(workqueue->worker));
140 if (ret != RHINO_SUCCESS) {
141 return ret;
142 }
143
144 ret = krhino_sem_del(&(workqueue->sem));
145 if (ret != RHINO_SUCCESS) {
146 return ret;
147 }
148
149 RHINO_CRITICAL_ENTER();
150 klist_rm_init(&(workqueue->workqueue_node));
151 TRACE_WORKQUEUE_DEL(g_active_task[cpu_cur_get()], workqueue);
152 RHINO_CRITICAL_EXIT();
153
154 return RHINO_SUCCESS;
155 }
156
work_timer_cb(void * timer,void * arg)157 static void work_timer_cb(void *timer, void *arg)
158 {
159 CPSR_ALLOC();
160 kstat_t ret;
161 kwork_t *work = ((ktimer_t *)timer)->priv;
162 kworkqueue_t *wq = (kworkqueue_t *)arg;
163
164 RHINO_CRITICAL_ENTER();
165 if (wq->work_current == work) {
166 RHINO_CRITICAL_EXIT();
167 return;
168 }
169
170 if (work->work_exit == 1) {
171 RHINO_CRITICAL_EXIT();
172 return;
173 }
174
175 /* NOTE: the work MUST be initialized firstly */
176 klist_rm_init(&(work->work_node));
177 klist_insert(&(wq->work_list), &(work->work_node));
178
179 work->wq = wq;
180 work->work_exit = 1;
181 RHINO_CRITICAL_EXIT();
182
183 ret = krhino_sem_give(&(wq->sem));
184 if (ret != RHINO_SUCCESS) {
185 return;
186 }
187
188 }
189
krhino_work_init(kwork_t * work,work_handle_t handle,void * arg,tick_t dly)190 kstat_t krhino_work_init(kwork_t *work, work_handle_t handle, void *arg,
191 tick_t dly)
192 {
193 kstat_t ret;
194
195 if (work == NULL) {
196 return RHINO_NULL_PTR;
197 }
198
199 if (handle == NULL) {
200 return RHINO_NULL_PTR;
201 }
202
203 NULL_PARA_CHK(work);
204 NULL_PARA_CHK(handle);
205
206 memset(work, 0, sizeof(kwork_t));
207
208 klist_init(&(work->work_node));
209 work->handle = handle;
210 work->arg = arg;
211 work->dly = dly;
212 work->wq = NULL;
213
214 if (dly > 0) {
215 ret = krhino_timer_dyn_create((ktimer_t **)(&work->timer), "WORK-TIMER", work_timer_cb,
216 work->dly, 0, (void *)work, 0);
217 if (ret != RHINO_SUCCESS) {
218 return ret;
219 }
220 }
221
222 TRACE_WORK_INIT(krhino_cur_task_get(), work);
223
224 return RHINO_SUCCESS;
225 }
226
krhino_work_run(kworkqueue_t * workqueue,kwork_t * work)227 kstat_t krhino_work_run(kworkqueue_t *workqueue, kwork_t *work)
228 {
229 CPSR_ALLOC();
230 kstat_t ret;
231
232 NULL_PARA_CHK(workqueue);
233 NULL_PARA_CHK(work);
234
235 RHINO_CRITICAL_ENTER();
236
237 if (work->dly == 0) {
238 if (workqueue->work_current == work) {
239 RHINO_CRITICAL_EXIT();
240 return RHINO_WORKQUEUE_WORK_RUNNING;
241 }
242
243 if (work->work_exit == 1) {
244 RHINO_CRITICAL_EXIT();
245 return RHINO_WORKQUEUE_WORK_EXIST;
246 }
247
248 /* NOTE: the work MUST be initialized firstly */
249 klist_rm_init(&(work->work_node));
250 klist_insert(&(workqueue->work_list), &(work->work_node));
251
252 work->wq = workqueue;
253 work->work_exit = 1;
254
255 RHINO_CRITICAL_EXIT();
256 ret = krhino_sem_give(&(workqueue->sem));
257 if (ret != RHINO_SUCCESS) {
258 return ret;
259 }
260
261 } else {
262 work->timer->priv = work;
263 RHINO_CRITICAL_EXIT();
264 ret = krhino_timer_arg_change_auto(work->timer, (void *)workqueue);
265 if (ret != RHINO_SUCCESS) {
266 return ret;
267 }
268 }
269
270 return RHINO_SUCCESS;
271 }
272
krhino_work_sched(kwork_t * work)273 kstat_t krhino_work_sched(kwork_t *work)
274 {
275 return krhino_work_run(&g_workqueue_default, work);
276 }
277
krhino_work_cancel(kwork_t * work)278 kstat_t krhino_work_cancel(kwork_t *work)
279 {
280 CPSR_ALLOC();
281 kworkqueue_t *wq;
282
283 NULL_PARA_CHK(work);
284
285 wq = (kworkqueue_t *)work->wq;
286
287 if (wq == NULL) {
288 if (work->dly > 0) {
289 krhino_timer_stop(work->timer);
290 }
291 return RHINO_SUCCESS;
292 }
293
294 RHINO_CRITICAL_ENTER();
295 if (wq->work_current == work) {
296 RHINO_CRITICAL_EXIT();
297 return RHINO_WORKQUEUE_WORK_RUNNING;
298 }
299
300 if (work->work_exit == 1) {
301 RHINO_CRITICAL_EXIT();
302 return RHINO_WORKQUEUE_WORK_EXIST;
303 }
304
305 klist_rm_init(&(work->work_node));
306 work->wq = NULL;
307 RHINO_CRITICAL_EXIT();
308
309 return RHINO_SUCCESS;
310 }
311
workqueue_init(void)312 void workqueue_init(void)
313 {
314 klist_init(&g_workqueue_list_head);
315
316 krhino_workqueue_create(&g_workqueue_default, "DEFAULT-WORKQUEUE",
317 RHINO_CONFIG_WORKQUEUE_TASK_PRIO, g_workqueue_stack,
318 RHINO_CONFIG_WORKQUEUE_STACK_SIZE);
319 }
320 #endif
321
322