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