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, NULL);
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, NULL);
40 		zassert_equal(read_data, data[0], NULL);
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, NULL);
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, NULL);
57 
58 		ret = k_msgq_get(pmsgq, &rx_data, K_FOREVER);
59 		zassert_equal(ret, 0, NULL);
60 		zassert_equal(rx_data, data[i], NULL);
61 
62 		/**TESTPOINT: Check if msg read is the msg deleted*/
63 		zassert_equal(read_data, rx_data, NULL);
64 		/**TESTPOINT: msgq free get*/
65 		zassert_equal(k_msgq_num_free_get(pmsgq), i + 1, NULL);
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, NULL);
78 	zassert_equal(k_msgq_num_used_get(pmsgq), 0, NULL);
79 	zassert_equal(k_msgq_peek(pmsgq, &read_data), -ENOMSG, NULL);
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, NULL);
117 
118 	ret = k_msgq_get(p1, &rx_buf[1], K_FOREVER);
119 
120 	zassert_equal(ret, 0, NULL);
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, NULL);
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, NULL);
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, NULL);
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, NULL);
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, NULL);
229 	zassert_equal(k_msgq_num_used_get(p1), 1, NULL);
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, NULL);
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  */
test_msgq_thread(void)253 void test_msgq_thread(void)
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, NULL);
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  */
test_msgq_thread_overflow(void)270 void test_msgq_thread_overflow(void)
271 {
272 	int ret;
273 
274 	/**TESTPOINT: init via k_msgq_init*/
275 	k_msgq_init(&msgq, tbuffer, MSG_SIZE, 1);
276 	ret = k_sem_init(&end_sema, 0, 1);
277 	zassert_equal(ret, 0, NULL);
278 
279 	msgq_thread_overflow(&msgq);
280 	msgq_thread_overflow(&kmsgq);
281 }
282 
283 #ifdef CONFIG_USERSPACE
284 /**
285  * @brief Test user thread to kernel thread data passing via message queue
286  * @see k_msgq_alloc_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
287  */
test_msgq_user_thread(void)288 void test_msgq_user_thread(void)
289 {
290 	struct k_msgq *q;
291 	int ret;
292 
293 	q = k_object_alloc(K_OBJ_MSGQ);
294 	zassert_not_null(q, "couldn't alloc message queue");
295 	zassert_false(k_msgq_alloc_init(q, MSG_SIZE, MSGQ_LEN), NULL);
296 	ret = k_sem_init(&end_sema, 0, 1);
297 	zassert_equal(ret, 0, NULL);
298 
299 	msgq_thread(q);
300 }
301 
302 /**
303  * @brief Test thread to thread data passing via message queue
304  * @see k_msgq_alloc_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
305  */
test_msgq_user_thread_overflow(void)306 void test_msgq_user_thread_overflow(void)
307 {
308 	struct k_msgq *q;
309 	int ret;
310 
311 	q = k_object_alloc(K_OBJ_MSGQ);
312 	zassert_not_null(q, "couldn't alloc message queue");
313 	zassert_false(k_msgq_alloc_init(q, MSG_SIZE, 1), NULL);
314 	ret = k_sem_init(&end_sema, 0, 1);
315 	zassert_equal(ret, 0, NULL);
316 
317 	msgq_thread_overflow(q);
318 }
319 #endif /* CONFIG_USERSPACE */
320 
321 /**
322  * @brief Test thread to isr data passing via message queue
323  * @see k_msgq_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
324  */
test_msgq_isr(void)325 void test_msgq_isr(void)
326 {
327 	static struct k_msgq stack_msgq;
328 
329 	/**TESTPOINT: init via k_msgq_init*/
330 	k_msgq_init(&stack_msgq, tbuffer, MSG_SIZE, MSGQ_LEN);
331 
332 	msgq_isr(&stack_msgq);
333 	msgq_isr(&kmsgq);
334 }
335 
336 /**
337  * @brief Test pending writer in msgq
338  * @see k_msgq_init(), k_msgq_get(), k_msgq_put(), k_msgq_purge()
339  */
test_msgq_pend_thread(void)340 void test_msgq_pend_thread(void)
341 {
342 	int ret;
343 
344 	k_msgq_init(&msgq1, tbuffer1, MSG_SIZE, 1);
345 	ret = k_sem_init(&end_sema, 0, 1);
346 	zassert_equal(ret, 0, NULL);
347 
348 	msgq_thread_data_passing(&msgq1);
349 }
350 
351 /**
352  * @brief Test k_msgq_alloc_init()
353  * @details Initialization and buffer allocation for msgq from resource
354  * pool with various parameters
355  * @see k_msgq_alloc_init(), k_msgq_cleanup()
356  */
test_msgq_alloc(void)357 void test_msgq_alloc(void)
358 {
359 	int ret;
360 
361 	k_msgq_alloc_init(&kmsgq_test_alloc, MSG_SIZE, MSGQ_LEN);
362 	msgq_isr(&kmsgq_test_alloc);
363 	k_msgq_cleanup(&kmsgq_test_alloc);
364 
365 	/** Requesting buffer allocation from the test pool.*/
366 	ret = k_msgq_alloc_init(&kmsgq_test_alloc, MSG_SIZE * 128, MSGQ_LEN);
367 	zassert_true(ret == -ENOMEM,
368 		"resource pool is smaller then requested buffer");
369 
370 	/* Requesting a huge size of MSG to validate overflow*/
371 	ret = k_msgq_alloc_init(&kmsgq_test_alloc, OVERFLOW_SIZE_MSG, MSGQ_LEN);
372 	zassert_true(ret == -EINVAL, "Invalid request");
373 }
374 
375 /**
376  * @brief Get message from an empty queue
377  *
378  * @details
379  * - A thread get message from an empty message queue will get a -ENOMSG if
380  *   timeout is set to K_NO_WAIT
381  * - A thread get message from an empty message queue will be blocked if timeout
382  *   is set to a positive value or K_FOREVER
383  *
384  * @see k_msgq_get()
385  */
test_msgq_empty(void)386 void test_msgq_empty(void)
387 {
388 	int pri = k_thread_priority_get(k_current_get()) - 1;
389 	int ret;
390 
391 	k_msgq_init(&msgq1, tbuffer1, MSG_SIZE, 1);
392 	ret = k_sem_init(&end_sema, 0, 1);
393 	zassert_equal(ret, 0, NULL);
394 
395 	k_tid_t tid = k_thread_create(&tdata2, tstack2, STACK_SIZE,
396 				      get_empty_entry, &msgq1, NULL,
397 				      NULL, pri, 0, K_NO_WAIT);
398 
399 	k_sem_take(&end_sema, K_FOREVER);
400 	/* that getting thread is being blocked now */
401 	zassert_equal(tid->base.thread_state, _THREAD_PENDING, NULL);
402 	/* since there is a thread is waiting for message, this queue
403 	 * can't be cleanup
404 	 */
405 	ret = k_msgq_cleanup(&msgq1);
406 	zassert_equal(ret, -EBUSY, NULL);
407 
408 	/* put a message to wake that getting thread */
409 	ret = k_msgq_put(&msgq1, &data[0], K_NO_WAIT);
410 	zassert_equal(ret, 0, NULL);
411 
412 	k_thread_abort(tid);
413 }
414 
415 /**
416  * @brief Put message to a full queue
417  *
418  * @details
419  * - A thread put message to a full message queue will get a -ENOMSG if
420  *   timeout is set to K_NO_WAIT
421  * - A thread put message to a full message queue will be blocked if timeout
422  *   is set to a positive value or K_FOREVER
423  *
424  * @see k_msgq_put()
425  */
test_msgq_full(void)426 void test_msgq_full(void)
427 {
428 	int pri = k_thread_priority_get(k_current_get()) - 1;
429 	int ret;
430 
431 	k_msgq_init(&msgq1, tbuffer1, MSG_SIZE, 1);
432 	ret = k_sem_init(&end_sema, 0, 1);
433 	zassert_equal(ret, 0, NULL);
434 
435 	ret = k_msgq_put(&msgq1, &data[0], K_NO_WAIT);
436 	zassert_equal(ret, 0, NULL);
437 
438 	k_tid_t tid = k_thread_create(&tdata2, tstack2, STACK_SIZE,
439 					put_full_entry, &msgq1, NULL,
440 					NULL, pri, 0, K_NO_WAIT);
441 	k_sem_take(&end_sema, K_FOREVER);
442 	/* that putting thread is being blocked now */
443 	zassert_equal(tid->base.thread_state, _THREAD_PENDING, NULL);
444 	k_thread_abort(tid);
445 }
446 
447 /**
448  * @}
449  */
450