1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/kernel.h>
9 
10 #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
11 #define MAIL_LEN 64
12 #define HIGH_PRIO 1
13 #define LOW_PRIO  8
14 
15 static K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
16 static K_THREAD_STACK_DEFINE(high_stack, STACK_SIZE);
17 static K_THREAD_STACK_DEFINE(low_stack, STACK_SIZE);
18 
19 static struct k_thread tdata, high_tdata, low_tdata;
20 static struct k_mbox mbox, multi_tmbox;
21 static struct k_sem sync_sema;
22 static k_tid_t tid1, receiver_tid;
23 static char msg_data[2][MAIL_LEN] = {
24 	"send to high prio",
25 	"send to low prio"};
26 
27 static enum mmsg_type {
28 	PUT_GET_NULL = 0,
29 	TARGET_SOURCE
30 } info_type;
31 
msg_sender(struct k_mbox * pmbox,k_timeout_t timeout)32 static void msg_sender(struct k_mbox *pmbox, k_timeout_t timeout)
33 {
34 	static struct k_mbox_msg mmsg;
35 	int ret;
36 
37 	(void)memset(&mmsg, 0, sizeof(mmsg));
38 
39 	switch (info_type) {
40 	case PUT_GET_NULL:
41 		/* mbox sync put empty message */
42 		mmsg.info = PUT_GET_NULL;
43 		mmsg.size = 0;
44 		mmsg.tx_data = NULL;
45 
46 		ret = k_mbox_put(pmbox, &mmsg, timeout);
47 		zassert_ok(ret, "k_mbox_put() failed, ret %d", ret);
48 		break;
49 	default:
50 		break;
51 	}
52 }
53 
msg_receiver(struct k_mbox * pmbox,k_tid_t thd_id,k_timeout_t timeout)54 static void msg_receiver(struct k_mbox *pmbox, k_tid_t thd_id,
55 			 k_timeout_t timeout)
56 {
57 	static struct k_mbox_msg mmsg;
58 	static char rxdata[MAIL_LEN];
59 	int ret;
60 
61 	switch (info_type) {
62 	case PUT_GET_NULL:
63 		mmsg.size = sizeof(rxdata);
64 		mmsg.rx_source_thread = thd_id;
65 
66 		ret = k_mbox_get(pmbox, &mmsg, rxdata, timeout);
67 		if (K_TIMEOUT_EQ(timeout, K_FOREVER)) {
68 			zassert_ok(ret, "k_mbox_get() ret %d", ret);
69 		} else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
70 			zassert_false(ret == 0, "k_mbox_get() ret %d", ret);
71 		} else {
72 			zassert_ok(ret, "k_mbox_get() ret %d", ret);
73 		}
74 		break;
75 	default:
76 		break;
77 	}
78 }
79 
test_mbox_init(void)80 static void test_mbox_init(void)
81 {
82 	k_mbox_init(&mbox);
83 	k_mbox_init(&multi_tmbox);
84 
85 	k_sem_init(&sync_sema, 0, 2);
86 }
87 
test_send(void * p1,void * p2,void * p3)88 static void test_send(void *p1, void *p2, void *p3)
89 {
90 	msg_sender((struct k_mbox *)p1, K_NO_WAIT);
91 }
92 
93 /* Receive message from any thread with no wait */
ZTEST(mbox_usage,test_msg_receiver)94 ZTEST(mbox_usage, test_msg_receiver)
95 {
96 	static k_tid_t tid;
97 
98 	info_type = PUT_GET_NULL;
99 	msg_receiver(&mbox, K_ANY, K_NO_WAIT);
100 
101 	tid = k_thread_create(&tdata, tstack, STACK_SIZE,
102 			      test_send, &mbox, NULL, NULL,
103 			      K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
104 
105 	msg_receiver(&mbox, K_ANY, K_MSEC(2));
106 	k_thread_abort(tid);
107 }
108 
test_send_un(void * p1,void * p2,void * p3)109 static void test_send_un(void *p1, void *p2, void *p3)
110 {
111 	TC_PRINT("Sender UNLIMITED\n");
112 	msg_sender((struct k_mbox *)p1, K_FOREVER);
113 }
114 
115 /* Receive message from thread tid1 */
ZTEST(mbox_usage,test_msg_receiver_unlimited)116 ZTEST(mbox_usage, test_msg_receiver_unlimited)
117 {
118 	info_type = PUT_GET_NULL;
119 
120 	receiver_tid = k_current_get();
121 	tid1 = k_thread_create(&tdata, tstack, STACK_SIZE,
122 			      test_send_un, &mbox, NULL, NULL,
123 			      K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
124 
125 	msg_receiver(&mbox, tid1, K_FOREVER);
126 	k_thread_abort(tid1);
127 }
128 
thread_low_prio(void * p1,void * p2,void * p3)129 static void thread_low_prio(void *p1, void *p2, void *p3)
130 {
131 	static struct k_mbox_msg mmsg = {0};
132 	static char rxdata[MAIL_LEN];
133 	int ret;
134 
135 	mmsg.rx_source_thread = K_ANY;
136 	mmsg.size = sizeof(rxdata);
137 	ret = k_mbox_get(&multi_tmbox, &mmsg, rxdata, K_FOREVER);
138 
139 	zassert_equal(ret, 0, "low prio get msg failed");
140 	zassert_equal(memcmp(rxdata, msg_data[1], MAIL_LEN), 0,
141 		      "low prio data error");
142 
143 	k_sem_give(&sync_sema);
144 }
145 
thread_high_prio(void * p1,void * p2,void * p3)146 static void thread_high_prio(void *p1, void *p2, void *p3)
147 {
148 	static struct k_mbox_msg mmsg = {0};
149 	static char rxdata[MAIL_LEN];
150 	int ret;
151 
152 	mmsg.rx_source_thread = K_ANY;
153 	mmsg.size = sizeof(rxdata);
154 	ret = k_mbox_get(&multi_tmbox, &mmsg, rxdata, K_FOREVER);
155 
156 	zassert_equal(ret, 0, "high prio get msg failed");
157 	zassert_equal(memcmp(rxdata, msg_data[0], MAIL_LEN), 0,
158 		      "high prio data error");
159 
160 	k_sem_give(&sync_sema);
161 }
162 
ZTEST(mbox_usage_1cpu,test_multi_thread_send_get)163 ZTEST(mbox_usage_1cpu, test_multi_thread_send_get)
164 {
165 	static k_tid_t low_prio, high_prio;
166 	struct k_mbox_msg mmsg = {0};
167 
168 	k_sem_reset(&sync_sema);
169 	/* Create diff priority thread to receive msg with same mbox */
170 	low_prio = k_thread_create(&low_tdata, low_stack, STACK_SIZE,
171 				  thread_low_prio, &multi_tmbox, NULL, NULL,
172 				  LOW_PRIO, 0, K_NO_WAIT);
173 
174 	high_prio = k_thread_create(&high_tdata, high_stack, STACK_SIZE,
175 				    thread_high_prio, &multi_tmbox, NULL, NULL,
176 				    HIGH_PRIO, 0, K_NO_WAIT);
177 
178 	mmsg.size = sizeof(msg_data[0]);
179 	mmsg.tx_data = msg_data[0];
180 	mmsg.tx_target_thread = K_ANY;
181 	k_mbox_put(&multi_tmbox, &mmsg, K_FOREVER);
182 
183 	mmsg.size = sizeof(msg_data[1]);
184 	mmsg.tx_data = msg_data[1];
185 	mmsg.tx_target_thread = K_ANY;
186 	k_mbox_put(&multi_tmbox, &mmsg, K_FOREVER);
187 
188 	/* Sync with threads to ensure process end */
189 	k_sem_take(&sync_sema, K_FOREVER);
190 	k_sem_take(&sync_sema, K_FOREVER);
191 
192 	k_thread_abort(low_prio);
193 	k_thread_abort(high_prio);
194 }
195 
setup_mbox_usage(void)196 void *setup_mbox_usage(void)
197 {
198 	test_mbox_init();
199 
200 	return NULL;
201 }
202 
203 ZTEST_SUITE(mbox_usage, NULL, setup_mbox_usage, NULL, NULL, NULL);
204 
205 ZTEST_SUITE(mbox_usage_1cpu, NULL, setup_mbox_usage,
206 	ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL);
207