1 /*
2  * Copyright (c) 2016 Wind River Systems, Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/tc_util.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/kernel_structs.h>
11 #include <stdbool.h>
12 
13 #define  NUM_SECONDS(x)      ((x) * 1000)
14 #define  HALF_SECOND                (500)
15 #define  THIRD_SECOND               (333)
16 #define  FOURTH_SECOND              (250)
17 
18 #define COOP_STACKSIZE   (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
19 #define PREEM_STACKSIZE  (1024 + CONFIG_TEST_EXTRA_STACK_SIZE)
20 
21 #define FIFO_TEST_START       10
22 #define FIFO_TEST_END         20
23 
24 #define SEM_TEST_START        30
25 #define SEM_TEST_END          40
26 
27 #define LIFO_TEST_START       50
28 #define LIFO_TEST_END         60
29 
30 #define NON_NULL_PTR          ((void *)0x12345678)
31 
32 #ifdef CONFIG_COVERAGE_GCOV
33 #define OFFLOAD_WORKQUEUE_STACK_SIZE 4096
34 #else
35 #define OFFLOAD_WORKQUEUE_STACK_SIZE 1024
36 #endif
37 
38 #define OFFLOAD_WORKQUEUE_PRIORITY	(-1)
39 static struct k_work_q offload_work_q;
40 static K_THREAD_STACK_DEFINE(offload_work_q_stack,
41 			     OFFLOAD_WORKQUEUE_STACK_SIZE);
42 
43 struct fifo_data {
44 	intptr_t reserved;
45 	uint32_t data;
46 };
47 
48 struct lifo_data {
49 	intptr_t reserved;
50 	uint32_t data;
51 };
52 
53 struct offload_work {
54 	struct k_work work_item;
55 	struct k_sem *sem;
56 };
57 
58 static K_THREAD_STACK_ARRAY_DEFINE(coop_stack, 2, COOP_STACKSIZE);
59 static struct k_thread coop_thread[2];
60 
61 static struct k_fifo fifo;
62 static struct k_lifo lifo;
63 static struct k_timer timer;
64 
65 static struct k_sem start_test_sem;
66 static struct k_sem sync_test_sem;
67 static struct k_sem end_test_sem;
68 
69 struct fifo_data fifo_test_data[4] = {
70 	{ 0, FIFO_TEST_END + 1 }, { 0, FIFO_TEST_END + 2 },
71 	{ 0, FIFO_TEST_END + 3 }, { 0, FIFO_TEST_END + 4 }
72 };
73 
74 struct lifo_data lifo_test_data[4] = {
75 	{ 0, LIFO_TEST_END + 1 }, { 0, LIFO_TEST_END + 2 },
76 	{ 0, LIFO_TEST_END + 3 }, { 0, LIFO_TEST_END + 4 }
77 };
78 
79 static uint32_t timer_start_tick;
80 static uint32_t timer_end_tick;
81 static void *timer_data;
82 
83 static int __noinit coop_high_state;
84 static int __noinit coop_low_state;
85 static int __noinit task_high_state;
86 static int __noinit task_low_state;
87 
88 static int __noinit counter;
89 
my_fifo_get(struct k_fifo * my_fifo,int32_t timeout)90 static inline void *my_fifo_get(struct k_fifo *my_fifo, int32_t timeout)
91 {
92 	return k_fifo_get(my_fifo, K_MSEC(timeout));
93 }
94 
my_lifo_get(struct k_lifo * my_lifo,int32_t timeout)95 static inline void *my_lifo_get(struct k_lifo *my_lifo, int32_t timeout)
96 {
97 	return k_lifo_get(my_lifo, K_MSEC(timeout));
98 }
99 
increment_counter(void)100 static int increment_counter(void)
101 {
102 	int tmp;
103 	unsigned int key = irq_lock();
104 
105 	tmp = ++counter;
106 	irq_unlock(key);
107 
108 	return tmp;
109 }
110 
sync_threads(struct k_work * work)111 static void sync_threads(struct k_work *work)
112 {
113 	struct offload_work *offload =
114 		CONTAINER_OF(work, struct offload_work, work_item);
115 
116 	k_sem_give(offload->sem);
117 	k_sem_give(offload->sem);
118 	k_sem_give(offload->sem);
119 	k_sem_give(offload->sem);
120 
121 }
122 
fifo_tests(int32_t timeout,volatile int * state,void * (* get)(struct k_fifo *,int32_t),int (* sem_take)(struct k_sem *,k_timeout_t))123 static void fifo_tests(int32_t timeout, volatile int *state,
124 		       void *(*get)(struct k_fifo *, int32_t),
125 		       int (*sem_take)(struct k_sem *, k_timeout_t))
126 {
127 	struct fifo_data *data;
128 
129 	sem_take(&start_test_sem, K_FOREVER);
130 
131 	*state = FIFO_TEST_START;
132 	/* Expect this to time out */
133 	data = get(&fifo, timeout);
134 	if (data != NULL) {
135 		TC_ERROR("**** Unexpected data on FIFO get\n");
136 		return;
137 	}
138 	*state = increment_counter();
139 
140 	/* Sync up fifo test threads */
141 	sem_take(&sync_test_sem, K_FOREVER);
142 
143 	/* Expect this to receive data from the fifo */
144 	*state = FIFO_TEST_END;
145 	data = get(&fifo, timeout);
146 	if (data == NULL) {
147 		TC_ERROR("**** No data on FIFO get\n");
148 		return;
149 	}
150 	*state = increment_counter();
151 
152 	if (data->data != *state) {
153 		TC_ERROR("**** Got FIFO data %d, not %d (%d)\n",
154 			 data->data, *state, timeout);
155 		return;
156 	}
157 
158 	sem_take(&end_test_sem, K_FOREVER);
159 }
160 
lifo_tests(int32_t timeout,volatile int * state,void * (* get)(struct k_lifo *,int32_t),int (* sem_take)(struct k_sem *,k_timeout_t))161 static void lifo_tests(int32_t timeout, volatile int *state,
162 		       void *(*get)(struct k_lifo *, int32_t),
163 		       int (*sem_take)(struct k_sem *, k_timeout_t))
164 {
165 	struct lifo_data *data;
166 
167 	sem_take(&start_test_sem, K_FOREVER);
168 
169 	*state = LIFO_TEST_START;
170 	/* Expect this to time out */
171 	data = get(&lifo, timeout);
172 	if (data != NULL) {
173 		TC_ERROR("**** Unexpected data on LIFO get\n");
174 		return;
175 	}
176 	*state = increment_counter();
177 
178 	/* Sync up all threads */
179 	sem_take(&sync_test_sem, K_FOREVER);
180 
181 	/* Expect this to receive data from the lifo */
182 	*state = LIFO_TEST_END;
183 	data = get(&lifo, timeout);
184 	if (data == NULL) {
185 		TC_ERROR("**** No data on LIFO get\n");
186 		return;
187 	}
188 	*state = increment_counter();
189 
190 	if (data->data != *state) {
191 		TC_ERROR("**** Got LIFO data %d, not %d (%d)\n",
192 			 data->data, *state, timeout);
193 		return;
194 	}
195 
196 	sem_take(&end_test_sem, K_FOREVER);
197 }
198 
timer_tests(void)199 static void timer_tests(void)
200 {
201 	k_sem_take(&start_test_sem, K_FOREVER);
202 
203 	timer_start_tick = k_uptime_get_32();
204 
205 	k_timer_start(&timer, K_SECONDS(1), K_NO_WAIT);
206 
207 	if (k_timer_status_sync(&timer)) {
208 		timer_data = timer.user_data;
209 	}
210 
211 	timer_end_tick = k_uptime_get_32();
212 
213 	k_sem_take(&end_test_sem, K_FOREVER);
214 }
215 
coop_high(void * arg1,void * arg2,void * arg3)216 static void coop_high(void *arg1, void *arg2, void *arg3)
217 {
218 	ARG_UNUSED(arg1);
219 	ARG_UNUSED(arg2);
220 	ARG_UNUSED(arg3);
221 
222 	fifo_tests(NUM_SECONDS(1), &coop_high_state, my_fifo_get, k_sem_take);
223 
224 	lifo_tests(NUM_SECONDS(1), &coop_high_state, my_lifo_get, k_sem_take);
225 }
226 
coop_low(void * arg1,void * arg2,void * arg3)227 static void coop_low(void *arg1, void *arg2, void *arg3)
228 {
229 	ARG_UNUSED(arg1);
230 	ARG_UNUSED(arg2);
231 	ARG_UNUSED(arg3);
232 
233 	fifo_tests(HALF_SECOND, &coop_low_state, my_fifo_get, k_sem_take);
234 
235 	lifo_tests(HALF_SECOND, &coop_low_state, my_lifo_get, k_sem_take);
236 }
237 
task_high(void)238 void task_high(void)
239 {
240 	k_fifo_init(&fifo);
241 	k_lifo_init(&lifo);
242 
243 	k_timer_init(&timer, NULL, NULL);
244 	timer.user_data = NON_NULL_PTR;
245 
246 	k_sem_init(&start_test_sem, 0, UINT_MAX);
247 	k_sem_init(&sync_test_sem, 0, UINT_MAX);
248 	k_sem_init(&end_test_sem, 0, UINT_MAX);
249 
250 	k_work_queue_start(&offload_work_q,
251 		       offload_work_q_stack,
252 		       K_THREAD_STACK_SIZEOF(offload_work_q_stack),
253 		       OFFLOAD_WORKQUEUE_PRIORITY, NULL);
254 
255 	counter = SEM_TEST_START;
256 
257 	k_thread_create(&coop_thread[0], coop_stack[0], COOP_STACKSIZE,
258 			coop_high, NULL, NULL, NULL, K_PRIO_COOP(3), 0,
259 			K_NO_WAIT);
260 
261 	k_thread_create(&coop_thread[1], coop_stack[1], COOP_STACKSIZE,
262 			coop_low, NULL, NULL, NULL, K_PRIO_COOP(7), 0,
263 			K_NO_WAIT);
264 
265 	counter = FIFO_TEST_START;
266 	fifo_tests(THIRD_SECOND, &task_high_state, my_fifo_get, k_sem_take);
267 
268 	counter = LIFO_TEST_START;
269 	lifo_tests(THIRD_SECOND, &task_high_state, my_lifo_get, k_sem_take);
270 
271 	timer_tests();
272 }
273 
task_low(void)274 void task_low(void)
275 {
276 	fifo_tests(FOURTH_SECOND, &task_low_state, my_fifo_get, k_sem_take);
277 
278 	lifo_tests(FOURTH_SECOND, &task_low_state, my_lifo_get, k_sem_take);
279 }
280 
281 /**
282  * @brief Test pending
283  *
284  * @defgroup kernel_pending_tests Pending tests
285  *
286  * @ingroup all_tests
287  *
288  * @{
289  */
290 
291 /**
292  * @brief Test pending of workq, fifo and lifo
293  *
294  * @see k_sleep(), K_THREAD_DEFINE()
295  */
ZTEST(pending,test_pending_fifo)296 ZTEST(pending, test_pending_fifo)
297 {
298 	/*
299 	 * Main thread(test_main) priority was 9 but ztest thread runs at
300 	 * priority -1. To run the test smoothly make both main and ztest
301 	 * threads run at same priority level.
302 	 */
303 	k_thread_priority_set(k_current_get(), 9);
304 
305 	struct offload_work offload1 = {0};
306 
307 	k_work_init(&offload1.work_item, sync_threads);
308 	offload1.sem = &start_test_sem;
309 	k_work_submit_to_queue(&offload_work_q, &offload1.work_item);
310 
311 	/*
312 	 * Verify that preemptible threads 'task_high' and 'task_low' do not
313 	 * busy-wait. If they are not busy-waiting, then they must be pending.
314 	 */
315 
316 	TC_PRINT("Testing preemptible threads block on fifos ...\n");
317 	zassert_false((coop_high_state != FIFO_TEST_START) ||
318 		      (coop_low_state != FIFO_TEST_START) ||
319 		      (task_high_state != FIFO_TEST_START) ||
320 		      (task_low_state != FIFO_TEST_START), NULL);
321 
322 	/* Give waiting threads time to time-out */
323 	k_sleep(K_SECONDS(2));
324 
325 	/*
326 	 * Verify that the cooperative and preemptible threads timed-out in
327 	 * the correct order.
328 	 */
329 
330 	TC_PRINT("Testing fifos time-out in correct order ...\n");
331 	zassert_false((task_low_state != FIFO_TEST_START + 1) ||
332 		      (task_high_state != FIFO_TEST_START + 2) ||
333 		      (coop_low_state != FIFO_TEST_START + 3) ||
334 		      (coop_high_state != FIFO_TEST_START + 4),
335 		      "**** Threads timed-out in unexpected order");
336 
337 	counter = FIFO_TEST_END;
338 
339 	k_work_init(&offload1.work_item, sync_threads);
340 	offload1.sem = &sync_test_sem;
341 	k_work_submit_to_queue(&offload_work_q, &offload1.work_item);
342 
343 	/*
344 	 * Two cooperative and two preemptible threads should be waiting on
345 	 * the FIFO
346 	 */
347 
348 	/* Add data to the FIFO */
349 	TC_PRINT("Testing  fifos delivered data correctly ...\n");
350 	k_fifo_put(&fifo, &fifo_test_data[0]);
351 	k_fifo_put(&fifo, &fifo_test_data[1]);
352 	k_fifo_put(&fifo, &fifo_test_data[2]);
353 	k_fifo_put(&fifo, &fifo_test_data[3]);
354 
355 	zassert_false((coop_high_state != FIFO_TEST_END + 1) ||
356 		      (coop_low_state != FIFO_TEST_END + 2) ||
357 		      (task_high_state != FIFO_TEST_END + 3) ||
358 		      (task_low_state != FIFO_TEST_END + 4),
359 		      "**** Unexpected delivery order");
360 }
361 
362 
ZTEST(pending,test_pending_lifo)363 ZTEST(pending, test_pending_lifo)
364 {
365 	/*
366 	 * Main thread(test_main) priority was 9 but ztest thread runs at
367 	 * priority -1. To run the test smoothly make both main and ztest
368 	 * threads run at same priority level.
369 	 */
370 	k_thread_priority_set(k_current_get(), 9);
371 
372 	struct offload_work offload1 = {0};
373 	struct offload_work offload2 = {0};
374 
375 	k_work_init(&offload1.work_item, sync_threads);
376 	offload1.sem = &end_test_sem;
377 	k_work_submit_to_queue(&offload_work_q, &offload1.work_item);
378 
379 	k_work_init(&offload2.work_item, sync_threads);
380 	offload2.sem = &start_test_sem;
381 	k_work_submit_to_queue(&offload_work_q, &offload2.work_item);
382 
383 	/*
384 	 * Verify that cooperative threads 'task_high' and 'task_low' do not
385 	 * busy-wait. If they are not busy-waiting, then they must be pending.
386 	 */
387 
388 	TC_PRINT("Testing preemptible threads block on lifos ...\n");
389 	zassert_false((coop_high_state != LIFO_TEST_START) ||
390 		      (coop_low_state != LIFO_TEST_START) ||
391 		      (task_high_state != LIFO_TEST_START) ||
392 		      (task_low_state != LIFO_TEST_START), NULL);
393 
394 	/* Give waiting threads time to time-out */
395 	k_sleep(K_SECONDS(2));
396 
397 	TC_PRINT("Testing lifos time-out in correct order ...\n");
398 	zassert_false((task_low_state != LIFO_TEST_START + 1) ||
399 		      (task_high_state != LIFO_TEST_START + 2) ||
400 		      (coop_low_state != LIFO_TEST_START + 3) ||
401 		      (coop_high_state != LIFO_TEST_START + 4),
402 		      "**** Threads timed-out in unexpected order");
403 
404 	counter = LIFO_TEST_END;
405 
406 	k_work_init(&offload1.work_item, sync_threads);
407 	offload1.sem = &sync_test_sem;
408 	k_work_submit_to_queue(&offload_work_q, &offload1.work_item);
409 
410 	/*
411 	 * Two cooperative threads and two preemptive threads should
412 	 * be waiting on the LIFO
413 	 */
414 
415 	/* Add data to the LIFO */
416 	k_lifo_put(&lifo, &lifo_test_data[0]);
417 	k_lifo_put(&lifo, &lifo_test_data[1]);
418 	k_lifo_put(&lifo, &lifo_test_data[2]);
419 	k_lifo_put(&lifo, &lifo_test_data[3]);
420 
421 	TC_PRINT("Testing lifos delivered data correctly ...\n");
422 	zassert_false((coop_high_state != LIFO_TEST_END + 1) ||
423 		      (coop_low_state != LIFO_TEST_END + 2) ||
424 		      (task_high_state != LIFO_TEST_END + 3) ||
425 		      (task_low_state != LIFO_TEST_END + 4),
426 		      "**** Unexpected timeout order");
427 
428 }
429 
ZTEST(pending,test_pending_timer)430 ZTEST(pending, test_pending_timer)
431 {
432 	/*
433 	 * Main thread(test_main) priority was 9 but ztest thread runs at
434 	 * priority -1. To run the test smoothly make both main and ztest
435 	 * threads run at same priority level.
436 	 */
437 	k_thread_priority_set(k_current_get(), 9);
438 
439 	struct offload_work offload2 = {0};
440 
441 	k_work_init(&offload2.work_item, sync_threads);
442 	offload2.sem = &end_test_sem;
443 	k_work_submit_to_queue(&offload_work_q, &offload2.work_item);
444 
445 	timer_end_tick = 0U;
446 	k_sem_give(&start_test_sem);    /* start timer tests */
447 
448 	/*
449 	 * NOTE: The timer test is running in the context of high_task().
450 	 * Scheduling is expected to yield to high_task().  If high_task()
451 	 * does not pend as expected, then timer_end_tick will be non-zero.
452 	 */
453 
454 	TC_PRINT("Testing preemptible thread waiting on timer ...\n");
455 	zassert_equal(timer_end_tick, 0, "Task did not pend on timer");
456 
457 	/* Let the timer expire */
458 	k_sleep(K_SECONDS(2));
459 
460 	zassert_false((timer_end_tick < timer_start_tick + NUM_SECONDS(1)),
461 			"Task waiting on timer error");
462 
463 	zassert_equal(timer_data, NON_NULL_PTR,
464 				"Incorrect data from timer");
465 
466 	k_sem_give(&end_test_sem);
467 }
468 
469 /**
470  * @}
471  */
472 
473 K_THREAD_DEFINE(TASK_LOW, PREEM_STACKSIZE, task_low, NULL, NULL, NULL,
474 		7, 0, 0);
475 
476 K_THREAD_DEFINE(TASK_HIGH, PREEM_STACKSIZE, task_high, NULL, NULL, NULL,
477 		5, 0, 0);
478 
479 ZTEST_SUITE(pending, NULL, NULL,
480 		ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL);
481