1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * @file
9 * @brief Use stack API's in different scenarios
10 *
11 * This module tests following three basic scenarios:
12 *
13 * Scenario #1
14 * Test thread enters items into a stack, starts the Child thread and
15 * waits for a semaphore. Child thread extracts all items from the stack
16 * and enters some items back into the stack. Child thread gives the
17 * semaphore for Test thread to continue. Once the control is returned
18 * back to Test thread, it extracts all items from the stack.
19 *
20 * Scenario #2
21 * Test thread enters an item into stack2, starts a Child thread and
22 * extract an item from stack1 once the item is there. The child thread
23 * will extract an item from stack2 once the item is there and and enter
24 * an item to stack1. The flow of control goes from Test thread to Child
25 * thread and so forth.
26 *
27 * Scenario #3
28 * Tests the ISR interfaces. Test thread pushes items into stack2 and gives
29 * control to the Child thread. Child thread pops items from stack2 and then
30 * pushes items into stack1. Child thread gives back control to the Test thread
31 * and Test thread pops the items from stack1.
32 * All the Push and Pop operations happen in ISR Context.
33 */
34
35
36 /**
37 * @brief Tests for Kernel stack objects
38 * @defgroup kernel_stack_tests Stacks
39 * @ingroup all_tests
40 * @{
41 * @}
42 */
43
44 #include <zephyr/ztest.h>
45 #include <zephyr/irq_offload.h>
46
47 #define TSTACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
48 #define STACK_LEN 4
49
50 /* stack objects used in this test */
51 K_STACK_DEFINE(stack1, STACK_LEN);
52 K_STACK_DEFINE(stack2, STACK_LEN);
53
54 /* thread info * */
55 K_THREAD_STACK_DEFINE(threadstack, TSTACK_SIZE);
56 struct k_thread thread_data;
57
58 /* Data pushed to stack */
59 static ZTEST_DMEM stack_data_t data1[STACK_LEN] = { 0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD };
60 static ZTEST_DMEM stack_data_t data2[STACK_LEN] = { 0x1111, 0x2222, 0x3333, 0x4444 };
61 static ZTEST_DMEM stack_data_t data_isr[STACK_LEN] = { 0xABCD, 0xABCD, 0xABCD,
62 0xABCD };
63
64 /* semaphore to sync threads */
65 static struct k_sem end_sema;
66
67
68
69 K_HEAP_DEFINE(test_pool, 128 * 3);
70
71 extern struct k_stack kstack;
72 extern struct k_stack stack;
73 extern struct k_sem end_sema;
74
75 /* entry of contexts */
tIsr_entry_push(const void * p)76 static void tIsr_entry_push(const void *p)
77 {
78 uint32_t i;
79
80 /* Push items to stack */
81 for (i = 0U; i < STACK_LEN; i++) {
82 k_stack_push((struct k_stack *)p, data_isr[i]);
83 }
84 }
85
tIsr_entry_pop(const void * p)86 static void tIsr_entry_pop(const void *p)
87 {
88 uint32_t i;
89
90 /* Pop items from stack */
91 for (i = 0U; i < STACK_LEN; i++) {
92 if (p == &stack1) {
93 k_stack_pop((struct k_stack *)p, &data1[i], K_NO_WAIT);
94 } else {
95 k_stack_pop((struct k_stack *)p, &data2[i], K_NO_WAIT);
96 }
97 }
98 }
99
thread_entry_fn_single(void * p1,void * p2,void * p3)100 static void thread_entry_fn_single(void *p1, void *p2, void *p3)
101 {
102 stack_data_t tmp[STACK_LEN];
103 uint32_t i;
104
105 /* Pop items from stack */
106 for (i = STACK_LEN; i; i--) {
107 k_stack_pop((struct k_stack *)p1, &tmp[i - 1], K_NO_WAIT);
108 }
109 zassert_false(memcmp(tmp, data1, sizeof(tmp)),
110 "Push & Pop items does not match");
111
112 /* Push items from stack */
113 for (i = 0U; i < STACK_LEN; i++) {
114 k_stack_push((struct k_stack *)p1, data2[i]);
115 }
116
117 /* Give control back to Test thread */
118 k_sem_give(&end_sema);
119 }
120
thread_entry_fn_dual(void * p1,void * p2,void * p3)121 static void thread_entry_fn_dual(void *p1, void *p2, void *p3)
122 {
123 stack_data_t tmp[STACK_LEN];
124 uint32_t i;
125
126 for (i = 0U; i < STACK_LEN; i++) {
127 /* Pop items from stack2 */
128 k_stack_pop(p2, &tmp[i], K_FOREVER);
129
130 /* Push items to stack1 */
131 k_stack_push(p1, data1[i]);
132
133 }
134 zassert_false(memcmp(tmp, data2, sizeof(tmp)),
135 "Push & Pop items does not match");
136 }
137
thread_entry_fn_isr(void * p1,void * p2,void * p3)138 static void thread_entry_fn_isr(void *p1, void *p2, void *p3)
139 {
140 /* Pop items from stack2 */
141 irq_offload(tIsr_entry_pop, (const void *)p2);
142 zassert_false(memcmp(data_isr, data2, sizeof(data_isr)),
143 "Push & Pop items does not match");
144
145 /* Push items to stack1 */
146 irq_offload(tIsr_entry_push, (const void *)p1);
147
148 /* Give control back to Test thread */
149 k_sem_give(&end_sema);
150 }
151
152 /**
153 * @addtogroup kernel_stack_tests
154 * @{
155 */
156
157 /**
158 * @brief Verify data passing between threads using single stack
159 * @see k_stack_push(), #K_STACK_DEFINE(x), k_stack_pop()
160 */
ZTEST_USER(stack_usage,test_single_stack_play)161 ZTEST_USER(stack_usage, test_single_stack_play)
162 {
163 stack_data_t tmp[STACK_LEN];
164 uint32_t i;
165
166 /* Init kernel objects */
167 k_sem_init(&end_sema, 0, 1);
168
169 /* Push items to stack */
170 for (i = 0U; i < STACK_LEN; i++) {
171 k_stack_push(&stack1, data1[i]);
172 }
173
174 k_tid_t tid = k_thread_create(&thread_data, threadstack, TSTACK_SIZE,
175 thread_entry_fn_single, &stack1, NULL,
176 NULL, K_PRIO_PREEMPT(0), K_USER |
177 K_INHERIT_PERMS, K_NO_WAIT);
178
179 /* Let the child thread run */
180 k_sem_take(&end_sema, K_FOREVER);
181
182 /* Pop items from stack */
183 for (i = STACK_LEN; i; i--) {
184 k_stack_pop(&stack1, &tmp[i - 1], K_NO_WAIT);
185 }
186
187 zassert_false(memcmp(tmp, data2, sizeof(tmp)),
188 "Push & Pop items does not match");
189
190 /* Clear the spawn thread to avoid side effect */
191 k_thread_abort(tid);
192 }
193
194 /**
195 * @brief Verify data passing between threads using dual stack
196 * @see k_stack_push(), #K_STACK_DEFINE(x), k_stack_pop()
197 */
ZTEST_USER(stack_usage_1cpu,test_dual_stack_play)198 ZTEST_USER(stack_usage_1cpu, test_dual_stack_play)
199 {
200 stack_data_t tmp[STACK_LEN];
201 uint32_t i;
202
203 k_tid_t tid = k_thread_create(&thread_data, threadstack, TSTACK_SIZE,
204 thread_entry_fn_dual, &stack1, &stack2,
205 NULL, K_PRIO_PREEMPT(0), K_USER |
206 K_INHERIT_PERMS, K_NO_WAIT);
207
208 for (i = 0U; i < STACK_LEN; i++) {
209 /* Push items to stack2 */
210 k_stack_push(&stack2, data2[i]);
211
212 /* Pop items from stack1 */
213 k_stack_pop(&stack1, &tmp[i], K_FOREVER);
214 }
215
216 zassert_false(memcmp(tmp, data1, sizeof(tmp)),
217 "Push & Pop items does not match");
218
219 /* Clear the spawn thread to avoid side effect */
220 k_thread_abort(tid);
221 }
222
223 /**
224 * @brief Verify data passing between thread and ISR
225 * @see k_stack_push(), #K_STACK_DEFINE(x), k_stack_pop()
226 */
ZTEST(stack_usage_1cpu,test_isr_stack_play)227 ZTEST(stack_usage_1cpu, test_isr_stack_play)
228 {
229 /* Init kernel objects */
230 k_sem_init(&end_sema, 0, 1);
231
232 k_tid_t tid = k_thread_create(&thread_data, threadstack, TSTACK_SIZE,
233 thread_entry_fn_isr, &stack1, &stack2,
234 NULL, K_PRIO_PREEMPT(0),
235 K_INHERIT_PERMS, K_NO_WAIT);
236
237
238 /* Push items to stack2 */
239 irq_offload(tIsr_entry_push, (const void *)&stack2);
240
241 /* Let the child thread run */
242 k_sem_take(&end_sema, K_FOREVER);
243
244 /* Pop items from stack1 */
245 irq_offload(tIsr_entry_pop, (const void *)&stack1);
246
247 zassert_false(memcmp(data_isr, data1, sizeof(data_isr)),
248 "Push & Pop items does not match");
249
250 /* Clear the spawn thread to avoid side effect */
251 k_thread_abort(tid);
252 }
253
254 /* the thread entry */
thread_entry_wait(void * p1,void * p2,void * p3)255 void thread_entry_wait(void *p1, void *p2, void *p3)
256 {
257 stack_data_t *txdata = p3;
258
259 k_stack_push(p1, *(txdata + 2));
260 k_stack_push(p1, *(txdata + 3));
261 }
262
263 /**
264 * @brief Test that the stack pop can be waited
265 * if no item available
266 *
267 * @details Create and initialize a new stack
268 * Set two timeout parameters to indicate
269 * the maximum amount of time the thread will wait.
270 *
271 * @ingroup kernel_stack_tests
272 *
273 * @see k_stack_push(), #K_STACK_DEFINE(x), k_stack_pop()
274 */
ZTEST(stack_usage,test_stack_pop_can_wait)275 ZTEST(stack_usage, test_stack_pop_can_wait)
276 {
277 struct k_stack stack3;
278 stack_data_t tx_data[STACK_LEN] = { 0xaa, 0xbb, 0xcc, 0xdd };
279 stack_data_t rx_data[STACK_LEN] = { 0 };
280
281 k_stack_alloc_init(&stack3, 2);
282 k_tid_t tid = k_thread_create(&thread_data, threadstack,
283 TSTACK_SIZE, thread_entry_wait, &stack3,
284 NULL, tx_data, K_PRIO_PREEMPT(0), 0,
285 K_NO_WAIT);
286
287 for (int i = 0; i < 2; i++) {
288 k_stack_push(&stack3, tx_data[i]);
289 }
290
291 for (int i = 0; i < 3; i++) {
292 k_stack_pop(&stack3, &rx_data[i], K_FOREVER);
293 }
294
295 zassert_true(rx_data[2] == tx_data[2], "wait forever and pop failed\n");
296 k_stack_pop(&stack3, &rx_data[3], K_MSEC(50));
297 zassert_true(rx_data[3] == tx_data[3], "Wait maximum time pop failed\n");
298 /* Clear the spawn thread to avoid side effect */
299 k_thread_abort(tid);
300 /*free the buffer allocated*/
301 k_stack_cleanup(&stack3);
302 }
303
304 /**
305 * @}
306 */
307
308 extern struct k_stack threadstack1;
309 extern struct k_thread thread_data1;
310 extern struct k_sem end_sema1;
311
stack_setup(void)312 static void *stack_setup(void)
313 {
314 k_thread_access_grant(k_current_get(), &stack1, &stack2, &thread_data,
315 &end_sema, &threadstack, &kstack, &stack, &thread_data1,
316 &end_sema1, &threadstack1);
317
318 k_thread_heap_assign(k_current_get(), &test_pool);
319
320 return NULL;
321 }
322
323 ZTEST_SUITE(stack_usage, NULL, stack_setup, NULL, NULL, NULL);
324
325 ZTEST_SUITE(stack_contexts, NULL, stack_setup, NULL, NULL, NULL);
326
327 ZTEST_SUITE(stack_fail, NULL, stack_setup, NULL, NULL, NULL);
328
329 ZTEST_SUITE(stack_usage_1cpu, NULL, stack_setup,
330 ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL);
331