• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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