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