1 /*
2  * Copyright (C) 2015-2017 Alibaba Group Holding Limited
3  */
4 
5 #include "k_api.h"
6 
7 #if (RHINO_CONFIG_SEM > 0)
sem_create(ksem_t * sem,const name_t * name,sem_count_t count,uint8_t mm_alloc_flag)8 static kstat_t sem_create(ksem_t *sem, const name_t *name, sem_count_t count,
9                           uint8_t mm_alloc_flag)
10 {
11 #if (RHINO_CONFIG_KOBJ_LIST > 0)
12     CPSR_ALLOC();
13 #endif
14 
15     NULL_PARA_CHK(sem);
16     NULL_PARA_CHK(name);
17 
18     memset(sem, 0, sizeof(ksem_t));
19 
20     /* init the list */
21     klist_init(&sem->blk_obj.blk_list);
22 
23     /* init resource */
24     sem->count              = count;
25     sem->peak_count         = count;
26     sem->blk_obj.name       = name;
27     sem->blk_obj.blk_policy = BLK_POLICY_PRI;
28     sem->mm_alloc_flag      = mm_alloc_flag;
29 #if (RHINO_CONFIG_TASK_DEL > 0)
30     sem->blk_obj.cancel     = 1u;
31 #endif
32 
33 #if (RHINO_CONFIG_KOBJ_LIST > 0)
34     RHINO_CRITICAL_ENTER();
35     klist_insert(&(g_kobj_list.sem_head), &sem->sem_item);
36     RHINO_CRITICAL_EXIT();
37 #endif
38 
39     sem->blk_obj.obj_type = RHINO_SEM_OBJ_TYPE;
40 
41     TRACE_SEM_CREATE(krhino_cur_task_get(), sem);
42 
43     return RHINO_SUCCESS;
44 }
45 
krhino_sem_create(ksem_t * sem,const name_t * name,sem_count_t count)46 kstat_t krhino_sem_create(ksem_t *sem, const name_t *name, sem_count_t count)
47 {
48     return sem_create(sem, name, count, K_OBJ_STATIC_ALLOC);
49 }
50 
krhino_sem_del(ksem_t * sem)51 kstat_t krhino_sem_del(ksem_t *sem)
52 {
53     CPSR_ALLOC();
54     klist_t *blk_list_head;
55 
56     NULL_PARA_CHK(sem);
57 
58     RHINO_CRITICAL_ENTER();
59 
60     INTRPT_NESTED_LEVEL_CHK();
61 
62     if (sem->blk_obj.obj_type != RHINO_SEM_OBJ_TYPE) {
63         RHINO_CRITICAL_EXIT();
64         return RHINO_KOBJ_TYPE_ERR;
65     }
66 
67     if (sem->mm_alloc_flag != K_OBJ_STATIC_ALLOC) {
68         RHINO_CRITICAL_EXIT();
69         return RHINO_KOBJ_DEL_ERR;
70     }
71 
72     blk_list_head = &sem->blk_obj.blk_list;
73     sem->blk_obj.obj_type = RHINO_OBJ_TYPE_NONE;
74 
75     /* all task blocked on this queue is waken up */
76     while (!is_klist_empty(blk_list_head)) {
77         pend_task_rm(krhino_list_entry(blk_list_head->next, ktask_t, task_list));
78     }
79 
80 #if (RHINO_CONFIG_KOBJ_LIST > 0)
81     klist_rm(&sem->sem_item);
82 #endif
83 
84     TRACE_SEM_DEL(g_active_task[cpu_cur_get()], sem);
85     RHINO_CRITICAL_EXIT_SCHED();
86 
87     return RHINO_SUCCESS;
88 }
89 
90 #if (RHINO_CONFIG_KOBJ_DYN_ALLOC > 0)
krhino_sem_dyn_create(ksem_t ** sem,const name_t * name,sem_count_t count)91 kstat_t krhino_sem_dyn_create(ksem_t **sem, const name_t *name,
92                               sem_count_t count)
93 {
94     kstat_t  stat;
95     ksem_t  *sem_obj;
96 
97     NULL_PARA_CHK(sem);
98 
99     sem_obj = krhino_mm_alloc(sizeof(ksem_t));
100 
101     if (sem_obj == NULL) {
102         return RHINO_NO_MEM;
103     }
104 
105     stat = sem_create(sem_obj, name, count, K_OBJ_DYN_ALLOC);
106 
107     if (stat != RHINO_SUCCESS) {
108         krhino_mm_free(sem_obj);
109         return stat;
110     }
111 
112     *sem = sem_obj;
113 
114     return stat;
115 }
116 
krhino_sem_dyn_del(ksem_t * sem)117 kstat_t krhino_sem_dyn_del(ksem_t *sem)
118 {
119     CPSR_ALLOC();
120     klist_t *blk_list_head;
121 
122     NULL_PARA_CHK(sem);
123 
124     RHINO_CRITICAL_ENTER();
125 
126     INTRPT_NESTED_LEVEL_CHK();
127 
128     if (sem->blk_obj.obj_type != RHINO_SEM_OBJ_TYPE) {
129         RHINO_CRITICAL_EXIT();
130         return RHINO_KOBJ_TYPE_ERR;
131     }
132 
133     if (sem->mm_alloc_flag != K_OBJ_DYN_ALLOC) {
134         RHINO_CRITICAL_EXIT();
135         return RHINO_KOBJ_DEL_ERR;
136     }
137 
138     blk_list_head = &sem->blk_obj.blk_list;
139     sem->blk_obj.obj_type = RHINO_OBJ_TYPE_NONE;
140 
141     /* all task blocked on this queue is waken up */
142     while (!is_klist_empty(blk_list_head)) {
143         pend_task_rm(krhino_list_entry(blk_list_head->next, ktask_t, task_list));
144     }
145 
146 #if (RHINO_CONFIG_KOBJ_LIST > 0)
147     klist_rm(&sem->sem_item);
148 #endif
149 
150     TRACE_SEM_DEL(g_active_task[cpu_cur_get()], sem);
151     RHINO_CRITICAL_EXIT_SCHED();
152 
153     krhino_mm_free(sem);
154 
155     return RHINO_SUCCESS;
156 }
157 
158 #endif
159 
sem_give(ksem_t * sem,uint8_t opt_wake_all)160 static kstat_t sem_give(ksem_t *sem, uint8_t opt_wake_all)
161 {
162     CPSR_ALLOC();
163     uint8_t  cur_cpu_num;
164     klist_t *blk_list_head;
165 
166     RHINO_CRITICAL_ENTER();
167 
168     if (sem->blk_obj.obj_type != RHINO_SEM_OBJ_TYPE) {
169         RHINO_CRITICAL_EXIT();
170         return RHINO_KOBJ_TYPE_ERR;
171     }
172 
173     cur_cpu_num = cpu_cur_get();
174     (void)cur_cpu_num;
175 
176     blk_list_head = &sem->blk_obj.blk_list;
177 
178     if (is_klist_empty(blk_list_head)) {
179         if (sem->count == (sem_count_t)-1) {
180 
181             TRACE_SEM_OVERFLOW(g_active_task[cur_cpu_num], sem);
182             RHINO_CRITICAL_EXIT();
183 
184             return RHINO_SEM_OVF;
185         }
186 
187         /* increase resource */
188         sem->count++;
189 
190         if (sem->count > sem->peak_count) {
191             sem->peak_count = sem->count;
192         }
193 
194         TRACE_SEM_CNT_INCREASE(g_active_task[cur_cpu_num], sem);
195         RHINO_CRITICAL_EXIT();
196         return RHINO_SUCCESS;
197     }
198 
199     /* wake all the task blocked on this semaphore */
200     if (opt_wake_all) {
201         while (!is_klist_empty(blk_list_head)) {
202             TRACE_SEM_TASK_WAKE(g_active_task[cur_cpu_num],
203                                 krhino_list_entry(blk_list_head->next, ktask_t, task_list),
204                                 sem, opt_wake_all);
205 
206             pend_task_wakeup(krhino_list_entry(blk_list_head->next, ktask_t, task_list));
207         }
208     } else {
209         TRACE_SEM_TASK_WAKE(g_active_task[cur_cpu_num],
210                             krhino_list_entry(blk_list_head->next, ktask_t, task_list),
211                             sem, opt_wake_all);
212 
213         /* wake up the highest prio task block on the semaphore */
214         pend_task_wakeup(krhino_list_entry(blk_list_head->next, ktask_t, task_list));
215     }
216 
217     TRACE_SEM_GIVE(sem, opt_wake_all);
218     RHINO_CRITICAL_EXIT_SCHED();
219 
220     return RHINO_SUCCESS;
221 }
222 
krhino_sem_give(ksem_t * sem)223 kstat_t krhino_sem_give(ksem_t *sem)
224 {
225     NULL_PARA_CHK(sem);
226 
227     return sem_give(sem, WAKE_ONE_SEM);
228 }
229 
krhino_sem_give_all(ksem_t * sem)230 kstat_t krhino_sem_give_all(ksem_t *sem)
231 {
232     NULL_PARA_CHK(sem);
233 
234     return sem_give(sem, WAKE_ALL_SEM);
235 }
236 
krhino_sem_take(ksem_t * sem,tick_t ticks)237 kstat_t krhino_sem_take(ksem_t *sem, tick_t ticks)
238 {
239     CPSR_ALLOC();
240     uint8_t cur_cpu_num;
241     kstat_t stat;
242 
243     NULL_PARA_CHK(sem);
244 
245     RHINO_CRITICAL_ENTER();
246 
247     cur_cpu_num = cpu_cur_get();
248     TASK_CANCEL_CHK(sem);
249 
250     INTRPT_NESTED_LEVEL_CHK();
251 
252     if (sem->blk_obj.obj_type != RHINO_SEM_OBJ_TYPE) {
253         RHINO_CRITICAL_EXIT();
254         return RHINO_KOBJ_TYPE_ERR;
255     }
256 
257     if (sem->count > 0u) {
258         sem->count--;
259 
260         TRACE_SEM_GET_SUCCESS(g_active_task[cur_cpu_num], sem);
261         RHINO_CRITICAL_EXIT();
262 
263         return RHINO_SUCCESS;
264     }
265 
266     /* can't get semphore, and return immediately if wait_option is  RHINO_NO_WAIT */
267     if (ticks == RHINO_NO_WAIT) {
268         RHINO_CRITICAL_EXIT();
269         return RHINO_NO_PEND_WAIT;
270     }
271 
272     if (g_sched_lock[cur_cpu_num] > 0u) {
273         RHINO_CRITICAL_EXIT();
274         return RHINO_SCHED_DISABLE;
275     }
276 
277     pend_to_blk_obj(&sem->blk_obj, g_active_task[cur_cpu_num], ticks);
278 
279     TRACE_SEM_GET_BLK(g_active_task[cur_cpu_num], sem, ticks);
280 
281     RHINO_CRITICAL_EXIT_SCHED();
282 
283     RHINO_CPU_INTRPT_DISABLE();
284 
285     stat = pend_state_end_proc(g_active_task[cpu_cur_get()], &sem->blk_obj);
286 
287     RHINO_CPU_INTRPT_ENABLE();
288 
289     return stat;
290 }
291 
krhino_sem_count_set(ksem_t * sem,sem_count_t sem_count)292 kstat_t krhino_sem_count_set(ksem_t *sem, sem_count_t sem_count)
293 {
294     CPSR_ALLOC();
295     klist_t *blk_list_head;
296 
297     NULL_PARA_CHK(sem);
298 
299     blk_list_head = &sem->blk_obj.blk_list;
300 
301     RHINO_CRITICAL_ENTER();
302 
303     INTRPT_NESTED_LEVEL_CHK();
304 
305     if (sem->blk_obj.obj_type != RHINO_SEM_OBJ_TYPE) {
306         RHINO_CRITICAL_EXIT();
307         return RHINO_KOBJ_TYPE_ERR;
308     }
309 
310     /* set new count */
311     if (sem->count > 0u) {
312         sem->count = sem_count;
313     } else {
314         if (is_klist_empty(blk_list_head)) {
315             sem->count = sem_count;
316         } else {
317             RHINO_CRITICAL_EXIT();
318             return RHINO_SEM_TASK_WAITING;
319         }
320     }
321 
322     /* update sem peak count if need */
323     if (sem->count > sem->peak_count) {
324         sem->peak_count = sem->count;
325     }
326 
327     RHINO_CRITICAL_EXIT();
328 
329     return RHINO_SUCCESS;
330 }
331 
krhino_sem_count_get(ksem_t * sem,sem_count_t * count)332 kstat_t krhino_sem_count_get(ksem_t *sem, sem_count_t *count)
333 {
334     CPSR_ALLOC();
335 
336     NULL_PARA_CHK(sem);
337     NULL_PARA_CHK(count);
338 
339     RHINO_CRITICAL_ENTER();
340    *count = sem->count;
341     RHINO_CRITICAL_EXIT();
342 
343     return RHINO_SUCCESS;
344 }
345 
346 #endif /* RHINO_CONFIG_SEM */
347 
348