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
test_thread_entry(void * para)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
test_main_thread_entry(void * para)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
test_mutex_pi(void)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
test_main_timeout_entry(void * para)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
test_timeout_entry(void * para)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
test_mutex_pi_timeout(void)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
test_recursive_mutex_depend_entry(void * para)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
test_recursive_mutex_depend_hi_pri_entry(void * para)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
test_mutex_pi_recursive_prio_update(void)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
test_mutex_waiter_to_wakeup_entry(void * para)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
wakeup_func(void * para)283 static void wakeup_func(void *para)
284 {
285 rt_thread_resume(t_hi_prio);
286 }
test_mutex_pi_wakeup_mutex_waiter(void)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
utest_tc_init(void)334 static rt_err_t utest_tc_init(void)
335 {
336 return RT_EOK;
337 }
338
utest_tc_cleanup(void)339 static rt_err_t utest_tc_cleanup(void)
340 {
341 return RT_EOK;
342 }
343
testcase(void)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 ************************/
354