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