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