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