1 /*
2  * Copyright (c) 2024 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/ztest.h>
9 #include <stdio.h>
10 
11 
12 /* COMMON DEFFINITIONS */
13 #define STACK_SIZE	500
14 #define LIST_LEN 8
15 
16 static struct k_sem sema;
17 static struct k_thread tdata;
18 
19 static K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
20 
21 
22 /* FIFO SCENARIO */
23 /* Thread A enters items into a fifo, starts Thread B and waits for a semaphore. */
24 /* Thread B extracts all items from the fifo and enters some items back into the fifo. */
25 /* Thread B gives the semaphore for Thread A to continue. */
26 /* Once the control is returned back to Thread A, it extracts all items from the fifo. */
27 /* Verify the data's correctness. */
28 
29 static K_FIFO_DEFINE(fifo);
30 struct fifo_item_t {
31 	void *fifo_reserved;   /* 1st word reserved for use by FIFO */
32 	uint8_t value;
33 };
34 static struct fifo_item_t fifo_data[LIST_LEN];
35 
thread_entry_fn_fifo(void * p1,void * p2,void * p3)36 static void thread_entry_fn_fifo(void *p1, void *p2, void *p3)
37 {
38 	struct fifo_item_t  *rx_data;
39 	uint32_t i;
40 
41 	/* Get items from fifo */
42 	for (i = 0U; i < LIST_LEN; i++) {
43 		rx_data = k_fifo_get((struct k_fifo *)p1, K_NO_WAIT);
44 		zassert_equal(rx_data->value, fifo_data[i].value);
45 	}
46 
47 	/* Put items into fifo */
48 	for (i = 0U; i < LIST_LEN; i++) {
49 		fifo_data[i].value *= i;
50 		k_fifo_put((struct k_fifo *)p1, &fifo_data[i]);
51 	}
52 
53 	/* Give control back to Thread A */
54 	k_sem_give(&sema);
55 }
56 
57 
ZTEST(kernel,test_fifo_usage)58 ZTEST(kernel, test_fifo_usage)
59 {
60 	struct fifo_item_t *rx_data;
61 	uint32_t i;
62 
63 	/* Init binary semaphore */
64 	k_sem_init(&sema, 0, 1);
65 
66 	/* Set and Put items into fifo */
67 	for (i = 0U; i < LIST_LEN; i++) {
68 		fifo_data[i].value = i;
69 		k_fifo_put(&fifo, &fifo_data[i]);
70 	}
71 
72 	/* Create the Thread B */
73 	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
74 					thread_entry_fn_fifo, &fifo, NULL, NULL,
75 					K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_NO_WAIT);
76 
77 	/* Let the thread B run */
78 	k_sem_take(&sema, K_FOREVER);
79 
80 	/* Get items from fifo */
81 	for (i = 0U; i < LIST_LEN; i++) {
82 		rx_data = k_fifo_get(&fifo, K_NO_WAIT);
83 		zassert_equal(rx_data->value, fifo_data[i].value);
84 	}
85 
86 	/* Clear the spawn thread */
87 	k_thread_abort(tid);
88 }
89 
90 /* LIFO SCENARIO */
91 /* Thread A enters items into a lifo, starts Thread B and waits for a semaphore. */
92 /* Thread B extracts all items from the lifo and enters some items back into the lifo. */
93 /* Thread B gives the semaphore for Thread A to continue. */
94 /* Once the control is returned back to Thread A, it extracts all items from the lifo. */
95 /* Verify the data's correctness. */
96 
97 struct lifo_item_t {
98 	void *LIFO_reserved;   /* 1st word reserved for use by LIFO */
99 	uint8_t value;
100 };
101 static struct lifo_item_t lifo_data[LIST_LEN];
102 K_LIFO_DEFINE(lifo);
103 
104 
thread_entry_fn_lifo(void * p1,void * p2,void * p3)105 static void thread_entry_fn_lifo(void *p1, void *p2, void *p3)
106 {
107 	struct lifo_item_t  *rx_data;
108 	uint32_t i;
109 
110 	/* Get items from lifo */
111 	for (i = 0U; i < LIST_LEN; i++) {
112 		rx_data = k_lifo_get((struct k_lifo *)p1, K_NO_WAIT);
113 		zassert_equal(rx_data->value, lifo_data[LIST_LEN-1-i].value);
114 	}
115 
116 	/* Put items into lifo */
117 	for (i = 0U; i < LIST_LEN; i++) {
118 		lifo_data[i].value *= i;
119 		k_lifo_put((struct k_lifo *)p1, &lifo_data[i]);
120 	}
121 
122 	/* Give control back to Thread A */
123 	k_sem_give(&sema);
124 }
125 
ZTEST(kernel,test_lifo_usage)126 ZTEST(kernel, test_lifo_usage)
127 {
128 	struct lifo_item_t *rx_data;
129 	uint32_t i;
130 
131 	/* Init binary semaphore */
132 	k_sem_init(&sema, 0, 1);
133 
134 	/* Set and Put items into lifo */
135 	for (i = 0U; i < LIST_LEN; i++) {
136 		lifo_data[i].value = i;
137 		k_lifo_put(&lifo, &lifo_data[i]);
138 	}
139 
140 	/* Create the Thread B */
141 	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
142 					thread_entry_fn_lifo, &lifo, NULL, NULL,
143 					K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_NO_WAIT);
144 
145 	/* Let the thread B run */
146 	k_sem_take(&sema, K_FOREVER);
147 
148 	/* Get items from lifo */
149 	for (i = 0U; i < LIST_LEN; i++) {
150 		rx_data = k_lifo_get(&lifo, K_NO_WAIT);
151 		zassert_equal(rx_data->value, lifo_data[LIST_LEN-1-i].value);
152 	}
153 
154 	/* Clear the spawn thread */
155 	k_thread_abort(tid);
156 
157 }
158 
159 /* STACK SCENARIO */
160 /* Thread A enters items into a stack, starts thread B and waits for a semaphore. */
161 /* Thread B extracts all items from the stack and enters some items back into the stack. */
162 /* Thread B gives the semaphore for Thread A to continue. */
163 /* Once the control is returned back to Thread A, it extracts all items from the stack. */
164 /* Verify the data's correctness. */
165 
166 
167 #define STACK_LEN	8
168 #define MAX_ITEMS	8
169 
170 K_STACK_DEFINE(stack, STACK_LEN);
171 stack_data_t stack_data[MAX_ITEMS];
172 
173 
thread_entry_fn_stack(void * p1,void * p2,void * p3)174 static void thread_entry_fn_stack(void *p1, void *p2, void *p3)
175 {
176 	stack_data_t *rx_data;
177 	stack_data_t data[MAX_ITEMS];
178 
179 	/* fill data to compare */
180 	for (int i = 0; i < STACK_LEN; i++) {
181 		data[i] = i;
182 	}
183 
184 	/* read data from a stack */
185 	for (int i = 0; i < STACK_LEN; i++) {
186 		k_stack_pop((struct k_stack *)p1, (stack_data_t *)&rx_data, K_NO_WAIT);
187 	}
188 
189 	zassert_false(memcmp(rx_data, data, STACK_LEN),
190 		      "Push & Pop items does not match");
191 
192 	/* Push data into a stack */
193 	for (int i = 0; i < STACK_LEN; i++) {
194 		stack_data[i] *= i;
195 		k_stack_push((struct k_stack *)p1, (stack_data_t)&stack_data[i]);
196 	}
197 
198 	/* Give control back to Thread A */
199 	k_sem_give(&sema);
200 }
201 
202 
ZTEST(kernel,test_stack_usage)203 ZTEST(kernel, test_stack_usage)
204 {
205 	stack_data_t *rx_data;
206 
207 	/* Init binary semaphore */
208 	k_sem_init(&sema, 0, 1);
209 
210 	/* Push data into a stack */
211 	for (int i = 0; i < STACK_LEN; i++) {
212 		stack_data[i] = i;
213 		k_stack_push(&stack, (stack_data_t)&stack_data[i]);
214 	}
215 
216 	/* Create the Thread B */
217 	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
218 					thread_entry_fn_stack, &stack, NULL, NULL,
219 					K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_NO_WAIT);
220 
221 	/* Let the thread B run */
222 	k_sem_take(&sema, K_FOREVER);
223 
224 	/* read data from a stack */
225 	for (int i = 0; i < STACK_LEN; i++) {
226 		k_stack_pop(&stack, (stack_data_t *)&rx_data, K_NO_WAIT);
227 	}
228 
229 
230 	/* Verify the correctness */
231 	zassert_false(memcmp(rx_data, stack_data, STACK_LEN),
232 		      "Push & Pop items does not match");
233 
234 	/* Clear the spawn thread */
235 	k_thread_abort(tid);
236 }
237 
238 /* MUTEX SCENARIO */
239 /* Initialize the mutex. */
240 /* Start the two Threads with the entry points. */
241 /* The entry points change variable and use lock and unlock mutex functions to */
242 /* synchronize the access to that variable. */
243 /* Join all threads. */
244 /* Verify the variable. */
245 
246 #define NUMBER_OF_ITERATIONS 10000
247 
248 static uint32_t mutex_data;
249 static struct k_thread tdata_2;
250 static K_THREAD_STACK_DEFINE(tstack_2, STACK_SIZE);
251 
252 K_MUTEX_DEFINE(mutex);
253 
thread_entry_fn_mutex(void * p1,void * p2,void * p3)254 static void thread_entry_fn_mutex(void *p1, void *p2, void *p3)
255 {
256 	uint32_t i;
257 
258 	for (i = 0; i < NUMBER_OF_ITERATIONS; i++) {
259 		k_mutex_lock((struct k_mutex *)p1, K_FOREVER);
260 		mutex_data += 1;
261 		k_mutex_unlock((struct k_mutex *)p1);
262 	}
263 }
264 
thread_entry_fn_mutex_2(void * p1,void * p2,void * p3)265 static void thread_entry_fn_mutex_2(void *p1, void *p2, void *p3)
266 {
267 	uint32_t i;
268 
269 	for (i = 0; i < NUMBER_OF_ITERATIONS*2; i++) {
270 		k_mutex_lock((struct k_mutex *)p1, K_FOREVER);
271 		mutex_data -= 1;
272 		k_mutex_unlock((struct k_mutex *)p1);
273 	}
274 }
275 
ZTEST(kernel,test_mutex_usage)276 ZTEST(kernel, test_mutex_usage)
277 {
278 
279     /* Create the Thread A */
280 	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
281 					thread_entry_fn_mutex, &mutex, &mutex_data, NULL,
282 					K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_FOREVER);
283 
284 	/* Create the Thread B */
285 	k_tid_t tid2 = k_thread_create(&tdata_2, tstack_2, STACK_SIZE,
286 					thread_entry_fn_mutex_2, &mutex, &mutex_data, NULL,
287 					K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_FOREVER);
288 
289 	/* Start the Thread A */
290 	k_thread_start(tid);
291 	/* Start the Thread B */
292 	k_thread_start(tid2);
293 	/* Wait for end of Thread A */
294 	k_thread_join(&tdata, K_FOREVER);
295 	/* Wait for end of Thread B */
296 	k_thread_join(&tdata_2, K_FOREVER);
297 	/* Verify data after the end of the threads */
298 	zassert_equal(mutex_data, -10000);
299 
300 	/* Clear the spawn threads */
301 	k_thread_abort(tid);
302 	k_thread_abort(tid2);
303 }
304 
305 
306 ZTEST_SUITE(kernel, NULL, NULL,
307 		ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL);
308