1 /*
2 * Copyright (C) 2021 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
17 #include "refbase.h"
18
19 namespace OHOS {
WeakRefCounter(RefCounter * counter,void * cookie)20 WeakRefCounter::WeakRefCounter(RefCounter *counter, void *cookie)
21 : atomicWeak_(0), refCounter_(counter), cookie_(cookie)
22 {
23 if (refCounter_ != nullptr) {
24 refCounter_->IncRefCount();
25 }
26 }
27
~WeakRefCounter()28 WeakRefCounter::~WeakRefCounter()
29 {
30 if (refCounter_ != nullptr) {
31 refCounter_->DecRefCount();
32 }
33 }
34
GetRefPtr()35 void* WeakRefCounter::GetRefPtr()
36 {
37 if (refCounter_ == nullptr) {
38 return nullptr;
39 }
40 if ((cookie_ != nullptr) && (!refCounter_->IsRefPtrValid())) {
41 cookie_ = nullptr;
42 }
43 return cookie_;
44 }
45
IncWeakRefCount(const void * objectId)46 void WeakRefCounter::IncWeakRefCount(const void *objectId)
47 {
48 if (atomicWeak_.fetch_add(1, std::memory_order_relaxed) == 0) {
49 refCounter_->IncWeakRefCount(objectId);
50 }
51 }
52
DecWeakRefCount(const void * objectId)53 void WeakRefCounter::DecWeakRefCount(const void *objectId)
54 {
55 if (atomicWeak_.fetch_sub(1, std::memory_order_release) == 1) {
56 refCounter_->DecWeakRefCount(objectId);
57 delete this;
58 }
59 }
60
AttemptIncStrongRef(const void * objectId)61 bool WeakRefCounter::AttemptIncStrongRef(const void *objectId)
62 {
63 int unuse = 0;
64 return refCounter_->AttemptIncStrongRef(objectId, unuse);
65 }
66
RefCounter()67 RefCounter::RefCounter()
68 : atomicStrong_(INITIAL_PRIMARY_VALUE), atomicWeak_(0), atomicRefCount_(0), atomicFlags_(0), atomicAttempt_(0)
69 {
70 }
GetRefCount()71 int RefCounter::GetRefCount()
72 {
73 return atomicRefCount_.load(std::memory_order_relaxed);
74 }
75
IncRefCount()76 void RefCounter::IncRefCount()
77 {
78 atomicRefCount_.fetch_add(1, std::memory_order_relaxed);
79 }
80
DecRefCount()81 void RefCounter::DecRefCount()
82 {
83 if (atomicRefCount_.load(std::memory_order_relaxed) > 0) {
84 if (atomicRefCount_.fetch_sub(1, std::memory_order_release) == 1) {
85 delete (this);
86 }
87 }
88 }
89
SetCallback(const RefPtrCallback & callback)90 void RefCounter::SetCallback(const RefPtrCallback& callback)
91 {
92 callback_ = callback;
93 }
94
RemoveCallback()95 void RefCounter::RemoveCallback()
96 {
97 callback_ = nullptr;
98 }
99
IsRefPtrValid()100 bool RefCounter::IsRefPtrValid()
101 {
102 return callback_ != nullptr;
103 }
104
~RefCounter()105 RefCounter::~RefCounter()
106 {
107 }
108
IncStrongRefCount(const void *)109 int RefCounter::IncStrongRefCount(const void * /*objectId*/)
110 {
111 int curCount = atomicStrong_.load(std::memory_order_relaxed);
112 if (curCount >= 0) {
113 curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
114 if (curCount == INITIAL_PRIMARY_VALUE) {
115 atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
116 }
117 }
118 return curCount;
119 }
120
DecStrongRefCount(const void *)121 int RefCounter::DecStrongRefCount(const void * /*objectId*/)
122 {
123 int curCount = GetStrongRefCount();
124 if (curCount == INITIAL_PRIMARY_VALUE) {
125 // unexpected case: there had never a strong reference.
126 } else if (curCount > 0) {
127 // we should update the current count here.
128 // it may be changed after last operation.
129 curCount = atomicStrong_.fetch_sub(1, std::memory_order_release);
130 }
131 return curCount;
132 }
133
GetStrongRefCount()134 int RefCounter::GetStrongRefCount()
135 {
136 return atomicStrong_.load(std::memory_order_relaxed);
137 }
138
IncWeakRefCount(const void *)139 int RefCounter::IncWeakRefCount(const void * /*objectId*/)
140 {
141 return atomicWeak_.fetch_add(1, std::memory_order_relaxed);
142 }
143
DecWeakRefCount(const void *)144 int RefCounter::DecWeakRefCount(const void * /*objectId*/)
145 {
146 int curCount = GetWeakRefCount();
147 if (curCount > 0) {
148 curCount = atomicWeak_.fetch_sub(1, std::memory_order_release);
149 }
150 int strongRefCount = GetStrongRefCount();
151 if ((curCount == 1) || (strongRefCount == 0 && !IsLifeTimeExtended())) {
152 if (callback_) {
153 callback_();
154 }
155 }
156 return curCount;
157 }
158
GetWeakRefCount()159 int RefCounter::GetWeakRefCount()
160 {
161 return atomicWeak_.load(std::memory_order_relaxed);
162 }
163
SetAttemptAcquire()164 void RefCounter::SetAttemptAcquire()
165 {
166 (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed);
167 }
168
IsAttemptAcquireSet()169 bool RefCounter::IsAttemptAcquireSet()
170 {
171 return static_cast<bool>(atomicAttempt_.load(std::memory_order_relaxed) > 0);
172 }
173
ClearAttemptAcquire()174 void RefCounter::ClearAttemptAcquire()
175 {
176 atomicAttempt_.fetch_sub(1, std::memory_order_relaxed);
177 }
178
ExtendObjectLifetime()179 void RefCounter::ExtendObjectLifetime()
180 {
181 atomicFlags_.fetch_or(FLAG_EXTEND_LIFE_TIME, std::memory_order_relaxed);
182 }
183
IsLifeTimeExtended()184 bool RefCounter::IsLifeTimeExtended()
185 {
186 return static_cast<bool>(atomicFlags_.load(std::memory_order_relaxed) & FLAG_EXTEND_LIFE_TIME);
187 }
188
AttemptIncStrongRef(const void * objectId,int & outCount)189 bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount)
190 {
191 int curCount = GetStrongRefCount();
192 IncWeakRefCount(objectId);
193
194 // if the object already had strong references.just promoting it.
195 while ((curCount > 0) && (curCount != INITIAL_PRIMARY_VALUE)) {
196 if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
197 goto attempt_success;
198 }
199
200 // someone else changed the counter.re-acquire the counter value.
201 curCount = atomicStrong_.load(std::memory_order_relaxed);
202 }
203
204 if ((curCount == INITIAL_PRIMARY_VALUE) && !IsLifeTimeExtended()) {
205 // this object has a "normal" life-time,
206 while (curCount > 0) {
207 if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
208 goto attempt_success;
209 }
210
211 curCount = atomicStrong_.load(std::memory_order_relaxed);
212 }
213 }
214
215 if (IsLifeTimeExtended()) {
216 curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
217 }
218
219 attempt_success:
220 if (curCount >= INITIAL_PRIMARY_VALUE) {
221 outCount = curCount;
222 atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
223 return true;
224 }
225
226 if (curCount < 0 || (!IsLifeTimeExtended() && curCount == 0)) {
227 // the object destroyed on strong reference count reduce to zero.
228 DecWeakRefCount(objectId);
229 return false;
230 }
231 return true;
232 }
233
RefBase()234 RefBase::RefBase() : refs_(new RefCounter())
235 {
236 refs_->IncRefCount();
237 refs_->SetCallback([this] {
238 this->RefPtrCallback();
239 });
240 }
241
RefBase(const RefBase &)242 RefBase::RefBase(const RefBase& /*other*/)
243 {
244 refs_ = new RefCounter();
245 if (refs_ != nullptr) {
246 refs_->IncRefCount();
247 refs_->SetCallback([this] {
248 this->RefPtrCallback();
249 });
250 }
251 }
252
RefPtrCallback()253 void RefBase::RefPtrCallback()
254 {
255 delete this;
256 }
257
258 /*
259 * The two ends of the assignment are two independent and exclusive,
260 * and the application should not share the reference counter.
261 * RISK: If there is a reference count on the left of the equal sign,
262 * it may cause a reference count exception
263 */
operator =(const RefBase &)264 RefBase &RefBase::operator=(const RefBase& /*other*/)
265 {
266 if (refs_ != nullptr) {
267 refs_->RemoveCallback();
268 refs_->DecRefCount();
269 }
270 refs_ = new RefCounter();
271 if (refs_ != nullptr) {
272 refs_->IncRefCount();
273 refs_->SetCallback([this] {
274 this->RefPtrCallback();
275 });
276 }
277 return *this;
278 }
279
RefBase(RefBase && other)280 RefBase::RefBase(RefBase &&other) noexcept
281 {
282 refs_ = other.refs_;
283 other.refs_ = nullptr;
284 }
285
operator =(RefBase && other)286 RefBase &RefBase::operator=(RefBase &&other) noexcept
287 {
288 if (refs_ == other.refs_) {
289 return *this;
290 }
291 if (refs_ != nullptr) {
292 refs_->RemoveCallback();
293 refs_->DecRefCount();
294 }
295 refs_ = other.refs_;
296 other.refs_ = nullptr;
297 return *this;
298 }
299
~RefBase()300 RefBase::~RefBase()
301 {
302 if (refs_ != nullptr) {
303 refs_->RemoveCallback();
304 refs_->DecRefCount();
305 refs_ = nullptr;
306 }
307 }
308
ExtendObjectLifetime()309 void RefBase::ExtendObjectLifetime()
310 {
311 refs_->ExtendObjectLifetime();
312 }
313
IncStrongRef(const void * objectId)314 void RefBase::IncStrongRef(const void *objectId)
315 {
316 if (refs_ == nullptr) {
317 return;
318 }
319 const int curCount = refs_->IncStrongRefCount(objectId);
320 IncWeakRef(objectId);
321 if (curCount == INITIAL_PRIMARY_VALUE) {
322 OnFirstStrongRef(objectId);
323 }
324 if (refs_->IsAttemptAcquireSet()) {
325 refs_->ClearAttemptAcquire();
326 refs_->DecStrongRefCount(objectId);
327 }
328 }
329
DecStrongRef(const void * objectId)330 void RefBase::DecStrongRef(const void *objectId)
331 {
332 if (refs_ == nullptr) {
333 return;
334 }
335 const int curCount = refs_->DecStrongRefCount(objectId);
336 if (curCount == 1) {
337 OnLastStrongRef(objectId);
338 }
339 DecWeakRef(objectId);
340 }
341
GetSptrRefCount()342 int RefBase::GetSptrRefCount()
343 {
344 if (refs_ != nullptr) {
345 return refs_->GetStrongRefCount();
346 } else {
347 return 0;
348 }
349 }
350
CreateWeakRef(void * cookie)351 WeakRefCounter *RefBase::CreateWeakRef(void *cookie)
352 {
353 if (refs_ != nullptr) {
354 return new WeakRefCounter(refs_, cookie);
355 }
356
357 return nullptr;
358 }
359
IncWeakRef(const void * objectId)360 void RefBase::IncWeakRef(const void *objectId)
361 {
362 if (refs_ != nullptr) {
363 refs_->IncWeakRefCount(objectId);
364 }
365 }
366
DecWeakRef(const void * objectId)367 void RefBase::DecWeakRef(const void *objectId)
368 {
369 if (refs_ != nullptr) {
370 refs_->DecWeakRefCount(objectId);
371 }
372 }
373
GetWptrRefCount()374 int RefBase::GetWptrRefCount()
375 {
376 if (refs_ != nullptr) {
377 return refs_->GetWeakRefCount();
378 } else {
379 return 0;
380 }
381 }
382
AttemptAcquire(const void * objectId)383 bool RefBase::AttemptAcquire(const void *objectId)
384 {
385 if (refs_ != nullptr) {
386 int count = 0;
387 if (refs_->AttemptIncStrongRef(objectId, count)) {
388 if (count == INITIAL_PRIMARY_VALUE) {
389 OnFirstStrongRef(objectId);
390 }
391 refs_->SetAttemptAcquire();
392 return true;
393 }
394 }
395 return false;
396 }
397
AttemptIncStrongRef(const void * objectId)398 bool RefBase::AttemptIncStrongRef(const void *objectId)
399 {
400 if ((refs_ != nullptr) && (OnAttemptPromoted(objectId))) {
401 int count = 0;
402 bool ret = refs_->AttemptIncStrongRef(objectId, count);
403 if (count == INITIAL_PRIMARY_VALUE) {
404 OnFirstStrongRef(objectId);
405 }
406 return ret;
407 }
408 return false;
409 }
410
IsAttemptAcquireSet()411 bool RefBase::IsAttemptAcquireSet()
412 {
413 if (refs_ != nullptr) {
414 return refs_->IsAttemptAcquireSet();
415 }
416 return false;
417 }
418
IsExtendLifeTimeSet()419 bool RefBase::IsExtendLifeTimeSet()
420 {
421 if (refs_ != nullptr) {
422 return refs_->IsLifeTimeExtended();
423 }
424 return false;
425 }
426
OnFirstStrongRef(const void *)427 void RefBase::OnFirstStrongRef(const void *)
428 {}
429
OnLastStrongRef(const void *)430 void RefBase::OnLastStrongRef(const void *)
431 {}
432
OnLastWeakRef(const void *)433 void RefBase::OnLastWeakRef(const void *)
434 {}
435
OnAttemptPromoted(const void *)436 bool RefBase::OnAttemptPromoted(const void *)
437 {
438 return true;
439 }
440 } // namespace OHOS
441