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