1 /*
2  * Copyright (C) 2015-2017 Alibaba Group Holding Limited
3  */
4 
5 #include "k_api.h"
6 
7 #if (RHINO_CONFIG_QUEUE > 0)
task_msg_recv(ktask_t * task,void * msg)8 RHINO_INLINE void task_msg_recv(ktask_t *task, void *msg)
9 {
10     task->msg = msg;
11     pend_task_wakeup(task);
12 }
13 
queue_create(kqueue_t * queue,const name_t * name,void ** start,size_t msg_num,uint8_t mm_alloc_flag)14 static kstat_t queue_create(kqueue_t *queue, const name_t *name, void **start,
15                             size_t msg_num, uint8_t mm_alloc_flag)
16 {
17 #if (RHINO_CONFIG_KOBJ_LIST > 0)
18     CPSR_ALLOC();
19 #endif
20 
21     NULL_PARA_CHK(queue);
22     NULL_PARA_CHK(start);
23     NULL_PARA_CHK(name);
24 
25     if (msg_num == 0u) {
26         return RHINO_INV_PARAM;
27     }
28 
29     memset(queue, 0, sizeof(kqueue_t));
30 
31     /* init the queue blocked list */
32     klist_init(&queue->blk_obj.blk_list);
33 
34     queue->blk_obj.name       = name;
35     queue->blk_obj.blk_policy = BLK_POLICY_PRI;
36     queue->msg_q.queue_start  = start;
37 
38     ringbuf_init(&queue->ringbuf, (void *)start, msg_num * sizeof(void *),
39                  RINGBUF_TYPE_FIX, sizeof(void *));
40 
41     queue->msg_q.size     = msg_num;
42     queue->msg_q.cur_num  = 0u;
43     queue->msg_q.peak_num = 0u;
44     queue->mm_alloc_flag  = mm_alloc_flag;
45 #if (RHINO_CONFIG_TASK_DEL > 0)
46     queue->blk_obj.cancel = 1u;
47 #endif
48 
49 #if (RHINO_CONFIG_KOBJ_LIST > 0)
50     RHINO_CRITICAL_ENTER();
51     klist_insert(&(g_kobj_list.queue_head), &queue->queue_item);
52     RHINO_CRITICAL_EXIT();
53 #endif
54 
55     queue->blk_obj.obj_type = RHINO_QUEUE_OBJ_TYPE;
56 
57     return RHINO_SUCCESS;
58 }
59 
krhino_queue_create(kqueue_t * queue,const name_t * name,void ** start,size_t msg_num)60 kstat_t krhino_queue_create(kqueue_t *queue, const name_t *name, void **start,
61                             size_t msg_num)
62 {
63     return queue_create(queue, name, start, msg_num, K_OBJ_STATIC_ALLOC);
64 }
65 
krhino_queue_del(kqueue_t * queue)66 kstat_t krhino_queue_del(kqueue_t *queue)
67 {
68     CPSR_ALLOC();
69     klist_t *blk_list_head;
70 
71     NULL_PARA_CHK(queue);
72 
73     RHINO_CRITICAL_ENTER();
74 
75     INTRPT_NESTED_LEVEL_CHK();
76 
77     if (queue->blk_obj.obj_type != RHINO_QUEUE_OBJ_TYPE) {
78         RHINO_CRITICAL_EXIT();
79         return RHINO_KOBJ_TYPE_ERR;
80     }
81 
82     if (queue->mm_alloc_flag != K_OBJ_STATIC_ALLOC) {
83         RHINO_CRITICAL_EXIT();
84         return RHINO_KOBJ_DEL_ERR;
85     }
86 
87     blk_list_head = &queue->blk_obj.blk_list;
88 
89     queue->blk_obj.obj_type = RHINO_OBJ_TYPE_NONE;
90 
91     /* all task blocked on this queue is waken up */
92     while (!is_klist_empty(blk_list_head)) {
93         pend_task_rm(krhino_list_entry(blk_list_head->next, ktask_t, task_list));
94     }
95 
96 #if (RHINO_CONFIG_KOBJ_LIST > 0)
97     klist_rm(&queue->queue_item);
98 #endif
99 
100     ringbuf_reset(&queue->ringbuf);
101 
102     RHINO_CRITICAL_EXIT_SCHED();
103 
104     return RHINO_SUCCESS;
105 }
106 
107 #if (RHINO_CONFIG_KOBJ_DYN_ALLOC > 0)
krhino_queue_dyn_create(kqueue_t ** queue,const name_t * name,size_t msg_num)108 kstat_t krhino_queue_dyn_create(kqueue_t **queue, const name_t *name,
109                                 size_t msg_num)
110 {
111     kstat_t   stat;
112     kqueue_t *queue_obj;
113     void     **msg_start;
114 
115     NULL_PARA_CHK(queue);
116 
117     queue_obj = krhino_mm_alloc(sizeof(kqueue_t));
118     if (queue_obj == NULL) {
119         return RHINO_NO_MEM;
120     }
121 
122     msg_start = krhino_mm_alloc(msg_num * sizeof(void *));
123     if (msg_start == NULL) {
124         krhino_mm_free(queue_obj);
125         return RHINO_NO_MEM;
126     }
127 
128     stat = queue_create(queue_obj, name, (void **)msg_start, msg_num,
129                         K_OBJ_DYN_ALLOC);
130     if (stat != RHINO_SUCCESS) {
131         krhino_mm_free(msg_start);
132         krhino_mm_free(queue_obj);
133         return stat;
134     }
135 
136     *queue = queue_obj;
137 
138     return stat;
139 }
140 
krhino_queue_dyn_del(kqueue_t * queue)141 kstat_t krhino_queue_dyn_del(kqueue_t *queue)
142 {
143     CPSR_ALLOC();
144     klist_t *blk_list_head;
145 
146     NULL_PARA_CHK(queue);
147 
148     RHINO_CRITICAL_ENTER();
149 
150     INTRPT_NESTED_LEVEL_CHK();
151 
152     if (queue->blk_obj.obj_type != RHINO_QUEUE_OBJ_TYPE) {
153         RHINO_CRITICAL_EXIT();
154         return RHINO_KOBJ_TYPE_ERR;
155     }
156 
157     if (queue->mm_alloc_flag != K_OBJ_DYN_ALLOC) {
158         RHINO_CRITICAL_EXIT();
159         return RHINO_KOBJ_DEL_ERR;
160     }
161 
162     blk_list_head = &queue->blk_obj.blk_list;
163 
164     queue->blk_obj.obj_type = RHINO_OBJ_TYPE_NONE;
165 
166     /* all task blocked on this queue is waken up */
167     while (!is_klist_empty(blk_list_head)) {
168         pend_task_rm(krhino_list_entry(blk_list_head->next, ktask_t, task_list));
169     }
170 
171 #if (RHINO_CONFIG_KOBJ_LIST > 0)
172     klist_rm(&queue->queue_item);
173 #endif
174 
175     ringbuf_reset(&queue->ringbuf);
176 
177     RHINO_CRITICAL_EXIT_SCHED();
178 
179     krhino_mm_free(queue->msg_q.queue_start);
180     krhino_mm_free(queue);
181 
182     return RHINO_SUCCESS;
183 }
184 #endif
185 
msg_send(kqueue_t * p_q,void * p_void,uint8_t opt_wake_all)186 static kstat_t msg_send(kqueue_t *p_q, void *p_void, uint8_t opt_wake_all)
187 {
188     CPSR_ALLOC();
189     klist_t *blk_list_head;
190 
191     NULL_PARA_CHK(p_q);
192 
193     RHINO_CRITICAL_ENTER();
194 
195     if (p_q->blk_obj.obj_type != RHINO_QUEUE_OBJ_TYPE) {
196         RHINO_CRITICAL_EXIT();
197         return RHINO_KOBJ_TYPE_ERR;
198     }
199 
200     if (p_q->msg_q.cur_num >= p_q->msg_q.size) {
201         RHINO_CRITICAL_EXIT();
202         return RHINO_QUEUE_FULL;
203     }
204 
205     blk_list_head = &p_q->blk_obj.blk_list;
206 
207     /* queue is not full here, if there is no blocked receive task */
208     if (is_klist_empty(blk_list_head)) {
209         p_q->msg_q.cur_num++;
210 
211         /* update peak_num for debug */
212         if (p_q->msg_q.cur_num > p_q->msg_q.peak_num) {
213             p_q->msg_q.peak_num = p_q->msg_q.cur_num;
214         }
215 
216         ringbuf_queue_push(&p_q->ringbuf, &p_void, sizeof(void *));
217 
218         RHINO_CRITICAL_EXIT();
219         return RHINO_SUCCESS;
220     }
221 
222     /* wake all the task blocked on this queue */
223     if (opt_wake_all) {
224         while (!is_klist_empty(blk_list_head)) {
225             task_msg_recv(krhino_list_entry(blk_list_head->next, ktask_t, task_list),
226                           p_void);
227         }
228     } else {
229         task_msg_recv(krhino_list_entry(blk_list_head->next, ktask_t, task_list),
230                       p_void);
231     }
232 
233     RHINO_CRITICAL_EXIT_SCHED();
234 
235     return RHINO_SUCCESS;
236 }
237 
krhino_queue_back_send(kqueue_t * queue,void * msg)238 kstat_t krhino_queue_back_send(kqueue_t *queue, void *msg)
239 {
240     return msg_send(queue, msg, WAKE_ONE_TASK);
241 }
242 
krhino_queue_all_send(kqueue_t * queue,void * msg)243 kstat_t krhino_queue_all_send(kqueue_t *queue, void *msg)
244 {
245     return msg_send(queue, msg, WAKE_ALL_TASK);
246 }
247 
krhino_queue_recv(kqueue_t * queue,tick_t ticks,void ** msg)248 kstat_t krhino_queue_recv(kqueue_t *queue, tick_t ticks, void **msg)
249 {
250     CPSR_ALLOC();
251     kstat_t ret;
252     uint8_t cur_cpu_num;
253 
254     NULL_PARA_CHK(queue);
255     NULL_PARA_CHK(msg);
256 
257     RHINO_CRITICAL_ENTER();
258 
259     cur_cpu_num = cpu_cur_get();
260     TASK_CANCEL_CHK(queue);
261 
262     if ((g_intrpt_nested_level[cur_cpu_num] > 0u) && (ticks != RHINO_NO_WAIT)) {
263         RHINO_CRITICAL_EXIT();
264         return RHINO_NOT_CALLED_BY_INTRPT;
265     }
266 
267     if (queue->blk_obj.obj_type != RHINO_QUEUE_OBJ_TYPE) {
268         RHINO_CRITICAL_EXIT();
269         return RHINO_KOBJ_TYPE_ERR;
270     }
271 
272     /* if queue has msgs, just receive it */
273     if (queue->msg_q.cur_num > 0u) {
274 
275         ringbuf_queue_pop(&queue->ringbuf, msg, NULL);
276 
277         queue->msg_q.cur_num--;
278 
279         RHINO_CRITICAL_EXIT();
280 
281         return RHINO_SUCCESS;
282     }
283 
284     if (ticks == RHINO_NO_WAIT) {
285         *msg = NULL;
286         RHINO_CRITICAL_EXIT();
287 
288         return RHINO_NO_PEND_WAIT;
289     }
290 
291     /* if system is locked, block operation is not allowed */
292     if (g_sched_lock[cur_cpu_num] > 0u) {
293         *msg = NULL;
294         RHINO_CRITICAL_EXIT();
295         return RHINO_SCHED_DISABLE;
296     }
297 
298     pend_to_blk_obj(&queue->blk_obj, g_active_task[cur_cpu_num], ticks);
299 
300     RHINO_CRITICAL_EXIT_SCHED();
301 
302     RHINO_CPU_INTRPT_DISABLE();
303 
304     cur_cpu_num = cpu_cur_get();
305 
306     ret = pend_state_end_proc(g_active_task[cur_cpu_num], &queue->blk_obj);
307 
308     switch (ret) {
309         case RHINO_SUCCESS:
310             *msg = g_active_task[cur_cpu_num]->msg;
311             break;
312         default:
313             *msg = NULL;
314             break;
315     }
316 
317     RHINO_CPU_INTRPT_ENABLE();
318 
319     return ret;
320 }
321 
krhino_queue_is_full(kqueue_t * queue)322 kstat_t krhino_queue_is_full(kqueue_t *queue)
323 {
324     CPSR_ALLOC();
325     kstat_t ret;
326 
327     NULL_PARA_CHK(queue);
328 
329     RHINO_CRITICAL_ENTER();
330 
331     if (queue->blk_obj.obj_type != RHINO_QUEUE_OBJ_TYPE) {
332         RHINO_CRITICAL_EXIT();
333         return RHINO_KOBJ_TYPE_ERR;
334     }
335 
336     if (queue->msg_q.cur_num >= queue->msg_q.size) {
337         ret = RHINO_QUEUE_FULL;
338     } else {
339         ret = RHINO_QUEUE_NOT_FULL;
340     }
341 
342     RHINO_CRITICAL_EXIT();
343 
344     return ret;
345 }
346 
krhino_queue_flush(kqueue_t * queue)347 kstat_t krhino_queue_flush(kqueue_t *queue)
348 {
349     CPSR_ALLOC();
350 
351     NULL_PARA_CHK(queue);
352 
353     RHINO_CRITICAL_ENTER();
354 
355     INTRPT_NESTED_LEVEL_CHK();
356 
357     if (queue->blk_obj.obj_type != RHINO_QUEUE_OBJ_TYPE) {
358         RHINO_CRITICAL_EXIT();
359         return RHINO_KOBJ_TYPE_ERR;
360     }
361 
362     queue->msg_q.cur_num = 0u;
363     ringbuf_reset(&queue->ringbuf);
364 
365     RHINO_CRITICAL_EXIT();
366 
367     return RHINO_SUCCESS;
368 }
369 
krhino_queue_info_get(kqueue_t * queue,msg_info_t * info)370 kstat_t krhino_queue_info_get(kqueue_t *queue, msg_info_t *info)
371 {
372     CPSR_ALLOC();
373     klist_t *blk_list_head;
374 
375     if (queue == NULL) {
376         return RHINO_NULL_PTR;
377     }
378 
379     if (info == NULL) {
380         return RHINO_NULL_PTR;
381     }
382 
383     NULL_PARA_CHK(queue);
384     NULL_PARA_CHK(info);
385 
386     RHINO_CPU_INTRPT_DISABLE();
387 
388     if (queue->blk_obj.obj_type != RHINO_QUEUE_OBJ_TYPE) {
389         RHINO_CPU_INTRPT_ENABLE();
390         return RHINO_KOBJ_TYPE_ERR;
391     }
392 
393     blk_list_head           = &queue->blk_obj.blk_list;
394 
395     info->msg_q.peak_num    = queue->msg_q.peak_num;
396     info->msg_q.cur_num     = queue->msg_q.cur_num;
397     info->msg_q.queue_start = queue->msg_q.queue_start;
398     info->msg_q.size        = queue->msg_q.size;
399     info->pend_entry        = blk_list_head->next;
400 
401     RHINO_CPU_INTRPT_ENABLE();
402 
403     return RHINO_SUCCESS;
404 }
405 #endif
406 
407