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 * 2021-09.01 luckyzjq the first version
9 * 2023-09-15 xqyjlj change stack size in cpu64
10 */
11 #define __RT_IPC_SOURCE__
12
13 #include <rtthread.h>
14 #include <stdlib.h>
15 #include "utest.h"
16
17 #ifdef ARCH_CPU_64BIT
18 #define THREAD_STACKSIZE 8192
19 #else
20 #define THREAD_STACKSIZE 4096
21 #endif
22
23 static struct rt_mutex static_mutex;
24
25 #ifdef RT_USING_HEAP
26 static rt_mutex_t dynamic_mutex;
27 #endif /* RT_USING_HEAP */
28
29 static volatile int _sync_flag;
30
31 /* init test */
test_static_mutex_init(void)32 static void test_static_mutex_init(void)
33 {
34 rt_err_t result = -RT_ERROR;
35
36 result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
37 if (RT_EOK != result)
38 {
39 uassert_true(RT_FALSE);
40 }
41
42 result = rt_mutex_detach(&static_mutex);
43 if (RT_EOK != result)
44 {
45 uassert_true(RT_FALSE);
46 }
47
48 result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
49 if (RT_EOK != result)
50 {
51 uassert_true(RT_FALSE);
52 }
53
54 result = rt_mutex_detach(&static_mutex);
55 if (RT_EOK != result)
56 {
57 uassert_true(RT_FALSE);
58 }
59
60 uassert_true(RT_TRUE);
61 }
62
63 /* static take test */
static_mutex_take_entry(void * param)64 static void static_mutex_take_entry(void *param)
65 {
66 rt_err_t result;
67 rt_mutex_t mutex;
68
69 int rand_num = rand() % 0x1000;
70 mutex = (rt_mutex_t)param;
71
72 result = rt_mutex_take(mutex, rand_num);
73 if (RT_EOK == result)
74 {
75 uassert_true(RT_FALSE);
76 }
77 _sync_flag++;
78 }
79
test_static_mutex_take(void)80 static void test_static_mutex_take(void)
81 {
82 rt_err_t result;
83
84 _sync_flag = 0;
85
86 result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
87 if (RT_EOK != result)
88 {
89 uassert_true(RT_FALSE);
90 return;
91 }
92
93 /* take mutex and not release */
94 result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
95 if (RT_EOK != result)
96 uassert_true(RT_FALSE);
97
98 rt_thread_t tid = rt_thread_create("mutex_th",
99 static_mutex_take_entry,
100 &static_mutex,
101 THREAD_STACKSIZE,
102 10,
103 10);
104 if (RT_NULL == tid)
105 {
106 uassert_true(RT_FALSE);
107 return;
108 }
109
110 /* startup thread take second */
111 rt_thread_startup(tid);
112
113 while (_sync_flag != 1)
114 {
115 rt_thread_mdelay(10);
116 }
117
118 result = rt_mutex_detach(&static_mutex);
119 if (RT_EOK != result)
120 uassert_true(RT_FALSE);
121
122 uassert_true(RT_TRUE);
123 }
124
125 /* static release test */
static_mutex_release_entry(void * param)126 static void static_mutex_release_entry(void *param)
127 {
128 rt_err_t result;
129 rt_mutex_t mutex;
130
131 int rand_num = rand() % 0x1000;
132 mutex = (rt_mutex_t)param;
133
134 result = rt_mutex_take(mutex, rand_num);
135 if (RT_EOK != result)
136 {
137 uassert_true(RT_FALSE);
138 }
139 _sync_flag++;
140 }
test_static_mutex_release(void)141 static void test_static_mutex_release(void)
142 {
143 rt_err_t result;
144
145 _sync_flag = 0;
146
147 result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
148 if (RT_EOK != result)
149 {
150 uassert_true(RT_FALSE);
151 return;
152 }
153
154 result = rt_mutex_release(&static_mutex);
155 uassert_true(result < 0);
156
157 /* take mutex */
158 result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
159 if (RT_EOK != result)
160 uassert_true(RT_FALSE);
161
162 /* release mutex */
163 result = rt_mutex_release(&static_mutex);
164 if (RT_EOK != result)
165 uassert_true(RT_FALSE);
166
167 rt_thread_t tid = rt_thread_create("mutex_th",
168 static_mutex_release_entry,
169 &static_mutex,
170 THREAD_STACKSIZE,
171 10,
172 10);
173 if (RT_NULL == tid)
174 {
175 uassert_true(RT_FALSE);
176 return;
177 }
178
179 /* startup thread and take mutex second */
180 rt_thread_startup(tid);
181
182 while (_sync_flag != 1)
183 {
184 rt_thread_mdelay(10);
185 }
186
187 result = rt_mutex_detach(&static_mutex);
188 if (RT_EOK != result)
189 uassert_true(RT_FALSE);
190
191 uassert_true(RT_TRUE);
192 }
193
194 /* static trytake test */
static_mutex_trytake_entry(void * param)195 static void static_mutex_trytake_entry(void *param)
196 {
197 rt_err_t result;
198 rt_mutex_t mutex;
199
200 mutex = (rt_mutex_t)param;
201
202 result = rt_mutex_trytake(mutex);
203 if (RT_EOK == result)
204 {
205 uassert_true(RT_FALSE);
206 }
207 _sync_flag++;
208 }
test_static_mutex_trytake(void)209 static void test_static_mutex_trytake(void)
210 {
211 rt_err_t result;
212
213 _sync_flag = 0;
214
215 result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
216 if (RT_EOK != result)
217 {
218 uassert_true(RT_FALSE);
219 return;
220 }
221
222 /* take mutex and not release */
223 result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
224 if (RT_EOK != result)
225 uassert_true(RT_FALSE);
226
227 rt_thread_t tid = rt_thread_create("mutex_th",
228 static_mutex_trytake_entry,
229 &static_mutex,
230 THREAD_STACKSIZE,
231 10,
232 10);
233 if (RT_NULL == tid)
234 {
235 uassert_true(RT_FALSE);
236 return;
237 }
238
239 /* startup thread and trytake mutex second */
240 rt_thread_startup(tid);
241
242 while (_sync_flag != 1)
243 {
244 rt_thread_mdelay(10);
245 }
246
247 result = rt_mutex_detach(&static_mutex);
248 if (RT_EOK != result)
249 uassert_true(RT_FALSE);
250
251 uassert_true(RT_TRUE);
252 }
253
254 static rt_thread_t tid1 = RT_NULL;
255 static rt_thread_t tid2 = RT_NULL;
256 static rt_thread_t tid3 = RT_NULL;
257
258 /* static mutex priority reverse test */
static_thread1_entry(void * param)259 static void static_thread1_entry(void *param)
260 {
261 /* let system schedule */
262 rt_thread_mdelay(100);
263
264 /* thread3 hode mutex thread2 take mutex */
265 /* check thread2 and thread3 priority */
266 if (RT_SCHED_PRIV(tid2).current_priority != RT_SCHED_PRIV(tid3).current_priority)
267 {
268 uassert_true(RT_FALSE);
269 }
270 else
271 {
272 uassert_true(RT_TRUE);
273 }
274 _sync_flag++;
275 }
276
static_thread2_entry(void * param)277 static void static_thread2_entry(void *param)
278 {
279 rt_err_t result;
280 rt_mutex_t mutex = (rt_mutex_t)param;
281
282 /* let system schedule */
283 rt_thread_mdelay(50);
284
285 result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
286 if (result == RT_EOK)
287 {
288 rt_mutex_release(mutex);
289 }
290 _sync_flag++;
291 }
static_thread3_entry(void * param)292 static void static_thread3_entry(void *param)
293 {
294 rt_tick_t tick;
295 rt_err_t result;
296 rt_mutex_t mutex = (rt_mutex_t)param;
297
298 result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
299 if (result != RT_EOK)
300 {
301 uassert_true(RT_FALSE);
302 }
303
304 tick = rt_tick_get();
305 while (rt_tick_get() - tick < (RT_TICK_PER_SECOND / 2));
306
307 rt_mutex_release(mutex);
308 _sync_flag++;
309 }
310
test_static_pri_reverse(void)311 static void test_static_pri_reverse(void)
312 {
313 rt_err_t result;
314 tid1 = RT_NULL;
315 tid2 = RT_NULL;
316 tid3 = RT_NULL;
317
318 _sync_flag = 0;
319
320 result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
321 if (RT_EOK != result)
322 {
323 uassert_true(RT_FALSE);
324 return;
325 }
326
327 /* thread1 */
328 tid1 = rt_thread_create("thread1",
329 static_thread1_entry,
330 &static_mutex,
331 UTEST_THR_STACK_SIZE,
332 10 - 1,
333 10);
334 if (tid1 != RT_NULL)
335 rt_thread_startup(tid1);
336
337 /* thread2 */
338 tid2 = rt_thread_create("thread2",
339 static_thread2_entry,
340 &static_mutex,
341 UTEST_THR_STACK_SIZE,
342 10,
343 10);
344 if (tid2 != RT_NULL)
345 rt_thread_startup(tid2);
346
347 /* thread3 */
348 tid3 = rt_thread_create("thread3",
349 static_thread3_entry,
350 &static_mutex,
351 UTEST_THR_STACK_SIZE,
352 10 + 1,
353 10);
354 if (tid3 != RT_NULL)
355 rt_thread_startup(tid3);
356
357 while (_sync_flag != 3)
358 {
359 rt_thread_mdelay(10);
360 }
361
362 result = rt_mutex_detach(&static_mutex);
363 if (RT_EOK != result)
364 uassert_true(RT_FALSE);
365
366 uassert_true(RT_TRUE);
367 }
368
369 /* create test */
test_dynamic_mutex_create(void)370 static void test_dynamic_mutex_create(void)
371 {
372 rt_err_t result = -RT_ERROR;
373
374 /* PRIO mode */
375 dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
376 if (RT_NULL == dynamic_mutex)
377 {
378 uassert_true(RT_FALSE);
379 }
380
381 result = rt_mutex_delete(dynamic_mutex);
382 if (RT_EOK != result)
383 {
384 uassert_true(RT_FALSE);
385 }
386
387 /* FIFO mode */
388 dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
389 if (RT_NULL == dynamic_mutex)
390 {
391 uassert_true(RT_FALSE);
392 }
393
394 result = rt_mutex_delete(dynamic_mutex);
395 if (RT_EOK != result)
396 {
397 uassert_true(RT_FALSE);
398 }
399
400 uassert_true(RT_TRUE);
401 }
402
403 /* dynamic take test */
dynamic_mutex_take_entry(void * param)404 static void dynamic_mutex_take_entry(void *param)
405 {
406 rt_err_t result;
407 rt_mutex_t mutex;
408
409 int rand_num = rand() % 0x1000;
410 mutex = (rt_mutex_t)param;
411
412 result = rt_mutex_take(mutex, rand_num);
413 if (RT_EOK == result)
414 {
415 uassert_true(RT_FALSE);
416 }
417 _sync_flag++;
418 }
419
test_dynamic_mutex_take(void)420 static void test_dynamic_mutex_take(void)
421 {
422 rt_err_t result;
423
424 _sync_flag = 0;
425
426 dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
427 if (RT_NULL == dynamic_mutex)
428 {
429 uassert_true(RT_FALSE);
430 return;
431 }
432
433 /* take mutex and not release */
434 result = rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER);
435 if (RT_EOK != result)
436 uassert_true(RT_FALSE);
437
438 rt_thread_t tid = rt_thread_create("mutex_th",
439 dynamic_mutex_take_entry,
440 dynamic_mutex,
441 THREAD_STACKSIZE,
442 10,
443 10);
444 if (RT_NULL == tid)
445 {
446 uassert_true(RT_FALSE);
447 return;
448 }
449
450 /* startup thread take second */
451 rt_thread_startup(tid);
452
453 while (_sync_flag != 1)
454 {
455 rt_thread_mdelay(10);
456 }
457
458 result = rt_mutex_delete(dynamic_mutex);
459 if (RT_EOK != result)
460 uassert_true(RT_FALSE);
461
462 uassert_true(RT_TRUE);
463 }
464
465 /* dynamic release test */
dynamic_mutex_release_entry(void * param)466 static void dynamic_mutex_release_entry(void *param)
467 {
468 rt_err_t result;
469 rt_mutex_t mutex;
470
471 int rand_num = rand() % 0x1000;
472 mutex = (rt_mutex_t)param;
473
474 result = rt_mutex_take(mutex, rand_num);
475 if (RT_EOK != result)
476 {
477 uassert_true(RT_FALSE);
478 }
479 _sync_flag++;
480 }
test_dynamic_mutex_release(void)481 static void test_dynamic_mutex_release(void)
482 {
483 rt_err_t result;
484
485 _sync_flag = 0;
486 dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
487 if (RT_NULL == dynamic_mutex)
488 {
489 uassert_true(RT_FALSE);
490 return;
491 }
492
493 result = rt_mutex_release(dynamic_mutex);
494 uassert_true(result < 0);
495
496 /* take mutex */
497 result = rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER);
498 if (RT_EOK != result)
499 uassert_true(RT_FALSE);
500
501 /* release mutex */
502 result = rt_mutex_release(dynamic_mutex);
503 if (RT_EOK != result)
504 uassert_true(RT_FALSE);
505
506 rt_thread_t tid = rt_thread_create("mutex_th",
507 dynamic_mutex_release_entry,
508 dynamic_mutex,
509 THREAD_STACKSIZE,
510 10,
511 10);
512 if (RT_NULL == tid)
513 {
514 uassert_true(RT_FALSE);
515 return;
516 }
517
518 /* startup thread and take mutex second */
519 rt_thread_startup(tid);
520
521 while (_sync_flag != 1)
522 {
523 rt_thread_mdelay(10);
524 }
525
526 result = rt_mutex_delete(dynamic_mutex);
527 if (RT_EOK != result)
528 uassert_true(RT_FALSE);
529
530 uassert_true(RT_TRUE);
531 }
532
533 /* dynamic trytake test */
dynamic_mutex_trytake_entry(void * param)534 static void dynamic_mutex_trytake_entry(void *param)
535 {
536 rt_err_t result;
537 rt_mutex_t mutex;
538
539 mutex = (rt_mutex_t)param;
540
541 result = rt_mutex_trytake(mutex);
542 if (RT_EOK == result)
543 {
544 uassert_true(RT_FALSE);
545 }
546 _sync_flag++;
547 }
test_dynamic_mutex_trytake(void)548 static void test_dynamic_mutex_trytake(void)
549 {
550 rt_err_t result;
551
552 _sync_flag = 0;
553 dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
554 if (RT_NULL == dynamic_mutex)
555 {
556 uassert_true(RT_FALSE);
557 return;
558 }
559
560 /* take mutex and not release */
561 result = rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER);
562 if (RT_EOK != result)
563 uassert_true(RT_FALSE);
564
565 rt_thread_t tid = rt_thread_create("mutex_th",
566 dynamic_mutex_trytake_entry,
567 dynamic_mutex,
568 THREAD_STACKSIZE,
569 10,
570 10);
571 if (RT_NULL == tid)
572 {
573 uassert_true(RT_FALSE);
574 return;
575 }
576
577 /* startup thread and trytake mutex second */
578 rt_thread_startup(tid);
579
580 while (_sync_flag != 1)
581 {
582 rt_thread_mdelay(10);
583 }
584
585 result = rt_mutex_delete(dynamic_mutex);
586 if (RT_EOK != result)
587 uassert_true(RT_FALSE);
588
589 uassert_true(RT_TRUE);
590 }
591
592 /* dynamic mutex priority reverse test */
dynamic_thread1_entry(void * param)593 static void dynamic_thread1_entry(void *param)
594 {
595 /* let system schedule */
596 rt_thread_mdelay(100);
597
598 /* thread3 hode mutex thread2 take mutex */
599 /* check thread2 and thread3 priority */
600 if (RT_SCHED_PRIV(tid2).current_priority != RT_SCHED_PRIV(tid3).current_priority)
601 {
602 uassert_true(RT_FALSE);
603 }
604 else
605 {
606 uassert_true(RT_TRUE);
607 }
608 _sync_flag++;
609 }
610
dynamic_thread2_entry(void * param)611 static void dynamic_thread2_entry(void *param)
612 {
613 rt_err_t result;
614 rt_mutex_t mutex = (rt_mutex_t)param;
615
616 /* let system schedule */
617 rt_thread_mdelay(50);
618
619 result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
620 if (result == RT_EOK)
621 {
622 rt_mutex_release(mutex);
623 }
624 _sync_flag++;
625 }
dynamic_thread3_entry(void * param)626 static void dynamic_thread3_entry(void *param)
627 {
628 rt_tick_t tick;
629 rt_err_t result;
630 rt_mutex_t mutex = (rt_mutex_t)param;
631
632 result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
633 if (result != RT_EOK)
634 {
635 uassert_true(RT_FALSE);
636 }
637
638 tick = rt_tick_get();
639 while (rt_tick_get() - tick < (RT_TICK_PER_SECOND / 2));
640
641 rt_mutex_release(mutex);
642 _sync_flag++;
643 }
644
test_dynamic_pri_reverse(void)645 static void test_dynamic_pri_reverse(void)
646 {
647 rt_err_t result;
648 tid1 = RT_NULL;
649 tid2 = RT_NULL;
650 tid3 = RT_NULL;
651
652 _sync_flag = 0;
653 dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
654 if (RT_NULL == dynamic_mutex)
655 {
656 uassert_true(RT_FALSE);
657 return;
658 }
659
660 /* thread1 */
661 tid1 = rt_thread_create("thread1",
662 dynamic_thread1_entry,
663 dynamic_mutex,
664 UTEST_THR_STACK_SIZE,
665 10 - 1,
666 10);
667 if (tid1 != RT_NULL)
668 rt_thread_startup(tid1);
669
670 /* thread2 */
671 tid2 = rt_thread_create("thread2",
672 dynamic_thread2_entry,
673 dynamic_mutex,
674 UTEST_THR_STACK_SIZE,
675 10,
676 10);
677 if (tid2 != RT_NULL)
678 rt_thread_startup(tid2);
679
680 /* thread3 */
681 tid3 = rt_thread_create("thread3",
682 dynamic_thread3_entry,
683 dynamic_mutex,
684 UTEST_THR_STACK_SIZE,
685 10 + 1,
686 10);
687 if (tid3 != RT_NULL)
688 rt_thread_startup(tid3);
689
690 while (_sync_flag != 3)
691 {
692 rt_thread_mdelay(10);
693 }
694
695 result = rt_mutex_delete(dynamic_mutex);
696 if (RT_EOK != result)
697 uassert_true(RT_FALSE);
698
699 uassert_true(RT_TRUE);
700 }
701
recursive_lock_test_entry(void * param)702 static void recursive_lock_test_entry(void *param)
703 {
704 rt_err_t result;
705 rt_mutex_t mutex = (rt_mutex_t)param;
706
707 result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
708 uassert_true(result == RT_EOK);
709 uassert_true(_sync_flag == 0);
710 result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
711 uassert_true(result == RT_EOK);
712 _sync_flag++;
713 }
714
test_recurse_lock(void)715 static void test_recurse_lock(void)
716 {
717 rt_err_t result;
718
719 _sync_flag = 0;
720 result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
721 uassert_true(result == RT_EOK);
722
723 /* take mutex and not release */
724 result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
725 uassert_true(result == RT_EOK);
726
727 /* take mutex twice */
728 result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
729 uassert_true(result == RT_EOK);
730
731 rt_thread_t tid = rt_thread_create("mutex_th",
732 recursive_lock_test_entry,
733 &static_mutex,
734 THREAD_STACKSIZE,
735 10,
736 10);
737 _sync_flag = -1;
738
739 if (tid != RT_NULL)
740 rt_thread_startup(tid);
741
742 result = rt_mutex_release(&static_mutex);
743 uassert_true(result == RT_EOK);
744
745 _sync_flag = 0;
746
747 result = rt_mutex_release(&static_mutex);
748 uassert_true(result == RT_EOK);
749
750 while (_sync_flag != 1)
751 {
752 rt_thread_mdelay(10);
753 }
754
755 result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
756 uassert_true(result == RT_EOK);
757
758 result = rt_mutex_detach(&static_mutex);
759 uassert_true(result == RT_EOK);
760 }
761
utest_tc_init(void)762 static rt_err_t utest_tc_init(void)
763 {
764 #ifdef RT_USING_HEAP
765 dynamic_mutex = RT_NULL;
766 #endif /* RT_USING_HEAP */
767
768 return RT_EOK;
769 }
770
utest_tc_cleanup(void)771 static rt_err_t utest_tc_cleanup(void)
772 {
773 #ifdef RT_USING_HEAP
774 dynamic_mutex = RT_NULL;
775 #endif /* RT_USING_HEAP */
776
777 return RT_EOK;
778 }
779
testcase(void)780 static void testcase(void)
781 {
782 UTEST_UNIT_RUN(test_static_mutex_init);
783 UTEST_UNIT_RUN(test_static_mutex_take);
784 UTEST_UNIT_RUN(test_static_mutex_release);
785 UTEST_UNIT_RUN(test_static_mutex_trytake);
786 UTEST_UNIT_RUN(test_static_pri_reverse);
787 #ifdef RT_USING_HEAP
788 UTEST_UNIT_RUN(test_dynamic_mutex_create);
789 UTEST_UNIT_RUN(test_dynamic_mutex_take);
790 UTEST_UNIT_RUN(test_dynamic_mutex_release);
791 UTEST_UNIT_RUN(test_dynamic_mutex_trytake);
792 UTEST_UNIT_RUN(test_dynamic_pri_reverse);
793 #endif
794 UTEST_UNIT_RUN(test_recurse_lock);
795 }
796 UTEST_TC_EXPORT(testcase, "testcases.kernel.mutex_tc", utest_tc_init, utest_tc_cleanup, 1000);
797
798 /********************* end of file ************************/
799