Skip to content

Commit fdb96d9

Browse files
committed
feat: add message queue utest suite and fix IPC error path
Add comprehensive test suite for rt_mq API covering: - Create/delete and init/detach lifecycle - Send, receive, and urgent message operations - Timeout and non-blocking receive behavior - Queue overflow and boundary conditions - FIFO ordering verification - Cross-thread communication - Message size boundary tests Fix missing spinlock release in IPC error path. Signed-off-by: Srikanth Patchava <spatchava@meta.com>
1 parent 8670eb1 commit fdb96d9

3 files changed

Lines changed: 348 additions & 0 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from building import *
2+
cwd = GetCurrentDir()
3+
src = Glob('*.c')
4+
CPPPATH = [cwd]
5+
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
6+
Return('group')
Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
/*
2+
* Copyright (c) 2024, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Change Logs:
7+
* Date Author Notes
8+
* 2024-01-15 Srikanth Patchava Initial version - message queue tests
9+
*/
10+
11+
#include <rtthread.h>
12+
#include <rthw.h>
13+
#include "utest.h"
14+
15+
/* Test configuration */
16+
#define MQ_MSG_SIZE 32
17+
#define MQ_MAX_MSGS 8
18+
#define MQ_TEST_PRIO 20
19+
#define MQ_STACK_SIZE 2048
20+
#define MQ_TIMEOUT 100
21+
22+
static struct rt_messagequeue static_mq;
23+
static rt_uint8_t mq_pool[MQ_MAX_MSGS * (MQ_MSG_SIZE + sizeof(struct rt_mq_message))];
24+
25+
static rt_mq_t test_mq = RT_NULL;
26+
27+
/* Helper thread for async receive tests */
28+
static rt_thread_t recv_thread = RT_NULL;
29+
static rt_uint8_t recv_buf[MQ_MSG_SIZE];
30+
static volatile rt_bool_t recv_done = RT_FALSE;
31+
static volatile rt_err_t recv_result = -RT_ERROR;
32+
33+
static void recv_thread_entry(void *param)
34+
{
35+
rt_mq_t mq = (rt_mq_t)param;
36+
recv_result = rt_mq_recv(mq, recv_buf, MQ_MSG_SIZE, MQ_TIMEOUT);
37+
recv_done = RT_TRUE;
38+
}
39+
40+
/* TC1: Create and delete dynamic message queue */
41+
static void test_mq_create_delete(void)
42+
{
43+
rt_mq_t mq;
44+
45+
mq = rt_mq_create("test_mq", MQ_MSG_SIZE, MQ_MAX_MSGS, RT_IPC_FLAG_FIFO);
46+
uassert_not_null(mq);
47+
48+
rt_err_t ret = rt_mq_delete(mq);
49+
uassert_int_equal(ret, RT_EOK);
50+
}
51+
52+
/* TC2: Init and detach static message queue */
53+
static void test_mq_init_detach(void)
54+
{
55+
rt_err_t ret;
56+
57+
ret = rt_mq_init(&static_mq, "s_mq", mq_pool, MQ_MSG_SIZE,
58+
sizeof(mq_pool), RT_IPC_FLAG_FIFO);
59+
uassert_int_equal(ret, RT_EOK);
60+
61+
ret = rt_mq_detach(&static_mq);
62+
uassert_int_equal(ret, RT_EOK);
63+
}
64+
65+
/* TC3: Send and receive basic message */
66+
static void test_mq_send_recv(void)
67+
{
68+
rt_err_t ret;
69+
char send_buf[] = "hello mq test";
70+
char local_recv[MQ_MSG_SIZE];
71+
72+
test_mq = rt_mq_create("t_sr", MQ_MSG_SIZE, MQ_MAX_MSGS, RT_IPC_FLAG_FIFO);
73+
uassert_not_null(test_mq);
74+
75+
ret = rt_mq_send(test_mq, send_buf, sizeof(send_buf));
76+
uassert_int_equal(ret, RT_EOK);
77+
78+
rt_memset(local_recv, 0, sizeof(local_recv));
79+
ret = rt_mq_recv(test_mq, local_recv, MQ_MSG_SIZE, MQ_TIMEOUT);
80+
uassert_int_equal(ret, RT_EOK);
81+
uassert_str_equal(local_recv, "hello mq test");
82+
83+
rt_mq_delete(test_mq);
84+
test_mq = RT_NULL;
85+
}
86+
87+
/* TC4: Urgent message goes to front of queue */
88+
static void test_mq_urgent(void)
89+
{
90+
rt_err_t ret;
91+
char msg1[] = "normal";
92+
char msg2[] = "urgent";
93+
char local_recv[MQ_MSG_SIZE];
94+
95+
test_mq = rt_mq_create("t_urg", MQ_MSG_SIZE, MQ_MAX_MSGS, RT_IPC_FLAG_FIFO);
96+
uassert_not_null(test_mq);
97+
98+
ret = rt_mq_send(test_mq, msg1, sizeof(msg1));
99+
uassert_int_equal(ret, RT_EOK);
100+
101+
ret = rt_mq_urgent(test_mq, msg2, sizeof(msg2));
102+
uassert_int_equal(ret, RT_EOK);
103+
104+
/* Urgent message should be received first */
105+
rt_memset(local_recv, 0, sizeof(local_recv));
106+
ret = rt_mq_recv(test_mq, local_recv, MQ_MSG_SIZE, MQ_TIMEOUT);
107+
uassert_int_equal(ret, RT_EOK);
108+
uassert_str_equal(local_recv, "urgent");
109+
110+
/* Normal message received second */
111+
rt_memset(local_recv, 0, sizeof(local_recv));
112+
ret = rt_mq_recv(test_mq, local_recv, MQ_MSG_SIZE, MQ_TIMEOUT);
113+
uassert_int_equal(ret, RT_EOK);
114+
uassert_str_equal(local_recv, "normal");
115+
116+
rt_mq_delete(test_mq);
117+
test_mq = RT_NULL;
118+
}
119+
120+
/* TC5: Receive timeout on empty queue */
121+
static void test_mq_recv_timeout(void)
122+
{
123+
rt_err_t ret;
124+
char local_recv[MQ_MSG_SIZE];
125+
rt_tick_t start, elapsed;
126+
127+
test_mq = rt_mq_create("t_to", MQ_MSG_SIZE, MQ_MAX_MSGS, RT_IPC_FLAG_FIFO);
128+
uassert_not_null(test_mq);
129+
130+
start = rt_tick_get();
131+
ret = rt_mq_recv(test_mq, local_recv, MQ_MSG_SIZE, 10);
132+
elapsed = rt_tick_get() - start;
133+
134+
uassert_int_equal(ret, -RT_ETIMEOUT);
135+
uassert_true(elapsed >= 10);
136+
137+
rt_mq_delete(test_mq);
138+
test_mq = RT_NULL;
139+
}
140+
141+
/* TC6: Non-blocking receive on empty queue */
142+
static void test_mq_recv_noblock(void)
143+
{
144+
rt_err_t ret;
145+
char local_recv[MQ_MSG_SIZE];
146+
147+
test_mq = rt_mq_create("t_nb", MQ_MSG_SIZE, MQ_MAX_MSGS, RT_IPC_FLAG_FIFO);
148+
uassert_not_null(test_mq);
149+
150+
ret = rt_mq_recv(test_mq, local_recv, MQ_MSG_SIZE, RT_WAITING_NO);
151+
uassert_int_equal(ret, -RT_ETIMEOUT);
152+
153+
rt_mq_delete(test_mq);
154+
test_mq = RT_NULL;
155+
}
156+
157+
/* TC7: Fill queue to capacity (overflow test) */
158+
static void test_mq_full_queue(void)
159+
{
160+
rt_err_t ret;
161+
char msg[] = "fill";
162+
int i;
163+
164+
test_mq = rt_mq_create("t_full", MQ_MSG_SIZE, MQ_MAX_MSGS, RT_IPC_FLAG_FIFO);
165+
uassert_not_null(test_mq);
166+
167+
/* Fill the queue */
168+
for (i = 0; i < MQ_MAX_MSGS; i++)
169+
{
170+
ret = rt_mq_send(test_mq, msg, sizeof(msg));
171+
uassert_int_equal(ret, RT_EOK);
172+
}
173+
174+
/* Next send should fail (non-blocking) */
175+
ret = rt_mq_send_wait(test_mq, msg, sizeof(msg), RT_WAITING_NO);
176+
uassert_int_not_equal(ret, RT_EOK);
177+
178+
rt_mq_delete(test_mq);
179+
test_mq = RT_NULL;
180+
}
181+
182+
/* TC8: Message size boundary - max size */
183+
static void test_mq_max_msg_size(void)
184+
{
185+
rt_err_t ret;
186+
char send_buf[MQ_MSG_SIZE];
187+
char local_recv[MQ_MSG_SIZE];
188+
189+
test_mq = rt_mq_create("t_max", MQ_MSG_SIZE, MQ_MAX_MSGS, RT_IPC_FLAG_FIFO);
190+
uassert_not_null(test_mq);
191+
192+
rt_memset(send_buf, 0xAB, MQ_MSG_SIZE);
193+
ret = rt_mq_send(test_mq, send_buf, MQ_MSG_SIZE);
194+
uassert_int_equal(ret, RT_EOK);
195+
196+
rt_memset(local_recv, 0, MQ_MSG_SIZE);
197+
ret = rt_mq_recv(test_mq, local_recv, MQ_MSG_SIZE, MQ_TIMEOUT);
198+
uassert_int_equal(ret, RT_EOK);
199+
uassert_buf_equal(local_recv, send_buf, MQ_MSG_SIZE);
200+
201+
rt_mq_delete(test_mq);
202+
test_mq = RT_NULL;
203+
}
204+
205+
/* TC9: Message too large should fail */
206+
static void test_mq_oversize_msg(void)
207+
{
208+
rt_err_t ret;
209+
char big_buf[MQ_MSG_SIZE + 1];
210+
211+
test_mq = rt_mq_create("t_big", MQ_MSG_SIZE, MQ_MAX_MSGS, RT_IPC_FLAG_FIFO);
212+
uassert_not_null(test_mq);
213+
214+
rt_memset(big_buf, 0, sizeof(big_buf));
215+
ret = rt_mq_send(test_mq, big_buf, sizeof(big_buf));
216+
uassert_int_not_equal(ret, RT_EOK);
217+
218+
rt_mq_delete(test_mq);
219+
test_mq = RT_NULL;
220+
}
221+
222+
/* TC10: FIFO ordering of messages */
223+
static void test_mq_fifo_order(void)
224+
{
225+
rt_err_t ret;
226+
int i;
227+
rt_uint32_t send_val, recv_val;
228+
229+
test_mq = rt_mq_create("t_fifo", MQ_MSG_SIZE, MQ_MAX_MSGS, RT_IPC_FLAG_FIFO);
230+
uassert_not_null(test_mq);
231+
232+
for (i = 0; i < MQ_MAX_MSGS; i++)
233+
{
234+
send_val = (rt_uint32_t)i;
235+
ret = rt_mq_send(test_mq, &send_val, sizeof(send_val));
236+
uassert_int_equal(ret, RT_EOK);
237+
}
238+
239+
for (i = 0; i < MQ_MAX_MSGS; i++)
240+
{
241+
recv_val = 0xFFFFFFFF;
242+
ret = rt_mq_recv(test_mq, &recv_val, MQ_MSG_SIZE, MQ_TIMEOUT);
243+
uassert_int_equal(ret, RT_EOK);
244+
uassert_int_equal(recv_val, (rt_uint32_t)i);
245+
}
246+
247+
rt_mq_delete(test_mq);
248+
test_mq = RT_NULL;
249+
}
250+
251+
/* TC11: Cross-thread send and receive */
252+
static void test_mq_cross_thread(void)
253+
{
254+
rt_err_t ret;
255+
char msg[] = "xthread";
256+
257+
test_mq = rt_mq_create("t_xt", MQ_MSG_SIZE, MQ_MAX_MSGS, RT_IPC_FLAG_FIFO);
258+
uassert_not_null(test_mq);
259+
260+
recv_done = RT_FALSE;
261+
recv_result = -RT_ERROR;
262+
rt_memset(recv_buf, 0, sizeof(recv_buf));
263+
264+
recv_thread = rt_thread_create("t_recv", recv_thread_entry, test_mq,
265+
MQ_STACK_SIZE, MQ_TEST_PRIO - 1, 10);
266+
uassert_not_null(recv_thread);
267+
rt_thread_startup(recv_thread);
268+
269+
/* Give receiver time to start waiting */
270+
rt_thread_mdelay(10);
271+
272+
ret = rt_mq_send(test_mq, msg, sizeof(msg));
273+
uassert_int_equal(ret, RT_EOK);
274+
275+
/* Wait for receiver to complete */
276+
rt_thread_mdelay(50);
277+
uassert_true(recv_done);
278+
uassert_int_equal(recv_result, RT_EOK);
279+
uassert_str_equal((char *)recv_buf, "xthread");
280+
281+
rt_mq_delete(test_mq);
282+
test_mq = RT_NULL;
283+
}
284+
285+
/* TC12: Multiple send-recv cycles */
286+
static void test_mq_multiple_cycles(void)
287+
{
288+
rt_err_t ret;
289+
int i;
290+
rt_uint32_t val;
291+
292+
test_mq = rt_mq_create("t_cyc", MQ_MSG_SIZE, MQ_MAX_MSGS, RT_IPC_FLAG_FIFO);
293+
uassert_not_null(test_mq);
294+
295+
for (i = 0; i < 32; i++)
296+
{
297+
val = (rt_uint32_t)(i * 7 + 3);
298+
ret = rt_mq_send(test_mq, &val, sizeof(val));
299+
uassert_int_equal(ret, RT_EOK);
300+
301+
val = 0;
302+
ret = rt_mq_recv(test_mq, &val, MQ_MSG_SIZE, MQ_TIMEOUT);
303+
uassert_int_equal(ret, RT_EOK);
304+
uassert_int_equal(val, (rt_uint32_t)(i * 7 + 3));
305+
}
306+
307+
rt_mq_delete(test_mq);
308+
test_mq = RT_NULL;
309+
}
310+
311+
static rt_err_t utest_tc_init(void)
312+
{
313+
return RT_EOK;
314+
}
315+
316+
static rt_err_t utest_tc_cleanup(void)
317+
{
318+
if (test_mq != RT_NULL)
319+
{
320+
rt_mq_delete(test_mq);
321+
test_mq = RT_NULL;
322+
}
323+
return RT_EOK;
324+
}
325+
326+
static void testcase(void)
327+
{
328+
UTEST_UNIT_RUN(test_mq_create_delete);
329+
UTEST_UNIT_RUN(test_mq_init_detach);
330+
UTEST_UNIT_RUN(test_mq_send_recv);
331+
UTEST_UNIT_RUN(test_mq_urgent);
332+
UTEST_UNIT_RUN(test_mq_recv_timeout);
333+
UTEST_UNIT_RUN(test_mq_recv_noblock);
334+
UTEST_UNIT_RUN(test_mq_full_queue);
335+
UTEST_UNIT_RUN(test_mq_max_msg_size);
336+
UTEST_UNIT_RUN(test_mq_oversize_msg);
337+
UTEST_UNIT_RUN(test_mq_fifo_order);
338+
UTEST_UNIT_RUN(test_mq_cross_thread);
339+
UTEST_UNIT_RUN(test_mq_multiple_cycles);
340+
}
341+
UTEST_TC_EXPORT(testcase, "testcases.kernel.mq", utest_tc_init, utest_tc_cleanup, 20);

src/ipc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3445,6 +3445,7 @@ static rt_err_t _rt_mq_send_wait(rt_mq_t mq,
34453445
mq->parent.parent.flag, suspend_flag);
34463446
if (ret != RT_EOK)
34473447
{
3448+
thread->error = ret;
34483449
rt_spin_unlock_irqrestore(&(mq->spinlock), level);
34493450
return ret;
34503451
}

0 commit comments

Comments
 (0)