Skip to content

Commit 9631f04

Browse files
authored
[utest]add mutex_pi_tc
* add mutex_pi * fix assertion error when thread wakeup while waiting mutex
1 parent 0c16568 commit 9631f04

File tree

3 files changed

+362
-3
lines changed

3 files changed

+362
-3
lines changed

examples/utest/testcases/kernel/SConscript

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ if GetDepend(['UTEST_SIGNAL_TC']):
3333
src += ['signal_tc.c']
3434

3535
if GetDepend(['UTEST_MUTEX_TC']):
36-
src += ['mutex_tc.c']
36+
src += ['mutex_tc.c', 'mutex_pi_tc.c']
3737

3838
if GetDepend(['UTEST_MAILBOX_TC']):
3939
src += ['mailbox_tc.c']
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
/*
2+
* Copyright (c) 2006-2019, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Change Logs:
7+
* Date Author Notes
8+
*/
9+
#define __RT_IPC_SOURCE__
10+
11+
#include <rtthread.h>
12+
#include <stdlib.h>
13+
#include "utest.h"
14+
15+
#ifdef ARCH_CPU_64BIT
16+
#define THREAD_STACKSIZE 8192
17+
#else
18+
#define THREAD_STACKSIZE 4096
19+
#endif
20+
21+
#define MUTEX_NUM 3
22+
#define THREAD_NUM 5
23+
24+
static struct rt_mutex _mutex[MUTEX_NUM];
25+
static volatile int _sync_flag;
26+
27+
static void test_thread_entry(void *para)
28+
{
29+
while (!_sync_flag)
30+
{
31+
rt_thread_delay(1);
32+
}
33+
34+
rt_ubase_t thread_id = (rt_ubase_t)para;
35+
rt_err_t ret;
36+
rt_thread_mdelay(50 + thread_id * 100);
37+
ret = rt_mutex_take(&_mutex[thread_id % MUTEX_NUM], RT_WAITING_FOREVER);
38+
uassert_true(ret == RT_EOK);
39+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == RT_SCHED_PRIV(rt_thread_self()).init_priority);
40+
41+
if (thread_id == 1)
42+
{
43+
rt_thread_mdelay(100); // wait for main thread re-get _mutex[1]
44+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 8);
45+
}
46+
47+
ret = rt_mutex_release(&_mutex[thread_id % MUTEX_NUM]);
48+
uassert_true(ret == RT_EOK);
49+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == RT_SCHED_PRIV(rt_thread_self()).init_priority);
50+
51+
_sync_flag ++;
52+
}
53+
54+
static void test_main_thread_entry(void *para)
55+
{
56+
while (!_sync_flag)
57+
{
58+
rt_thread_delay(1);
59+
}
60+
61+
rt_err_t ret;
62+
63+
ret = rt_mutex_take(&_mutex[0], RT_WAITING_FOREVER);
64+
uassert_true(ret == RT_EOK);
65+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 12);
66+
rt_thread_mdelay(100); // wait for t0 take mutex0
67+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 12);
68+
69+
ret = rt_mutex_take(&_mutex[1], RT_WAITING_FOREVER);
70+
uassert_true(ret == RT_EOK);
71+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 12);
72+
rt_thread_mdelay(100); // wait for t1 take mutex1
73+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 9);
74+
75+
ret = rt_mutex_take(&_mutex[2], RT_WAITING_FOREVER);
76+
uassert_true(ret == RT_EOK);
77+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 9);
78+
rt_thread_mdelay(100); // wait for t2 take mutex2
79+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 8);
80+
81+
rt_thread_mdelay(100); // wait for t3 take mutex0
82+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 7);
83+
84+
rt_thread_mdelay(100); // wait for t4 take mutex1
85+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 7);
86+
87+
rt_thread_mdelay(100);
88+
rt_mutex_release(&_mutex[0]); // give _mutex0 to t3
89+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 8);
90+
91+
rt_thread_mdelay(100);
92+
rt_mutex_release(&_mutex[1]); // give _mutex1 to t1
93+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 8);
94+
95+
rt_thread_mdelay(50);
96+
rt_mutex_take(&_mutex[1], RT_WAITING_FOREVER); // re-get _mutex1, which is hold by t1
97+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 8);
98+
rt_mutex_release(&_mutex[1]); // give _mutex1 to thread t1
99+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 8);
100+
101+
rt_thread_mdelay(100);
102+
rt_mutex_release(&_mutex[2]);
103+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 12);
104+
105+
_sync_flag ++;
106+
}
107+
108+
static void test_mutex_pi(void)
109+
{
110+
rt_thread_t t_main;
111+
rt_thread_t t[THREAD_NUM];
112+
rt_uint8_t prio[THREAD_NUM] = {13, 9, 8, 7, 11}; // prio of threads
113+
114+
for (int i = 0; i < MUTEX_NUM; i++)
115+
{
116+
rt_mutex_init(&_mutex[i], "test1", 0);
117+
}
118+
119+
_sync_flag = 0;
120+
121+
t_main = rt_thread_create("t_main", test_main_thread_entry, RT_NULL, THREAD_STACKSIZE, 12, 10000);
122+
uassert_true(t_main != RT_NULL);
123+
rt_thread_startup(t_main);
124+
125+
for (rt_ubase_t i = 0; i < THREAD_NUM; i++)
126+
{
127+
t[i] = rt_thread_create("t", test_thread_entry, (void *)i, THREAD_STACKSIZE, prio[i], 10000);
128+
uassert_true(t[i] != RT_NULL);
129+
rt_thread_startup(t[i]);
130+
}
131+
132+
_sync_flag = 1;
133+
134+
while (_sync_flag != THREAD_NUM + 1 + 1)
135+
{
136+
rt_thread_mdelay(100);
137+
}
138+
139+
for (int i = 0; i < MUTEX_NUM; i++)
140+
{
141+
rt_mutex_detach(&_mutex[i]);
142+
}
143+
}
144+
145+
static struct rt_mutex _timeout_mutex;
146+
147+
static void test_main_timeout_entry(void *para)
148+
{
149+
rt_err_t ret;
150+
151+
ret = rt_mutex_take(&_timeout_mutex, RT_WAITING_FOREVER);
152+
uassert_true(ret == -RT_EOK);
153+
rt_thread_mdelay(100);
154+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 10);
155+
rt_thread_mdelay(100);
156+
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 12);
157+
rt_mutex_release(&_timeout_mutex);
158+
_sync_flag ++;
159+
}
160+
161+
static void test_timeout_entry(void *para)
162+
{
163+
rt_err_t ret;
164+
165+
rt_thread_mdelay(50);
166+
ret = rt_mutex_take(&_timeout_mutex, rt_tick_from_millisecond(100));
167+
uassert_true(ret == -RT_ETIMEOUT);
168+
_sync_flag ++;
169+
}
170+
171+
static void test_mutex_pi_timeout(void)
172+
{
173+
_sync_flag = 0;
174+
175+
rt_mutex_init(&_timeout_mutex, "_timeout_mutex", 0);
176+
177+
rt_thread_t t1 = rt_thread_create("t1", test_main_timeout_entry, RT_NULL, THREAD_STACKSIZE, 12, 10000);
178+
uassert_true(t1 != RT_NULL);
179+
rt_thread_startup(t1);
180+
181+
rt_thread_t t2 = rt_thread_create("t2", test_timeout_entry, (void *)t1, THREAD_STACKSIZE, 10, 10000);
182+
uassert_true(t2 != RT_NULL);
183+
rt_thread_startup(t2);
184+
185+
while (_sync_flag != 2)
186+
{
187+
rt_thread_mdelay(100);
188+
}
189+
190+
rt_mutex_detach(&_timeout_mutex);
191+
}
192+
193+
#define TC_THREAD_NUM 4
194+
#define TC_MUTEX_NUM TC_THREAD_NUM
195+
static rt_thread_t t[TC_THREAD_NUM], t_hi_prio;
196+
static struct rt_mutex m[TC_MUTEX_NUM];
197+
198+
static void test_recursive_mutex_depend_entry(void *para)
199+
{
200+
rt_ubase_t id = (rt_ubase_t)para;
201+
202+
rt_mutex_take(&m[id], RT_WAITING_FOREVER);
203+
204+
rt_thread_mdelay(50);
205+
206+
if (id != 0)
207+
{
208+
rt_mutex_take(&m[id - 1], RT_WAITING_FOREVER);
209+
}
210+
211+
if (id == 0)
212+
{
213+
rt_thread_mdelay(250);
214+
rt_mutex_release(&m[id]);
215+
}
216+
else
217+
{
218+
rt_mutex_release(&m[id - 1]);
219+
rt_mutex_release(&m[id]);
220+
}
221+
_sync_flag ++;
222+
}
223+
224+
static void test_recursive_mutex_depend_hi_pri_entry(void *para)
225+
{
226+
rt_thread_mdelay(100);
227+
rt_err_t err = rt_mutex_take(&m[TC_MUTEX_NUM - 1], rt_tick_from_millisecond(100));
228+
uassert_true(err == -RT_ETIMEOUT);
229+
_sync_flag ++;
230+
}
231+
232+
static void test_mutex_pi_recursive_prio_update(void)
233+
{
234+
_sync_flag = 0;
235+
236+
for (int i = 0; i < TC_MUTEX_NUM; i++)
237+
{
238+
rt_mutex_init(&m[i], "test", 0);
239+
}
240+
241+
for (rt_ubase_t i = 0; i < TC_THREAD_NUM; i++)
242+
{
243+
t[i] = rt_thread_create("t", test_recursive_mutex_depend_entry, (void *)i, THREAD_STACKSIZE, 10, 10000);
244+
rt_thread_startup(t[i]);
245+
}
246+
t_hi_prio = rt_thread_create("t", test_recursive_mutex_depend_hi_pri_entry, (void *)RT_NULL, THREAD_STACKSIZE, 3, 10000);
247+
rt_thread_startup(t_hi_prio);
248+
249+
rt_thread_mdelay(150);
250+
251+
for (int i = 0; i < TC_THREAD_NUM; i++)
252+
{
253+
uassert_true(RT_SCHED_PRIV(t[i]).current_priority == 3);
254+
}
255+
256+
rt_thread_mdelay(100);
257+
258+
for (int i = 0; i < TC_THREAD_NUM; i++)
259+
{
260+
uassert_true(RT_SCHED_PRIV(t[i]).current_priority == 10);
261+
}
262+
263+
while (_sync_flag != TC_THREAD_NUM + 1)
264+
{
265+
rt_thread_mdelay(100);
266+
}
267+
268+
for (int i = 0; i < TC_MUTEX_NUM; i++)
269+
{
270+
rt_mutex_detach(&m[i]);
271+
}
272+
_sync_flag ++;
273+
}
274+
275+
static void test_mutex_waiter_to_wakeup_entry(void *para)
276+
{
277+
rt_thread_mdelay(100);
278+
rt_err_t err = rt_mutex_take(&m[TC_MUTEX_NUM - 1], RT_WAITING_FOREVER);
279+
uassert_true(err == -RT_EINTR);
280+
_sync_flag ++;
281+
}
282+
283+
static void wakeup_func(void *para)
284+
{
285+
rt_thread_resume(t_hi_prio);
286+
}
287+
static void test_mutex_pi_wakeup_mutex_waiter(void)
288+
{
289+
struct rt_timer wakeup_timer;
290+
291+
_sync_flag = 0;
292+
293+
for (int i = 0; i < TC_MUTEX_NUM; i++)
294+
{
295+
rt_mutex_init(&m[i], "test", 0);
296+
}
297+
298+
for (rt_ubase_t i = 0; i < TC_THREAD_NUM; i++)
299+
{
300+
t[i] = rt_thread_create("t", test_recursive_mutex_depend_entry, (void *)i, THREAD_STACKSIZE, 10, 10000);
301+
rt_thread_startup(t[i]);
302+
}
303+
t_hi_prio = rt_thread_create("t", test_mutex_waiter_to_wakeup_entry, (void *)RT_NULL, THREAD_STACKSIZE, 3, 10000);
304+
rt_thread_startup(t_hi_prio);
305+
306+
rt_timer_init(&wakeup_timer, "wakeup_timer", wakeup_func, RT_NULL, rt_tick_from_millisecond(200), RT_TIMER_FLAG_ONE_SHOT);
307+
rt_timer_start(&wakeup_timer);
308+
rt_thread_mdelay(150);
309+
310+
for (int i = 0; i < TC_THREAD_NUM; i++)
311+
{
312+
uassert_true(RT_SCHED_PRIV(t[i]).current_priority == 3);
313+
}
314+
315+
rt_thread_mdelay(100);
316+
317+
for (int i = 0; i < TC_THREAD_NUM; i++)
318+
{
319+
uassert_true(RT_SCHED_PRIV(t[i]).current_priority == 10);
320+
}
321+
322+
while (_sync_flag != TC_THREAD_NUM + 1)
323+
{
324+
rt_thread_mdelay(100);
325+
}
326+
327+
for (int i = 0; i < TC_MUTEX_NUM; i++)
328+
{
329+
rt_mutex_detach(&m[i]);
330+
}
331+
rt_timer_detach(&wakeup_timer);
332+
}
333+
334+
static rt_err_t utest_tc_init(void)
335+
{
336+
return RT_EOK;
337+
}
338+
339+
static rt_err_t utest_tc_cleanup(void)
340+
{
341+
return RT_EOK;
342+
}
343+
344+
static void testcase(void)
345+
{
346+
UTEST_UNIT_RUN(test_mutex_pi);
347+
UTEST_UNIT_RUN(test_mutex_pi_recursive_prio_update);
348+
UTEST_UNIT_RUN(test_mutex_pi_timeout);
349+
UTEST_UNIT_RUN(test_mutex_pi_wakeup_mutex_waiter);
350+
}
351+
UTEST_TC_EXPORT(testcase, "testcases.kernel.mutex_pi_tc", utest_tc_init, utest_tc_cleanup, 1000);
352+
353+
/********************* end of file ************************/

src/ipc.c

+8-2
Original file line numberDiff line numberDiff line change
@@ -1450,13 +1450,13 @@ static rt_err_t _rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout, int suspend
14501450

14511451
rt_spin_lock(&(mutex->spinlock));
14521452

1453-
if (thread->error == RT_EOK)
1453+
if (mutex->owner == thread)
14541454
{
14551455
/**
14561456
* get mutex successfully
14571457
* Note: assert to avoid an unexpected resume
14581458
*/
1459-
RT_ASSERT(mutex->owner == thread);
1459+
RT_ASSERT(thread->error == RT_EOK);
14601460
}
14611461
else
14621462
{
@@ -1468,6 +1468,12 @@ static rt_err_t _rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout, int suspend
14681468
/* get value first before calling to other APIs */
14691469
ret = thread->error;
14701470

1471+
/* unexpected resume */
1472+
if (ret == RT_EOK)
1473+
{
1474+
ret = -RT_EINTR;
1475+
}
1476+
14711477
rt_sched_lock(&slvl);
14721478

14731479
/**

0 commit comments

Comments
 (0)