• 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  
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  
DebugRefBase(const void * objectId)162  void RefCounter::DebugRefBase([[maybe_unused]]const void* objectId)
163  {
164  #ifdef DEBUG_REFBASE
165      if (enableTrack) {
166  #ifdef PRINT_TRACK_AT_ONCE
167          PrintRefs(objectId);
168  #else
169          GetNewTrace(objectId);
170  #endif
171      }
172  #endif
173  }
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(objectId);
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(objectId);
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(objectId);
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(objectId);
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  
GetAttemptAcquire()305  int RefCounter::GetAttemptAcquire()
306  {
307      return atomicAttempt_.load(std::memory_order_relaxed);
308  }
309  
SetAttemptAcquire()310  void RefCounter::SetAttemptAcquire()
311  {
312      (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed);
313  }
314  
IsAttemptAcquireSet()315  bool RefCounter::IsAttemptAcquireSet()
316  {
317      return static_cast<bool>(atomicAttempt_.load(std::memory_order_relaxed) > 0);
318  }
319  
ClearAttemptAcquire()320  void RefCounter::ClearAttemptAcquire()
321  {
322      atomicAttempt_.fetch_sub(1, std::memory_order_relaxed);
323  }
324  
ExtendObjectLifetime()325  void RefCounter::ExtendObjectLifetime()
326  {
327      atomicFlags_.fetch_or(FLAG_EXTEND_LIFE_TIME, std::memory_order_relaxed);
328  }
329  
IsLifeTimeExtended()330  bool RefCounter::IsLifeTimeExtended()
331  {
332      return static_cast<bool>(atomicFlags_.load(std::memory_order_relaxed) & FLAG_EXTEND_LIFE_TIME);
333  }
334  
AttemptIncStrongRef(const void * objectId,int & outCount)335  bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount)
336  {
337      int curCount = GetStrongRefCount();
338      IncWeakRefCount(objectId);
339  
340      // if the object already had strong references.just promoting it.
341      while ((curCount > 0) && (curCount != INITIAL_PRIMARY_VALUE)) {
342          if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
343              goto ATTEMPT_SUCCESS;
344          }
345          // someone else changed the counter.re-acquire the counter value.
346          curCount = atomicStrong_.load(std::memory_order_relaxed);
347      }
348  
349      if ((curCount == INITIAL_PRIMARY_VALUE) && !IsLifeTimeExtended()) {
350          // this object has a "normal" life-time,
351          while (curCount > 0) {
352              if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
353                  goto ATTEMPT_SUCCESS;
354              }
355              curCount = atomicStrong_.load(std::memory_order_relaxed);
356          }
357      }
358  
359      if (IsLifeTimeExtended()) {
360          curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
361      }
362  
363  ATTEMPT_SUCCESS:
364      if (curCount == INITIAL_PRIMARY_VALUE) {
365          outCount = curCount;
366          atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
367          return true;
368      }
369  
370      if (curCount < 0 || (!IsLifeTimeExtended() && curCount == 0)) {
371          // the object destroyed on strong reference count reduce to zero.
372          DecWeakRefCount(objectId);
373          return false;
374      }
375  
376      return true;
377  }
378  
AttemptIncStrong(const void * objectId)379  bool RefCounter::AttemptIncStrong(const void *objectId)
380  {
381      IncWeakRefCount(objectId);
382      int curCount = GetStrongRefCount();
383      while (curCount > 0) {
384          if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
385              break;
386          }
387          // curCount has been updated.
388      }
389      if (curCount <= 0) {
390          DecWeakRefCount(objectId);
391      }
392      return curCount > 0;
393  }
394  
RefBase()395  RefBase::RefBase() : refs_(new RefCounter())
396  {
397      refs_->IncRefCount();
398      refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
399  }
400  
RefBase(const RefBase &)401  RefBase::RefBase(const RefBase &)
402  {
403      refs_ = new (std::nothrow) RefCounter();
404      if (refs_ != nullptr) {
405          refs_->IncRefCount();
406          refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
407      }
408  }
409  
RefPtrCallback()410  void RefBase::RefPtrCallback()
411  {
412      delete this;
413  }
414  
415  /*
416   * The two ends of the assignment are two independent and exclusive,
417   * and the application should not share the reference counter.
418   * RISK: If there is a reference count on the left of the equal sign,
419   * it may cause a reference count exception
420   */
operator =(const RefBase &)421  RefBase &RefBase::operator=(const RefBase &)
422  {
423      if (refs_ != nullptr) {
424          refs_->RemoveCallback();
425          refs_->DecRefCount();
426      }
427  
428      refs_ = new (std::nothrow) RefCounter();
429      if (refs_ != nullptr) {
430          refs_->IncRefCount();
431          refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
432      }
433  
434      return *this;
435  }
436  
RefBase(RefBase && other)437  RefBase::RefBase(RefBase &&other) noexcept
438  {
439      refs_ = other.refs_;
440      other.refs_ = nullptr;
441  }
442  
operator =(RefBase && other)443  RefBase &RefBase::operator=(RefBase &&other) noexcept
444  {
445      if (refs_ == other.refs_) {
446          return *this;
447      }
448  
449      if (refs_ != nullptr) {
450          refs_->RemoveCallback();
451          refs_->DecRefCount();
452      }
453  
454      refs_ = other.refs_;
455      other.refs_ = nullptr;
456      return *this;
457  }
458  
~RefBase()459  RefBase::~RefBase()
460  {
461      if (refs_ != nullptr) {
462          refs_->RemoveCallback();
463          if ((refs_->IsLifeTimeExtended() && refs_->GetWeakRefCount() == 0) ||
464               refs_->GetStrongRefCount() == INITIAL_PRIMARY_VALUE) {
465              refs_->DecRefCount();
466          }
467          refs_ = nullptr;
468      }
469  }
470  
ExtendObjectLifetime()471  void RefBase::ExtendObjectLifetime()
472  {
473      refs_->ExtendObjectLifetime();
474  }
475  
IncStrongRef(const void * objectId)476  void RefBase::IncStrongRef(const void *objectId)
477  {
478      if (refs_ == nullptr) {
479          return;
480      }
481  
482      IncWeakRef(objectId);
483      const int curCount = refs_->IncStrongRefCount(objectId);
484      if (!refs_->IsLifeTimeExtended() && curCount == 0) {
485          UTILS_LOGF("%{public}p still incStrongRef after last strong ref", this);
486      }
487      if (curCount == INITIAL_PRIMARY_VALUE) {
488          OnFirstStrongRef(objectId);
489      }
490  }
491  
CheckIsAttemptAcquireSet(const void * objectId)492  void RefBase::CheckIsAttemptAcquireSet(const void *objectId)
493  {
494      if (refs_->IsAttemptAcquireSet()) {
495          refs_->ClearAttemptAcquire();
496          const int attemptCount = refs_->GetAttemptAcquire();
497          if (attemptCount < 0) {
498              UTILS_LOGF("Multi-threads trigger illegal decstrong from %{public}d due to AttemptIncStrong in ipc",
499                  attemptCount);
500          }
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 <= 0) {
515          UTILS_LOGF("%{public}p call decStrongRef too many times", this);
516      }
517      if (curCount == 1) {
518          std::atomic_thread_fence(std::memory_order_acquire);
519          OnLastStrongRef(objectId);
520          if (!refs->IsLifeTimeExtended()) {
521              if (refs->callback_) {
522                  refs->callback_();
523              }
524          }
525      }
526  
527      refs->DecWeakRefCount(objectId);
528  }
529  
GetSptrRefCount()530  int RefBase::GetSptrRefCount()
531  {
532      if (refs_ == nullptr) {
533          return 0;
534      }
535      return refs_->GetStrongRefCount();
536  }
537  
CreateWeakRef(void * cookie)538  WeakRefCounter *RefBase::CreateWeakRef(void *cookie)
539  {
540      if (refs_ != nullptr) {
541          return new WeakRefCounter(refs_, cookie);
542      }
543      return nullptr;
544  }
545  
IncWeakRef(const void * objectId)546  void RefBase::IncWeakRef(const void *objectId)
547  {
548      if (refs_ != nullptr) {
549          refs_->IncWeakRefCount(objectId);
550      }
551  }
552  
GetRefCounter() const553  RefCounter *RefBase::GetRefCounter() const
554  {
555      return refs_;
556  }
557  
DecWeakRef(const void * objectId)558  void RefBase::DecWeakRef(const void *objectId)
559  {
560      if (refs_ != nullptr) {
561          refs_->DecWeakRefCount(objectId);
562      }
563  }
564  
GetWptrRefCount()565  int RefBase::GetWptrRefCount()
566  {
567      if (refs_ == nullptr) {
568          return 0;
569      }
570      return refs_->GetWeakRefCount();
571  }
572  
AttemptAcquire(const void * objectId)573  bool RefBase::AttemptAcquire(const void *objectId)
574  {
575      if (refs_ == nullptr) {
576          return false;
577      }
578  
579      int count = 0;
580      if (refs_->AttemptIncStrongRef(objectId, count)) {
581          refs_->SetAttemptAcquire();
582          if (count == INITIAL_PRIMARY_VALUE) {
583              OnFirstStrongRef(objectId);
584          }
585  
586          return true;
587      }
588      return false;
589  }
590  
AttemptIncStrongRef(const void * objectId)591  bool RefBase::AttemptIncStrongRef(const void *objectId)
592  {
593      if ((refs_ != nullptr) && (OnAttemptPromoted(objectId))) {
594          int count = 0;
595          bool ret = refs_->AttemptIncStrongRef(objectId, count);
596          if (count == INITIAL_PRIMARY_VALUE) {
597              OnFirstStrongRef(objectId);
598          }
599          return ret;
600      }
601  
602      return false;
603  }
604  
AttemptIncStrong(const void * objectId)605  bool RefBase::AttemptIncStrong(const void *objectId)
606  {
607      if (refs_ == nullptr) {
608          return false;
609      }
610      if (refs_->AttemptIncStrong(objectId)) {
611          refs_->SetAttemptAcquire();
612          return true;
613      }
614      return false;
615  }
616  
IsAttemptAcquireSet()617  bool RefBase::IsAttemptAcquireSet()
618  {
619      if (refs_ == nullptr) {
620          return false;
621      }
622      return refs_->IsAttemptAcquireSet();
623  }
624  
IsExtendLifeTimeSet()625  bool RefBase::IsExtendLifeTimeSet()
626  {
627      if (refs_ == nullptr) {
628          return false;
629      }
630      return refs_->IsLifeTimeExtended();
631  }
632  
OnFirstStrongRef(const void *)633  void RefBase::OnFirstStrongRef(const void*)
634  {}
635  
OnLastStrongRef(const void *)636  void RefBase::OnLastStrongRef(const void*)
637  {}
638  
OnLastWeakRef(const void *)639  void RefBase::OnLastWeakRef(const void*)
640  {}
641  
OnAttemptPromoted(const void *)642  bool RefBase::OnAttemptPromoted(const void*)
643  {
644      return true;
645  }
646  
647  #if ((defined DEBUG_REFBASE) && (!defined TRACK_ALL))
EnableTracker()648  void RefBase::EnableTracker()
649  {
650      refs_->EnableTracker();
651  }
652  #else
EnableTracker()653  void RefBase::EnableTracker()
654  {
655  }
656  #endif
657  
658  }  // namespace OHOS
659