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