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