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