1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8
9 #define TIMEOUT K_MSEC(100)
10 #if !defined(CONFIG_BOARD_QEMU_X86)
11 #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
12 #else
13 #define STACK_SIZE (640 + CONFIG_TEST_EXTRA_STACK_SIZE)
14 #endif
15 #define MAIL_LEN 64
16
17 /**
18 * @brief Tests for the mailbox kernel object
19 * @defgroup kernel_mbox_api Mailbox
20 * @ingroup all_tests
21 * @{
22 * @}
23 */
24
25 /**TESTPOINT: init via K_MBOX_DEFINE*/
26 K_MBOX_DEFINE(kmbox);
27
28 static struct k_mbox mbox;
29
30 static k_tid_t sender_tid, receiver_tid, random_tid;
31
32 static K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
33 static K_THREAD_STACK_DEFINE(tstack_1, STACK_SIZE);
34 static K_THREAD_STACK_ARRAY_DEFINE(waiting_get_stack, 5, STACK_SIZE);
35 static struct k_thread tdata, async_tid, waiting_get_tid[5];
36
37 static struct k_sem end_sema, sync_sema;
38
39 static enum mmsg_type {
40 PUT_GET_NULL = 0,
41 PUT_GET_BUFFER,
42 ASYNC_PUT_GET_BUFFER,
43 ASYNC_PUT_GET_BLOCK,
44 TARGET_SOURCE_THREAD_BUFFER,
45 MAX_INFO_TYPE,
46 INCORRECT_RECEIVER_TID,
47 INCORRECT_TRANSMIT_TID,
48 TIMED_OUT_MBOX_GET,
49 MSG_TID_MISMATCH,
50 DISPOSE_SIZE_0_MSG,
51 ASYNC_PUT_TO_WAITING_GET,
52 GET_WAITING_PUT_INCORRECT_TID,
53 ASYNC_MULTIPLE_PUT,
54 MULTIPLE_WAITING_GET
55 } info_type;
56
57 static char data[MAX_INFO_TYPE][MAIL_LEN] = {
58 "send/recv an empty message",
59 "send/recv msg using a buffer",
60 "async send/recv msg using a memory block",
61 "specify target/source thread, using a memory block"
62 };
63
async_put_sema_give(void * p1,void * p2,void * p3)64 static void async_put_sema_give(void *p1, void *p2, void *p3)
65 {
66 k_sem_give(&sync_sema);
67 }
68
69
mbox_get_waiting_thread(void * p1,void * p2,void * p3)70 static void mbox_get_waiting_thread(void *p1, void *p2, void *p3)
71 {
72 int thread_number = POINTER_TO_INT(p1);
73 struct k_mbox *pmbox = p2;
74 struct k_mbox_msg mmsg = {0};
75
76 switch (thread_number) {
77 case 0:
78 mmsg.rx_source_thread = K_ANY;
79 break;
80
81 case 1:
82 mmsg.rx_source_thread = random_tid;
83 break;
84
85 case 2:
86 mmsg.rx_source_thread = receiver_tid;
87 break;
88
89 case 3:
90 mmsg.rx_source_thread = &async_tid;
91 break;
92
93 case 4:
94 mmsg.rx_source_thread = K_ANY;
95 break;
96
97 default:
98 break;
99 }
100
101 mmsg.size = 0;
102 zassert_true(k_mbox_get(pmbox, &mmsg, NULL, K_FOREVER) == 0,
103 "Failure at thread number %d", thread_number);
104
105 }
106
tmbox_put(struct k_mbox * pmbox)107 static void tmbox_put(struct k_mbox *pmbox)
108 {
109 struct k_mbox_msg mmsg = {0};
110
111 switch (info_type) {
112 case PUT_GET_NULL:
113 /**TESTPOINT: mbox sync put empty message*/
114 mmsg.info = PUT_GET_NULL;
115 mmsg.size = 0;
116 mmsg.tx_data = NULL;
117 mmsg.tx_target_thread = K_ANY;
118 k_mbox_put(pmbox, &mmsg, K_FOREVER);
119 break;
120 case PUT_GET_BUFFER:
121 __fallthrough;
122 case TARGET_SOURCE_THREAD_BUFFER:
123 /**TESTPOINT: mbox sync put buffer*/
124 mmsg.info = PUT_GET_BUFFER;
125 mmsg.size = sizeof(data[info_type]);
126 mmsg.tx_data = data[info_type];
127 if (info_type == TARGET_SOURCE_THREAD_BUFFER) {
128 mmsg.tx_target_thread = receiver_tid;
129 } else {
130 mmsg.tx_target_thread = K_ANY;
131 }
132 k_mbox_put(pmbox, &mmsg, K_FOREVER);
133 break;
134 case ASYNC_PUT_GET_BUFFER:
135 /**TESTPOINT: mbox async put buffer*/
136 mmsg.info = ASYNC_PUT_GET_BUFFER;
137 mmsg.size = sizeof(data[info_type]);
138 mmsg.tx_data = data[info_type];
139 mmsg.tx_target_thread = K_ANY;
140 k_mbox_async_put(pmbox, &mmsg, &sync_sema);
141 /*wait for msg being taken*/
142 k_sem_take(&sync_sema, K_FOREVER);
143 break;
144 case ASYNC_PUT_GET_BLOCK:
145 __fallthrough;
146 case INCORRECT_TRANSMIT_TID:
147 mmsg.tx_target_thread = random_tid;
148 zassert_true(k_mbox_put(pmbox,
149 &mmsg,
150 K_NO_WAIT) == -ENOMSG, NULL);
151 break;
152 case MSG_TID_MISMATCH:
153 /* keep one msg in the queue and try to get with a wrong tid */
154 mmsg.info = PUT_GET_NULL;
155 mmsg.size = 0;
156 mmsg.tx_data = NULL;
157 mmsg.tx_target_thread = sender_tid;
158 /* timeout because this msg wont be received with a _get*/
159 k_mbox_put(pmbox, &mmsg, TIMEOUT);
160 break;
161
162 case DISPOSE_SIZE_0_MSG:
163 /* Get a msg and dispose it by making the size = 0 */
164 mmsg.size = 0;
165 mmsg.tx_data = data[1];
166 mmsg.tx_target_thread = K_ANY;
167 zassert_true(k_mbox_put(pmbox, &mmsg, K_FOREVER) == 0);
168 break;
169
170 case ASYNC_PUT_TO_WAITING_GET:
171 k_sem_take(&sync_sema, K_FOREVER);
172 mmsg.size = sizeof(data[0]);
173 mmsg.tx_data = data[0];
174 mmsg.tx_target_thread = K_ANY;
175 k_mbox_async_put(pmbox, &mmsg, NULL);
176 break;
177 case GET_WAITING_PUT_INCORRECT_TID:
178 k_sem_take(&sync_sema, K_FOREVER);
179 mmsg.size = sizeof(data[0]);
180 mmsg.tx_data = data[0];
181 mmsg.tx_target_thread = random_tid;
182 k_mbox_async_put(pmbox, &mmsg, &sync_sema);
183 break;
184 case ASYNC_MULTIPLE_PUT:
185 mmsg.size = sizeof(data[0]);
186 mmsg.tx_data = data[0];
187 mmsg.tx_target_thread = K_ANY;
188 k_mbox_async_put(pmbox, &mmsg, NULL);
189
190 mmsg.tx_data = data[1];
191 mmsg.tx_target_thread = &async_tid;
192 k_mbox_async_put(pmbox, &mmsg, NULL);
193
194 mmsg.tx_data = data[1];
195 mmsg.tx_target_thread = receiver_tid;
196 k_mbox_async_put(pmbox, &mmsg, NULL);
197
198 mmsg.tx_data = data[1];
199 mmsg.tx_target_thread = &async_tid;
200 k_mbox_async_put(pmbox, &mmsg, NULL);
201
202 mmsg.tx_data = data[2];
203 mmsg.tx_target_thread = receiver_tid;
204 k_mbox_async_put(pmbox, &mmsg, &sync_sema);
205
206 k_sem_take(&sync_sema, K_FOREVER);
207 break;
208
209 case MULTIPLE_WAITING_GET:
210 k_sem_take(&sync_sema, K_FOREVER);
211
212 mmsg.size = sizeof(data[0]);
213 mmsg.tx_data = data[0];
214 mmsg.tx_target_thread = K_ANY;
215 k_mbox_put(pmbox, &mmsg, K_NO_WAIT);
216
217 mmsg.tx_data = data[1];
218 mmsg.tx_target_thread = &async_tid;
219 k_mbox_put(pmbox, &mmsg, K_NO_WAIT);
220
221 mmsg.tx_data = data[1];
222 mmsg.tx_target_thread = receiver_tid;
223 k_mbox_put(pmbox, &mmsg, K_NO_WAIT);
224
225 mmsg.tx_data = data[1];
226 mmsg.tx_target_thread = &async_tid;
227 k_mbox_put(pmbox, &mmsg, K_NO_WAIT);
228
229 mmsg.tx_data = data[2];
230 mmsg.tx_target_thread = receiver_tid;
231 k_mbox_put(pmbox, &mmsg, K_NO_WAIT);
232
233 break;
234 default:
235 break;
236 }
237 }
238
tmbox_get(struct k_mbox * pmbox)239 static void tmbox_get(struct k_mbox *pmbox)
240 {
241 struct k_mbox_msg mmsg = {0};
242 char rxdata[MAIL_LEN];
243
244 switch (info_type) {
245 case PUT_GET_NULL:
246 /**TESTPOINT: mbox sync get buffer*/
247 mmsg.size = sizeof(rxdata);
248 mmsg.rx_source_thread = K_ANY;
249 /*verify return value*/
250 zassert_true(k_mbox_get(pmbox, &mmsg, rxdata, K_FOREVER) == 0,
251 NULL);
252 /*verify .info*/
253 zassert_equal(mmsg.info, PUT_GET_NULL);
254 /*verify .size*/
255 zassert_equal(mmsg.size, 0);
256 break;
257 case PUT_GET_BUFFER:
258 __fallthrough;
259 case TARGET_SOURCE_THREAD_BUFFER:
260 /**TESTPOINT: mbox sync get buffer*/
261 mmsg.size = sizeof(rxdata);
262 if (info_type == TARGET_SOURCE_THREAD_BUFFER) {
263 mmsg.rx_source_thread = sender_tid;
264 } else {
265 mmsg.rx_source_thread = K_ANY;
266 }
267 zassert_true(k_mbox_get(pmbox, &mmsg, rxdata, K_FOREVER) == 0,
268 NULL);
269 zassert_equal(mmsg.info, PUT_GET_BUFFER);
270 zassert_equal(mmsg.size, sizeof(data[info_type]));
271 /*verify rxdata*/
272 zassert_true(memcmp(rxdata, data[info_type], MAIL_LEN) == 0,
273 NULL);
274 break;
275 case ASYNC_PUT_GET_BUFFER:
276 /**TESTPOINT: mbox async get buffer*/
277 mmsg.size = sizeof(rxdata);
278 mmsg.rx_source_thread = K_ANY;
279 zassert_true(k_mbox_get(pmbox, &mmsg, NULL, K_FOREVER) == 0,
280 NULL);
281 zassert_equal(mmsg.info, ASYNC_PUT_GET_BUFFER);
282 zassert_equal(mmsg.size, sizeof(data[info_type]));
283 k_mbox_data_get(&mmsg, rxdata);
284 zassert_true(memcmp(rxdata, data[info_type], MAIL_LEN) == 0,
285 NULL);
286 break;
287 case ASYNC_PUT_GET_BLOCK:
288 __fallthrough;
289 case INCORRECT_RECEIVER_TID:
290 mmsg.rx_source_thread = random_tid;
291 zassert_true(k_mbox_get
292 (pmbox, &mmsg, NULL, K_NO_WAIT) == -ENOMSG,
293 NULL);
294 break;
295 case TIMED_OUT_MBOX_GET:
296 mmsg.rx_source_thread = random_tid;
297 zassert_true(k_mbox_get(pmbox, &mmsg, NULL, TIMEOUT) == -EAGAIN,
298 NULL);
299 break;
300 case MSG_TID_MISMATCH:
301 mmsg.rx_source_thread = random_tid;
302 zassert_true(k_mbox_get
303 (pmbox, &mmsg, NULL, K_NO_WAIT) == -ENOMSG, NULL);
304 break;
305
306 case DISPOSE_SIZE_0_MSG:
307 mmsg.rx_source_thread = K_ANY;
308 mmsg.size = 0;
309 zassert_true(k_mbox_get(pmbox, &mmsg, &rxdata, K_FOREVER) == 0,
310 NULL);
311 break;
312
313 case ASYNC_PUT_TO_WAITING_GET:
314
315 /* Create a new thread to trigger the semaphore needed for the
316 * async put.
317 */
318 k_thread_create(&async_tid, tstack_1, STACK_SIZE,
319 async_put_sema_give, NULL, NULL, NULL,
320 K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
321 mmsg.rx_source_thread = K_ANY;
322 mmsg.size = 0;
323 /* Here get is blocked until the thread we created releases
324 * the semaphore and the async put completes it operation.
325 */
326 zassert_true(k_mbox_get(pmbox, &mmsg, NULL, K_FOREVER) == 0,
327 NULL);
328 break;
329 case GET_WAITING_PUT_INCORRECT_TID:
330 /* Create a new thread to trigger the semaphore needed for the
331 * async put.
332 */
333 k_thread_create(&async_tid, tstack_1, STACK_SIZE,
334 async_put_sema_give, NULL, NULL, NULL,
335 K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
336 mmsg.rx_source_thread = &async_tid;
337 mmsg.size = 0;
338 /* Here the get is waiting for a async put to complete
339 * but the TIDs of the msgs doesn't match and hence
340 * causing a timeout.
341 */
342 zassert_true(k_mbox_get(pmbox, &mmsg, NULL, TIMEOUT) == -EAGAIN,
343 NULL);
344 /* clean up */
345 mmsg.rx_source_thread = K_ANY;
346 zassert_true(k_mbox_get(pmbox, &mmsg, NULL, TIMEOUT) == 0,
347 NULL);
348 break;
349
350 case ASYNC_MULTIPLE_PUT:
351 /* Async put has now populated the msgs. Now retrieve all
352 * the msgs from the mailbox.
353 */
354 mmsg.rx_source_thread = K_ANY;
355 mmsg.size = 0;
356 /* get K_any msg */
357 zassert_true(k_mbox_get(pmbox, &mmsg, NULL, TIMEOUT) == 0,
358 NULL);
359 /* get the msg specific to receiver_tid */
360 mmsg.rx_source_thread = sender_tid;
361 zassert_true(k_mbox_get
362 (pmbox, &mmsg, NULL, TIMEOUT) == 0, NULL);
363
364 /* get msg from async or random tid */
365 mmsg.rx_source_thread = K_ANY;
366 zassert_true(k_mbox_get
367 (pmbox, &mmsg, NULL, TIMEOUT) == 0, NULL);
368 break;
369 case MULTIPLE_WAITING_GET:
370 /* Create 5 threads who will wait on a mbox_get. */
371 for (uint32_t i = 0; i < 5; i++) {
372 k_thread_create(&waiting_get_tid[i],
373 waiting_get_stack[i],
374 STACK_SIZE,
375 mbox_get_waiting_thread,
376 INT_TO_POINTER(i), pmbox, NULL,
377 K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
378 }
379 /* Create a new thread to trigger the semaphore needed for the
380 * async put. This will trigger the start of the msg transfer.
381 */
382 k_thread_create(&async_tid, tstack_1, STACK_SIZE,
383 async_put_sema_give, NULL, NULL, NULL,
384 K_PRIO_PREEMPT(1), 0, K_NO_WAIT);
385 break;
386
387 default:
388 break;
389 }
390 }
391
392
393
394 /*entry of contexts*/
tmbox_entry(void * p1,void * p2,void * p3)395 static void tmbox_entry(void *p1, void *p2, void *p3)
396 {
397 tmbox_get((struct k_mbox *)p1);
398 k_sem_give(&end_sema);
399 }
400
tmbox(struct k_mbox * pmbox)401 static void tmbox(struct k_mbox *pmbox)
402 {
403 /*test case setup*/
404 k_sem_reset(&end_sema);
405 k_sem_reset(&sync_sema);
406
407 /**TESTPOINT: thread-thread data passing via mbox*/
408 sender_tid = k_current_get();
409 receiver_tid = k_thread_create(&tdata, tstack, STACK_SIZE,
410 tmbox_entry, pmbox, NULL, NULL,
411 K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
412
413 tmbox_put(pmbox);
414 k_sem_take(&end_sema, K_FOREVER);
415
416 /*test case teardown*/
417 k_thread_abort(receiver_tid);
418 }
419
420 /*test cases*/
ZTEST(mbox_api,test_mbox_kinit)421 ZTEST(mbox_api, test_mbox_kinit)
422 {
423 /**TESTPOINT: init via k_mbox_init*/
424 k_mbox_init(&mbox);
425 }
426
ZTEST(mbox_api,test_mbox_kdefine)427 ZTEST(mbox_api, test_mbox_kdefine)
428 {
429 info_type = PUT_GET_NULL;
430 tmbox(&kmbox);
431 }
432
433 static ZTEST_BMEM char __aligned(4) buffer[8];
434
435 /**
436 *
437 * @brief Test mailbox enhance capabilities
438 *
439 * @details
440 * - Define and initialized a message queue and a mailbox
441 * - Verify the capability of message queue and mailbox
442 * - with same data.
443 *
444 * @ingroup kernel_mbox_api
445 *
446 * @see k_msgq_init() k_msgq_put() k_mbox_async_put() k_mbox_get()
447 */
ZTEST(mbox_api,test_enhance_capability)448 ZTEST(mbox_api, test_enhance_capability)
449 {
450 info_type = ASYNC_PUT_GET_BUFFER;
451 struct k_msgq msgq;
452
453 k_msgq_init(&msgq, buffer, 4, 2);
454 /* send buffer with message queue */
455 int ret = k_msgq_put(&msgq, &data[info_type], K_NO_WAIT);
456
457 zassert_equal(ret, 0, "message queue put successful");
458
459 /* send same buffer with mailbox */
460 tmbox(&mbox);
461 }
462
463 /*
464 *
465 * @brife Test any number of mailbox can be defined
466 *
467 * @details
468 * - Define multi mailbox and verify the mailbox whether as
469 * expected
470 * - Verify the mailbox can be used
471 *
472 */
ZTEST(mbox_api,test_define_multi_mbox)473 ZTEST(mbox_api, test_define_multi_mbox)
474 {
475 /**TESTPOINT: init via k_mbox_init*/
476 struct k_mbox mbox1, mbox2, mbox3;
477
478 k_mbox_init(&mbox1);
479 k_mbox_init(&mbox2);
480 k_mbox_init(&mbox3);
481
482 /* verify via send message */
483 info_type = PUT_GET_NULL;
484 tmbox(&mbox1);
485 tmbox(&mbox2);
486 tmbox(&mbox3);
487 }
488
ZTEST(mbox_api,test_mbox_put_get_null)489 ZTEST(mbox_api, test_mbox_put_get_null)
490 {
491 info_type = PUT_GET_NULL;
492 tmbox(&mbox);
493 }
494
ZTEST(mbox_api,test_mbox_put_get_buffer)495 ZTEST(mbox_api, test_mbox_put_get_buffer)
496 {
497 info_type = PUT_GET_BUFFER;
498 tmbox(&mbox);
499 }
500
ZTEST(mbox_api,test_mbox_async_put_get_buffer)501 ZTEST(mbox_api, test_mbox_async_put_get_buffer)
502 {
503 info_type = ASYNC_PUT_GET_BUFFER;
504 tmbox(&mbox);
505 }
506
ZTEST(mbox_api,test_mbox_async_put_get_block)507 ZTEST(mbox_api, test_mbox_async_put_get_block)
508 {
509 info_type = ASYNC_PUT_GET_BLOCK;
510 tmbox(&mbox);
511 }
512
ZTEST(mbox_api,test_mbox_target_source_thread_buffer)513 ZTEST(mbox_api, test_mbox_target_source_thread_buffer)
514 {
515 info_type = TARGET_SOURCE_THREAD_BUFFER;
516 tmbox(&mbox);
517 }
518
ZTEST(mbox_api,test_mbox_incorrect_receiver_tid)519 ZTEST(mbox_api, test_mbox_incorrect_receiver_tid)
520 {
521 info_type = INCORRECT_RECEIVER_TID;
522 tmbox(&mbox);
523 }
524
ZTEST(mbox_api,test_mbox_incorrect_transmit_tid)525 ZTEST(mbox_api, test_mbox_incorrect_transmit_tid)
526 {
527 info_type = INCORRECT_TRANSMIT_TID;
528 tmbox(&mbox);
529 }
530
ZTEST(mbox_api,test_mbox_timed_out_mbox_get)531 ZTEST(mbox_api, test_mbox_timed_out_mbox_get)
532 {
533 info_type = TIMED_OUT_MBOX_GET;
534 tmbox(&mbox);
535 }
536
ZTEST(mbox_api,test_mbox_msg_tid_mismatch)537 ZTEST(mbox_api, test_mbox_msg_tid_mismatch)
538 {
539 info_type = MSG_TID_MISMATCH;
540 tmbox(&mbox);
541 }
542
ZTEST(mbox_api,test_mbox_dispose_size_0_msg)543 ZTEST(mbox_api, test_mbox_dispose_size_0_msg)
544 {
545 info_type = DISPOSE_SIZE_0_MSG;
546 tmbox(&mbox);
547 }
548
ZTEST(mbox_api,test_mbox_async_put_to_waiting_get)549 ZTEST(mbox_api, test_mbox_async_put_to_waiting_get)
550 {
551 info_type = ASYNC_PUT_TO_WAITING_GET;
552 tmbox(&mbox);
553 }
554
ZTEST(mbox_api,test_mbox_get_waiting_put_incorrect_tid)555 ZTEST(mbox_api, test_mbox_get_waiting_put_incorrect_tid)
556 {
557 info_type = GET_WAITING_PUT_INCORRECT_TID;
558 tmbox(&mbox);
559 }
560
ZTEST(mbox_api,test_mbox_async_multiple_put)561 ZTEST(mbox_api, test_mbox_async_multiple_put)
562 {
563 info_type = ASYNC_MULTIPLE_PUT;
564 tmbox(&mbox);
565 }
566
ZTEST(mbox_api,test_mbox_multiple_waiting_get)567 ZTEST(mbox_api, test_mbox_multiple_waiting_get)
568 {
569 info_type = MULTIPLE_WAITING_GET;
570 tmbox(&mbox);
571
572 /* cleanup the sender threads */
573 for (int i = 0; i < 5 ; i++) {
574 k_thread_abort(&waiting_get_tid[i]);
575 }
576 }
577
setup_mbox_api(void)578 void *setup_mbox_api(void)
579 {
580 k_sem_init(&end_sema, 0, 1);
581 k_sem_init(&sync_sema, 0, 1);
582 k_mbox_init(&mbox);
583
584 return NULL;
585 }
586
587 ZTEST_SUITE(mbox_api, NULL, setup_mbox_api, NULL, NULL, NULL);
588