1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2021-08-28     Sherman      the first version
9  * 2023-09-15     xqyjlj       change stack size in cpu64
10  *                             fix in smp
11  */
12 
13 #include <rtthread.h>
14 #include "utest.h"
15 
16 #define THREAD_STACKSIZE UTEST_THR_STACK_SIZE
17 
18 #define MSG_SIZE    4
19 #define MAX_MSGS    5
20 
21 static struct rt_messagequeue static_mq;
22 static rt_uint8_t mq_buf[RT_MQ_BUF_SIZE(MSG_SIZE, MAX_MSGS)];
23 
24 static struct rt_thread mq_send_thread;
25 static struct rt_thread mq_recv_thread;
26 static rt_uint8_t mq_send_stack[UTEST_THR_STACK_SIZE];
27 static rt_uint8_t mq_recv_stack[UTEST_THR_STACK_SIZE];
28 
29 static struct rt_event finish_e;
30 #define MQSEND_FINISH   0x01
31 #define MQRECV_FINIHS   0x02
32 
33 #ifdef RT_USING_HEAP
34 static rt_mq_t dynamic_mq;
35 #endif /* RT_USING_HEAP */
36 
test_mq_init(void)37 static void test_mq_init(void)
38 {
39     rt_err_t ret;
40     ret = rt_mq_init(&static_mq,"testmq1", mq_buf, MSG_SIZE, sizeof(mq_buf), RT_IPC_FLAG_FIFO);
41     uassert_true(ret == RT_EOK);
42 }
43 
test_mq_create(void)44 static void test_mq_create(void)
45 {
46 #ifdef RT_USING_HEAP
47     dynamic_mq = rt_mq_create("testmq2", MSG_SIZE, MAX_MSGS, RT_IPC_FLAG_FIFO);
48     uassert_true(dynamic_mq != RT_NULL);
49 #endif /* RT_USING_HEAP */
50 }
51 
mq_send_case(rt_mq_t testmq)52 static void mq_send_case(rt_mq_t testmq)
53 {
54     rt_uint32_t send_buf[MAX_MSGS+1] = {0};
55     rt_err_t ret = RT_EOK;
56 
57     for (int var = 0; var < MAX_MSGS; ++var)
58     {
59         send_buf[var] = var + 1;
60         ret = rt_mq_send_wait(testmq, &send_buf[var], sizeof(send_buf[0]), RT_WAITING_FOREVER);
61         uassert_true(ret == RT_EOK);
62     }
63     send_buf[MAX_MSGS] = MAX_MSGS + 1;
64     ret = rt_mq_send(testmq, &send_buf[MAX_MSGS], sizeof(send_buf[0]));
65     uassert_true(ret == -RT_EFULL);
66 
67     ret = rt_mq_send_wait(testmq, &send_buf[MAX_MSGS], sizeof(send_buf[0]), RT_WAITING_FOREVER);
68     uassert_true(ret == RT_EOK);
69 
70     while (testmq->entry != 0)
71     {
72         rt_thread_delay(100);
73     }
74 
75     ret = rt_mq_send(testmq, &send_buf[1], sizeof(send_buf[0]));
76     uassert_true(ret == RT_EOK);
77 
78     ret = rt_mq_send(testmq, &send_buf[2], sizeof(send_buf[0]));
79     uassert_true(ret == RT_EOK);
80 
81     ret = rt_mq_urgent(testmq, &send_buf[0], sizeof(send_buf[0]));
82     uassert_true(ret == RT_EOK);
83 
84     while (testmq->entry != 0)
85     {
86         rt_thread_delay(100);
87     }
88 
89 #ifdef RT_USING_MESSAGEQUEUE_PRIORITY
90     ret = rt_mq_send_wait_prio(testmq, &send_buf[3], sizeof(send_buf[0]), 3, 0, RT_UNINTERRUPTIBLE);
91     uassert_true(ret == RT_EOK);
92     ret = rt_mq_send_wait_prio(testmq, &send_buf[0], sizeof(send_buf[0]), 0, 0, RT_UNINTERRUPTIBLE);
93     uassert_true(ret == RT_EOK);
94 
95     ret = rt_mq_send_wait_prio(testmq, &send_buf[2], sizeof(send_buf[0]), 1, 0, RT_UNINTERRUPTIBLE);
96     uassert_true(ret == RT_EOK);
97     ret = rt_mq_send_wait_prio(testmq, &send_buf[4], sizeof(send_buf[0]), 4, 0, RT_UNINTERRUPTIBLE);
98     uassert_true(ret == RT_EOK);
99     ret = rt_mq_send_wait_prio(testmq, &send_buf[1], sizeof(send_buf[0]), 1, 0, RT_UNINTERRUPTIBLE);
100     uassert_true(ret == RT_EOK);
101 
102     while (testmq->entry != 0)
103     {
104         rt_thread_delay(100);
105     }
106 #endif
107 
108     ret = rt_mq_send(testmq, &send_buf[1], sizeof(send_buf[0]));
109     uassert_true(ret == RT_EOK);
110     ret = rt_mq_control(testmq, RT_IPC_CMD_RESET, RT_NULL);
111     uassert_true(ret == RT_EOK);
112     uassert_true(testmq->entry == 0);
113 }
114 
mq_send_entry(void * param)115 static void mq_send_entry(void *param)
116 {
117     mq_send_case(&static_mq);
118 
119 #ifdef RT_USING_HEAP
120     if(dynamic_mq != RT_NULL)
121     {
122         mq_send_case(dynamic_mq);
123     }
124 #endif /* RT_USING_HEAP */
125 
126     rt_event_send(&finish_e, MQSEND_FINISH);
127 }
128 
mq_recv_case(rt_mq_t testmq)129 static void mq_recv_case(rt_mq_t testmq)
130 {
131     rt_uint32_t recv_buf[MAX_MSGS+1] = {0};
132     rt_ssize_t ret = RT_EOK;
133 
134     for (int var = 0; var < MAX_MSGS + 1; ++var)
135     {
136         ret = rt_mq_recv(testmq, &recv_buf[var], sizeof(recv_buf[0]), RT_WAITING_FOREVER);
137         uassert_true(ret >= 0);
138         uassert_true(recv_buf[var] == (var + 1));
139     }
140 
141     for (int var = 0; var < 3; ++var)
142     {
143         ret = rt_mq_recv(testmq, &recv_buf[var], sizeof(recv_buf[0]), RT_WAITING_FOREVER);
144         uassert_true(ret >= 0);
145         uassert_true(recv_buf[var] == (var + 1));
146     }
147 #ifdef RT_USING_MESSAGEQUEUE_PRIORITY
148     rt_int32_t msg_prio;
149     while (testmq->entry == MAX_MSGS)
150     {
151         rt_thread_delay(100);
152     }
153     for (int var = 0; var < MAX_MSGS; ++var)
154     {
155         ret = rt_mq_recv_prio(testmq, &recv_buf[var], sizeof(recv_buf[0]), &msg_prio, RT_WAITING_FOREVER, RT_UNINTERRUPTIBLE);
156         rt_kprintf("msg_prio = %d\r\n", msg_prio);
157         uassert_true(ret >= 0);
158         uassert_true(recv_buf[var] == (MAX_MSGS - var));
159     }
160 #endif
161 }
162 
mq_recv_entry(void * param)163 static void mq_recv_entry(void *param)
164 {
165     mq_recv_case(&static_mq);
166 
167 #ifdef RT_USING_HEAP
168     if(dynamic_mq != RT_NULL)
169     {
170         mq_recv_case(dynamic_mq);
171     }
172 #endif /* RT_USING_HEAP */
173     rt_event_send(&finish_e, MQRECV_FINIHS);
174 }
175 
test_mq_testcase(void)176 static void test_mq_testcase(void)
177 {
178     rt_thread_startup(&mq_send_thread);
179     rt_thread_startup(&mq_recv_thread);
180 
181     rt_event_recv(&finish_e, MQSEND_FINISH | MQRECV_FINIHS, RT_EVENT_FLAG_AND, RT_WAITING_FOREVER, RT_NULL);
182 }
183 
test_mq_detach(void)184 static void test_mq_detach(void)
185 {
186     rt_err_t ret = rt_mq_detach(&static_mq);
187     uassert_true(ret == RT_EOK);
188 }
189 
test_mq_delete(void)190 static void test_mq_delete(void)
191 {
192 #ifdef RT_USING_HEAP
193     rt_err_t ret = rt_mq_delete(dynamic_mq);
194     uassert_true(ret == RT_EOK);
195 #endif /* RT_USING_HEAP */
196 }
197 
utest_tc_init(void)198 static rt_err_t utest_tc_init(void)
199 {
200     rt_err_t ret ;
201     ret = rt_thread_init(&mq_send_thread, "mq_send", mq_send_entry, RT_NULL, mq_send_stack, sizeof(mq_send_stack), 22, 20);
202     if(ret != RT_EOK)
203         return -RT_ERROR;
204 
205     ret = rt_thread_init(&mq_recv_thread, "mq_recv", mq_recv_entry, RT_NULL, mq_recv_stack, sizeof(mq_recv_stack), 23, 20);
206     if(ret != RT_EOK)
207         return -RT_ERROR;
208 
209 #ifdef RT_USING_SMP
210     rt_thread_control(&mq_send_thread, RT_THREAD_CTRL_BIND_CPU, (void *)0);
211     rt_thread_control(&mq_recv_thread, RT_THREAD_CTRL_BIND_CPU, (void *)0);
212 #endif
213 
214     ret = rt_event_init(&finish_e, "finish", RT_IPC_FLAG_FIFO);
215     if(ret != RT_EOK)
216             return -RT_ERROR;
217 
218     return RT_EOK;
219 }
220 
utest_tc_cleanup(void)221 static rt_err_t utest_tc_cleanup(void)
222 {
223     return RT_EOK;
224 }
225 
testcase(void)226 static void testcase(void)
227 {
228     UTEST_UNIT_RUN(test_mq_init);
229     UTEST_UNIT_RUN(test_mq_create);
230     UTEST_UNIT_RUN(test_mq_testcase);
231     UTEST_UNIT_RUN(test_mq_detach);
232     UTEST_UNIT_RUN(test_mq_delete);
233 }
234 UTEST_TC_EXPORT(testcase, "testcases.kernel.messagequeue_tc", utest_tc_init, utest_tc_cleanup, 1000);
235