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