1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-11-20 Shell add test suites
9 */
10
11 #include "common.h"
12 #include "rtconfig.h"
13 #include "utest_assert.h"
14
15 #include <rtdevice.h>
16 #include <rtdef.h>
17
18 static struct rt_mutex _local_mtx;
19 static struct rt_condvar _local_cv;
20 #define THREAD_NUM 8
21 #define STACK_SIZE (0x2000)
22
23 static volatile int start_num;
24 static volatile int waken_num;
25
thr_func(void * arg)26 static void thr_func(void *arg)
27 {
28 int rc;
29 rt_mutex_t mutex = &_local_mtx;
30 rt_condvar_t cond = &_local_cv;
31 rt_mutex_take(mutex, RT_WAITING_FOREVER);
32
33 start_num++;
34 rc = rt_condvar_timedwait(cond, mutex, RT_KILLABLE, RT_WAITING_FOREVER);
35 if (rc != 0)
36 {
37 LOG_E("cond_wait returned %d\n", rc);
38 uassert_false(1);
39 return;
40 }
41
42 if (rt_mutex_get_owner(mutex) != rt_thread_self())
43 {
44 LOG_E("Should not be able to lock the mutex again");
45 uassert_false(1);
46 return;
47 }
48 else
49 {
50 uassert_true(1);
51 }
52 LOG_I("Thread was wakened and acquired the mutex again");
53 waken_num++;
54
55 if (rt_mutex_release(mutex) != 0)
56 {
57 LOG_E("Failed to release the mutex");
58 uassert_false(1);
59 return;
60 }
61 else
62 {
63 uassert_true(1);
64 }
65
66 return ;
67 }
68
69 static void *stack_addr[THREAD_NUM];
70
condvar_broadcast_tc(void)71 static void condvar_broadcast_tc(void)
72 {
73 rt_mutex_t mutex = &_local_mtx;
74 rt_condvar_t cond = &_local_cv;
75 struct rt_thread thread[THREAD_NUM];
76
77 for (size_t i = 0; i < THREAD_NUM; i++)
78 {
79 if (rt_thread_init(&thread[i], "utest", thr_func, RT_NULL,
80 stack_addr[i], STACK_SIZE, 25, 100) != 0)
81 {
82 LOG_E("Fail to create thread[%d]\n", i);
83 return;
84 }
85 rt_thread_startup(&thread[i]);
86 }
87
88 while (start_num < THREAD_NUM)
89 rt_thread_mdelay(1);
90
91 rt_mutex_take(mutex, RT_WAITING_FOREVER);
92 if (rt_condvar_broadcast(cond))
93 {
94 uassert_false(1);
95 return ;
96 }
97 rt_mutex_release(mutex);
98
99 rt_thread_mdelay(1);
100
101 if (waken_num < THREAD_NUM)
102 {
103 LOG_E("[Main thread] Not all waiters were wakened\n");
104 uassert_false(1);
105 return ;
106 }
107 else
108 {
109 utest_int_equal(waken_num, THREAD_NUM);
110 }
111 LOG_I("[Main thread] all waiters were wakened\n");
112
113 return;
114 }
115
utest_tc_init(void)116 static rt_err_t utest_tc_init(void)
117 {
118 start_num = 0;
119 waken_num = 0;
120 if (rt_mutex_init(&_local_mtx, "utest", RT_IPC_FLAG_PRIO) != 0)
121 {
122 perror("pthread_mutex_init() error");
123 uassert_false(1);
124 return -1;
125 }
126
127 rt_condvar_init(&_local_cv, NULL);
128
129 for (size_t i = 0; i < THREAD_NUM; i++)
130 {
131 stack_addr[i] =
132 rt_pages_alloc_ext(rt_page_bits(STACK_SIZE), PAGE_ANY_AVAILABLE);
133 utest_int_not_equal(stack_addr[i], RT_NULL);
134 }
135 return RT_EOK;
136 }
137
utest_tc_cleanup(void)138 static rt_err_t utest_tc_cleanup(void)
139 {
140 rt_mutex_detach(&_local_mtx);
141 rt_condvar_detach(&_local_cv);
142
143 for (size_t i = 0; i < THREAD_NUM; i++)
144 {
145 rt_pages_free(stack_addr[i], rt_page_bits(STACK_SIZE));
146 stack_addr[i] = 0;
147 }
148 return RT_EOK;
149 }
150
testcase(void)151 static void testcase(void)
152 {
153 UTEST_UNIT_RUN(condvar_broadcast_tc);
154 }
155 UTEST_TC_EXPORT(testcase, "testcases.ipc.condvar.broadcast", utest_tc_init,
156 utest_tc_cleanup, 10);
157