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