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