1 /*
2  * Copyright (c) 2016 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "test_msgq.h"
8 
9 /**TESTPOINT: init via K_MSGQ_DEFINE*/
10 K_MSGQ_DEFINE(kmsgq, MSG_SIZE, MSGQ_LEN, 4);
11 K_MSGQ_DEFINE(kmsgq_test_alloc, MSG_SIZE, MSGQ_LEN, 4);
12 struct k_msgq msgq;
13 struct k_msgq msgq1;
14 K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
15 K_THREAD_STACK_DEFINE(tstack1, STACK_SIZE);
16 K_THREAD_STACK_DEFINE(tstack2, STACK_SIZE);
17 struct k_thread tdata;
18 struct k_thread tdata1;
19 struct k_thread tdata2;
20 static ZTEST_BMEM char __aligned(4) tbuffer[MSG_SIZE * MSGQ_LEN];
21 static ZTEST_DMEM char __aligned(4) tbuffer1[MSG_SIZE];
22 static ZTEST_DMEM uint32_t data[MSGQ_LEN] = { MSG0, MSG1 };
23 struct k_sem end_sema;
24 
put_msgq(struct k_msgq * pmsgq)25 static void put_msgq(struct k_msgq *pmsgq)
26 {
27 	int ret;
28 	uint32_t read_data;
29 
30 	for (int i = 0; i < MSGQ_LEN; i++) {
31 		ret = k_msgq_put(pmsgq, (void *)&data[i], K_NO_WAIT);
32 		zassert_equal(ret, 0);
33 
34 		/**TESTPOINT: Check if k_msgq_peek reads msgq
35 		 * in FIFO manner.
36 		 * Everytime msg is enqueued, msg read should
37 		 * always be the first message
38 		 */
39 		zassert_equal(k_msgq_peek(pmsgq, &read_data), 0);
40 		zassert_equal(read_data, data[0]);
41 
42 		/**TESTPOINT: msgq free get*/
43 		zassert_equal(k_msgq_num_free_get(pmsgq),
44 				MSGQ_LEN - 1 - i, NULL);
45 		/**TESTPOINT: msgq used get*/
46 		zassert_equal(k_msgq_num_used_get(pmsgq), i + 1);
47 	}
48 }
49 
get_msgq(struct k_msgq * pmsgq)50 static void get_msgq(struct k_msgq *pmsgq)
51 {
52 	uint32_t rx_data, read_data;
53 	int ret;
54 
55 	for (int i = 0; i < MSGQ_LEN; i++) {
56 		zassert_equal(k_msgq_peek(pmsgq, &read_data), 0);
57 
58 		ret = k_msgq_get(pmsgq, &rx_data, K_FOREVER);
59 		zassert_equal(ret, 0);
60 		zassert_equal(rx_data, data[i]);
61 
62 		/**TESTPOINT: Check if msg read is the msg deleted*/
63 		zassert_equal(read_data, rx_data);
64 		/**TESTPOINT: msgq free get*/
65 		zassert_equal(k_msgq_num_free_get(pmsgq), i + 1);
66 		/**TESTPOINT: msgq used get*/
67 		zassert_equal(k_msgq_num_used_get(pmsgq),
68 				MSGQ_LEN - 1 - i, NULL);
69 	}
70 }
71 
purge_msgq(struct k_msgq * pmsgq)72 static void purge_msgq(struct k_msgq *pmsgq)
73 {
74 	uint32_t read_data;
75 
76 	k_msgq_purge(pmsgq);
77 	zassert_equal(k_msgq_num_free_get(pmsgq), MSGQ_LEN);
78 	zassert_equal(k_msgq_num_used_get(pmsgq), 0);
79 	zassert_equal(k_msgq_peek(pmsgq, &read_data), -ENOMSG);
80 }
81 
tisr_entry(const void * p)82 static void tisr_entry(const void *p)
83 {
84 	put_msgq((struct k_msgq *)p);
85 }
86 
thread_entry(void * p1,void * p2,void * p3)87 static void thread_entry(void *p1, void *p2, void *p3)
88 {
89 	get_msgq((struct k_msgq *)p1);
90 	k_sem_give(&end_sema);
91 }
92 
msgq_thread(struct k_msgq * pmsgq)93 static void msgq_thread(struct k_msgq *pmsgq)
94 {
95 	/**TESTPOINT: thread-thread data passing via message queue*/
96 	put_msgq(pmsgq);
97 	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
98 				      thread_entry, pmsgq, NULL, NULL,
99 				      K_PRIO_PREEMPT(0),
100 				      K_USER | K_INHERIT_PERMS, K_NO_WAIT);
101 	k_sem_take(&end_sema, K_FOREVER);
102 	k_thread_abort(tid);
103 
104 	/**TESTPOINT: msgq purge*/
105 	purge_msgq(pmsgq);
106 }
107 
thread_entry_overflow(void * p1,void * p2,void * p3)108 static void thread_entry_overflow(void *p1, void *p2, void *p3)
109 {
110 	int ret;
111 
112 	uint32_t rx_buf[MSGQ_LEN];
113 
114 	ret = k_msgq_get(p1, &rx_buf[0], K_FOREVER);
115 
116 	zassert_equal(ret, 0);
117 
118 	ret = k_msgq_get(p1, &rx_buf[1], K_FOREVER);
119 
120 	zassert_equal(ret, 0);
121 
122 	k_sem_give(&end_sema);
123 }
124 
msgq_thread_overflow(struct k_msgq * pmsgq)125 static void msgq_thread_overflow(struct k_msgq *pmsgq)
126 {
127 	int ret;
128 
129 	ret = k_msgq_put(pmsgq, (void *)&data[0], K_FOREVER);
130 
131 	zassert_equal(ret, 0);
132 
133 	/**TESTPOINT: thread-thread data passing via message queue*/
134 	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
135 				      thread_entry_overflow, pmsgq, NULL, NULL,
136 				      K_PRIO_PREEMPT(0),
137 				      K_USER | K_INHERIT_PERMS, K_NO_WAIT);
138 
139 	ret = k_msgq_put(pmsgq, (void *)&data[1], K_FOREVER);
140 
141 	zassert_equal(ret, 0);
142 
143 	k_sem_take(&end_sema, K_FOREVER);
144 	k_thread_abort(tid);
145 
146 	/**TESTPOINT: msgq purge*/
147 	k_msgq_purge(pmsgq);
148 }
149 
msgq_isr(struct k_msgq * pmsgq)150 static void msgq_isr(struct k_msgq *pmsgq)
151 {
152 	/**TESTPOINT: thread-isr data passing via message queue*/
153 	irq_offload(tisr_entry, (const void *)pmsgq);
154 	get_msgq(pmsgq);
155 
156 	/**TESTPOINT: msgq purge*/
157 	purge_msgq(pmsgq);
158 }
159 
thread_entry_get_data(void * p1,void * p2,void * p3)160 static void thread_entry_get_data(void *p1, void *p2, void *p3)
161 {
162 	static uint32_t rx_buf[MSGQ_LEN];
163 	int i = 0;
164 
165 	while (k_msgq_get(p1, &rx_buf[i], K_NO_WAIT) != 0) {
166 		++i;
167 	}
168 
169 	k_sem_give(&end_sema);
170 }
171 
pend_thread_entry(void * p1,void * p2,void * p3)172 static void pend_thread_entry(void *p1, void *p2, void *p3)
173 {
174 	int ret;
175 
176 	ret = k_msgq_put(p1, &data[1], TIMEOUT);
177 	zassert_equal(ret, 0);
178 }
179 
msgq_thread_data_passing(struct k_msgq * pmsgq)180 static void msgq_thread_data_passing(struct k_msgq *pmsgq)
181 {
182 	while (k_msgq_put(pmsgq, &data[0], K_NO_WAIT) != 0) {
183 	}
184 
185 	k_tid_t tid = k_thread_create(&tdata2, tstack2, STACK_SIZE,
186 					pend_thread_entry, pmsgq, NULL,
187 					NULL, K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
188 
189 	k_tid_t tid1 = k_thread_create(&tdata1, tstack1, STACK_SIZE,
190 					thread_entry_get_data, pmsgq, NULL,
191 					NULL, K_PRIO_PREEMPT(1), 0, K_NO_WAIT);
192 
193 	k_sem_take(&end_sema, K_FOREVER);
194 	k_thread_abort(tid);
195 	k_thread_abort(tid1);
196 
197 	/**TESTPOINT: msgq purge*/
198 	k_msgq_purge(pmsgq);
199 }
200 
get_empty_entry(void * p1,void * p2,void * p3)201 static void get_empty_entry(void *p1, void *p2, void *p3)
202 {
203 	int ret;
204 	static uint32_t rx_buf[MSGQ_LEN];
205 
206 	/* make sure there is no message in the queue */
207 	ret = k_msgq_peek(p1, rx_buf);
208 	zassert_equal(ret, -ENOMSG, "Peek message from empty queue");
209 
210 	ret = k_msgq_get(p1, rx_buf, K_NO_WAIT);
211 	zassert_equal(ret, -ENOMSG, "Got message from empty queue");
212 
213 	/* blocked to TIMEOUT */
214 	ret = k_msgq_get(p1, rx_buf, TIMEOUT);
215 	zassert_equal(ret, -EAGAIN, "Got message from empty queue");
216 
217 	k_sem_give(&end_sema);
218 	/* blocked forever */
219 	ret = k_msgq_get(p1, rx_buf, K_FOREVER);
220 	zassert_equal(ret, 0);
221 }
222 
put_full_entry(void * p1,void * p2,void * p3)223 static void put_full_entry(void *p1, void *p2, void *p3)
224 {
225 	int ret;
226 
227 	/* make sure the queue is full */
228 	zassert_equal(k_msgq_num_free_get(p1), 0);
229 	zassert_equal(k_msgq_num_used_get(p1), 1);
230 
231 	ret = k_msgq_put(p1, &data[1], K_NO_WAIT);
232 	zassert_equal(ret, -ENOMSG, "Put message to full queue");
233 
234 	/* blocked to TIMEOUT */
235 	ret = k_msgq_put(p1, &data[1], TIMEOUT);
236 	zassert_equal(ret, -EAGAIN, "Put message to full queue");
237 
238 	k_sem_give(&end_sema);
239 	/* blocked forever */
240 	ret = k_msgq_put(p1, &data[1], K_FOREVER);
241 	zassert_equal(ret, 0);
242 }
243 
244 /**
245  * @addtogroup kernel_message_queue_tests
246  * @{
247  */
248 
249 /**
250  * @brief Test thread to thread data passing via message queue
251  * @see k_msgq_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
252  */
ZTEST(msgq_api_1cpu,test_msgq_thread)253 ZTEST(msgq_api_1cpu, test_msgq_thread)
254 {
255 	int ret;
256 
257 	/**TESTPOINT: init via k_msgq_init*/
258 	k_msgq_init(&msgq, tbuffer, MSG_SIZE, MSGQ_LEN);
259 	ret = k_sem_init(&end_sema, 0, 1);
260 	zassert_equal(ret, 0);
261 
262 	msgq_thread(&msgq);
263 	msgq_thread(&kmsgq);
264 }
265 
266 /**
267  * @brief Test thread to thread data passing via message queue
268  * @see k_msgq_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
269  */
ZTEST(msgq_api,test_msgq_thread_overflow)270 ZTEST(msgq_api, test_msgq_thread_overflow)
271 {
272 	int ret;
273 
274 	/**TESTPOINT: init via k_msgq_init*/
275 	k_msgq_init(&msgq, tbuffer, MSG_SIZE, 2);
276 	ret = k_sem_init(&end_sema, 0, 1);
277 	zassert_equal(ret, 0);
278 
279 	ret = k_msgq_put(&msgq, (void *)&data[0], K_FOREVER);
280 	zassert_equal(ret, 0);
281 
282 	msgq_thread_overflow(&msgq);
283 	msgq_thread_overflow(&kmsgq);
284 
285 	/*verify the write pointer not reset to the buffer start*/
286 	zassert_false(msgq.write_ptr == msgq.buffer_start,
287 		"Invalid add operation of message queue");
288 }
289 
290 #ifdef CONFIG_USERSPACE
291 /**
292  * @brief Test user thread to kernel thread data passing via message queue
293  * @see k_msgq_alloc_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
294  */
ZTEST_USER(msgq_api,test_msgq_user_thread)295 ZTEST_USER(msgq_api, test_msgq_user_thread)
296 {
297 	struct k_msgq *q;
298 	int ret;
299 
300 	q = k_object_alloc(K_OBJ_MSGQ);
301 	zassert_not_null(q, "couldn't alloc message queue");
302 	zassert_false(k_msgq_alloc_init(q, MSG_SIZE, MSGQ_LEN));
303 	ret = k_sem_init(&end_sema, 0, 1);
304 	zassert_equal(ret, 0);
305 
306 	msgq_thread(q);
307 }
308 
309 /**
310  * @brief Test thread to thread data passing via message queue
311  * @see k_msgq_alloc_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
312  */
ZTEST_USER(msgq_api,test_msgq_user_thread_overflow)313 ZTEST_USER(msgq_api, test_msgq_user_thread_overflow)
314 {
315 	struct k_msgq *q;
316 	int ret;
317 
318 	q = k_object_alloc(K_OBJ_MSGQ);
319 	zassert_not_null(q, "couldn't alloc message queue");
320 	zassert_false(k_msgq_alloc_init(q, MSG_SIZE, 1));
321 	ret = k_sem_init(&end_sema, 0, 1);
322 	zassert_equal(ret, 0);
323 
324 	msgq_thread_overflow(q);
325 }
326 #endif /* CONFIG_USERSPACE */
327 
328 /**
329  * @brief Test thread to isr data passing via message queue
330  * @see k_msgq_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
331  */
ZTEST(msgq_api,test_msgq_isr)332 ZTEST(msgq_api, test_msgq_isr)
333 {
334 	static struct k_msgq stack_msgq;
335 
336 	/**TESTPOINT: init via k_msgq_init*/
337 	k_msgq_init(&stack_msgq, tbuffer, MSG_SIZE, MSGQ_LEN);
338 
339 	msgq_isr(&stack_msgq);
340 	msgq_isr(&kmsgq);
341 }
342 
343 /**
344  * @brief Test pending writer in msgq
345  * @see k_msgq_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
346  */
ZTEST(msgq_api_1cpu,test_msgq_pend_thread)347 ZTEST(msgq_api_1cpu, test_msgq_pend_thread)
348 {
349 	int ret;
350 
351 	k_msgq_init(&msgq1, tbuffer1, MSG_SIZE, 1);
352 	ret = k_sem_init(&end_sema, 0, 1);
353 	zassert_equal(ret, 0);
354 
355 	msgq_thread_data_passing(&msgq1);
356 }
357 
358 /**
359  * @brief Test k_msgq_alloc_init()
360  * @details Initialization and buffer allocation for msgq from resource
361  * pool with various parameters
362  * @see k_msgq_alloc_init(), k_msgq_cleanup()
363  */
ZTEST(msgq_api,test_msgq_alloc)364 ZTEST(msgq_api, test_msgq_alloc)
365 {
366 	int ret;
367 
368 	k_msgq_alloc_init(&kmsgq_test_alloc, MSG_SIZE, MSGQ_LEN);
369 	msgq_isr(&kmsgq_test_alloc);
370 	k_msgq_cleanup(&kmsgq_test_alloc);
371 
372 	/** Requesting buffer allocation from the test pool.*/
373 	ret = k_msgq_alloc_init(&kmsgq_test_alloc, MSG_SIZE * 128, MSGQ_LEN);
374 	zassert_true(ret == -ENOMEM,
375 		"resource pool is smaller then requested buffer");
376 
377 	/* Requesting a huge size of MSG to validate overflow*/
378 	ret = k_msgq_alloc_init(&kmsgq_test_alloc, OVERFLOW_SIZE_MSG, MSGQ_LEN);
379 	zassert_true(ret == -EINVAL, "Invalid request");
380 }
381 
382 /**
383  * @brief Get message from an empty queue
384  *
385  * @details
386  * - A thread get message from an empty message queue will get a -ENOMSG if
387  *   timeout is set to K_NO_WAIT
388  * - A thread get message from an empty message queue will be blocked if timeout
389  *   is set to a positive value or K_FOREVER
390  *
391  * @see k_msgq_get()
392  */
ZTEST(msgq_api_1cpu,test_msgq_empty)393 ZTEST(msgq_api_1cpu, test_msgq_empty)
394 {
395 	int pri = k_thread_priority_get(k_current_get()) - 1;
396 	int ret;
397 
398 	k_msgq_init(&msgq1, tbuffer1, MSG_SIZE, 1);
399 	ret = k_sem_init(&end_sema, 0, 1);
400 	zassert_equal(ret, 0);
401 
402 	k_tid_t tid = k_thread_create(&tdata2, tstack2, STACK_SIZE,
403 				      get_empty_entry, &msgq1, NULL,
404 				      NULL, pri, 0, K_NO_WAIT);
405 
406 	k_sem_take(&end_sema, K_FOREVER);
407 	/* that getting thread is being blocked now */
408 	zassert_equal(tid->base.thread_state, _THREAD_PENDING);
409 	/* since there is a thread is waiting for message, this queue
410 	 * can't be cleanup
411 	 */
412 	ret = k_msgq_cleanup(&msgq1);
413 	zassert_equal(ret, -EBUSY);
414 
415 	/* put a message to wake that getting thread */
416 	ret = k_msgq_put(&msgq1, &data[0], K_NO_WAIT);
417 	zassert_equal(ret, 0);
418 
419 	k_thread_abort(tid);
420 }
421 
422 /**
423  * @brief Put message to a full queue
424  *
425  * @details
426  * - A thread put message to a full message queue will get a -ENOMSG if
427  *   timeout is set to K_NO_WAIT
428  * - A thread put message to a full message queue will be blocked if timeout
429  *   is set to a positive value or K_FOREVER
430  *
431  * @see k_msgq_put()
432  */
ZTEST(msgq_api_1cpu,test_msgq_full)433 ZTEST(msgq_api_1cpu, test_msgq_full)
434 {
435 	int pri = k_thread_priority_get(k_current_get()) - 1;
436 	int ret;
437 
438 	k_msgq_init(&msgq1, tbuffer1, MSG_SIZE, 1);
439 	ret = k_sem_init(&end_sema, 0, 1);
440 	zassert_equal(ret, 0);
441 
442 	ret = k_msgq_put(&msgq1, &data[0], K_NO_WAIT);
443 	zassert_equal(ret, 0);
444 
445 	k_tid_t tid = k_thread_create(&tdata2, tstack2, STACK_SIZE,
446 					put_full_entry, &msgq1, NULL,
447 					NULL, pri, 0, K_NO_WAIT);
448 	k_sem_take(&end_sema, K_FOREVER);
449 	/* that putting thread is being blocked now */
450 	zassert_equal(tid->base.thread_state, _THREAD_PENDING);
451 	k_thread_abort(tid);
452 }
453 
454 /**
455  * @}
456  */
457