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