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 22namespace OHOS { 23 24WeakRefCounter::WeakRefCounter(RefCounter *counter, void *cookie) 25 : atomicWeak_(0), refCounter_(counter), cookie_(cookie) 26{ 27 if (refCounter_ != nullptr) { 28 refCounter_->IncRefCount(); 29 } 30} 31 32WeakRefCounter::~WeakRefCounter() 33{ 34 if (refCounter_ != nullptr) { 35 refCounter_->DecRefCount(); 36 } 37} 38 39int WeakRefCounter::GetWeakRefCount() const 40{ 41 return atomicWeak_.load(std::memory_order_relaxed); 42} 43 44void* WeakRefCounter::GetRefPtr() 45{ 46 if ((cookie_ != nullptr) && (!refCounter_->IsRefPtrValid())) { 47 cookie_ = nullptr; 48 } 49 return cookie_; 50} 51 52void WeakRefCounter::IncWeakRefCount(const void *objectId) 53{ 54 if (atomicWeak_.fetch_add(1, std::memory_order_relaxed) == 0) { 55 refCounter_->IncWeakRefCount(objectId); 56 } 57} 58 59void 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 67bool 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. 80class RefTracker { 81public: 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 88private: 89 const void* ptrID; 90 int strongRefCnt; 91 int weakRefCnt; 92 int refCnt; 93 int PID; 94 int TID; 95 RefTracker* exTrace; 96}; 97 98RefTracker::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 103void 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 110RefTracker* 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 121void 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 129void 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 137void 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 151void 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 162void 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 175RefCounter::RefCounter() 176 : atomicStrong_(INITIAL_PRIMARY_VALUE), atomicWeak_(0), atomicRefCount_(0), atomicFlags_(0), atomicAttempt_(0) 177{ 178} 179 180int RefCounter::GetRefCount() 181{ 182 return atomicRefCount_.load(std::memory_order_relaxed); 183} 184 185void RefCounter::IncRefCount() 186{ 187 atomicRefCount_.fetch_add(1, std::memory_order_relaxed); 188} 189 190void 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 199void RefCounter::SetCallback(const RefPtrCallback& callback) 200{ 201 callback_ = callback; 202} 203 204void RefCounter::RemoveCallback() 205{ 206 callback_ = nullptr; 207} 208 209bool RefCounter::IsRefPtrValid() 210{ 211 return callback_ != nullptr; 212} 213 214#ifndef EMULATOR_PLATFORM 215void RefCounter::SetCanPromote(const CanPromote &canPromote) 216{ 217 canPromote_ = canPromote; 218} 219 220void RefCounter::RemoveCanPromote() 221{ 222 canPromote_ = nullptr; 223} 224 225bool RefCounter::IsCanPromoteValid() 226{ 227 return canPromote_ != nullptr; 228} 229#endif 230 231RefCounter::~RefCounter() 232{ 233#ifdef DEBUG_REFBASE 234 if (enableTrack) { 235#ifdef PRINT_TRACK_AT_ONCE 236 UTILS_LOGI("%{public}p end tracking", this); 237#else 238 PrintTracker(); 239#endif 240 } 241#endif 242} 243 244int RefCounter::IncStrongRefCount(const void* objectId) 245{ 246 DebugRefBase(objectId); 247 int curCount = atomicStrong_.load(std::memory_order_relaxed); 248 if (curCount >= 0) { 249 curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed); 250 if (curCount == INITIAL_PRIMARY_VALUE) { 251 atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release); 252 } 253 } 254 255 return curCount; 256} 257 258int RefCounter::DecStrongRefCount(const void* objectId) 259{ 260 DebugRefBase(objectId); 261 int curCount = GetStrongRefCount(); 262 if (curCount == INITIAL_PRIMARY_VALUE) { 263 // unexpected case: there had never a strong reference. 264 UTILS_LOGD("decStrongRef when there is nerver a strong reference"); 265 } else if (curCount > 0) { 266 // we should update the current count here. 267 // it may be changed after last operation. 268 curCount = atomicStrong_.fetch_sub(1, std::memory_order_release); 269 } 270 271 return curCount; 272} 273 274int RefCounter::GetStrongRefCount() 275{ 276 return atomicStrong_.load(std::memory_order_relaxed); 277} 278 279int RefCounter::IncWeakRefCount(const void* objectId) 280{ 281 DebugRefBase(objectId); 282 return atomicWeak_.fetch_add(1, std::memory_order_relaxed); 283} 284 285int RefCounter::DecWeakRefCount(const void* objectId) 286{ 287 DebugRefBase(objectId); 288 int curCount = GetWeakRefCount(); 289 if (curCount > 0) { 290 curCount = atomicWeak_.fetch_sub(1, std::memory_order_release); 291 } 292 293 if (curCount != 1) { 294 return curCount; 295 } 296 std::atomic_thread_fence(std::memory_order_acquire); 297 if (IsLifeTimeExtended()) { 298 if (callback_) { 299 callback_(); 300 } 301 } else { 302 // only weak ptr but never had a strong ref, we should do nothing here theoretically. But it may cause a leak. 303 if (GetStrongRefCount() == INITIAL_PRIMARY_VALUE) { 304 UTILS_LOGW("dec the last weakRef before it had a strong reference, delete refbase to avoid Memory Leak"); 305 if (callback_) { 306 callback_(); 307 } 308 } else { 309 // free RefCounter 310 DecRefCount(); 311 } 312 } 313 314 return curCount; 315} 316 317int RefCounter::GetWeakRefCount() 318{ 319 return atomicWeak_.load(std::memory_order_relaxed); 320} 321 322int RefCounter::GetAttemptAcquire() 323{ 324 return atomicAttempt_.load(std::memory_order_relaxed); 325} 326 327void RefCounter::SetAttemptAcquire() 328{ 329 (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed); 330} 331 332bool RefCounter::IsAttemptAcquireSet() 333{ 334 return static_cast<bool>(atomicAttempt_.load(std::memory_order_relaxed) > 0); 335} 336 337void RefCounter::ClearAttemptAcquire() 338{ 339 atomicAttempt_.fetch_sub(1, std::memory_order_relaxed); 340} 341 342void RefCounter::ExtendObjectLifetime() 343{ 344 atomicFlags_.fetch_or(FLAG_EXTEND_LIFE_TIME, std::memory_order_relaxed); 345} 346 347bool RefCounter::IsLifeTimeExtended() 348{ 349 return static_cast<bool>(atomicFlags_.load(std::memory_order_relaxed) & FLAG_EXTEND_LIFE_TIME); 350} 351 352bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount) 353{ 354 int curCount = GetStrongRefCount(); 355 IncWeakRefCount(objectId); 356 357 // if the object already had strong references.just promoting it. 358 while ((curCount > 0) && (curCount != INITIAL_PRIMARY_VALUE)) { 359 if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) { 360 goto ATTEMPT_SUCCESS; 361 } 362 // someone else changed the counter.re-acquire the counter value. 363 curCount = atomicStrong_.load(std::memory_order_relaxed); 364 } 365 366 if ((curCount == INITIAL_PRIMARY_VALUE) && !IsLifeTimeExtended()) { 367 // this object has a "normal" life-time, 368 while (curCount > 0) { 369 if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) { 370 goto ATTEMPT_SUCCESS; 371 } 372 curCount = atomicStrong_.load(std::memory_order_relaxed); 373 } 374 } 375 376 if (IsLifeTimeExtended()) { 377#ifndef EMULATOR_PLATFORM 378 if (!IsCanPromoteValid() || !canPromote_()) { 379 return false; 380 } 381#endif 382 curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed); 383 } 384 385ATTEMPT_SUCCESS: 386 if (curCount == INITIAL_PRIMARY_VALUE) { 387 outCount = curCount; 388 atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release); 389 return true; 390 } 391 392 if (curCount < 0 || (!IsLifeTimeExtended() && curCount == 0)) { 393 // the object destroyed on strong reference count reduce to zero. 394 DecWeakRefCount(objectId); 395 return false; 396 } 397 398 return true; 399} 400 401bool RefCounter::AttemptIncStrong(const void *objectId) 402{ 403 IncWeakRefCount(objectId); 404 int curCount = GetStrongRefCount(); 405 while (curCount > 0) { 406 if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) { 407 break; 408 } 409 // curCount has been updated. 410 } 411 if (curCount <= 0) { 412 DecWeakRefCount(objectId); 413 } 414 return curCount > 0; 415} 416 417RefBase::RefBase() : refs_(new RefCounter()) 418{ 419 refs_->IncRefCount(); 420 refs_->SetCallback([this] { this->RefPtrCallback(); }); 421#ifndef EMULATOR_PLATFORM 422 refs_->SetCanPromote([this] { return this->CanPromote(); }); 423#endif 424} 425 426RefBase::RefBase(const RefBase &) 427{ 428 refs_ = new (std::nothrow) RefCounter(); 429 if (refs_ != nullptr) { 430 refs_->IncRefCount(); 431 refs_->SetCallback([this] { this->RefPtrCallback(); }); 432#ifndef EMULATOR_PLATFORM 433 refs_->SetCanPromote([this] { return this->CanPromote(); }); 434#endif 435 } 436} 437 438#ifndef EMULATOR_PLATFORM 439bool RefBase::CanPromote() 440{ 441 return true; 442} 443#endif 444 445void RefBase::RefPtrCallback() 446{ 447 delete this; 448} 449 450/* 451 * The two ends of the assignment are two independent and exclusive, 452 * and the application should not share the reference counter. 453 * RISK: If there is a reference count on the left of the equal sign, 454 * it may cause a reference count exception 455 */ 456RefBase &RefBase::operator=(const RefBase &) 457{ 458 if (refs_ != nullptr) { 459 refs_->RemoveCallback(); 460 refs_->DecRefCount(); 461 } 462 463 refs_ = new (std::nothrow) RefCounter(); 464 if (refs_ != nullptr) { 465 refs_->IncRefCount(); 466 refs_->SetCallback([this] { this->RefPtrCallback(); }); 467#ifndef EMULATOR_PLATFORM 468 refs_->SetCanPromote([this] { return this->CanPromote(); }); 469#endif 470 } 471 472 return *this; 473} 474 475RefBase::RefBase(RefBase &&other) noexcept 476{ 477 refs_ = other.refs_; 478 other.refs_ = nullptr; 479} 480 481RefBase &RefBase::operator=(RefBase &&other) noexcept 482{ 483 if (refs_ == other.refs_) { 484 return *this; 485 } 486 487 if (refs_ != nullptr) { 488 refs_->RemoveCallback(); 489 refs_->DecRefCount(); 490 } 491 492 refs_ = other.refs_; 493 other.refs_ = nullptr; 494 return *this; 495} 496 497RefBase::~RefBase() 498{ 499 if (refs_ != nullptr) { 500 refs_->RemoveCallback(); 501 if ((refs_->IsLifeTimeExtended() && refs_->GetWeakRefCount() == 0) || 502 refs_->GetStrongRefCount() == INITIAL_PRIMARY_VALUE) { 503 refs_->DecRefCount(); 504 } 505 refs_ = nullptr; 506 } 507} 508 509void RefBase::ExtendObjectLifetime() 510{ 511 refs_->ExtendObjectLifetime(); 512} 513 514void RefBase::IncStrongRef(const void *objectId) 515{ 516 if (refs_ == nullptr) { 517 return; 518 } 519 520 IncWeakRef(objectId); 521 const int curCount = refs_->IncStrongRefCount(objectId); 522 if (!refs_->IsLifeTimeExtended() && curCount == 0) { 523 UTILS_LOGF("%{public}p still incStrongRef after last strong ref", this); 524 } 525 if (curCount == INITIAL_PRIMARY_VALUE) { 526 OnFirstStrongRef(objectId); 527 } 528} 529 530void RefBase::CheckIsAttemptAcquireSet(const void *objectId) 531{ 532 if (refs_->IsAttemptAcquireSet()) { 533 refs_->ClearAttemptAcquire(); 534 const int attemptCount = refs_->GetAttemptAcquire(); 535 if (attemptCount < 0) { 536 UTILS_LOGF("Multi-threads trigger illegal decstrong from %{public}d due to AttemptIncStrong in ipc", 537 attemptCount); 538 } 539 refs_->DecStrongRefCount(objectId); 540 refs_->DecWeakRefCount(objectId); 541 } 542} 543 544void RefBase::DecStrongRef(const void *objectId) 545{ 546 if (refs_ == nullptr) { 547 return; 548 } 549 550 RefCounter * const refs = refs_; 551 const int curCount = refs->DecStrongRefCount(objectId); 552 if (curCount <= 0) { 553 UTILS_LOGF("%{public}p call decStrongRef too many times", this); 554 } 555 if (curCount == 1) { 556 std::atomic_thread_fence(std::memory_order_acquire); 557 OnLastStrongRef(objectId); 558 if (!refs->IsLifeTimeExtended()) { 559 if (refs->callback_) { 560 refs->callback_(); 561 } 562 } 563 } 564 565 refs->DecWeakRefCount(objectId); 566} 567 568int RefBase::GetSptrRefCount() 569{ 570 if (refs_ == nullptr) { 571 return 0; 572 } 573 return refs_->GetStrongRefCount(); 574} 575 576WeakRefCounter *RefBase::CreateWeakRef(void *cookie) 577{ 578 if (refs_ != nullptr) { 579 return new WeakRefCounter(refs_, cookie); 580 } 581 return nullptr; 582} 583 584void RefBase::IncWeakRef(const void *objectId) 585{ 586 if (refs_ != nullptr) { 587 refs_->IncWeakRefCount(objectId); 588 } 589} 590 591RefCounter *RefBase::GetRefCounter() const 592{ 593 return refs_; 594} 595 596void RefBase::DecWeakRef(const void *objectId) 597{ 598 if (refs_ != nullptr) { 599 refs_->DecWeakRefCount(objectId); 600 } 601} 602 603int RefBase::GetWptrRefCount() 604{ 605 if (refs_ == nullptr) { 606 return 0; 607 } 608 return refs_->GetWeakRefCount(); 609} 610 611bool RefBase::AttemptAcquire(const void *objectId) 612{ 613 if (refs_ == nullptr) { 614 return false; 615 } 616 617 int count = 0; 618 if (refs_->AttemptIncStrongRef(objectId, count)) { 619 refs_->SetAttemptAcquire(); 620 if (count == INITIAL_PRIMARY_VALUE) { 621 OnFirstStrongRef(objectId); 622 } 623 624 return true; 625 } 626 return false; 627} 628 629bool RefBase::AttemptIncStrongRef(const void *objectId) 630{ 631 if ((refs_ != nullptr) && (OnAttemptPromoted(objectId))) { 632 int count = 0; 633 bool ret = refs_->AttemptIncStrongRef(objectId, count); 634 if (count == INITIAL_PRIMARY_VALUE) { 635 OnFirstStrongRef(objectId); 636 } 637 return ret; 638 } 639 640 return false; 641} 642 643bool RefBase::AttemptIncStrong(const void *objectId) 644{ 645 if (refs_ == nullptr) { 646 return false; 647 } 648 if (refs_->AttemptIncStrong(objectId)) { 649 refs_->SetAttemptAcquire(); 650 return true; 651 } 652 return false; 653} 654 655bool RefBase::IsAttemptAcquireSet() 656{ 657 if (refs_ == nullptr) { 658 return false; 659 } 660 return refs_->IsAttemptAcquireSet(); 661} 662 663bool RefBase::IsExtendLifeTimeSet() 664{ 665 if (refs_ == nullptr) { 666 return false; 667 } 668 return refs_->IsLifeTimeExtended(); 669} 670 671void RefBase::OnFirstStrongRef(const void*) 672{} 673 674void RefBase::OnLastStrongRef(const void*) 675{} 676 677void RefBase::OnLastWeakRef(const void*) 678{} 679 680bool RefBase::OnAttemptPromoted(const void*) 681{ 682 return true; 683} 684 685#if ((defined DEBUG_REFBASE) && (!defined TRACK_ALL)) 686void RefBase::EnableTracker() 687{ 688 refs_->EnableTracker(); 689} 690#else 691void RefBase::EnableTracker() 692{ 693} 694#endif 695 696} // namespace OHOS 697