1 /*
2 * Copyright (c) 2019 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include <zephyr/irq_offload.h>
9 #include <zephyr/sys/sem.h>
10
11 /* Macro declarations */
12 #define SEM_INIT_VAL (0U)
13 #define SEM_MAX_VAL (10U)
14 #define SEM_TIMEOUT (K_MSEC(100))
15 #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
16 #define TOTAL_THREADS_WAITING (3)
17
18 /******************************************************************************/
19 /* declaration */
20 ZTEST_BMEM struct sys_sem simple_sem;
21 ZTEST_BMEM struct sys_sem low_prio_sem;
22 ZTEST_BMEM struct sys_sem mid_prio_sem;
23 ZTEST_DMEM struct sys_sem high_prio_sem;
24 ZTEST_DMEM SYS_SEM_DEFINE(multiple_thread_sem, SEM_INIT_VAL, SEM_MAX_VAL);
25
26 K_THREAD_STACK_DEFINE(stack_1, STACK_SIZE);
27 K_THREAD_STACK_DEFINE(stack_2, STACK_SIZE);
28 K_THREAD_STACK_DEFINE(stack_3, STACK_SIZE);
29 K_THREAD_STACK_ARRAY_DEFINE(multiple_stack, TOTAL_THREADS_WAITING, STACK_SIZE);
30
31 struct k_thread sem_tid, sem_tid_1, sem_tid_2;
32 struct k_thread multiple_tid[TOTAL_THREADS_WAITING];
33
34 /******************************************************************************/
35 /* Helper functions */
isr_sem_give(const void * semaphore)36 static void isr_sem_give(const void *semaphore)
37 {
38 sys_sem_give((struct sys_sem *)semaphore);
39 }
40
isr_sem_take(const void * semaphore)41 static void isr_sem_take(const void *semaphore)
42 {
43 sys_sem_take((struct sys_sem *)semaphore, K_NO_WAIT);
44 }
45
sem_give_from_isr(void * semaphore)46 static void sem_give_from_isr(void *semaphore)
47 {
48 irq_offload(isr_sem_give, (const void *)semaphore);
49 }
50
sem_take_from_isr(void * semaphore)51 static void sem_take_from_isr(void *semaphore)
52 {
53 irq_offload(isr_sem_take, (const void *)semaphore);
54 }
55
sem_give_task(void * p1,void * p2,void * p3)56 static void sem_give_task(void *p1, void *p2, void *p3)
57 {
58 sys_sem_give(&simple_sem);
59 }
60
sem_take_timeout_forever_helper(void * p1,void * p2,void * p3)61 static void sem_take_timeout_forever_helper(void *p1, void *p2, void *p3)
62 {
63 k_sleep(K_MSEC(100));
64 sys_sem_give(&simple_sem);
65 }
66
sem_take_timeout_isr_helper(void * p1,void * p2,void * p3)67 static void sem_take_timeout_isr_helper(void *p1, void *p2, void *p3)
68 {
69 sem_give_from_isr(&simple_sem);
70 }
71
sem_take_multiple_low_prio_helper(void * p1,void * p2,void * p3)72 static void sem_take_multiple_low_prio_helper(void *p1, void *p2, void *p3)
73 {
74 int32_t ret_value;
75
76 ret_value = sys_sem_take(&low_prio_sem, K_FOREVER);
77 zassert_true(ret_value == 0, "sys_sem_take failed");
78
79 ret_value = sys_sem_take(&multiple_thread_sem, K_FOREVER);
80 zassert_true(ret_value == 0, "sys_sem_take failed");
81
82 sys_sem_give(&low_prio_sem);
83 }
84
sem_take_multiple_mid_prio_helper(void * p1,void * p2,void * p3)85 static void sem_take_multiple_mid_prio_helper(void *p1, void *p2, void *p3)
86 {
87 int32_t ret_value;
88
89 ret_value = sys_sem_take(&mid_prio_sem, K_FOREVER);
90 zassert_true(ret_value == 0, "sys_sem_take failed");
91
92 ret_value = sys_sem_take(&multiple_thread_sem, K_FOREVER);
93 zassert_true(ret_value == 0, "sys_sem_take failed");
94
95 sys_sem_give(&mid_prio_sem);
96 }
97
sem_take_multiple_high_prio_helper(void * p1,void * p2,void * p3)98 static void sem_take_multiple_high_prio_helper(void *p1, void *p2, void *p3)
99 {
100 int32_t ret_value;
101
102 ret_value = sys_sem_take(&high_prio_sem, K_FOREVER);
103 zassert_true(ret_value == 0, "sys_sem_take failed");
104
105 ret_value = sys_sem_take(&multiple_thread_sem, K_FOREVER);
106 zassert_true(ret_value == 0, "sys_sem_take failed");
107
108 sys_sem_give(&high_prio_sem);
109 }
110
sem_multiple_threads_wait_helper(void * p1,void * p2,void * p3)111 static void sem_multiple_threads_wait_helper(void *p1, void *p2, void *p3)
112 {
113 int ret_value;
114
115 /* get blocked until the test thread gives the semaphore */
116 ret_value = sys_sem_take(&multiple_thread_sem, K_FOREVER);
117 zassert_true(ret_value == 0, "sys_sem_take failed");
118
119 /* Inform the test thread that this thread has got multiple_thread_sem*/
120 sys_sem_give(&simple_sem);
121 }
122
123 /**
124 * @ingroup sys_sem_tests
125 * @{
126 */
127
128 #ifdef CONFIG_USERSPACE
ZTEST(sys_sem,test_basic_sem_test)129 ZTEST(sys_sem, test_basic_sem_test)
130 {
131 int32_t ret_value;
132
133 ret_value = sys_sem_init(NULL, SEM_INIT_VAL, SEM_MAX_VAL);
134 zassert_true(ret_value == -EINVAL,
135 "sys_sem_init returned not equal -EINVAL");
136
137 ret_value = sys_sem_init(&simple_sem, SEM_INIT_VAL, SEM_INIT_VAL);
138 zassert_true(ret_value == -EINVAL,
139 "sys_sem_init returned not equal -EINVAL");
140
141 ret_value = sys_sem_init(&simple_sem, UINT_MAX, SEM_MAX_VAL);
142 zassert_true(ret_value == -EINVAL,
143 "sys_sem_init returned not equal -EINVAL");
144
145 ret_value = sys_sem_init(&simple_sem, SEM_MAX_VAL, UINT_MAX);
146 zassert_true(ret_value == -EINVAL,
147 "sys_sem_init returned not equal -EINVAL");
148
149 sys_sem_init(&simple_sem, SEM_INIT_VAL, SEM_MAX_VAL);
150 sys_sem_take(&simple_sem, SEM_TIMEOUT);
151 sys_sem_give(&simple_sem);
152 }
153 #endif
154
155 /**
156 * @brief Test semaphore count when given by an ISR
157 */
ZTEST(sys_sem,test_simple_sem_from_isr)158 ZTEST(sys_sem, test_simple_sem_from_isr)
159 {
160 uint32_t signal_count;
161
162 sys_sem_init(&simple_sem, SEM_INIT_VAL, SEM_MAX_VAL);
163
164 for (int i = 0; i < 5; i++) {
165 sem_give_from_isr(&simple_sem);
166
167 signal_count = sys_sem_count_get(&simple_sem);
168 zassert_true(signal_count == (i + 1),
169 "signal count mismatch Expected %d, got %d",
170 (i + 1), signal_count);
171 }
172
173 }
174
175 /**
176 * @brief Test semaphore count when given by thread
177 */
ZTEST_USER(sys_sem,test_simple_sem_from_task)178 ZTEST_USER(sys_sem, test_simple_sem_from_task)
179 {
180 uint32_t signal_count;
181
182 sys_sem_init(&simple_sem, SEM_INIT_VAL, SEM_MAX_VAL);
183
184 for (int i = 0; i < 5; i++) {
185 sys_sem_give(&simple_sem);
186
187 signal_count = sys_sem_count_get(&simple_sem);
188 zassert_true(signal_count == (i + 1),
189 "signal count mismatch Expected %d, got %d",
190 (i + 1), signal_count);
191 }
192 }
193
194 /**
195 * @brief Test if sys_sem_take() decreases semaphore count
196 */
ZTEST_USER(sys_sem,test_sem_take_no_wait)197 ZTEST_USER(sys_sem, test_sem_take_no_wait)
198 {
199 uint32_t signal_count;
200 int32_t ret_value;
201
202 /* Initial condition */
203 sys_sem_init(&simple_sem, 5, SEM_MAX_VAL);
204
205 for (int i = 4; i >= 0; i--) {
206 ret_value = sys_sem_take(&simple_sem, K_NO_WAIT);
207 zassert_true(ret_value == 0,
208 "unable to do sys_sem_take which returned %d",
209 ret_value);
210
211 signal_count = sys_sem_count_get(&simple_sem);
212 zassert_true(signal_count == i,
213 "signal count mismatch Expected %d, got %d",
214 i, signal_count);
215 }
216
217 }
218
219 /**
220 * @brief Test sys_sem_take() when there is no semaphore to take
221 */
ZTEST_USER(sys_sem,test_sem_take_no_wait_fails)222 ZTEST_USER(sys_sem, test_sem_take_no_wait_fails)
223 {
224 uint32_t signal_count;
225 int32_t ret_value;
226
227 sys_sem_init(&simple_sem, SEM_INIT_VAL, SEM_MAX_VAL);
228
229 for (int i = 4; i >= 0; i--) {
230 ret_value = sys_sem_take(&simple_sem, K_NO_WAIT);
231 zassert_true(ret_value == -ETIMEDOUT,
232 "sys_sem_take returned when not possible");
233
234 signal_count = sys_sem_count_get(&simple_sem);
235 zassert_true(signal_count == 0U,
236 "signal count mismatch Expected 0, got %d",
237 signal_count);
238 }
239
240 }
241
242 /**
243 * @brief Test sys_sem_take() with timeout expiry
244 */
ZTEST_USER(sys_sem_1cpu,test_sem_take_timeout_fails)245 ZTEST_USER(sys_sem_1cpu, test_sem_take_timeout_fails)
246 {
247 int32_t ret_value;
248
249 sys_sem_init(&simple_sem, SEM_INIT_VAL, SEM_MAX_VAL);
250
251 for (int i = 4; i >= 0; i--) {
252 ret_value = sys_sem_take(&simple_sem, SEM_TIMEOUT);
253 zassert_true(ret_value == -ETIMEDOUT,
254 "sys_sem_take succeeded when its not possible");
255 }
256
257 }
258
259 /**
260 * @brief Test sys_sem_take() with timeout
261 */
ZTEST_USER(sys_sem,test_sem_take_timeout)262 ZTEST_USER(sys_sem, test_sem_take_timeout)
263 {
264 int32_t ret_value;
265 #ifdef CONFIG_USERSPACE
266 int thread_flags = K_USER | K_INHERIT_PERMS;
267 #else
268 int thread_flags = 0;
269 #endif
270
271 sys_sem_init(&simple_sem, SEM_INIT_VAL, SEM_MAX_VAL);
272
273 k_thread_create(&sem_tid, stack_1, STACK_SIZE,
274 sem_give_task, NULL, NULL, NULL,
275 K_PRIO_PREEMPT(0), thread_flags,
276 K_NO_WAIT);
277
278 ret_value = sys_sem_take(&simple_sem, SEM_TIMEOUT);
279 zassert_true(ret_value == 0,
280 "sys_sem_take failed when its shouldn't have");
281
282 k_thread_join(&sem_tid, K_FOREVER);
283 }
284
285 /**
286 * @brief Test sys_sem_take() with forever timeout
287 */
ZTEST_USER(sys_sem_1cpu,test_sem_take_timeout_forever)288 ZTEST_USER(sys_sem_1cpu, test_sem_take_timeout_forever)
289 {
290 int32_t ret_value;
291 #ifdef CONFIG_USERSPACE
292 int thread_flags = K_USER | K_INHERIT_PERMS;
293 #else
294 int thread_flags = 0;
295 #endif
296
297 sys_sem_init(&simple_sem, SEM_INIT_VAL, SEM_MAX_VAL);
298
299 k_thread_create(&sem_tid, stack_1, STACK_SIZE,
300 sem_take_timeout_forever_helper, NULL,
301 NULL, NULL, K_PRIO_PREEMPT(0), thread_flags,
302 K_NO_WAIT);
303
304 ret_value = sys_sem_take(&simple_sem, K_FOREVER);
305 zassert_true(ret_value == 0,
306 "sys_sem_take failed when its shouldn't have");
307
308 k_thread_join(&sem_tid, K_FOREVER);
309 }
310
311 /**
312 * @brief Test sys_sem_take() with timeout in ISR context
313 */
ZTEST(sys_sem_1cpu,test_sem_take_timeout_isr)314 ZTEST(sys_sem_1cpu, test_sem_take_timeout_isr)
315 {
316 int32_t ret_value;
317
318 sys_sem_init(&simple_sem, SEM_INIT_VAL, SEM_MAX_VAL);
319
320 k_thread_create(&sem_tid, stack_1, STACK_SIZE,
321 sem_take_timeout_isr_helper, NULL, NULL, NULL,
322 K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
323
324 ret_value = sys_sem_take(&simple_sem, SEM_TIMEOUT);
325 zassert_true(ret_value == 0,
326 "sys_sem_take failed when its shouldn't have");
327
328 k_thread_join(&sem_tid, K_FOREVER);
329 }
330
331 /**
332 * @brief Test multiple semaphore take
333 */
ZTEST_USER(sys_sem_1cpu,test_sem_take_multiple)334 ZTEST_USER(sys_sem_1cpu, test_sem_take_multiple)
335 {
336 uint32_t signal_count;
337 #ifdef CONFIG_USERSPACE
338 int thread_flags = K_USER | K_INHERIT_PERMS;
339 #else
340 int thread_flags = 0;
341 #endif
342
343 sys_sem_init(&high_prio_sem, SEM_INIT_VAL, SEM_MAX_VAL);
344 sys_sem_init(&mid_prio_sem, SEM_INIT_VAL, SEM_MAX_VAL);
345 sys_sem_init(&low_prio_sem, SEM_INIT_VAL, SEM_MAX_VAL);
346
347 k_thread_create(&sem_tid, stack_1, STACK_SIZE,
348 sem_take_multiple_low_prio_helper,
349 NULL, NULL, NULL,
350 K_PRIO_PREEMPT(3), thread_flags,
351 K_NO_WAIT);
352
353 k_thread_create(&sem_tid_1, stack_2, STACK_SIZE,
354 sem_take_multiple_mid_prio_helper,
355 NULL, NULL, NULL,
356 K_PRIO_PREEMPT(2), thread_flags,
357 K_NO_WAIT);
358
359 k_thread_create(&sem_tid_2, stack_3, STACK_SIZE,
360 sem_take_multiple_high_prio_helper,
361 NULL, NULL, NULL,
362 K_PRIO_PREEMPT(1), thread_flags,
363 K_NO_WAIT);
364
365
366 /* Lower the priority */
367 k_thread_priority_set(k_current_get(), K_PRIO_PREEMPT(3));
368
369 /* giving time for those 3 threads to complete */
370 k_yield();
371
372 /* Let these threads proceed to take the multiple_sem */
373 sys_sem_give(&high_prio_sem);
374 sys_sem_give(&mid_prio_sem);
375 sys_sem_give(&low_prio_sem);
376 k_yield();
377
378 /* enable the higher priority thread to run. */
379 sys_sem_give(&multiple_thread_sem);
380 k_yield();
381
382 /* check which threads completed. */
383 signal_count = sys_sem_count_get(&high_prio_sem);
384 zassert_true(signal_count == 1U,
385 "Higher priority threads didn't execute");
386
387 signal_count = sys_sem_count_get(&mid_prio_sem);
388 zassert_true(signal_count == 0U,
389 "Medium priority threads shouldn't have executed");
390
391 signal_count = sys_sem_count_get(&low_prio_sem);
392 zassert_true(signal_count == 0U,
393 "low priority threads shouldn't have executed");
394
395 /* enable the Medium priority thread to run. */
396 sys_sem_give(&multiple_thread_sem);
397 k_yield();
398
399 /* check which threads completed. */
400 signal_count = sys_sem_count_get(&high_prio_sem);
401 zassert_true(signal_count == 1U,
402 "Higher priority thread executed again");
403
404 signal_count = sys_sem_count_get(&mid_prio_sem);
405 zassert_true(signal_count == 1U,
406 "Medium priority thread didn't get executed");
407
408 signal_count = sys_sem_count_get(&low_prio_sem);
409 zassert_true(signal_count == 0U,
410 "low priority thread shouldn't have executed");
411
412 /* enable the low priority thread to run. */
413 sys_sem_give(&multiple_thread_sem);
414 k_yield();
415
416 /* check which threads completed. */
417 signal_count = sys_sem_count_get(&high_prio_sem);
418 zassert_true(signal_count == 1U,
419 "Higher priority thread executed again");
420
421 signal_count = sys_sem_count_get(&mid_prio_sem);
422 zassert_true(signal_count == 1U,
423 "Medium priority thread executed again");
424
425 signal_count = sys_sem_count_get(&low_prio_sem);
426 zassert_true(signal_count == 1U,
427 "low priority thread didn't get executed");
428
429 k_thread_join(&sem_tid, K_FOREVER);
430 k_thread_join(&sem_tid_1, K_FOREVER);
431 k_thread_join(&sem_tid_2, K_FOREVER);
432 }
433
434 /**
435 * @brief Test semaphore give and take and its count from ISR
436 */
ZTEST(sys_sem,test_sem_give_take_from_isr)437 ZTEST(sys_sem, test_sem_give_take_from_isr)
438 {
439 uint32_t signal_count;
440
441 sys_sem_init(&simple_sem, SEM_INIT_VAL, SEM_MAX_VAL);
442
443 /* Give semaphore from an isr and do a check for the count */
444 for (int i = 0; i < SEM_MAX_VAL; i++) {
445 sem_give_from_isr(&simple_sem);
446
447 signal_count = sys_sem_count_get(&simple_sem);
448 zassert_true(signal_count == i + 1,
449 "signal count mismatch Expected %d, got %d",
450 i + 1, signal_count);
451 }
452
453 /* Take semaphore from an isr and do a check for the count */
454 for (int i = SEM_MAX_VAL; i > 0; i--) {
455 sem_take_from_isr(&simple_sem);
456
457 signal_count = sys_sem_count_get(&simple_sem);
458 zassert_true(signal_count == (i - 1),
459 "signal count mismatch Expected %d, got %d",
460 (i - 1), signal_count);
461 }
462 }
463
464 /**
465 * @brief Test semaphore give limit count
466 */
ZTEST_USER(sys_sem,test_sem_give_limit)467 ZTEST_USER(sys_sem, test_sem_give_limit)
468 {
469 int32_t ret_value;
470 uint32_t signal_count;
471
472 sys_sem_init(&simple_sem, SEM_INIT_VAL, SEM_MAX_VAL);
473
474 /* Give semaphore and do a check for the count */
475 for (int i = 0; i < SEM_MAX_VAL; i++) {
476 ret_value = sys_sem_give(&simple_sem);
477 zassert_true(ret_value == 0,
478 "sys_sem_give failed when its shouldn't have");
479
480 signal_count = sys_sem_count_get(&simple_sem);
481 zassert_true(signal_count == i + 1,
482 "signal count mismatch Expected %d, got %d",
483 i + 1, signal_count);
484 }
485
486 do {
487 ret_value = sys_sem_give(&simple_sem);
488 if (ret_value == -EAGAIN) {
489 signal_count = sys_sem_count_get(&simple_sem);
490 zassert_true(signal_count == SEM_MAX_VAL,
491 "signal count mismatch Expected %d, got %d",
492 SEM_MAX_VAL, signal_count);
493
494 sys_sem_take(&simple_sem, K_FOREVER);
495 } else if (ret_value == 0) {
496 signal_count = sys_sem_count_get(&simple_sem);
497 zassert_true(signal_count == SEM_MAX_VAL,
498 "signal count mismatch Expected %d, got %d",
499 SEM_MAX_VAL, signal_count);
500 }
501 } while (ret_value == -EAGAIN);
502 }
503
504 /**
505 * @brief Test multiple semaphore take and give with wait
506 */
ZTEST_USER(sys_sem_1cpu,test_sem_multiple_threads_wait)507 ZTEST_USER(sys_sem_1cpu, test_sem_multiple_threads_wait)
508 {
509 uint32_t signal_count;
510 int32_t ret_value;
511 uint32_t repeat_count = 0U;
512 #ifdef CONFIG_USERSPACE
513 int thread_flags = K_USER | K_INHERIT_PERMS;
514 #else
515 int thread_flags = 0;
516 #endif
517
518 sys_sem_init(&simple_sem, SEM_INIT_VAL, SEM_MAX_VAL);
519
520 do {
521 for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
522 k_thread_create(&multiple_tid[i],
523 multiple_stack[i], STACK_SIZE,
524 sem_multiple_threads_wait_helper,
525 NULL, NULL, NULL,
526 CONFIG_ZTEST_THREAD_PRIORITY,
527 thread_flags, K_NO_WAIT);
528 }
529
530 /* giving time for the other threads to execute */
531 k_yield();
532
533 /* Give the semaphores */
534 for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
535 sys_sem_give(&multiple_thread_sem);
536 }
537
538 /* giving time for the other threads to execute */
539 k_yield();
540
541 /* check if all the threads are done. */
542 for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
543 ret_value = sys_sem_take(&simple_sem, K_FOREVER);
544 zassert_true(ret_value == 0,
545 "Some of the threads didn't get multiple_thread_sem"
546 );
547 }
548
549 signal_count = sys_sem_count_get(&simple_sem);
550 zassert_true(signal_count == 0U,
551 "signal count mismatch Expected 0, got %d",
552 signal_count);
553
554 signal_count = sys_sem_count_get(&multiple_thread_sem);
555 zassert_true(signal_count == 0U,
556 "signal count mismatch Expected 0, got %d",
557 signal_count);
558
559 repeat_count++;
560
561 for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
562 k_thread_join(&multiple_tid[i], K_FOREVER);
563 }
564 } while (repeat_count < 2);
565 }
566
567 /**
568 * @}
569 */
570
k_sys_fatal_error_handler(unsigned int reason,const z_arch_esf_t * pEsf)571 void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *pEsf)
572 {
573 printk("Caught system error -- reason %d\n", reason);
574 printk("Unexpected fault during test\n");
575 printk("PROJECT EXECUTION FAILED\n");
576 k_fatal_halt(reason);
577 }
578
sys_sem_setup(void)579 void *sys_sem_setup(void)
580 {
581 #ifdef CONFIG_USERSPACE
582 k_thread_access_grant(k_current_get(),
583 &stack_1, &stack_2, &stack_3,
584 &sem_tid, &sem_tid_1, &sem_tid_2);
585
586 for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
587 k_thread_access_grant(k_current_get(),
588 &multiple_tid[i], &multiple_stack[i]);
589 }
590 #endif
591
592 return NULL;
593 }
594
595 ZTEST_SUITE(sys_sem, NULL, sys_sem_setup, NULL, NULL, NULL);
596
597 ZTEST_SUITE(sys_sem_1cpu, NULL, sys_sem_setup, ztest_simple_1cpu_before,
598 ztest_simple_1cpu_after, NULL);
599
600 /******************************************************************************/
601