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 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 DebugRefBase(const void * objectId)162 void RefCounter::DebugRefBase([[maybe_unused]]const void* objectId) 163 { 164 #ifdef DEBUG_REFBASE 165 if (enableTrack) { 166 #ifdef PRINT_TRACK_AT_ONCE 167 PrintRefs(objectId); 168 #else 169 GetNewTrace(objectId); 170 #endif 171 } 172 #endif 173 } 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(objectId); 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(objectId); 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(objectId); 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(objectId); 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 GetAttemptAcquire()305 int RefCounter::GetAttemptAcquire() 306 { 307 return atomicAttempt_.load(std::memory_order_relaxed); 308 } 309 SetAttemptAcquire()310 void RefCounter::SetAttemptAcquire() 311 { 312 (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed); 313 } 314 IsAttemptAcquireSet()315 bool RefCounter::IsAttemptAcquireSet() 316 { 317 return static_cast<bool>(atomicAttempt_.load(std::memory_order_relaxed) > 0); 318 } 319 ClearAttemptAcquire()320 void RefCounter::ClearAttemptAcquire() 321 { 322 atomicAttempt_.fetch_sub(1, std::memory_order_relaxed); 323 } 324 ExtendObjectLifetime()325 void RefCounter::ExtendObjectLifetime() 326 { 327 atomicFlags_.fetch_or(FLAG_EXTEND_LIFE_TIME, std::memory_order_relaxed); 328 } 329 IsLifeTimeExtended()330 bool RefCounter::IsLifeTimeExtended() 331 { 332 return static_cast<bool>(atomicFlags_.load(std::memory_order_relaxed) & FLAG_EXTEND_LIFE_TIME); 333 } 334 AttemptIncStrongRef(const void * objectId,int & outCount)335 bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount) 336 { 337 int curCount = GetStrongRefCount(); 338 IncWeakRefCount(objectId); 339 340 // if the object already had strong references.just promoting it. 341 while ((curCount > 0) && (curCount != INITIAL_PRIMARY_VALUE)) { 342 if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) { 343 goto ATTEMPT_SUCCESS; 344 } 345 // someone else changed the counter.re-acquire the counter value. 346 curCount = atomicStrong_.load(std::memory_order_relaxed); 347 } 348 349 if ((curCount == INITIAL_PRIMARY_VALUE) && !IsLifeTimeExtended()) { 350 // this object has a "normal" life-time, 351 while (curCount > 0) { 352 if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) { 353 goto ATTEMPT_SUCCESS; 354 } 355 curCount = atomicStrong_.load(std::memory_order_relaxed); 356 } 357 } 358 359 if (IsLifeTimeExtended()) { 360 curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed); 361 } 362 363 ATTEMPT_SUCCESS: 364 if (curCount == INITIAL_PRIMARY_VALUE) { 365 outCount = curCount; 366 atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release); 367 return true; 368 } 369 370 if (curCount < 0 || (!IsLifeTimeExtended() && curCount == 0)) { 371 // the object destroyed on strong reference count reduce to zero. 372 DecWeakRefCount(objectId); 373 return false; 374 } 375 376 return true; 377 } 378 AttemptIncStrong(const void * objectId)379 bool RefCounter::AttemptIncStrong(const void *objectId) 380 { 381 IncWeakRefCount(objectId); 382 int curCount = GetStrongRefCount(); 383 while (curCount > 0) { 384 if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) { 385 break; 386 } 387 // curCount has been updated. 388 } 389 if (curCount <= 0) { 390 DecWeakRefCount(objectId); 391 } 392 return curCount > 0; 393 } 394 RefBase()395 RefBase::RefBase() : refs_(new RefCounter()) 396 { 397 refs_->IncRefCount(); 398 refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this)); 399 } 400 RefBase(const RefBase &)401 RefBase::RefBase(const RefBase &) 402 { 403 refs_ = new (std::nothrow) RefCounter(); 404 if (refs_ != nullptr) { 405 refs_->IncRefCount(); 406 refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this)); 407 } 408 } 409 RefPtrCallback()410 void RefBase::RefPtrCallback() 411 { 412 delete this; 413 } 414 415 /* 416 * The two ends of the assignment are two independent and exclusive, 417 * and the application should not share the reference counter. 418 * RISK: If there is a reference count on the left of the equal sign, 419 * it may cause a reference count exception 420 */ operator =(const RefBase &)421 RefBase &RefBase::operator=(const RefBase &) 422 { 423 if (refs_ != nullptr) { 424 refs_->RemoveCallback(); 425 refs_->DecRefCount(); 426 } 427 428 refs_ = new (std::nothrow) RefCounter(); 429 if (refs_ != nullptr) { 430 refs_->IncRefCount(); 431 refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this)); 432 } 433 434 return *this; 435 } 436 RefBase(RefBase && other)437 RefBase::RefBase(RefBase &&other) noexcept 438 { 439 refs_ = other.refs_; 440 other.refs_ = nullptr; 441 } 442 operator =(RefBase && other)443 RefBase &RefBase::operator=(RefBase &&other) noexcept 444 { 445 if (refs_ == other.refs_) { 446 return *this; 447 } 448 449 if (refs_ != nullptr) { 450 refs_->RemoveCallback(); 451 refs_->DecRefCount(); 452 } 453 454 refs_ = other.refs_; 455 other.refs_ = nullptr; 456 return *this; 457 } 458 ~RefBase()459 RefBase::~RefBase() 460 { 461 if (refs_ != nullptr) { 462 refs_->RemoveCallback(); 463 if ((refs_->IsLifeTimeExtended() && refs_->GetWeakRefCount() == 0) || 464 refs_->GetStrongRefCount() == INITIAL_PRIMARY_VALUE) { 465 refs_->DecRefCount(); 466 } 467 refs_ = nullptr; 468 } 469 } 470 ExtendObjectLifetime()471 void RefBase::ExtendObjectLifetime() 472 { 473 refs_->ExtendObjectLifetime(); 474 } 475 IncStrongRef(const void * objectId)476 void RefBase::IncStrongRef(const void *objectId) 477 { 478 if (refs_ == nullptr) { 479 return; 480 } 481 482 IncWeakRef(objectId); 483 const int curCount = refs_->IncStrongRefCount(objectId); 484 if (!refs_->IsLifeTimeExtended() && curCount == 0) { 485 UTILS_LOGF("%{public}p still incStrongRef after last strong ref", this); 486 } 487 if (curCount == INITIAL_PRIMARY_VALUE) { 488 OnFirstStrongRef(objectId); 489 } 490 } 491 CheckIsAttemptAcquireSet(const void * objectId)492 void RefBase::CheckIsAttemptAcquireSet(const void *objectId) 493 { 494 if (refs_->IsAttemptAcquireSet()) { 495 refs_->ClearAttemptAcquire(); 496 const int attemptCount = refs_->GetAttemptAcquire(); 497 if (attemptCount < 0) { 498 UTILS_LOGF("Multi-threads trigger illegal decstrong from %{public}d due to AttemptIncStrong in ipc", 499 attemptCount); 500 } 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 <= 0) { 515 UTILS_LOGF("%{public}p call decStrongRef too many times", this); 516 } 517 if (curCount == 1) { 518 std::atomic_thread_fence(std::memory_order_acquire); 519 OnLastStrongRef(objectId); 520 if (!refs->IsLifeTimeExtended()) { 521 if (refs->callback_) { 522 refs->callback_(); 523 } 524 } 525 } 526 527 refs->DecWeakRefCount(objectId); 528 } 529 GetSptrRefCount()530 int RefBase::GetSptrRefCount() 531 { 532 if (refs_ == nullptr) { 533 return 0; 534 } 535 return refs_->GetStrongRefCount(); 536 } 537 CreateWeakRef(void * cookie)538 WeakRefCounter *RefBase::CreateWeakRef(void *cookie) 539 { 540 if (refs_ != nullptr) { 541 return new WeakRefCounter(refs_, cookie); 542 } 543 return nullptr; 544 } 545 IncWeakRef(const void * objectId)546 void RefBase::IncWeakRef(const void *objectId) 547 { 548 if (refs_ != nullptr) { 549 refs_->IncWeakRefCount(objectId); 550 } 551 } 552 GetRefCounter() const553 RefCounter *RefBase::GetRefCounter() const 554 { 555 return refs_; 556 } 557 DecWeakRef(const void * objectId)558 void RefBase::DecWeakRef(const void *objectId) 559 { 560 if (refs_ != nullptr) { 561 refs_->DecWeakRefCount(objectId); 562 } 563 } 564 GetWptrRefCount()565 int RefBase::GetWptrRefCount() 566 { 567 if (refs_ == nullptr) { 568 return 0; 569 } 570 return refs_->GetWeakRefCount(); 571 } 572 AttemptAcquire(const void * objectId)573 bool RefBase::AttemptAcquire(const void *objectId) 574 { 575 if (refs_ == nullptr) { 576 return false; 577 } 578 579 int count = 0; 580 if (refs_->AttemptIncStrongRef(objectId, count)) { 581 refs_->SetAttemptAcquire(); 582 if (count == INITIAL_PRIMARY_VALUE) { 583 OnFirstStrongRef(objectId); 584 } 585 586 return true; 587 } 588 return false; 589 } 590 AttemptIncStrongRef(const void * objectId)591 bool RefBase::AttemptIncStrongRef(const void *objectId) 592 { 593 if ((refs_ != nullptr) && (OnAttemptPromoted(objectId))) { 594 int count = 0; 595 bool ret = refs_->AttemptIncStrongRef(objectId, count); 596 if (count == INITIAL_PRIMARY_VALUE) { 597 OnFirstStrongRef(objectId); 598 } 599 return ret; 600 } 601 602 return false; 603 } 604 AttemptIncStrong(const void * objectId)605 bool RefBase::AttemptIncStrong(const void *objectId) 606 { 607 if (refs_ == nullptr) { 608 return false; 609 } 610 if (refs_->AttemptIncStrong(objectId)) { 611 refs_->SetAttemptAcquire(); 612 return true; 613 } 614 return false; 615 } 616 IsAttemptAcquireSet()617 bool RefBase::IsAttemptAcquireSet() 618 { 619 if (refs_ == nullptr) { 620 return false; 621 } 622 return refs_->IsAttemptAcquireSet(); 623 } 624 IsExtendLifeTimeSet()625 bool RefBase::IsExtendLifeTimeSet() 626 { 627 if (refs_ == nullptr) { 628 return false; 629 } 630 return refs_->IsLifeTimeExtended(); 631 } 632 OnFirstStrongRef(const void *)633 void RefBase::OnFirstStrongRef(const void*) 634 {} 635 OnLastStrongRef(const void *)636 void RefBase::OnLastStrongRef(const void*) 637 {} 638 OnLastWeakRef(const void *)639 void RefBase::OnLastWeakRef(const void*) 640 {} 641 OnAttemptPromoted(const void *)642 bool RefBase::OnAttemptPromoted(const void*) 643 { 644 return true; 645 } 646 647 #if ((defined DEBUG_REFBASE) && (!defined TRACK_ALL)) EnableTracker()648 void RefBase::EnableTracker() 649 { 650 refs_->EnableTracker(); 651 } 652 #else EnableTracker()653 void RefBase::EnableTracker() 654 { 655 } 656 #endif 657 658 } // namespace OHOS 659