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-03-24     WangXiaoyao  Complete testcase for synchronization
9  */
10 #ifndef __TEST_SYNCHRONIZATION_H__
11 #define __TEST_SYNCHRONIZATION_H__
12 
13 #include "common.h"
14 #include "semaphore.h"
15 
16 #ifdef RT_USING_SMP
17 
18 #define THREAD_CNT RT_CPUS_NR
19 #define TEST_TIMES 2000
20 #define PRIO (UTEST_THR_PRIORITY + 1)
21 /* size of mapping buffer */
22 #define BUF_SIZE (64ul << 10)
23 
24 /* engage with sibling */
25 struct rt_semaphore done;
26 static semaphore_t sem1[THREAD_CNT / 2];
27 static semaphore_t sem2[THREAD_CNT / 2];
28 
map(void)29 static void *map(void)
30 {
31     int err;
32     int flags = MMF_PREFETCH;
33     size_t attr = MMU_MAP_K_RWCB;
34     void *vaddr = 0;
35     err =
36         rt_aspace_map(&rt_kernel_space, &vaddr, BUF_SIZE, attr, flags, &rt_mm_dummy_mapper, 0);
37     if (err)
38         uassert_true(0);
39     return vaddr;
40 }
41 
unmap(void * buf)42 static void unmap(void *buf)
43 {
44     int err;
45     err =
46         rt_aspace_unmap(&rt_kernel_space, buf);
47     if (err)
48         uassert_true(0);
49     return ;
50 }
51 
group1_entry(void * param)52 static void group1_entry(void *param)
53 {
54     const size_t id = (size_t)param;
55     size_t test_times = TEST_TIMES;
56     size_t alive = test_times / 10;
57     void *buf;
58 
59     while (test_times--)
60     {
61         if (test_times % alive == 0)
62             uassert_true(1);
63 
64         buf = map();
65 
66         memset(buf, 'A' + id, BUF_SIZE);
67         /* if other core write to our cache, force the changes to be visible to us */
68         rt_hw_dmb();
69 
70         if (memtest(buf, 'A' + id, BUF_SIZE))
71             uassert_true(0);
72 
73         semaphore_signal(&sem1[id]);
74         semaphore_wait(&sem2[id]);
75         unmap(buf);
76     }
77 
78     rt_sem_release(&done);
79     return;
80 }
81 
group2_entry(void * param)82 static void group2_entry(void *param)
83 {
84     const size_t id = (size_t)param;
85     size_t test_times = TEST_TIMES;
86     size_t alive = test_times / 10;
87     void *buf;
88 
89     while (test_times--)
90     {
91         if (test_times % alive == 0)
92             uassert_true(1);
93 
94         semaphore_signal(&sem2[id]);
95         semaphore_wait(&sem1[id]);
96         buf = map();
97 
98         memset(buf, 'a' + id, BUF_SIZE);
99         /* if other core write to our cache, force the changes to be visible to us */
100         rt_hw_dmb();
101 
102         if (memtest(buf, 'a' + id, BUF_SIZE))
103             uassert_true(0);
104 
105         unmap(buf);
106     }
107 
108     rt_sem_release(&done);
109     return;
110 }
111 
112 /**
113  * @brief On a smp system, we create at least 4 threads
114  * 2 doing map, 2 doing unmapping at the same moment
115  */
116 
synchronization_tc(void)117 static void synchronization_tc(void)
118 {
119     rt_thread_t group1[THREAD_CNT / 2];
120     rt_thread_t group2[THREAD_CNT / 2];
121 
122     rt_sem_init(&done, __func__, 0, RT_IPC_FLAG_FIFO);
123 
124     for (size_t i = 0; i < THREAD_CNT / 2; i++)
125     {
126         char name[RT_NAME_MAX];
127         rt_sprintf(name, "grp1_%d", i);
128         group1[i] =
129             rt_thread_create(name, group1_entry, (void *)i, ARCH_PAGE_SIZE, PRIO, 10);
130         uassert_true(!!group1[i]);
131         semaphore_init(&sem1[i], 0);
132 
133         uassert_true(!rt_thread_startup(group1[i]));
134     }
135 
136     for (size_t i = 0; i < THREAD_CNT / 2; i++)
137     {
138         char name[RT_NAME_MAX];
139         rt_sprintf(name, "grp2_%d", i);
140         group2[i] =
141             rt_thread_create(name, group2_entry, (void *)i, ARCH_PAGE_SIZE, PRIO, 10);
142         uassert_true(!!group2[i]);
143         semaphore_init(&sem2[i], 0);
144 
145         uassert_true(!rt_thread_startup(group2[i]));
146     }
147 
148     /* wait all thread exit */
149     for (size_t i = 0; i < (THREAD_CNT / 2 * 2); i++)
150     {
151         rt_sem_take(&done, RT_WAITING_FOREVER);
152     }
153     LOG_I("all threads exit");
154     rt_sem_detach(&done);
155 }
156 
157 #else /* RT_USING_SMP */
158 
synchronization_tc(void)159 static void synchronization_tc(void)
160 {
161     uassert_true(1);
162 }
163 #endif /* RT_USING_SMP */
164 
165 #endif /* __TEST_SYNCHRONIZATION_H__ */
166