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 struct PurgMem *pobj1 = PurgMemCreate(27, InitAlphabet, &initPara);
79 LoopPrintAlphabet(pobj1, 1);
80 struct AlphabetModifyParam a2b = {'A', 'B'};
81 ModifyPurgMemByFunc(pobj1, ModifyAlphabetX2Y, static_cast<void *>(&a2b));
82 LoopPrintAlphabet(pobj1, 1);
83 LoopReclaimPurgeable(1);
84
85 struct PurgMem *pobj2 = PurgMemCreate(27, InitAlphabet, &initPara);
86 LoopPrintAlphabet(pobj2, 1);
87 ModifyPurgMemByFunc(pobj2, ModifyAlphabetX2Y, static_cast<void *>(&a2b));
88 LoopPrintAlphabet(pobj2, 1);
89
90 if (PurgMemBeginRead(pobj1)) {
91 ASSERT_STREQ(alphabetFinal, static_cast<char *>(PurgMemGetContent(pobj1)));
92 PurgMemEndRead(pobj1);
93 } else {
94 std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
95 }
96
97 if (PurgMemBeginRead(pobj2)) {
98 ASSERT_STREQ(alphabetFinal, static_cast<char *>(PurgMemGetContent(pobj2)));
99 PurgMemEndRead(pobj2);
100 } else {
101 std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
102 }
103
104 PurgMemDestroy(pobj2);
105 PurgMemDestroy(pobj1);
106 }
107
108 HWTEST_F(PurgeableCTest, ReadTest, TestSize.Level1)
109 {
110 const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\0";
111 struct AlphabetInitParam initPara = {'A', 'Z'};
112 struct PurgMem *pobj = PurgMemCreate(27, InitAlphabet, &initPara);
113 LoopReclaimPurgeable(1);
114
115 unsigned int loopCount = 3;
116 /* loop read content */
117 for (unsigned int i = 0; i < loopCount; i++) {
118 if (!PurgMemBeginRead(pobj)) {
119 std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
120 continue;
121 }
122 ASSERT_STREQ(alphabet, static_cast<char *>(PurgMemGetContent(pobj)));
123 PurgMemEndRead(pobj);
124 }
125
126 PurgMemDestroy(pobj);
127 }
128
129 HWTEST_F(PurgeableCTest, WriteTest, TestSize.Level1)
130 {
131 const char alphabet[] = "CCCDEFGHIJKLMNOPQRSTUVWXYZ\0";
132 struct AlphabetInitParam initPara = {'A', 'Z'};
133 struct PurgMem *pobj = PurgMemCreate(27, InitAlphabet, &initPara);
134 LoopReclaimPurgeable(1);
135
136 struct AlphabetModifyParam a2b = {'A', 'B'};
137 struct AlphabetModifyParam b2c = {'B', 'C'};
138 ModifyPurgMemByFunc(pobj, ModifyAlphabetX2Y, static_cast<void *>(&a2b));
139 ModifyPurgMemByFunc(pobj, ModifyAlphabetX2Y, static_cast<void *>(&b2c));
140
141 if (PurgMemBeginRead(pobj)) {
142 ASSERT_STREQ(alphabet, static_cast<char *>(PurgMemGetContent(pobj)));
143 PurgMemEndRead(pobj);
144 } else {
145 std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
146 }
147
148 PurgMemDestroy(pobj);
149 LoopReclaimPurgeable(3);
150 }
151
152 HWTEST_F(PurgeableCTest, ReadWriteTest, TestSize.Level1)
153 {
154 const char alphabet[] = "DDDDEFGHIJKLMNOPQRSTUVWXYZ\0";
155 struct AlphabetInitParam initPara = {'A', 'Z'};
156 struct PurgMem *pobj = PurgMemCreate(27, InitAlphabet, &initPara);
157 LoopReclaimPurgeable(1);
158 LoopPrintAlphabet(pobj, 1);
159
160 struct AlphabetModifyParam a2b = {'A', 'B'};
161 struct AlphabetModifyParam b2c = {'B', 'C'};
162 struct AlphabetModifyParam c2d = {'C', 'D'};
163 ModifyPurgMemByFunc(pobj, ModifyAlphabetX2Y, static_cast<void *>(&a2b));
164 ModifyPurgMemByFunc(pobj, ModifyAlphabetX2Y, static_cast<void *>(&b2c));
165 ModifyPurgMemByFunc(pobj, ModifyAlphabetX2Y, static_cast<void *>(&c2d));
166
167 if (PurgMemBeginRead(pobj)) {
168 ASSERT_STREQ(alphabet, static_cast<char *>(PurgMemGetContent(pobj)));
169 PurgMemEndRead(pobj);
170 } else {
171 std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
172 }
173
174 PurgMemDestroy(pobj);
175 }
176
InitData_(void * data,size_t size,char start,char end)177 bool InitData_(void *data, size_t size, char start, char end)
178 {
179 char *str = (char *)data;
180 size_t len = 0;
181 for (char ch = start; ch <= end && len < size; ch++) {
182 str[len++] = ch;
183 }
184 str[len] = 0;
185 return true;
186 }
187
InitAlphabet(void * data,size_t size,void * param)188 bool InitAlphabet(void *data, size_t size, void *param)
189 {
190 struct AlphabetInitParam *para = (struct AlphabetInitParam *)param;
191 std::cout << "inter " << __func__ << std::endl;
192 bool ret = InitData_(data, size, para->start, para->end);
193 std::cout << "quit " << __func__ << ": " << para->start << "-" << para->end <<
194 ", data=[" << (char *)data << "]" << ", ret=" << (ret ? "true" : "false") << std::endl;
195 return ret;
196 }
197
ModifyData_(void * data,size_t size,char src,char dst)198 bool ModifyData_(void *data, size_t size, char src, char dst)
199 {
200 char *str = (char *)data;
201 size_t i = 0;
202 for (; i < size && str[i]; i++) {
203 if (str[i] == src) {
204 str[i] = dst;
205 }
206 }
207 str[i] = 0;
208 return true;
209 }
210
ModifyAlphabetX2Y(void * data,size_t size,void * param)211 bool ModifyAlphabetX2Y(void *data, size_t size, void *param)
212 {
213 struct AlphabetModifyParam *para = (struct AlphabetModifyParam *)param;
214 std::cout << "inter " << __func__ << ": " << para->src << "->" << para->dst <<
215 ", data=[" << (char *)data << "]" << std::endl;
216 bool ret = ModifyData_(data, size, para->src, para->dst);
217 std::cout << "quit , data=[" << (char *)data << "]" << __func__ <<
218 ", ret=" << (ret ? "true" : "false") << std::endl;
219 return ret;
220 }
221
LoopPrintAlphabet(struct PurgMem * pdata,unsigned int loopCount)222 void LoopPrintAlphabet(struct PurgMem *pdata, unsigned int loopCount)
223 {
224 std::cout << "inter " << __func__ << std::endl;
225 for (unsigned int i = 0; i < loopCount; i++) {
226 if (!PurgMemBeginRead(pdata)) {
227 std::cout << __func__ << ": " << i << ". ERROR! BeginRead failed." << std::endl;
228 break;
229 }
230 std::cout << __func__ << ": " << i << ". data=[" <<
231 (char *)PurgMemGetContent(pdata) << "]" << std::endl;
232 PurgMemEndRead(pdata);
233 std::this_thread::sleep_for(std::chrono::seconds(PRINT_INTERVAL_SECONDS));
234 }
235 std::cout << "quit " << __func__ << std::endl;
236 }
237
ReclaimPurgeable(void)238 bool ReclaimPurgeable(void)
239 {
240 FILE *f = fopen("/proc/sys/kernel/purgeable", "w");
241 if (!f) {
242 std::cout << __func__ << ": open file failed" << std::endl;
243 return false;
244 }
245 bool succ = true;
246 if (fputs("1", f) == EOF) {
247 succ = false;
248 }
249
250 if (fclose(f) == EOF) {
251 std::cout << __func__ << ": close file failed" << std::endl;
252 }
253
254 return succ;
255 }
256
LoopReclaimPurgeable(unsigned int loopCount)257 void LoopReclaimPurgeable(unsigned int loopCount)
258 {
259 bool ret = false;
260 std::cout << "inter " << __func__ << std::endl;
261 for (unsigned int i = 0; i < loopCount; i++) {
262 ret = ReclaimPurgeable();
263 std::cout << __func__ << ": " << i << ". Reclaim result=" << (ret ? "succ" : "fail") << std::endl;
264 std::this_thread::sleep_for(std::chrono::seconds(RECLAIM_INTERVAL_SECONDS)); /* wait reclaim finish */
265 }
266 std::cout << "quit " << __func__ << std::endl;
267 }
268
ModifyPurgMemByFunc(struct PurgMem * pdata,PurgMemModifyFunc Modfunc,void * param)269 void ModifyPurgMemByFunc(struct PurgMem *pdata, PurgMemModifyFunc Modfunc, void *param)
270 {
271 if (!PurgMemBeginWrite(pdata)) {
272 std::cout << __func__ << ": ERROR! BeginWrite failed." << std::endl;
273 return;
274 }
275 std::this_thread::sleep_for(std::chrono::seconds(MODIFY_INTERVAL_SECONDS));
276 std::cout << __func__ << " before mod data=[" << (char *)PurgMemGetContent(pdata) << "]" << std::endl;
277 PurgMemAppendModify(pdata, Modfunc, param);
278 std::cout<< __func__ << " after mod data=[" << (char *)PurgMemGetContent(pdata) << "]" << std::endl;
279
280 std::cout << __func__ << " data=[" << (char *)PurgMemGetContent(pdata) << "]" << std::endl;
281 PurgMemEndWrite(pdata);
282 }
283 } /* namespace */
284