1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cstdio>
17 #include <climits>
18 #include <thread>
19
20 #include "gtest/gtest.h"
21 #include "purgeable_mem_c.h"
22
23 namespace {
24 using namespace testing;
25 using namespace testing::ext;
26
27 struct AlphabetInitParam {
28 char start;
29 char end;
30 };
31
32 struct AlphabetModifyParam {
33 char src;
34 char dst;
35 };
36
37 static constexpr int PRINT_INTERVAL_SECONDS = 1;
38 static constexpr int RECLAIM_INTERVAL_SECONDS = 1;
39 static constexpr int MODIFY_INTERVAL_SECONDS = 2;
40
41 bool InitData(void *data, size_t size, char start, char end);
42 bool ModifyData(void *data, size_t size, char src, char dst);
43 bool InitAlphabet(void *data, size_t size, void *param);
44 bool ModifyAlphabetX2Y(void *data, size_t size, void *param);
45 void LoopPrintAlphabet(struct PurgMem *pdata, unsigned int loopCount);
46 bool ReclaimPurgeable(void);
47 void LoopReclaimPurgeable(unsigned int loopCount);
48 void ModifyPurgMemByFunc(struct PurgMem *pdata, PurgMemModifyFunc Modfunc, void *param);
49
50 class PurgeableCTest : public testing::Test {
51 public:
52 static void SetUpTestCase();
53 static void TearDownTestCase();
54 void SetUp();
55 void TearDown();
56 };
57
SetUpTestCase()58 void PurgeableCTest::SetUpTestCase()
59 {
60 }
61
TearDownTestCase()62 void PurgeableCTest::TearDownTestCase()
63 {
64 }
65
SetUp()66 void PurgeableCTest::SetUp()
67 {
68 }
69
TearDown()70 void PurgeableCTest::TearDown()
71 {
72 }
73
74 HWTEST_F(PurgeableCTest, MultiObjCreateTest, TestSize.Level1)
75 {
76 const char alphabetFinal[] = "BBCDEFGHIJKLMNOPQRSTUVWXYZ\0";
77 struct AlphabetInitParam initPara = {'A', 'Z'};
78 PurgMemCreate(0, InitAlphabet, &initPara);
79 struct PurgMem *pobj1 = PurgMemCreate(27, InitAlphabet, &initPara);
80 LoopPrintAlphabet(pobj1, 1);
81 struct AlphabetModifyParam a2b = {'A', 'B'};
82 ModifyPurgMemByFunc(pobj1, ModifyAlphabetX2Y, static_cast<void *>(&a2b));
83 LoopPrintAlphabet(pobj1, 1);
84 LoopReclaimPurgeable(1);
85
86 struct PurgMem *pobj2 = PurgMemCreate(27, InitAlphabet, &initPara);
87 LoopPrintAlphabet(pobj2, 1);
88 ModifyPurgMemByFunc(pobj2, ModifyAlphabetX2Y, static_cast<void *>(&a2b));
89 LoopPrintAlphabet(pobj2, 1);
90
91 if (PurgMemBeginRead(pobj1)) {
92 ASSERT_STREQ(alphabetFinal, static_cast<char *>(PurgMemGetContent(pobj1)));
93 PurgMemEndRead(pobj1);
94 } else {
95 std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
96 }
97
98 if (PurgMemBeginRead(pobj2)) {
99 ASSERT_STREQ(alphabetFinal, static_cast<char *>(PurgMemGetContent(pobj2)));
100 PurgMemEndRead(pobj2);
101 } else {
102 std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
103 }
104
105 PurgMemDestroy(pobj2);
106 PurgMemDestroy(pobj1);
107 }
108
109 HWTEST_F(PurgeableCTest, ReadTest, TestSize.Level1)
110 {
111 const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\0";
112 struct AlphabetInitParam initPara = {'A', 'Z'};
113 struct PurgMem *pobj = PurgMemCreate(27, InitAlphabet, &initPara);
114 LoopReclaimPurgeable(1);
115
116 unsigned int loopCount = 3;
117 /* loop read content */
118 for (unsigned int i = 0; i < loopCount; i++) {
119 if (!PurgMemBeginRead(pobj)) {
120 std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
121 continue;
122 }
123 ASSERT_STREQ(alphabet, static_cast<char *>(PurgMemGetContent(pobj)));
124 PurgMemEndRead(pobj);
125 }
126
127 PurgMemDestroy(pobj);
128 }
129
130 HWTEST_F(PurgeableCTest, WriteTest, TestSize.Level1)
131 {
132 const char alphabet[] = "CCCDEFGHIJKLMNOPQRSTUVWXYZ\0";
133 struct AlphabetInitParam initPara = {'A', 'Z'};
134 struct PurgMem *pobj = PurgMemCreate(27, InitAlphabet, &initPara);
135 LoopReclaimPurgeable(1);
136
137 struct AlphabetModifyParam a2b = {'A', 'B'};
138 struct AlphabetModifyParam b2c = {'B', 'C'};
139 ModifyPurgMemByFunc(pobj, ModifyAlphabetX2Y, static_cast<void *>(&a2b));
140 ModifyPurgMemByFunc(pobj, ModifyAlphabetX2Y, static_cast<void *>(&b2c));
141
142 if (PurgMemBeginRead(pobj)) {
143 ASSERT_STREQ(alphabet, static_cast<char *>(PurgMemGetContent(pobj)));
144 PurgMemEndRead(pobj);
145 } else {
146 std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
147 }
148
149 PurgMemDestroy(pobj);
150 LoopReclaimPurgeable(3);
151 }
152
153 HWTEST_F(PurgeableCTest, ReadWriteTest, TestSize.Level1)
154 {
155 const char alphabet[] = "DDDDEFGHIJKLMNOPQRSTUVWXYZ\0";
156 struct AlphabetInitParam initPara = {'A', 'Z'};
157 struct PurgMem *pobj = PurgMemCreate(27, InitAlphabet, &initPara);
158 LoopReclaimPurgeable(1);
159 LoopPrintAlphabet(pobj, 1);
160
161 struct AlphabetModifyParam a2b = {'A', 'B'};
162 struct AlphabetModifyParam b2c = {'B', 'C'};
163 struct AlphabetModifyParam c2d = {'C', 'D'};
164 ModifyPurgMemByFunc(pobj, ModifyAlphabetX2Y, static_cast<void *>(&a2b));
165 ModifyPurgMemByFunc(pobj, ModifyAlphabetX2Y, static_cast<void *>(&b2c));
166 ModifyPurgMemByFunc(pobj, ModifyAlphabetX2Y, static_cast<void *>(&c2d));
167
168 if (PurgMemBeginRead(pobj)) {
169 ASSERT_STREQ(alphabet, static_cast<char *>(PurgMemGetContent(pobj)));
170 PurgMemEndRead(pobj);
171 } else {
172 std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
173 }
174
175 PurgMemDestroy(pobj);
176 }
177
InitData(void * data,size_t size,char start,char end)178 bool InitData(void *data, size_t size, char start, char end)
179 {
180 char *str = (char *)data;
181 size_t len = 0;
182 for (char ch = start; ch <= end && len < size; ch++) {
183 str[len++] = ch;
184 }
185 str[len] = 0;
186 return true;
187 }
188
InitAlphabet(void * data,size_t size,void * param)189 bool InitAlphabet(void *data, size_t size, void *param)
190 {
191 struct AlphabetInitParam *para = (struct AlphabetInitParam *)param;
192 std::cout << "inter " << __func__ << std::endl;
193 bool ret = InitData(data, size, para->start, para->end);
194 std::cout << "quit " << __func__ << ": " << para->start << "-" << para->end <<
195 ", data=[" << (char *)data << "]" << ", ret=" << (ret ? "true" : "false") << std::endl;
196 return ret;
197 }
198
ModifyData(void * data,size_t size,char src,char dst)199 bool ModifyData(void *data, size_t size, char src, char dst)
200 {
201 char *str = (char *)data;
202 size_t i = 0;
203 for (; i < size && str[i]; i++) {
204 if (str[i] == src) {
205 str[i] = dst;
206 }
207 }
208 str[i] = 0;
209 return true;
210 }
211
ModifyAlphabetX2Y(void * data,size_t size,void * param)212 bool ModifyAlphabetX2Y(void *data, size_t size, void *param)
213 {
214 struct AlphabetModifyParam *para = (struct AlphabetModifyParam *)param;
215 std::cout << "inter " << __func__ << ": " << para->src << "->" << para->dst <<
216 ", data=[" << (char *)data << "]" << std::endl;
217 bool ret = ModifyData(data, size, para->src, para->dst);
218 std::cout << "quit , data=[" << (char *)data << "]" << __func__ <<
219 ", ret=" << (ret ? "true" : "false") << std::endl;
220 return ret;
221 }
222
LoopPrintAlphabet(struct PurgMem * pdata,unsigned int loopCount)223 void LoopPrintAlphabet(struct PurgMem *pdata, unsigned int loopCount)
224 {
225 std::cout << "inter " << __func__ << std::endl;
226 for (unsigned int i = 0; i < loopCount; i++) {
227 if (!PurgMemBeginRead(pdata)) {
228 std::cout << __func__ << ": " << i << ". ERROR! BeginRead failed." << std::endl;
229 break;
230 }
231 std::cout << __func__ << ": " << i << ". data=[" <<
232 (char *)PurgMemGetContent(pdata) << "]" << std::endl;
233 PurgMemEndRead(pdata);
234 std::this_thread::sleep_for(std::chrono::seconds(PRINT_INTERVAL_SECONDS));
235 }
236 std::cout << "quit " << __func__ << std::endl;
237 }
238
ReclaimPurgeable(void)239 bool ReclaimPurgeable(void)
240 {
241 FILE *f = fopen("/proc/sys/kernel/purgeable", "w");
242 if (!f) {
243 std::cout << __func__ << ": open file failed" << std::endl;
244 return false;
245 }
246 bool succ = true;
247 if (fputs("1", f) == EOF) {
248 succ = false;
249 }
250
251 if (fclose(f) == EOF) {
252 std::cout << __func__ << ": close file failed" << std::endl;
253 }
254
255 return succ;
256 }
257
LoopReclaimPurgeable(unsigned int loopCount)258 void LoopReclaimPurgeable(unsigned int loopCount)
259 {
260 bool ret = false;
261 std::cout << "inter " << __func__ << std::endl;
262 for (unsigned int i = 0; i < loopCount; i++) {
263 ret = ReclaimPurgeable();
264 std::cout << __func__ << ": " << i << ". Reclaim result=" << (ret ? "succ" : "fail") << std::endl;
265 std::this_thread::sleep_for(std::chrono::seconds(RECLAIM_INTERVAL_SECONDS)); /* wait reclaim finish */
266 }
267 std::cout << "quit " << __func__ << std::endl;
268 }
269
ModifyPurgMemByFunc(struct PurgMem * pdata,PurgMemModifyFunc Modfunc,void * param)270 void ModifyPurgMemByFunc(struct PurgMem *pdata, PurgMemModifyFunc Modfunc, void *param)
271 {
272 if (!PurgMemBeginWrite(pdata)) {
273 std::cout << __func__ << ": ERROR! BeginWrite failed." << std::endl;
274 return;
275 }
276 std::this_thread::sleep_for(std::chrono::seconds(MODIFY_INTERVAL_SECONDS));
277 std::cout << __func__ << " before mod data=[" << (char *)PurgMemGetContent(pdata) << "]" << std::endl;
278 PurgMemAppendModify(pdata, Modfunc, param);
279 std::cout<< __func__ << " after mod data=[" << (char *)PurgMemGetContent(pdata) << "]" << std::endl;
280
281 std::cout << __func__ << " data=[" << (char *)PurgMemGetContent(pdata) << "]" << std::endl;
282 PurgMemEndWrite(pdata);
283 }
284 } /* namespace */
285