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