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 "refbase.h"
17 #ifdef DEBUG_REFBASE
18 #include "utils_log.h"
19 #include <unistd.h>
20 #endif
21 
22 namespace OHOS {
23 
WeakRefCounter(RefCounter * counter,void * cookie)24 WeakRefCounter::WeakRefCounter(RefCounter *counter, void *cookie)
25     : atomicWeak_(0), refCounter_(counter), cookie_(cookie)
26 {
27     if (refCounter_ != nullptr) {
28         refCounter_->IncRefCount();
29     }
30 }
31 
~WeakRefCounter()32 WeakRefCounter::~WeakRefCounter()
33 {
34     if (refCounter_ != nullptr) {
35         refCounter_->DecRefCount();
36     }
37 }
38 
GetWeakRefCount() const39 int WeakRefCounter::GetWeakRefCount() const
40 {
41     return atomicWeak_.load(std::memory_order_relaxed);
42 }
43 
GetRefPtr()44 void* WeakRefCounter::GetRefPtr()
45 {
46     if ((cookie_ != nullptr) && (!refCounter_->IsRefPtrValid())) {
47         cookie_ = nullptr;
48     }
49     return cookie_;
50 }
51 
IncWeakRefCount(const void * objectId)52 void WeakRefCounter::IncWeakRefCount(const void *objectId)
53 {
54     if (atomicWeak_.fetch_add(1, std::memory_order_relaxed) == 0) {
55         refCounter_->IncWeakRefCount(objectId);
56     }
57 }
58 
DecWeakRefCount(const void * objectId)59 void WeakRefCounter::DecWeakRefCount(const void *objectId)
60 {
61     if (atomicWeak_.fetch_sub(1, std::memory_order_release) == 1) {
62         refCounter_->DecWeakRefCount(objectId);
63         delete this;
64     }
65 }
66 
AttemptIncStrongRef(const void * objectId)67 bool WeakRefCounter::AttemptIncStrongRef(const void *objectId)
68 {
69     int unuse = 0;
70     return refCounter_->AttemptIncStrongRef(objectId, unuse);
71 }
72 
73 #ifdef DEBUG_REFBASE
RefTracker(RefTracker * exTracker,const void * id,int strong,int weak,int ref,int pid,int tid)74 RefTracker::RefTracker(RefTracker* exTracker, const void* id, int strong, int weak, int ref, int pid, int tid)
75     : ptrID (id), strongRefCNT (strong), weakRefCNT (weak), refCNT (ref), PID (pid), TID (tid), exTrace (exTracker)
76 {
77 }
78 
GetTrace(RefTracker * exTracker,const void * id,int strong,int weak,int ref,int pid,int tid)79 void RefTracker::GetTrace(RefTracker* exTracker, const void* id, int strong, int weak, int ref, int pid, int tid)
80 {
81     ptrID = id;
82     strongRefCNT = strong;
83     weakRefCNT = weak;
84     refCNT = ref;
85     PID = pid;
86     TID = tid;
87     exTrace = exTracker;
88 }
89 
GetStrongTrace(RefTracker * exTracker,const void * id,int strong,int pid,int tid)90 void RefTracker::GetStrongTrace(RefTracker* exTracker, const void* id, int strong, int pid, int tid)
91 {
92     ptrID = id;
93     strongRefCNT = strong;
94     weakRefCNT = -(INITIAL_PRIMARY_VALUE);
95     refCNT = -(INITIAL_PRIMARY_VALUE);
96     PID = pid;
97     TID = tid;
98     exTrace = exTracker;
99 }
100 
GetWeakTrace(RefTracker * exTracker,const void * id,int weak,int pid,int tid)101 void RefTracker::GetWeakTrace(RefTracker* exTracker, const void* id, int weak, int pid, int tid)
102 {
103     ptrID = id;
104     strongRefCNT = -(INITIAL_PRIMARY_VALUE);
105     weakRefCNT = weak;
106     refCNT = -(INITIAL_PRIMARY_VALUE);
107     PID = pid;
108     TID = tid;
109     exTrace = exTracker;
110 }
111 
PrintTrace(const void * root)112 void RefTracker::PrintTrace(const void* root)
113 {
114     UTILS_LOGI("ptrID(%{public}lx) call %{public}lx. strongcnt: %{public}d weakcnt: %{public}d " \
115         "refcnt: %{public}d PID: %{public}d TID: %{public}d",
116         reinterpret_cast<size_t>(ptrID), reinterpret_cast<size_t>(root), strongRefCNT, weakRefCNT, refCNT, PID, TID);
117 }
118 
PrintStrongTrace(const void * root)119 void RefTracker::PrintStrongTrace(const void* root)
120 {
121     UTILS_LOGI("ptrID(%{public}lx) call %{public}lx. strongcnt: %{public}d PID: %{public}d TID: %{public}d",
122         reinterpret_cast<size_t>(ptrID), reinterpret_cast<size_t>(root), strongRefCNT, PID, TID);
123 }
124 
PrintWeakTrace(const void * root)125 void RefTracker::PrintWeakTrace(const void* root)
126 {
127     UTILS_LOGI("ptrID(%{public}lx) call %{public}lx. weakcnt: %{public}d PID: %{public}d TID: %{public}d",
128         reinterpret_cast<size_t>(ptrID), reinterpret_cast<size_t>(root), weakRefCNT, PID, TID);
129 }
130 
GetexTrace()131 RefTracker* RefTracker::GetexTrace()
132 {
133     return exTrace;
134 }
135 
PopTrace(const void * root)136 RefTracker* RefTracker::PopTrace(const void* root)
137 {
138     RefTracker* ref = exTrace;
139     PrintTrace(root);
140     delete this;
141     return ref;
142 }
143 
GetNewTrace(const void * objectId)144 void RefCounter::GetNewTrace(const void* objectId)
145 {
146     std::lock_guard<std::mutex> lock(trackerMutex);
147     RefTracker* newTracker = new RefTracker(refTracker, objectId, atomicStrong_.load(std::memory_order_relaxed),
148         atomicWeak_.load(std::memory_order_relaxed), atomicRefCount_.load(std::memory_order_relaxed),
149         getpid(), gettid());
150     refTracker = newTracker;
151 }
152 
PrintTracker()153 void RefCounter::PrintTracker()
154 {
155     std::lock_guard<std::mutex> lock(trackerMutex);
156     while (refTracker) {
157         refTracker = refTracker->PopTrace(this);
158     }
159 }
160 #endif
161 
RefCounter()162 RefCounter::RefCounter()
163     : atomicStrong_(INITIAL_PRIMARY_VALUE), atomicWeak_(0), atomicRefCount_(0), atomicFlags_(0), atomicAttempt_(0)
164 {
165 }
166 
GetRefCount()167 int RefCounter::GetRefCount()
168 {
169     return atomicRefCount_.load(std::memory_order_relaxed);
170 }
171 
IncRefCount()172 void RefCounter::IncRefCount()
173 {
174     atomicRefCount_.fetch_add(1, std::memory_order_relaxed);
175 }
176 
DecRefCount()177 void RefCounter::DecRefCount()
178 {
179     if (atomicRefCount_.load(std::memory_order_relaxed) > 0) {
180         if (atomicRefCount_.fetch_sub(1, std::memory_order_release) == 1) {
181             delete (this);
182         }
183     }
184 }
185 
SetCallback(const RefPtrCallback & callback)186 void RefCounter::SetCallback(const RefPtrCallback& callback)
187 {
188     callback_ = callback;
189 }
190 
RemoveCallback()191 void RefCounter::RemoveCallback()
192 {
193     callback_ = nullptr;
194 }
195 
IsRefPtrValid()196 bool RefCounter::IsRefPtrValid()
197 {
198     return callback_ != nullptr;
199 }
200 
201 #ifndef ROSEN_EMULATOR
SetCanPromote(const CanPromote & canPromote)202 void RefCounter::SetCanPromote(const CanPromote &canPromote)
203 {
204     canPromote_ = canPromote;
205 }
206 
RemoveCanPromote()207 void RefCounter::RemoveCanPromote()
208 {
209     canPromote_ = nullptr;
210 }
211 
IsCanPromoteValid()212 bool RefCounter::IsCanPromoteValid()
213 {
214     return canPromote_ != nullptr;
215 }
216 #endif
217 
~RefCounter()218 RefCounter::~RefCounter()
219 {
220 #ifdef DEBUG_REFBASE
221     PrintTracker();
222 #endif
223 }
224 
IncStrongRefCount(const void * objectId)225 int RefCounter::IncStrongRefCount(const void* objectId)
226 {
227 #ifdef DEBUG_REFBASE
228     GetNewTrace(objectId);
229 #endif
230     int curCount = atomicStrong_.load(std::memory_order_relaxed);
231     if (curCount >= 0) {
232         curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
233         if (curCount == INITIAL_PRIMARY_VALUE) {
234             atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
235         }
236     }
237 
238     return curCount;
239 }
240 
DecStrongRefCount(const void * objectId)241 int RefCounter::DecStrongRefCount(const void* objectId)
242 {
243 #ifdef DEBUG_REFBASE
244     GetNewTrace(objectId);
245 #endif
246     int curCount = GetStrongRefCount();
247     if (curCount == INITIAL_PRIMARY_VALUE) {
248         // unexpected case: there had never a strong reference.
249     } else if (curCount > 0) {
250         // we should update the current count here.
251         // it may be changed after last operation.
252         curCount = atomicStrong_.fetch_sub(1, std::memory_order_release);
253     }
254 
255     return curCount;
256 }
257 
GetStrongRefCount()258 int RefCounter::GetStrongRefCount()
259 {
260     return atomicStrong_.load(std::memory_order_relaxed);
261 }
262 
IncWeakRefCount(const void * objectId)263 int RefCounter::IncWeakRefCount(const void* objectId)
264 {
265 #ifdef DEBUG_REFBASE
266     GetNewTrace(objectId);
267 #endif
268     return atomicWeak_.fetch_add(1, std::memory_order_relaxed);
269 }
270 
DecWeakRefCount(const void * objectId)271 int RefCounter::DecWeakRefCount(const void* objectId)
272 {
273 #ifdef DEBUG_REFBASE
274     GetNewTrace(objectId);
275 #endif
276     int curCount = GetWeakRefCount();
277     if (curCount > 0) {
278         curCount = atomicWeak_.fetch_sub(1, std::memory_order_release);
279     }
280 
281     if (curCount != 1) {
282         return curCount;
283     }
284 
285     if (IsLifeTimeExtended() && GetStrongRefCount() == 0) {
286         if (callback_) {
287             callback_();
288         }
289     } else {
290         // only weak ptr case: no strong reference, delete the object
291         if (GetStrongRefCount() == INITIAL_PRIMARY_VALUE) {
292             if (callback_) {
293                 callback_();
294             }
295         } else {
296             // free RefCounter
297             DecRefCount();
298         }
299     }
300 
301     return curCount;
302 }
303 
GetWeakRefCount()304 int RefCounter::GetWeakRefCount()
305 {
306     return atomicWeak_.load(std::memory_order_relaxed);
307 }
308 
SetAttemptAcquire()309 void RefCounter::SetAttemptAcquire()
310 {
311     (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed);
312 }
313 
IsAttemptAcquireSet()314 bool RefCounter::IsAttemptAcquireSet()
315 {
316     return static_cast<bool>(atomicAttempt_.load(std::memory_order_relaxed) > 0);
317 }
318 
ClearAttemptAcquire()319 void RefCounter::ClearAttemptAcquire()
320 {
321     atomicAttempt_.fetch_sub(1, std::memory_order_relaxed);
322 }
323 
ExtendObjectLifetime()324 void RefCounter::ExtendObjectLifetime()
325 {
326     atomicFlags_.fetch_or(FLAG_EXTEND_LIFE_TIME, std::memory_order_relaxed);
327 }
328 
IsLifeTimeExtended()329 bool RefCounter::IsLifeTimeExtended()
330 {
331     return static_cast<bool>(atomicFlags_.load(std::memory_order_relaxed) & FLAG_EXTEND_LIFE_TIME);
332 }
333 
AttemptIncStrongRef(const void * objectId,int & outCount)334 bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount)
335 {
336     int curCount = GetStrongRefCount();
337     IncWeakRefCount(objectId);
338 
339     // if the object already had strong references.just promoting it.
340     while ((curCount > 0) && (curCount != INITIAL_PRIMARY_VALUE)) {
341         if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
342             goto ATTEMPT_SUCCESS;
343         }
344         // someone else changed the counter.re-acquire the counter value.
345         curCount = atomicStrong_.load(std::memory_order_relaxed);
346     }
347 
348     if ((curCount == INITIAL_PRIMARY_VALUE) && !IsLifeTimeExtended()) {
349         // this object has a "normal" life-time,
350         while (curCount > 0) {
351             if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
352                 goto ATTEMPT_SUCCESS;
353             }
354             curCount = atomicStrong_.load(std::memory_order_relaxed);
355         }
356     }
357 
358     if (IsLifeTimeExtended()) {
359 #ifndef ROSEN_EMULATOR
360         if (!IsCanPromoteValid() || !canPromote_()) {
361             return false;
362         }
363 #endif
364         curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
365     }
366 
367 ATTEMPT_SUCCESS:
368     if (curCount >= INITIAL_PRIMARY_VALUE) {
369         outCount = curCount;
370         atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
371         return true;
372     }
373 
374     if (curCount < 0 || (!IsLifeTimeExtended() && curCount == 0)) {
375         // the object destroyed on strong reference count reduce to zero.
376         DecWeakRefCount(objectId);
377         return false;
378     }
379 
380     return true;
381 }
382 
AttemptIncStrong(const void * objectId)383 bool RefCounter::AttemptIncStrong(const void *objectId)
384 {
385     IncWeakRefCount(objectId);
386     int curCount = GetStrongRefCount();
387     while (curCount > 0) {
388         if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
389             break;
390         }
391         // curCount has been updated.
392     }
393     if (curCount <= 0) {
394         DecWeakRefCount(objectId);
395     }
396     return curCount > 0;
397 }
398 
RefBase()399 RefBase::RefBase() : refs_(new RefCounter())
400 {
401     refs_->IncRefCount();
402     refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
403 #ifndef ROSEN_EMULATOR
404     refs_->SetCanPromote([this] { return this->CanPromote(); });
405 #endif
406 }
407 
RefBase(const RefBase &)408 RefBase::RefBase(const RefBase &)
409 {
410     refs_ = new (std::nothrow) RefCounter();
411     if (refs_ != nullptr) {
412         refs_->IncRefCount();
413         refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
414 #ifndef ROSEN_EMULATOR
415         refs_->SetCanPromote([this] { return this->CanPromote(); });
416 #endif
417     }
418 }
419 
420 #ifndef ROSEN_EMULATOR
CanPromote()421 bool RefBase::CanPromote()
422 {
423     return true;
424 }
425 #endif
426 
RefPtrCallback()427 void RefBase::RefPtrCallback()
428 {
429     delete this;
430 }
431 
432 /*
433  * The two ends of the assignment are two independent and exclusive,
434  * and the application should not share the reference counter.
435  * RISK: If there is a reference count on the left of the equal sign,
436  * it may cause a reference count exception
437  */
operator =(const RefBase &)438 RefBase &RefBase::operator=(const RefBase &)
439 {
440     if (refs_ != nullptr) {
441         refs_->RemoveCallback();
442         refs_->DecRefCount();
443     }
444 
445     refs_ = new (std::nothrow) RefCounter();
446     if (refs_ != nullptr) {
447         refs_->IncRefCount();
448         refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
449 #ifndef ROSEN_EMULATOR
450         refs_->SetCanPromote([this] { return this->CanPromote(); });
451 #endif
452     }
453 
454     return *this;
455 }
456 
RefBase(RefBase && other)457 RefBase::RefBase(RefBase &&other) noexcept
458 {
459     refs_ = other.refs_;
460     other.refs_ = nullptr;
461 }
462 
operator =(RefBase && other)463 RefBase &RefBase::operator=(RefBase &&other) noexcept
464 {
465     if (refs_ == other.refs_) {
466         return *this;
467     }
468 
469     if (refs_ != nullptr) {
470         refs_->RemoveCallback();
471         refs_->DecRefCount();
472     }
473 
474     refs_ = other.refs_;
475     other.refs_ = nullptr;
476     return *this;
477 }
478 
~RefBase()479 RefBase::~RefBase()
480 {
481     if (refs_ != nullptr) {
482         refs_->RemoveCallback();
483         if ((refs_->IsLifeTimeExtended() && refs_->GetWeakRefCount() == 0) ||
484              refs_->GetStrongRefCount() == INITIAL_PRIMARY_VALUE) {
485             refs_->DecRefCount();
486         }
487         refs_ = nullptr;
488     }
489 }
490 
ExtendObjectLifetime()491 void RefBase::ExtendObjectLifetime()
492 {
493     refs_->ExtendObjectLifetime();
494 }
495 
IncStrongRef(const void * objectId)496 void RefBase::IncStrongRef(const void *objectId)
497 {
498     if (refs_ == nullptr) {
499         return;
500     }
501 
502     IncWeakRef(objectId);
503     const int curCount = refs_->IncStrongRefCount(objectId);
504     if (curCount == INITIAL_PRIMARY_VALUE) {
505         OnFirstStrongRef(objectId);
506     }
507     if (refs_->IsAttemptAcquireSet()) {
508         refs_->ClearAttemptAcquire();
509         refs_->DecStrongRefCount(objectId);
510         refs_->DecWeakRefCount(objectId);
511     }
512 }
513 
DecStrongRef(const void * objectId)514 void RefBase::DecStrongRef(const void *objectId)
515 {
516     if (refs_ == nullptr) {
517         return;
518     }
519 
520     RefCounter * const refs = refs_;
521     const int curCount = refs->DecStrongRefCount(objectId);
522     if (curCount == 1) {
523         OnLastStrongRef(objectId);
524         if (!refs->IsLifeTimeExtended()) {
525             if (refs->callback_) {
526                 refs->callback_();
527             }
528         }
529     }
530 
531     refs->DecWeakRefCount(objectId);
532 }
533 
GetSptrRefCount()534 int RefBase::GetSptrRefCount()
535 {
536     if (refs_ == nullptr) {
537         return 0;
538     }
539     return refs_->GetStrongRefCount();
540 }
541 
CreateWeakRef(void * cookie)542 WeakRefCounter *RefBase::CreateWeakRef(void *cookie)
543 {
544     if (refs_ != nullptr) {
545         return new WeakRefCounter(refs_, cookie);
546     }
547     return nullptr;
548 }
549 
IncWeakRef(const void * objectId)550 void RefBase::IncWeakRef(const void *objectId)
551 {
552     if (refs_ != nullptr) {
553         refs_->IncWeakRefCount(objectId);
554     }
555 }
556 
GetRefCounter() const557 RefCounter *RefBase::GetRefCounter() const
558 {
559     return refs_;
560 }
561 
DecWeakRef(const void * objectId)562 void RefBase::DecWeakRef(const void *objectId)
563 {
564     if (refs_ != nullptr) {
565         refs_->DecWeakRefCount(objectId);
566     }
567 }
568 
GetWptrRefCount()569 int RefBase::GetWptrRefCount()
570 {
571     if (refs_ == nullptr) {
572         return 0;
573     }
574     return refs_->GetWeakRefCount();
575 }
576 
AttemptAcquire(const void * objectId)577 bool RefBase::AttemptAcquire(const void *objectId)
578 {
579     if (refs_ == nullptr) {
580         return false;
581     }
582 
583     int count = 0;
584     if (refs_->AttemptIncStrongRef(objectId, count)) {
585         refs_->SetAttemptAcquire();
586         if (count == INITIAL_PRIMARY_VALUE) {
587             OnFirstStrongRef(objectId);
588         }
589 
590         return true;
591     }
592     return false;
593 }
594 
AttemptIncStrongRef(const void * objectId)595 bool RefBase::AttemptIncStrongRef(const void *objectId)
596 {
597     if ((refs_ != nullptr) && (OnAttemptPromoted(objectId))) {
598         int count = 0;
599         bool ret = refs_->AttemptIncStrongRef(objectId, count);
600         if (count == INITIAL_PRIMARY_VALUE) {
601             OnFirstStrongRef(objectId);
602         }
603         return ret;
604     }
605 
606     return false;
607 }
608 
AttemptIncStrong(const void * objectId)609 bool RefBase::AttemptIncStrong(const void *objectId)
610 {
611     if (refs_ == nullptr) {
612         return false;
613     }
614     if (refs_->AttemptIncStrong(objectId)) {
615         refs_->SetAttemptAcquire();
616         return true;
617     }
618     return false;
619 }
620 
IsAttemptAcquireSet()621 bool RefBase::IsAttemptAcquireSet()
622 {
623     if (refs_ == nullptr) {
624         return false;
625     }
626     return refs_->IsAttemptAcquireSet();
627 }
628 
IsExtendLifeTimeSet()629 bool RefBase::IsExtendLifeTimeSet()
630 {
631     if (refs_ == nullptr) {
632         return false;
633     }
634     return refs_->IsLifeTimeExtended();
635 }
636 
OnFirstStrongRef(const void *)637 void RefBase::OnFirstStrongRef(const void*)
638 {}
639 
OnLastStrongRef(const void *)640 void RefBase::OnLastStrongRef(const void*)
641 {}
642 
OnLastWeakRef(const void *)643 void RefBase::OnLastWeakRef(const void*)
644 {}
645 
OnAttemptPromoted(const void *)646 bool RefBase::OnAttemptPromoted(const void*)
647 {
648     return true;
649 }
650 
651 }  // namespace OHOS
652