• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
~RefCounter()201 RefCounter::~RefCounter()
202 {
203 #ifdef DEBUG_REFBASE
204     PrintTracker();
205 #endif
206 }
207 
IncStrongRefCount(const void * objectId)208 int RefCounter::IncStrongRefCount(const void* objectId)
209 {
210 #ifdef DEBUG_REFBASE
211     GetNewTrace(objectId);
212 #endif
213     int curCount = atomicStrong_.load(std::memory_order_relaxed);
214     if (curCount >= 0) {
215         curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
216         if (curCount == INITIAL_PRIMARY_VALUE) {
217             atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
218         }
219     }
220 
221     return curCount;
222 }
223 
DecStrongRefCount(const void * objectId)224 int RefCounter::DecStrongRefCount(const void* objectId)
225 {
226 #ifdef DEBUG_REFBASE
227     GetNewTrace(objectId);
228 #endif
229     int curCount = GetStrongRefCount();
230     if (curCount == INITIAL_PRIMARY_VALUE) {
231         // unexpected case: there had never a strong reference.
232     } else if (curCount > 0) {
233         // we should update the current count here.
234         // it may be changed after last operation.
235         curCount = atomicStrong_.fetch_sub(1, std::memory_order_release);
236     }
237 
238     return curCount;
239 }
240 
GetStrongRefCount()241 int RefCounter::GetStrongRefCount()
242 {
243     return atomicStrong_.load(std::memory_order_relaxed);
244 }
245 
IncWeakRefCount(const void * objectId)246 int RefCounter::IncWeakRefCount(const void* objectId)
247 {
248 #ifdef DEBUG_REFBASE
249     GetNewTrace(objectId);
250 #endif
251     return atomicWeak_.fetch_add(1, std::memory_order_relaxed);
252 }
253 
DecWeakRefCount(const void * objectId)254 int RefCounter::DecWeakRefCount(const void* objectId)
255 {
256 #ifdef DEBUG_REFBASE
257     GetNewTrace(objectId);
258 #endif
259     int curCount = GetWeakRefCount();
260     if (curCount > 0) {
261         curCount = atomicWeak_.fetch_sub(1, std::memory_order_release);
262     }
263 
264     if (curCount != 1) {
265         return curCount;
266     }
267 
268     if (IsLifeTimeExtended() && GetStrongRefCount() == 0) {
269         if (callback_) {
270             callback_();
271         }
272     } else {
273         // only weak ptr case: no strong reference, delete the object
274         if (GetStrongRefCount() == INITIAL_PRIMARY_VALUE) {
275             if (callback_) {
276                 callback_();
277             }
278         } else {
279             // free RefCounter
280             DecRefCount();
281         }
282     }
283 
284     return curCount;
285 }
286 
GetWeakRefCount()287 int RefCounter::GetWeakRefCount()
288 {
289     return atomicWeak_.load(std::memory_order_relaxed);
290 }
291 
SetAttemptAcquire()292 void RefCounter::SetAttemptAcquire()
293 {
294     (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed);
295 }
296 
IsAttemptAcquireSet()297 bool RefCounter::IsAttemptAcquireSet()
298 {
299     return static_cast<bool>(atomicAttempt_.load(std::memory_order_relaxed) > 0);
300 }
301 
ClearAttemptAcquire()302 void RefCounter::ClearAttemptAcquire()
303 {
304     atomicAttempt_.fetch_sub(1, std::memory_order_relaxed);
305 }
306 
ExtendObjectLifetime()307 void RefCounter::ExtendObjectLifetime()
308 {
309     atomicFlags_.fetch_or(FLAG_EXTEND_LIFE_TIME, std::memory_order_relaxed);
310 }
311 
IsLifeTimeExtended()312 bool RefCounter::IsLifeTimeExtended()
313 {
314     return static_cast<bool>(atomicFlags_.load(std::memory_order_relaxed) & FLAG_EXTEND_LIFE_TIME);
315 }
316 
AttemptIncStrongRef(const void * objectId,int & outCount)317 bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount)
318 {
319     int curCount = GetStrongRefCount();
320     IncWeakRefCount(objectId);
321 
322     // if the object already had strong references.just promoting it.
323     while ((curCount > 0) && (curCount != INITIAL_PRIMARY_VALUE)) {
324         if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
325             goto ATTEMPT_SUCCESS;
326         }
327         // someone else changed the counter.re-acquire the counter value.
328         curCount = atomicStrong_.load(std::memory_order_relaxed);
329     }
330 
331     if ((curCount == INITIAL_PRIMARY_VALUE) && !IsLifeTimeExtended()) {
332         // this object has a "normal" life-time,
333         while (curCount > 0) {
334             if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
335                 goto ATTEMPT_SUCCESS;
336             }
337             curCount = atomicStrong_.load(std::memory_order_relaxed);
338         }
339     }
340 
341     if (IsLifeTimeExtended()) {
342         curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
343     }
344 
345 ATTEMPT_SUCCESS:
346     if (curCount >= INITIAL_PRIMARY_VALUE) {
347         outCount = curCount;
348         atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
349         return true;
350     }
351 
352     if (curCount < 0 || (!IsLifeTimeExtended() && curCount == 0)) {
353         // the object destroyed on strong reference count reduce to zero.
354         DecWeakRefCount(objectId);
355         return false;
356     }
357 
358     return true;
359 }
360 
AttemptIncStrong(const void * objectId)361 bool RefCounter::AttemptIncStrong(const void *objectId)
362 {
363     IncWeakRefCount(objectId);
364     int curCount = GetStrongRefCount();
365     while (curCount > 0) {
366         if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
367             break;
368         }
369         // curCount has been updated.
370     }
371     if (curCount <= 0) {
372         DecWeakRefCount(objectId);
373     }
374     return curCount > 0;
375 }
376 
RefBase()377 RefBase::RefBase() : refs_(new RefCounter())
378 {
379     refs_->IncRefCount();
380     refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
381 }
382 
RefBase(const RefBase &)383 RefBase::RefBase(const RefBase &)
384 {
385     refs_ = new (std::nothrow) RefCounter();
386     if (refs_ != nullptr) {
387         refs_->IncRefCount();
388         refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
389     }
390 }
391 
RefPtrCallback()392 void RefBase::RefPtrCallback()
393 {
394     delete this;
395 }
396 
397 /*
398  * The two ends of the assignment are two independent and exclusive,
399  * and the application should not share the reference counter.
400  * RISK: If there is a reference count on the left of the equal sign,
401  * it may cause a reference count exception
402  */
operator =(const RefBase &)403 RefBase &RefBase::operator=(const RefBase &)
404 {
405     if (refs_ != nullptr) {
406         refs_->RemoveCallback();
407         refs_->DecRefCount();
408     }
409 
410     refs_ = new (std::nothrow) RefCounter();
411     if (refs_ != nullptr) {
412         refs_->IncRefCount();
413         refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
414     }
415 
416     return *this;
417 }
418 
RefBase(RefBase && other)419 RefBase::RefBase(RefBase &&other) noexcept
420 {
421     refs_ = other.refs_;
422     other.refs_ = nullptr;
423 }
424 
operator =(RefBase && other)425 RefBase &RefBase::operator=(RefBase &&other) noexcept
426 {
427     if (refs_ == other.refs_) {
428         return *this;
429     }
430 
431     if (refs_ != nullptr) {
432         refs_->RemoveCallback();
433         refs_->DecRefCount();
434     }
435 
436     refs_ = other.refs_;
437     other.refs_ = nullptr;
438     return *this;
439 }
440 
~RefBase()441 RefBase::~RefBase()
442 {
443     if (refs_ != nullptr) {
444         refs_->RemoveCallback();
445         if ((refs_->IsLifeTimeExtended() && refs_->GetWeakRefCount() == 0) ||
446              refs_->GetStrongRefCount() == INITIAL_PRIMARY_VALUE) {
447             refs_->DecRefCount();
448         }
449         refs_ = nullptr;
450     }
451 }
452 
ExtendObjectLifetime()453 void RefBase::ExtendObjectLifetime()
454 {
455     refs_->ExtendObjectLifetime();
456 }
457 
IncStrongRef(const void * objectId)458 void RefBase::IncStrongRef(const void *objectId)
459 {
460     if (refs_ == nullptr) {
461         return;
462     }
463 
464     IncWeakRef(objectId);
465     const int curCount = refs_->IncStrongRefCount(objectId);
466     if (curCount == INITIAL_PRIMARY_VALUE) {
467         OnFirstStrongRef(objectId);
468     }
469     if (refs_->IsAttemptAcquireSet()) {
470         refs_->ClearAttemptAcquire();
471         refs_->DecStrongRefCount(objectId);
472         refs_->DecWeakRefCount(objectId);
473     }
474 }
475 
DecStrongRef(const void * objectId)476 void RefBase::DecStrongRef(const void *objectId)
477 {
478     if (refs_ == nullptr) {
479         return;
480     }
481 
482     RefCounter * const refs = refs_;
483     const int curCount = refs->DecStrongRefCount(objectId);
484     if (curCount == 1) {
485         OnLastStrongRef(objectId);
486         if (!refs->IsLifeTimeExtended()) {
487             if (refs->callback_) {
488                 refs->callback_();
489             }
490         }
491     }
492 
493     refs->DecWeakRefCount(objectId);
494 }
495 
GetSptrRefCount()496 int RefBase::GetSptrRefCount()
497 {
498     if (refs_ == nullptr) {
499         return 0;
500     }
501     return refs_->GetStrongRefCount();
502 }
503 
CreateWeakRef(void * cookie)504 WeakRefCounter *RefBase::CreateWeakRef(void *cookie)
505 {
506     if (refs_ != nullptr) {
507         return new WeakRefCounter(refs_, cookie);
508     }
509     return nullptr;
510 }
511 
IncWeakRef(const void * objectId)512 void RefBase::IncWeakRef(const void *objectId)
513 {
514     if (refs_ != nullptr) {
515         refs_->IncWeakRefCount(objectId);
516     }
517 }
518 
GetRefCounter() const519 RefCounter *RefBase::GetRefCounter() const
520 {
521     return refs_;
522 }
523 
DecWeakRef(const void * objectId)524 void RefBase::DecWeakRef(const void *objectId)
525 {
526     if (refs_ != nullptr) {
527         refs_->DecWeakRefCount(objectId);
528     }
529 }
530 
GetWptrRefCount()531 int RefBase::GetWptrRefCount()
532 {
533     if (refs_ == nullptr) {
534         return 0;
535     }
536     return refs_->GetWeakRefCount();
537 }
538 
AttemptAcquire(const void * objectId)539 bool RefBase::AttemptAcquire(const void *objectId)
540 {
541     if (refs_ == nullptr) {
542         return false;
543     }
544 
545     int count = 0;
546     if (refs_->AttemptIncStrongRef(objectId, count)) {
547         refs_->SetAttemptAcquire();
548         if (count == INITIAL_PRIMARY_VALUE) {
549             OnFirstStrongRef(objectId);
550         }
551 
552         return true;
553     }
554     return false;
555 }
556 
AttemptIncStrongRef(const void * objectId)557 bool RefBase::AttemptIncStrongRef(const void *objectId)
558 {
559     if ((refs_ != nullptr) && (OnAttemptPromoted(objectId))) {
560         int count = 0;
561         bool ret = refs_->AttemptIncStrongRef(objectId, count);
562         if (count == INITIAL_PRIMARY_VALUE) {
563             OnFirstStrongRef(objectId);
564         }
565         return ret;
566     }
567 
568     return false;
569 }
570 
AttemptIncStrong(const void * objectId)571 bool RefBase::AttemptIncStrong(const void *objectId)
572 {
573     if (refs_ == nullptr) {
574         return false;
575     }
576     if (refs_->AttemptIncStrong(objectId)) {
577         refs_->SetAttemptAcquire();
578         return true;
579     }
580     return false;
581 }
582 
IsAttemptAcquireSet()583 bool RefBase::IsAttemptAcquireSet()
584 {
585     if (refs_ == nullptr) {
586         return false;
587     }
588     return refs_->IsAttemptAcquireSet();
589 }
590 
IsExtendLifeTimeSet()591 bool RefBase::IsExtendLifeTimeSet()
592 {
593     if (refs_ == nullptr) {
594         return false;
595     }
596     return refs_->IsLifeTimeExtended();
597 }
598 
OnFirstStrongRef(const void *)599 void RefBase::OnFirstStrongRef(const void*)
600 {}
601 
OnLastStrongRef(const void *)602 void RefBase::OnLastStrongRef(const void*)
603 {}
604 
OnLastWeakRef(const void *)605 void RefBase::OnLastWeakRef(const void*)
606 {}
607 
OnAttemptPromoted(const void *)608 bool RefBase::OnAttemptPromoted(const void*)
609 {
610     return true;
611 }
612 
613 }  // namespace OHOS
614