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