1 /*
2 * Copyright (c) 2021 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include <zephyr/ztest_error_hook.h>
9
10 /* Macro declarations */
11 #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
12 #define SEM_INIT_VAL (0U)
13 #define SEM_MAX_VAL (3U)
14 #define TOTAL_MAX (4U)
15 #define STACK_NUMS 5
16 #define PRIO 5
17 #define LOW_PRIO 8
18 #define HIGH_PRIO 2
19
20 static K_THREAD_STACK_ARRAY_DEFINE(multi_stack_give, STACK_NUMS, STACK_SIZE);
21 static K_THREAD_STACK_ARRAY_DEFINE(multi_stack_take, STACK_NUMS, STACK_SIZE);
22
23 static struct k_thread multi_tid_give[STACK_NUMS];
24 static struct k_thread multi_tid_take[STACK_NUMS];
25 static struct k_sem usage_sem, sync_sem, limit_sem, uninit_sem;
26 static ZTEST_DMEM int flag;
27 static ZTEST_DMEM atomic_t atomic_count;
28
29 /**
30 * @defgroup kernel_sys_sem_tests Semaphore
31 * @ingroup all_tests
32 * @{
33 * @}
34 */
35
sem_thread_give_uninit(void * p1,void * p2,void * p3)36 static void sem_thread_give_uninit(void *p1, void *p2, void *p3)
37 {
38 ztest_set_fault_valid(true);
39
40 /* use sem without initialise */
41 k_sem_give(&uninit_sem);
42
43 ztest_test_fail();
44 }
45
sem_thread_give(void * p1,void * p2,void * p3)46 static void sem_thread_give(void *p1, void *p2, void *p3)
47 {
48 flag = 1;
49 k_sem_give(&usage_sem);
50 }
51
thread_low_prio_sem_take(void * p1,void * p2,void * p3)52 static void thread_low_prio_sem_take(void *p1, void *p2, void *p3)
53 {
54 k_sem_take(&usage_sem, K_FOREVER);
55
56 flag = LOW_PRIO;
57 k_sem_give(&sync_sem);
58 }
59
thread_high_prio_sem_take(void * p1,void * p2,void * p3)60 static void thread_high_prio_sem_take(void *p1, void *p2, void *p3)
61 {
62 k_sem_take(&usage_sem, K_FOREVER);
63
64 flag = HIGH_PRIO;
65 k_sem_give(&sync_sem);
66 }
67
68 /**
69 * @brief Test semaphore usage with multiple thread
70 *
71 * @details Using semaphore with some situations
72 * - Use a uninitialized semaphore
73 * - Use semaphore normally
74 * - Use semaphore with different priority threads
75 *
76 * @ingroup kernel_sys_sem_tests
77 */
ZTEST_USER(kernel_sys_sem,test_multiple_thread_sem_usage)78 ZTEST_USER(kernel_sys_sem, test_multiple_thread_sem_usage)
79 {
80 k_sem_init(&usage_sem, SEM_INIT_VAL, SEM_MAX_VAL);
81 k_sem_init(&sync_sem, SEM_INIT_VAL, SEM_MAX_VAL);
82 /* Use a semaphore to synchronize processing between threads */
83 k_sem_reset(&usage_sem);
84 k_thread_create(&multi_tid_give[0], multi_stack_give[0], STACK_SIZE,
85 sem_thread_give, NULL, NULL,
86 NULL, PRIO, K_USER | K_INHERIT_PERMS,
87 K_NO_WAIT);
88
89 k_sem_take(&usage_sem, K_FOREVER);
90 zassert_equal(flag, 1, "value != 1");
91 zassert_equal(k_sem_count_get(&usage_sem), 0, "sem not be took");
92
93 k_sem_reset(&usage_sem);
94 /* Use sem with different priority thread */
95 k_thread_create(&multi_tid_take[0], multi_stack_take[0], STACK_SIZE,
96 thread_low_prio_sem_take, NULL, NULL,
97 NULL, LOW_PRIO, K_USER | K_INHERIT_PERMS,
98 K_NO_WAIT);
99
100 k_thread_create(&multi_tid_take[1], multi_stack_take[1], STACK_SIZE,
101 thread_high_prio_sem_take, NULL, NULL,
102 NULL, HIGH_PRIO, K_USER | K_INHERIT_PERMS,
103 K_NO_WAIT);
104
105 k_sleep(K_MSEC(50));
106
107 /* Verify if the high prio thread take sem first */
108 k_sem_give(&usage_sem);
109 k_sem_take(&sync_sem, K_FOREVER);
110 zassert_equal(flag, HIGH_PRIO, "high prio value error");
111
112 k_sem_give(&usage_sem);
113 k_sem_take(&sync_sem, K_FOREVER);
114 zassert_equal(flag, LOW_PRIO, "low prio value error");
115
116 k_thread_join(&multi_tid_give[0], K_FOREVER);
117 k_thread_join(&multi_tid_take[0], K_FOREVER);
118 k_thread_join(&multi_tid_take[1], K_FOREVER);
119
120 k_thread_create(&multi_tid_give[1], multi_stack_give[1], STACK_SIZE,
121 sem_thread_give_uninit, NULL, NULL,
122 NULL, PRIO, K_USER | K_INHERIT_PERMS,
123 K_NO_WAIT);
124 k_sleep(K_MSEC(20));
125 k_thread_join(&multi_tid_give[1], K_FOREVER);
126 }
127
multi_thread_sem_give(void * p1,void * p2,void * p3)128 static void multi_thread_sem_give(void *p1, void *p2, void *p3)
129 {
130 int count;
131
132 (void)atomic_inc(&atomic_count);
133 count = atomic_get(&atomic_count);
134 k_sem_give(&limit_sem);
135
136 if (count < TOTAL_MAX) {
137 zassert_equal(k_sem_count_get(&limit_sem), count, "multi get sem error");
138 } else {
139 zassert_equal(k_sem_count_get(&limit_sem), SEM_MAX_VAL, "count > SEM_MAX_VAL");
140 }
141
142 k_sem_take(&sync_sem, K_FOREVER);
143 }
144
multi_thread_sem_take(void * p1,void * p2,void * p3)145 static void multi_thread_sem_take(void *p1, void *p2, void *p3)
146 {
147 int count;
148
149 k_sem_take(&limit_sem, K_FOREVER);
150 (void)atomic_dec(&atomic_count);
151 count = atomic_get(&atomic_count);
152
153 if (count >= 0) {
154 zassert_equal(k_sem_count_get(&limit_sem), count, "multi take sem error");
155 } else {
156 zassert_equal(k_sem_count_get(&limit_sem), 0, "count < SEM_INIT_VAL");
157 }
158
159 k_sem_give(&sync_sem);
160 }
161
162 /**
163 * @brief Test max semaphore can be give and take with multiple thread
164 *
165 * @details
166 * - Define and initialize semaphore and thread.
167 * - Give sem by multiple threads.
168 * - Verify more than max count about semaphore can reach.
169 * - Take sem by multiple threads and verify if sem count is correct.
170 *
171 * @ingroup kernel_sys_sem_tests
172 */
ZTEST_USER(kernel_sys_sem,test_multi_thread_sem_limit)173 ZTEST_USER(kernel_sys_sem, test_multi_thread_sem_limit)
174 {
175 k_sem_init(&limit_sem, SEM_INIT_VAL, SEM_MAX_VAL);
176 k_sem_init(&sync_sem, SEM_INIT_VAL, SEM_MAX_VAL);
177
178 (void)atomic_set(&atomic_count, 0);
179 for (int i = 1; i <= TOTAL_MAX; i++) {
180 k_thread_create(&multi_tid_give[i], multi_stack_give[i], STACK_SIZE,
181 multi_thread_sem_give, NULL, NULL, NULL,
182 i, K_USER | K_INHERIT_PERMS, K_NO_WAIT);
183 }
184
185 k_sleep(K_MSEC(50));
186
187 (void)atomic_set(&atomic_count, SEM_MAX_VAL);
188 for (int i = 1; i <= TOTAL_MAX; i++) {
189 k_thread_create(&multi_tid_take[i], multi_stack_take[i], STACK_SIZE,
190 multi_thread_sem_take, NULL, NULL, NULL,
191 PRIO, K_USER | K_INHERIT_PERMS, K_NO_WAIT);
192 }
193
194 /* cleanup all threads for the following test cases */
195 k_sleep(K_MSEC(50));
196 for (int i = 1; i <= TOTAL_MAX; i++) {
197 k_thread_abort(&multi_tid_give[i]);
198 k_thread_abort(&multi_tid_take[i]);
199 }
200 }
201
test_init(void)202 void *test_init(void)
203 {
204 k_thread_access_grant(k_current_get(), &usage_sem, &sync_sem, &limit_sem,
205 &multi_tid_give[0], &multi_tid_give[1],
206 &multi_tid_give[2], &multi_tid_give[3],
207 &multi_tid_give[4], &multi_tid_take[4],
208 &multi_tid_take[2], &multi_tid_take[3],
209 &multi_tid_take[0], &multi_tid_take[1],
210 &multi_tid_give[5], &multi_tid_take[5],
211 &multi_stack_take[0], &multi_stack_take[1],
212 &multi_stack_take[3], &multi_stack_take[4],
213 &multi_stack_take[2], &multi_stack_give[0],
214 &multi_stack_give[1], &multi_stack_give[2],
215 &multi_stack_give[3], &multi_stack_give[4]);
216 return NULL;
217 }
218 ZTEST_SUITE(kernel_sys_sem, NULL, test_init,
219 ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL);
220