1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include "lifo_usage.h"
9 #include <zephyr/kernel.h>
10
11 #define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE)
12 #define LIST_LEN 2
13
14 struct k_lifo lifo, plifo;
15 static ldata_t lifo_data[LIST_LEN];
16 struct k_lifo timeout_order_lifo;
17
18 static struct k_thread tdata, tdata1;
19 static K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
20 static K_THREAD_STACK_DEFINE(tstack1, STACK_SIZE);
21
22 static struct k_sem start_sema, wait_sema;
23 void test_thread_pend_and_timeout(void *p1, void *p2, void *p3);
24
25 struct scratch_lifo_packet {
26 void *link_in_lifo;
27 void *data_if_needed;
28 };
29
30 struct reply_packet {
31 void *link_in_lifo;
32 int32_t reply;
33 };
34
35 struct timeout_order_data {
36 void *link_in_lifo;
37 struct k_lifo *klifo;
38 int32_t timeout;
39 int32_t timeout_order;
40 int32_t q_order;
41 };
42
43 static struct k_lifo lifo_timeout[2];
44
45 struct timeout_order_data timeout_order_data[] = {
46 {0, &lifo_timeout[0], 200, 2, 0},
47 {0, &lifo_timeout[0], 400, 4, 1},
48 {0, &lifo_timeout[0], 0, 0, 2},
49 {0, &lifo_timeout[0], 100, 1, 3},
50 {0, &lifo_timeout[0], 300, 3, 4},
51 };
52
53 struct timeout_order_data timeout_order_data_mult_lifo[] = {
54 {0, &lifo_timeout[1], 0, 0, 0},
55 {0, &lifo_timeout[0], 300, 3, 1},
56 {0, &lifo_timeout[0], 500, 5, 2},
57 {0, &lifo_timeout[1], 800, 8, 3},
58 {0, &lifo_timeout[1], 700, 7, 4},
59 {0, &lifo_timeout[0], 100, 1, 5},
60 {0, &lifo_timeout[0], 600, 6, 6},
61 {0, &lifo_timeout[0], 200, 2, 7},
62 {0, &lifo_timeout[1], 400, 4, 8},
63 };
64
65 #define NUM_SCRATCH_LIFO_PACKETS 20
66 #define TIMEOUT_ORDER_NUM_THREADS ARRAY_SIZE(timeout_order_data_mult_lifo)
67 #define TSTACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE)
68 #define LIFO_THREAD_PRIO -5
69
70 struct scratch_lifo_packet scratch_lifo_packets[NUM_SCRATCH_LIFO_PACKETS];
71
72 struct k_lifo scratch_lifo_packets_lifo;
73
74 static k_tid_t to_ord_tid[TIMEOUT_ORDER_NUM_THREADS];
75 static K_THREAD_STACK_ARRAY_DEFINE(ttstack,
76 TIMEOUT_ORDER_NUM_THREADS, TSTACK_SIZE);
77 static struct k_thread ttdata[TIMEOUT_ORDER_NUM_THREADS];
78
get_scratch_packet(void)79 static void *get_scratch_packet(void)
80 {
81 void *packet = k_lifo_get(&scratch_lifo_packets_lifo, K_NO_WAIT);
82
83 zassert_true(packet != NULL);
84 return packet;
85 }
86
put_scratch_packet(void * packet)87 static void put_scratch_packet(void *packet)
88 {
89 k_lifo_put(&scratch_lifo_packets_lifo, packet);
90 }
91
thread_entry_nowait(void * p1,void * p2,void * p3)92 static void thread_entry_nowait(void *p1, void *p2, void *p3)
93 {
94 void *ret;
95
96 ret = k_lifo_get((struct k_lifo *)p1, K_FOREVER);
97
98 /* data pushed at last should be read first */
99 zassert_equal(ret, (void *)&lifo_data[1]);
100
101 ret = k_lifo_get((struct k_lifo *)p1, K_FOREVER);
102
103 zassert_equal(ret, (void *)&lifo_data[0]);
104
105 k_sem_give(&start_sema);
106 }
107
is_timeout_in_range(uint32_t start_time,uint32_t timeout)108 static bool is_timeout_in_range(uint32_t start_time, uint32_t timeout)
109 {
110 uint32_t stop_time, diff;
111
112 stop_time = k_cycle_get_32();
113 diff = k_cyc_to_ms_floor32(stop_time - start_time);
114 return timeout <= diff;
115 }
116
test_multiple_threads_pending(struct timeout_order_data * test_data,int test_data_size)117 static int test_multiple_threads_pending(struct timeout_order_data *test_data,
118 int test_data_size)
119 {
120 int ii;
121
122 for (ii = 0; ii < test_data_size; ii++) {
123 to_ord_tid[ii] = k_thread_create(&ttdata[ii], ttstack[ii], TSTACK_SIZE,
124 test_thread_pend_and_timeout,
125 &test_data[ii], NULL, NULL,
126 LIFO_THREAD_PRIO, K_INHERIT_PERMS, K_NO_WAIT);
127 }
128
129 for (ii = 0; ii < test_data_size; ii++) {
130 struct timeout_order_data *data =
131 k_lifo_get(&timeout_order_lifo, K_FOREVER);
132
133 if (data->timeout_order == ii) {
134 TC_PRINT(" thread (q order: %d, t/o: %d, lifo %p)\n",
135 data->q_order, (int) data->timeout,
136 data->klifo);
137 } else {
138 zassert_equal(data->timeout_order, ii, " *** thread %d "
139 "woke up, expected %d\n",
140 data->timeout_order, ii);
141 return TC_FAIL;
142 }
143 }
144
145 return TC_PASS;
146 }
147
thread_entry_wait(void * p1,void * p2,void * p3)148 static void thread_entry_wait(void *p1, void *p2, void *p3)
149 {
150 k_lifo_put((struct k_lifo *)p1, (void *)&lifo_data[0]);
151
152 k_lifo_put((struct k_lifo *)p1, (void *)&lifo_data[1]);
153 k_sem_give(&wait_sema);
154 }
155
156 /**
157 * @brief LIFOs
158 * @defgroup kernel_lifo_tests LIFOs
159 * @ingroup all_tests
160 * @{
161 * @}
162 */
163
164 /**
165 * @addtogroup kernel_lifo_tests
166 * @{
167 */
168
169 /**
170 * @brief try getting data on lifo with special timeout value,
171 * return result in lifo
172 *
173 *
174 * @see k_lifo_put()
175 */
test_thread_timeout_reply_values(void * p1,void * p2,void * p3)176 static void test_thread_timeout_reply_values(void *p1, void *p2, void *p3)
177 {
178 struct reply_packet *reply_packet = (struct reply_packet *)p1;
179
180 reply_packet->reply =
181 !!k_lifo_get(&lifo_timeout[0], K_NO_WAIT);
182
183 k_lifo_put(&timeout_order_lifo, reply_packet);
184 }
185
186 /**
187 * @see k_lifo_put()
188 */
test_thread_timeout_reply_values_wfe(void * p1,void * p2,void * p3)189 static void test_thread_timeout_reply_values_wfe(void *p1, void *p2, void *p3)
190 {
191 struct reply_packet *reply_packet = (struct reply_packet *)p1;
192
193 reply_packet->reply =
194 !!k_lifo_get(&lifo_timeout[0], K_FOREVER);
195
196 k_lifo_put(&timeout_order_lifo, reply_packet);
197 }
198
199 /**
200 * @brief A thread sleeps then puts data on the lifo
201 *
202 * @see k_lifo_put()
203 */
test_thread_put_timeout(void * p1,void * p2,void * p3)204 static void test_thread_put_timeout(void *p1, void *p2, void *p3)
205 {
206 uint32_t timeout = *((uint32_t *)p2);
207
208 k_msleep(timeout);
209 k_lifo_put((struct k_lifo *)p1, get_scratch_packet());
210 }
211
212 /**
213 * @brief Test last in, first out queue using LIFO
214 * @see k_sem_init(), k_lifo_put(), k_lifo_get()
215 */
ZTEST(lifo_usage,test_lifo_nowait)216 ZTEST(lifo_usage, test_lifo_nowait)
217 {
218 k_lifo_init(&lifo);
219
220 k_sem_init(&start_sema, 0, 1);
221
222 /* put some data on lifo */
223 k_lifo_put(&lifo, (void *)&lifo_data[0]);
224
225 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
226 thread_entry_nowait, &lifo, NULL, NULL,
227 K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
228
229 k_lifo_put(&lifo, (void *)&lifo_data[1]);
230
231 /* Allow another thread to read lifo */
232 k_sem_take(&start_sema, K_FOREVER);
233 k_thread_abort(tid);
234 }
235
236 /**
237 * @brief Test pending reader in LIFO
238 * @see k_lifo_init(), k_lifo_get(), k_lifo_put()
239 */
ZTEST(lifo_usage_1cpu,test_lifo_wait)240 ZTEST(lifo_usage_1cpu, test_lifo_wait)
241 {
242 int *ret;
243
244 k_lifo_init(&plifo);
245 k_sem_init(&wait_sema, 0, 1);
246
247 k_tid_t tid = k_thread_create(&tdata1, tstack1, STACK_SIZE,
248 thread_entry_wait, &plifo, NULL, NULL,
249 K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
250
251 ret = k_lifo_get(&plifo, K_FOREVER);
252
253 zassert_equal(ret, (void *)&lifo_data[0]);
254
255 k_sem_take(&wait_sema, K_FOREVER);
256
257 ret = k_lifo_get(&plifo, K_FOREVER);
258
259 zassert_equal(ret, (void *)&lifo_data[1]);
260
261 k_thread_abort(tid);
262 }
263
264 /**
265 * @brief Test reading empty LIFO
266 * @see k_lifo_get()
267 */
ZTEST(lifo_usage_1cpu,test_timeout_empty_lifo)268 ZTEST(lifo_usage_1cpu, test_timeout_empty_lifo)
269 {
270 void *packet;
271
272 uint32_t start_time, timeout;
273
274 timeout = 100U;
275
276 start_time = k_cycle_get_32();
277
278 packet = k_lifo_get(&lifo_timeout[0], K_MSEC(timeout));
279
280 zassert_is_null(packet);
281
282 zassert_true(is_timeout_in_range(start_time, timeout));
283
284 /* Test empty lifo with timeout of K_NO_WAIT */
285 packet = k_lifo_get(&lifo_timeout[0], K_NO_WAIT);
286 zassert_is_null(packet);
287 }
288
289 /**
290 * @brief Test read and write operation in LIFO with timeout
291 * @see k_lifo_put(), k_lifo_get()
292 */
ZTEST(lifo_usage,test_timeout_non_empty_lifo)293 ZTEST(lifo_usage, test_timeout_non_empty_lifo)
294 {
295 void *packet, *scratch_packet;
296
297 /* Test k_lifo_get with K_NO_WAIT */
298 scratch_packet = get_scratch_packet();
299 k_lifo_put(&lifo_timeout[0], scratch_packet);
300 packet = k_lifo_get(&lifo_timeout[0], K_NO_WAIT);
301 zassert_true(packet != NULL);
302 put_scratch_packet(scratch_packet);
303
304 /* Test k_lifo_get with K_FOREVER */
305 scratch_packet = get_scratch_packet();
306 k_lifo_put(&lifo_timeout[0], scratch_packet);
307 packet = k_lifo_get(&lifo_timeout[0], K_FOREVER);
308 zassert_true(packet != NULL);
309 }
310
311 /**
312 * @brief Test LIFO with timeout
313 * @see k_lifo_put(), k_lifo_get()
314 */
ZTEST(lifo_usage_1cpu,test_timeout_lifo_thread)315 ZTEST(lifo_usage_1cpu, test_timeout_lifo_thread)
316 {
317 void *packet, *scratch_packet;
318 static volatile struct reply_packet reply_packet;
319 uint32_t start_time, timeout;
320
321 /*
322 * Test lifo with some timeout and child thread that puts
323 * data on the lifo on time
324 */
325 timeout = 10U;
326 start_time = k_cycle_get_32();
327
328 to_ord_tid[0] = k_thread_create(&ttdata[0], ttstack[0], TSTACK_SIZE,
329 test_thread_put_timeout, &lifo_timeout[0],
330 &timeout, NULL,
331 LIFO_THREAD_PRIO, K_INHERIT_PERMS, K_NO_WAIT);
332
333 packet = k_lifo_get(&lifo_timeout[0], K_MSEC(timeout + 10));
334 zassert_true(packet != NULL);
335 zassert_true(is_timeout_in_range(start_time, timeout));
336 put_scratch_packet(packet);
337
338 /*
339 * Test k_lifo_get with timeout of K_NO_WAIT and the lifo
340 * should be filled be filled by the child thread based on
341 * the data availability on another lifo. In this test child
342 * thread does not find data on lifo.
343 */
344 to_ord_tid[0] = k_thread_create(&ttdata[0], ttstack[0], TSTACK_SIZE,
345 test_thread_timeout_reply_values,
346 (void *)&reply_packet, NULL, NULL,
347 LIFO_THREAD_PRIO, K_INHERIT_PERMS, K_NO_WAIT);
348
349 k_yield();
350 packet = k_lifo_get(&timeout_order_lifo, K_NO_WAIT);
351 zassert_true(packet != NULL);
352 zassert_false(reply_packet.reply);
353
354 /*
355 * Test k_lifo_get with timeout of K_NO_WAIT and the lifo
356 * should be filled be filled by the child thread based on
357 * the data availability on another lifo. In this test child
358 * thread does find data on lifo.
359 */
360 scratch_packet = get_scratch_packet();
361 k_lifo_put(&lifo_timeout[0], scratch_packet);
362
363 to_ord_tid[0] = k_thread_create(&ttdata[0], ttstack[0], TSTACK_SIZE,
364 test_thread_timeout_reply_values,
365 (void *)&reply_packet, NULL, NULL,
366 LIFO_THREAD_PRIO, K_INHERIT_PERMS, K_NO_WAIT);
367
368 k_yield();
369 packet = k_lifo_get(&timeout_order_lifo, K_NO_WAIT);
370 zassert_true(packet != NULL);
371 zassert_true(reply_packet.reply);
372 put_scratch_packet(scratch_packet);
373
374 /*
375 * Test k_lifo_get with timeout of K_FOREVER and the lifo
376 * should be filled be filled by the child thread based on
377 * the data availability on another lifo. In this test child
378 * thread does find data on lifo.
379 */
380 scratch_packet = get_scratch_packet();
381 k_lifo_put(&lifo_timeout[0], scratch_packet);
382
383 to_ord_tid[0] = k_thread_create(&ttdata[0], ttstack[0], TSTACK_SIZE,
384 test_thread_timeout_reply_values_wfe,
385 (void *)&reply_packet, NULL, NULL,
386 LIFO_THREAD_PRIO, K_INHERIT_PERMS, K_NO_WAIT);
387
388 packet = k_lifo_get(&timeout_order_lifo, K_FOREVER);
389 zassert_true(packet != NULL);
390 zassert_true(reply_packet.reply);
391 put_scratch_packet(scratch_packet);
392 }
393
394 /**
395 * @brief a thread pends on a lifo then times out
396 * @see k_lifo_put(), k_lifo_get()
397 */
test_thread_pend_and_timeout(void * p1,void * p2,void * p3)398 void test_thread_pend_and_timeout(void *p1, void *p2, void *p3)
399 {
400 struct timeout_order_data *d = (struct timeout_order_data *)p1;
401 uint32_t start_time;
402 void *packet;
403
404 start_time = k_cycle_get_32();
405 packet = k_lifo_get(d->klifo, K_MSEC(d->timeout));
406 zassert_true(packet == NULL);
407 zassert_true(is_timeout_in_range(start_time, d->timeout));
408
409 k_lifo_put(&timeout_order_lifo, d);
410 }
411
412
413 /**
414 * @brief Test multiple pending readers in LIFO
415 * @details test multiple threads pending on the same lifo
416 * with different timeouts
417 * @see k_lifo_get()
418 */
ZTEST(lifo_usage_1cpu,test_timeout_threads_pend_on_lifo)419 ZTEST(lifo_usage_1cpu, test_timeout_threads_pend_on_lifo)
420 {
421 int32_t rv, test_data_size;
422
423 /*
424 * Test multiple threads pending on the same
425 * lifo with different timeouts
426 */
427 test_data_size = ARRAY_SIZE(timeout_order_data);
428 rv = test_multiple_threads_pending(timeout_order_data, test_data_size);
429 zassert_equal(rv, TC_PASS);
430 }
431
432 /**
433 * @brief Test LIFO initialization with various parameters
434 * @see k_lifo_init(), k_lifo_put()
435 */
test_para_init(void)436 static void test_para_init(void)
437 {
438 intptr_t ii;
439
440 /* Init kernel objects*/
441 k_lifo_init(&lifo_timeout[0]);
442
443 k_lifo_init(&lifo_timeout[0]);
444
445 k_lifo_init(&timeout_order_lifo);
446
447 k_lifo_init(&scratch_lifo_packets_lifo);
448
449 /* Fill Scratch LIFO*/
450
451 for (ii = 0; ii < NUM_SCRATCH_LIFO_PACKETS; ii++) {
452 scratch_lifo_packets[ii].data_if_needed = (void *)ii;
453 k_lifo_put(&scratch_lifo_packets_lifo,
454 (void *)&scratch_lifo_packets[ii]);
455 }
456
457 for (int i = 0; i < LIST_LEN; i++) {
458 lifo_data[i].data = i + 1;
459 }
460 }
461
462 /**
463 * @}
464 */
465
466 /** test case main entry */
lifo_usage_setup(void)467 void *lifo_usage_setup(void)
468 {
469 test_para_init();
470
471 return NULL;
472 }
473
474
475 ZTEST_SUITE(lifo_usage_1cpu, NULL, lifo_usage_setup,
476 ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL);
477
478 ZTEST_SUITE(lifo_usage, NULL, lifo_usage_setup, NULL, NULL, NULL);
479