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