• 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 <thread>
18 #include <memory> /* unique_ptr */
19 
20 #include "gtest/gtest.h"
21 #include "purgeable_mem.h"
22 
23 namespace OHOS {
24 namespace PurgeableMem {
25 using namespace testing;
26 using namespace testing::ext;
27 
28 static constexpr int PRINT_INTERVAL_SECONDS = 1;
29 static constexpr int RECLAIM_INTERVAL_SECONDS = 1;
30 static constexpr int MODIFY_INTERVAL_SECONDS = 2;
31 void LoopPrintAlphabet(PurgeableMem *pdata, unsigned int loopCount);
32 bool ReclaimPurgeable(void);
33 void LoopReclaimPurgeable(unsigned int loopCount);
34 void ModifyPurgMemByBuilder(PurgeableMem *pdata, std::unique_ptr<PurgeableMemBuilder> mod);
35 
36 class TestDataBuilder : public PurgeableMemBuilder {
37 public:
TestDataBuilder(char start,char end)38     TestDataBuilder(char start, char end)
39     {
40         this->start = start;
41         this->end = end;
42     }
43 
Build(void * data,size_t size)44     bool Build(void *data, size_t size)
45     {
46         char *str = (char *)data;
47         size_t len = 0;
48         for (char ch = start; ch <= end && len < size; ch++) {
49             str[len++] = ch;
50         }
51         str[len] = 0;
52         std::cout << "rebuild addr("<< (unsigned long long)str <<") " <<
53             start << "~" << end << ", data=[" << str << "]" << std::endl;
54         return true;
55     }
56 
~TestDataBuilder()57     ~TestDataBuilder()
58     {
59         std::cout << "~TestDataBuilder" << std::endl;
60     }
61 
62 private:
63     char start, end;
64 };
65 
66 class TestDataModifier : public PurgeableMemBuilder {
67 public:
TestDataModifier(char from,char to)68     TestDataModifier(char from, char to)
69     {
70         this->from = from;
71         this->to = to;
72     }
73 
Build(void * data,size_t size)74     bool Build(void *data, size_t size)
75     {
76         char *str = (char *)data;
77         for (size_t i = 0; str[i] && i < size; i++) {
78             if (str[i] == from) {
79                 str[i] = to;
80             }
81         }
82         std::cout << "modify addr("<< (unsigned long long)str <<") " <<
83             from << "->" << to << ", data=[" << str << "]" << std::endl;
84         return true;
85     }
86 
~TestDataModifier()87     ~TestDataModifier()
88     {
89         std::cout << "~TestDataModifier" << std::endl;
90     }
91 
92 private:
93     char from, to;
94 };
95 
96 class PurgeableCppTest : public testing::Test {
97 public:
98     static void SetUpTestCase();
99     static void TearDownTestCase();
100     void SetUp();
101     void TearDown();
102 };
103 
SetUpTestCase()104 void PurgeableCppTest::SetUpTestCase()
105 {
106 }
107 
TearDownTestCase()108 void PurgeableCppTest::TearDownTestCase()
109 {
110 }
111 
SetUp()112 void PurgeableCppTest::SetUp()
113 {
114 }
115 
TearDown()116 void PurgeableCppTest::TearDown()
117 {
118 }
119 /*
120  * @tc.number MULTI_OBJ_CREAT_Test_0100
121  * @tc.name Test Creat purgeable
122  * @tc.desc [C- SOFTWARE -0200]
123 */
124 HWTEST_F(PurgeableCppTest, MultiObjCreateTest, TestSize.Level1)
125 {
126     const char alphabetFinal[] = "BBCDEFGHIJKLMNOPQRSTUVWXYZ\0";
127     std::unique_ptr<PurgeableMemBuilder> builder = std::make_unique<TestDataBuilder>('A', 'Z');
128     std::unique_ptr<PurgeableMemBuilder> builder2 = std::make_unique<TestDataBuilder>('A', 'Z');
129     PurgeableMem pobj1(27, std::move(builder));
130     std::unique_ptr<PurgeableMemBuilder> mod = std::make_unique<TestDataModifier>('A', 'B');
131     std::unique_ptr<PurgeableMemBuilder> mod2 = std::make_unique<TestDataModifier>('A', 'B');
132 
133     LoopPrintAlphabet(&pobj1, 1);
134     ModifyPurgMemByBuilder(&pobj1, std::move(mod));
135     LoopPrintAlphabet(&pobj1, 1);
136     LoopReclaimPurgeable(1);
137 
138     PurgeableMem pobj2(27, std::move(builder2));
139     LoopPrintAlphabet(&pobj2, 1);
140     ModifyPurgMemByBuilder(&pobj2, std::move(mod2));
141     LoopPrintAlphabet(&pobj2, 1);
142 
143     if (pobj1.BeginRead()) {
144         ASSERT_STREQ(alphabetFinal, (char *)(pobj1.GetContent()));
145         pobj1.EndRead();
146     } else {
147         std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
148     }
149 
150     if (pobj2.BeginRead()) {
151         ASSERT_STREQ(alphabetFinal, (char *)(pobj2.GetContent()));
152         pobj2.EndRead();
153     } else {
154         std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
155     }
156 }
157 /*
158  * @tc.number PURGEABLE_READ_Test_0100
159  * @tc.name Test READ purgeable
160  * @tc.desc [C- SOFTWARE -0200]
161 */
162 HWTEST_F(PurgeableCppTest, ReadTest, TestSize.Level1)
163 {
164     const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\0";
165     std::unique_ptr<PurgeableMemBuilder> builder = std::make_unique<TestDataBuilder>('A', 'Z');
166     PurgeableMem *pobj = new PurgeableMem(27, std::move(builder));
167 
168     std::thread reclaimThread(LoopReclaimPurgeable, (unsigned int)(-1));
169     pthread_t reclaimPid = reclaimThread.native_handle();
170     reclaimThread.detach();
171 
172     unsigned int loopCount = 3;
173     /* loop read content */
174     for (unsigned int i = 0; i < loopCount; i++) {
175         if (!pobj->BeginRead()) {
176             std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
177             continue;
178         }
179         ASSERT_STREQ(alphabet, (char *)(pobj->GetContent()));
180         pobj->EndRead();
181     }
182 
183     pthread_cancel(reclaimPid); /* destroy reclaimThread */
184     delete pobj;
185     pobj = nullptr;
186 }
187 /*
188  * @tc.number PURGEABLE_WRITE_Test_0100
189  * @tc.name Test WRITE purgeable
190  * @tc.desc [C- SOFTWARE -0200]
191 */
192 HWTEST_F(PurgeableCppTest, WriteTest, TestSize.Level1)
193 {
194     const char alphabet[] = "CCCDEFGHIJKLMNOPQRSTUVWXYZ\0";
195     std::unique_ptr<PurgeableMemBuilder> builder = std::make_unique<TestDataBuilder>('A', 'Z');
196     PurgeableMem *pobj = new PurgeableMem(27, std::move(builder));
197     std::thread reclaimThread(LoopReclaimPurgeable, (unsigned int)(-1));
198     pthread_t reclaimPid = reclaimThread.native_handle();
199     reclaimThread.detach();
200 
201     std::unique_ptr<PurgeableMemBuilder> modA2B = std::make_unique<TestDataModifier>('A', 'B');
202     std::unique_ptr<PurgeableMemBuilder> modB2C = std::make_unique<TestDataModifier>('B', 'C');
203     ModifyPurgMemByBuilder(pobj, std::move(modA2B));
204     ModifyPurgMemByBuilder(pobj, std::move(modB2C));
205 
206     if (pobj->BeginRead()) {
207         ASSERT_STREQ(alphabet, (char *)(pobj->GetContent()));
208         pobj->EndRead();
209     } else {
210         std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
211     }
212 
213     pthread_cancel(reclaimPid); /* destroy reclaimThread */
214     delete pobj;
215     pobj = nullptr;
216     LoopReclaimPurgeable(3);
217 }
218 /*
219  * @tc.number PURGEABLE_READ_Test_0100
220  * @tc.name Test READWRITE purgeable
221  * @tc.desc [C- SOFTWARE -0200]
222 */
223 HWTEST_F(PurgeableCppTest, ReadWriteTest, TestSize.Level1)
224 {
225     const char alphabet[] = "DDDDEFGHIJKLMNOPQRSTUVWXYZ\0";
226     std::unique_ptr<PurgeableMemBuilder> builder = std::make_unique<TestDataBuilder>('A', 'Z');
227     PurgeableMem *pobj = new PurgeableMem(27, std::move(builder));
228     /* loop reclaim thread */
229     std::thread reclaimThread(LoopReclaimPurgeable, (unsigned int)(-1));
230     pthread_t reclaimPid = reclaimThread.native_handle();
231     reclaimThread.detach();
232     /* loop read thread */
233     std::thread readThread(LoopPrintAlphabet, pobj, (unsigned int)(-1));
234     pthread_t readPid = readThread.native_handle();
235     readThread.detach();
236 
237     std::unique_ptr<PurgeableMemBuilder> modA2B = std::make_unique<TestDataModifier>('A', 'B');
238     std::unique_ptr<PurgeableMemBuilder> modB2C = std::make_unique<TestDataModifier>('B', 'C');
239     std::unique_ptr<PurgeableMemBuilder> modC2D = std::make_unique<TestDataModifier>('C', 'D');
240     ModifyPurgMemByBuilder(pobj, std::move(modA2B));
241     ModifyPurgMemByBuilder(pobj, std::move(modB2C));
242     ModifyPurgMemByBuilder(pobj, std::move(modC2D));
243 
244     if (pobj->BeginRead()) {
245         ASSERT_STREQ(alphabet, (char *)(pobj->GetContent()));
246         pobj->EndRead();
247     } else {
248         std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
249     }
250 
251     pthread_cancel(readPid); /* destroy readThread */
252     pthread_cancel(reclaimPid); /* destroy reclaimThread */
253     std::this_thread::sleep_for(std::chrono::seconds(2 * PRINT_INTERVAL_SECONDS));
254     delete pobj;
255     pobj = nullptr;
256 }
257 
LoopPrintAlphabet(PurgeableMem * pdata,unsigned int loopCount)258 void LoopPrintAlphabet(PurgeableMem *pdata, unsigned int loopCount)
259 {
260     std::cout << "inter " << __func__ << std::endl;
261     for (unsigned int i = 0; i < loopCount; i++) {
262         if (!pdata->BeginRead()) {
263             std::cout << __func__ << ": " << i << ". ERROR! BeginRead failed." << std::endl;
264             break;
265         }
266         std::cout << __func__ << ": " << i << ". data=[" <<
267             (char *)(pdata->GetContent()) << "]" << std::endl;
268         pdata->EndRead();
269         std::this_thread::sleep_for(std::chrono::seconds(PRINT_INTERVAL_SECONDS));
270     }
271     std::cout << "quit " << __func__ << std::endl;
272 }
273 
ReclaimPurgeable(void)274 bool ReclaimPurgeable(void)
275 {
276     FILE *f = fopen("/proc/sys/kernel/purgeable", "w");
277     if (!f) {
278         std::cout << __func__ << ": open file failed" << std::endl;
279         return false;
280     }
281     bool succ = true;
282     if (fputs("1", f) == EOF) {
283         succ = false;
284     }
285 
286     if (fclose(f) == EOF) {
287         std::cout << __func__ << ": close file failed" << std::endl;
288     }
289 
290     return succ;
291 }
292 
LoopReclaimPurgeable(unsigned int loopCount)293 void LoopReclaimPurgeable(unsigned int loopCount)
294 {
295     bool ret = false;
296     std::cout << "inter " << __func__ << std::endl;
297     for (unsigned int i = 0; i < loopCount; i++) {
298         ret = ReclaimPurgeable();
299         std::cout << __func__ << ": " << i << ". Reclaim result=" << (ret ? "succ" : "fail") << std::endl;
300         std::this_thread::sleep_for(std::chrono::seconds(RECLAIM_INTERVAL_SECONDS)); /* wait reclaim finish */
301     }
302     std::cout << "quit " << __func__ << std::endl;
303 }
304 
ModifyPurgMemByBuilder(PurgeableMem * pdata,std::unique_ptr<PurgeableMemBuilder> mod)305 void ModifyPurgMemByBuilder(PurgeableMem *pdata, std::unique_ptr<PurgeableMemBuilder> mod)
306 {
307     if (!pdata->BeginWrite()) {
308         std::cout << __func__ << ": ERROR! BeginWrite failed." << std::endl;
309         return;
310     }
311     std::this_thread::sleep_for(std::chrono::seconds(MODIFY_INTERVAL_SECONDS));
312     std::cout << __func__ << " before mod data=[" << (char *)(pdata->GetContent()) << "]" << std::endl;
313     pdata->ModifyContentByBuilder(std::move(mod));
314     std::cout<< __func__ << " after mod data=[" << (char *)(pdata->GetContent()) << "]" << std::endl;
315 
316     std::cout << __func__ << " data=[" << (char *)(pdata->GetContent()) << "]" << std::endl;
317     pdata->EndWrite();
318 }
319 } /* namespace PurgeableMem */
320 } /* namespace OHOS */
321