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