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