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