• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 <sys/mman.h> /* mmap */
17 
18 #include "securec.h"
19 #include "pm_util.h"
20 #include "pm_state_c.h"
21 #include "pm_smartptr_util.h"
22 #include "pm_log.h"
23 
24 #include "purgeable_mem_base.h"
25 
26 namespace OHOS {
27 namespace PurgeableMem {
28 #ifdef LOG_TAG
29 #undef LOG_TAG
30 #endif
31 #define LOG_TAG "PurgeableMem"
32 const int MAX_BUILD_TRYTIMES = 3;
33 
RoundUp(size_t val,size_t align)34 static inline size_t RoundUp(size_t val, size_t align)
35 {
36     if (align == 0) {
37         return val;
38     }
39     return ((val + align - 1) / align) * align;
40 }
41 
PurgeableMemBase()42 PurgeableMemBase::PurgeableMemBase()
43 {
44 }
45 
~PurgeableMemBase()46 PurgeableMemBase::~PurgeableMemBase()
47 {
48 }
49 
BeginRead()50 bool PurgeableMemBase::BeginRead()
51 {
52     bool succ = false;
53     bool ret = false;
54     int tryTimes = 0;
55 
56     PM_HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString().c_str());
57     IF_NULL_LOG_ACTION(dataPtr_, "dataPtr is nullptr in BeginRead", return false);
58     IF_NULL_LOG_ACTION(builder_, "builder_ is nullptr in BeginRead", return false);
59     Pin();
60     PMState err = PM_OK;
61     while (true) {
62         try {
63             rwlock_.lock_shared();
64         } catch (...) {
65             err = PM_LOCK_READ_FAIL;
66             break;
67         }
68         if (!IfNeedRebuild_()) {
69             PM_HILOG_DEBUG(LOG_CORE, "%{public}s: not purged, return true. MAP_PUR=0x%{public}x",
70                 __func__, MAP_PURGEABLE);
71             ret = true;
72             break;
73         }
74         /* data is purged, will rebuild it */
75         rwlock_.unlock_shared();
76         try {
77             rwlock_.lock();
78         } catch (...) {
79             err = PM_LOCK_WRITE_FAIL;
80             break;
81         }
82         if (IfNeedRebuild_()) {
83             succ = BuildContent_();
84             if (succ) {
85                 AfterRebuildSucc();
86             }
87             PM_HILOG_DEBUG(LOG_CORE, "%{public}s: purged, built %{public}s", __func__, succ ? "succ" : "fail");
88         }
89         tryTimes++;
90         rwlock_.unlock();
91         if (!succ || tryTimes > MAX_BUILD_TRYTIMES) {
92             err = PMB_BUILD_ALL_FAIL;
93             break;
94         }
95     }
96 
97     if (!ret) {
98         PM_HILOG_ERROR(LOG_CORE, "%{public}s: err %{public}s, UxptePut. tryTime:%{public}d",
99             __func__, GetPMStateName(err), tryTimes);
100         Unpin();
101     }
102     return ret;
103 }
104 
EndRead()105 void PurgeableMemBase::EndRead()
106 {
107     PM_HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString().c_str());
108     rwlock_.unlock_shared();
109     Unpin();
110 }
111 
BeginWrite()112 bool PurgeableMemBase::BeginWrite()
113 {
114     PM_HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString().c_str());
115     if (dataPtr_ == nullptr) {
116         return false;
117     }
118     IF_NULL_LOG_ACTION(dataPtr_, "dataPtr is nullptr in BeginWrite", return false);
119     IF_NULL_LOG_ACTION(builder_, "builder_ is nullptr in BeginWrite", return false);
120 
121     Pin();
122     PMState err = PM_OK;
123     do {
124         try {
125             rwlock_.lock();
126         } catch (...) {
127             err = PM_LOCK_WRITE_FAIL;
128             break;
129         }
130         if (!IfNeedRebuild_()) {
131             /* data is not purged, return true */
132             break;
133         }
134         /* data purged, rebuild it */
135         if (BuildContent_()) {
136             /* data rebuild succ, return true */
137             AfterRebuildSucc();
138             break;
139         }
140         err = PMB_BUILD_ALL_FAIL;
141     } while (0);
142 
143     if (err == PM_OK) {
144         return true;
145     }
146 
147     rwlock_.unlock();
148     PM_HILOG_ERROR(LOG_CORE, "%{public}s: err %{public}s, UxptePut.", __func__, GetPMStateName(err));
149     Unpin();
150     return false;
151 }
152 
EndWrite()153 void PurgeableMemBase::EndWrite()
154 {
155     PM_HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString().c_str());
156     rwlock_.unlock();
157     Unpin();
158 }
159 
BeginReadWithDataLock()160 bool PurgeableMemBase::BeginReadWithDataLock()
161 {
162     if (!isDataValid_) {
163         return false;
164     }
165 
166     std::lock_guard<ffrt::mutex> lock(dataLock_);
167     if (!isDataValid_) {
168         return false;
169     }
170 
171     bool succ = false;
172     bool ret = false;
173     int tryTimes = 0;
174 
175     PM_HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString().c_str());
176     IF_NULL_LOG_ACTION(dataPtr_, "dataPtr is nullptr in BeginRead", return false);
177     IF_NULL_LOG_ACTION(builder_, "builder_ is nullptr in BeginRead", return false);
178     Pin();
179     PMState err = PM_OK;
180     while (true) {
181         if (!IfNeedRebuild_()) {
182             PM_HILOG_DEBUG(LOG_CORE, "%{public}s: not purged, return true. MAP_PUR=0x%{public}x",
183                 __func__, MAP_PURGEABLE);
184             ret = true;
185             break;
186         }
187 
188         succ = BuildContent_();
189         if (succ) {
190             AfterRebuildSucc();
191         }
192         PM_HILOG_DEBUG(LOG_CORE, "%{public}s: purged, built %{public}s", __func__, succ ? "succ" : "fail");
193 
194         tryTimes++;
195         if (!succ || tryTimes > MAX_BUILD_TRYTIMES) {
196             err = PMB_BUILD_ALL_FAIL;
197             break;
198         }
199     }
200 
201     if (!ret) {
202         PM_HILOG_ERROR(LOG_CORE, "%{public}s: err %{public}s, UxptePut. tryTime:%{public}d",
203             __func__, GetPMStateName(err), tryTimes);
204         Unpin();
205     }
206     return ret;
207 }
208 
EndReadWithDataLock()209 void PurgeableMemBase::EndReadWithDataLock()
210 {
211     if (isDataValid_) {
212         EndRead();
213     }
214 
215     return;
216 }
217 
ModifyContentByBuilder(std::unique_ptr<PurgeableMemBuilder> modifier)218 bool PurgeableMemBase::ModifyContentByBuilder(std::unique_ptr<PurgeableMemBuilder> modifier)
219 {
220     IF_NULL_LOG_ACTION(modifier, "input modifier is nullptr", return false);
221     if (!modifier->Build(dataPtr_, dataSizeInput_)) {
222         PM_HILOG_ERROR(LOG_CORE, "%{public}s: modify content by builder fail!!", __func__);
223         return false;
224     }
225     /* log modify */
226     if (builder_) {
227         builder_->AppendBuilder(std::move(modifier));
228     } else {
229         builder_ = std::move(modifier);
230     }
231     return true;
232 }
233 
IfNeedRebuild_()234 bool PurgeableMemBase::IfNeedRebuild_()
235 {
236     if (buildDataCount_ == 0 || IsPurged()) {
237         return true;
238     }
239     return false;
240 }
241 
AfterRebuildSucc()242 void PurgeableMemBase::AfterRebuildSucc()
243 {
244 }
245 
GetContent()246 void *PurgeableMemBase::GetContent()
247 {
248     return dataPtr_;
249 }
250 
GetContentSize()251 size_t PurgeableMemBase::GetContentSize()
252 {
253     return dataSizeInput_;
254 }
255 
IsPurged()256 bool PurgeableMemBase::IsPurged()
257 {
258     return false;
259 }
260 
BuildContent_()261 bool PurgeableMemBase::BuildContent_()
262 {
263     bool succ = false;
264     /* clear content before rebuild */
265     if (memset_s(dataPtr_, RoundUp(dataSizeInput_, PAGE_SIZE), 0, dataSizeInput_) != EOK) {
266         PM_HILOG_ERROR(LOG_CORE, "%{public}s, clear content fail", __func__);
267         return succ;
268     }
269     /* builder_ and dataPtr_ is never nullptr since it is checked by BeginAccess() before */
270     succ = builder_->BuildAll(dataPtr_, dataSizeInput_);
271     if (succ) {
272         buildDataCount_++;
273     }
274     return succ;
275 }
276 
ResizeData(size_t newSize)277 void PurgeableMemBase::ResizeData(size_t newSize)
278 {
279 }
280 
Pin()281 bool PurgeableMemBase::Pin()
282 {
283     return false;
284 }
285 
Unpin()286 bool PurgeableMemBase::Unpin()
287 {
288     return false;
289 }
290 
GetPinStatus() const291 int PurgeableMemBase::GetPinStatus() const
292 {
293     return 0;
294 }
295 
ToString() const296 inline std::string PurgeableMemBase::ToString() const
297 {
298     return "";
299 }
300 
SetRebuildSuccessCallback(std::function<void ()> & callback)301 void PurgeableMemBase::SetRebuildSuccessCallback(std::function<void()> &callback)
302 {
303     if (builder_) {
304         builder_->SetRebuildSuccessCallback(callback);
305     }
306 }
307 
IsDataValid()308 bool PurgeableMemBase::IsDataValid()
309 {
310     return isDataValid_;
311 }
312 
SetDataValid(bool target)313 void PurgeableMemBase::SetDataValid(bool target)
314 {
315     isDataValid_ = target;
316 }
317 } /* namespace PurgeableMem */
318 } /* namespace OHOS */
319