diff --git a/base/include/refbase.h b/base/include/refbase.h index 089fc4b5c98ce889e0cb35c7dcafcee2bc1b2bcb..68fb082d3a62f76feb3e3bd3bc0b1ae1687291b7 100644 --- a/base/include/refbase.h +++ b/base/include/refbase.h @@ -257,9 +257,19 @@ public: void EnableTracker(); #endif +#if ((defined DEBUG_REFBASE) && (defined PRINT_TRACK_AT_ONCE)) + /** + * @brief Enables tracking with domainId. It is applicable to debugging only. + */ + void EnableTrackerWithDomainId(unsigned int domainId); +#endif + private: void DebugRefBase(const void *objectId); + void RefBaseDebugPrint(int curCount, const void* caller, const void* objectId, + const char* operation, const char* countType); + std::atomic atomicStrong_; // = (num of sptr) or Initial-value std::atomic atomicWeak_; // = (num of sptr)+(num of WeakRefCounter) std::atomic atomicRefCount_; // = (num of WeakRefCounter) + 1 @@ -278,7 +288,7 @@ private: #endif std::mutex trackerMutex; // To ensure refTracker be thread-safe #ifdef PRINT_TRACK_AT_ONCE - void PrintRefs(const void* objectId); + unsigned int domainId_ = 0xD003D00; #else RefTracker* refTracker = nullptr; void GetNewTrace(const void* objectId); @@ -595,6 +605,12 @@ public: */ void EnableTracker(); + /** + * @brief Enables tracking of the RefBase object with domainId. This function will + * be implemented only if DEBUG_REFBASE, but not TRACK_ALL, is defined. + */ + void EnableTrackerWithDomainId(unsigned int domainId); + #ifdef OHOS_PLATFORM virtual bool CanPromote(); #endif diff --git a/base/src/refbase.cpp b/base/src/refbase.cpp index a39676c1989d7da4622cc56e95164713643584ab..f39a306cd3e77a4873399249158182a34cb068b9 100644 --- a/base/src/refbase.cpp +++ b/base/src/refbase.cpp @@ -21,6 +21,21 @@ namespace OHOS { +void RefCounter::RefBaseDebugPrint([[maybe_unused]] int curCount, + [[maybe_unused]] const void* caller, + [[maybe_unused]] const void* objectId, + [[maybe_unused]] const char* operation, + [[maybe_unused]] const char* countType) +{ +#if ((defined DEBUG_REFBASE) && (defined PRINT_TRACK_AT_ONCE)) + if (this->enableTrack) { + UTILS_LOGT(this->domainId_, "curCount: %{public}d, caller: %{public}p, " + "objectId: %{public}p, operation: %{public}s, countType: %{public}s, this: %{public}p", \ + curCount, caller, objectId, operation, countType, (void*)this); + } +#endif +} + WeakRefCounter::WeakRefCounter(RefCounter *counter, void *cookie) : atomicWeak_(0), refCounter_(counter), cookie_(cookie) { @@ -118,12 +133,11 @@ RefTracker* RefTracker::PopTrace(const void* refCounterPtr) #ifdef DEBUG_REFBASE #ifdef PRINT_TRACK_AT_ONCE -void RefCounter::PrintRefs(const void* objectId) +void RefCounter::EnableTrackerWithDomainId(unsigned int domainId) { std::lock_guard lock(trackerMutex); - UTILS_LOGI("%{public}p call %{public}p. strong: %{public}d weak: %{public}d " \ - "refcnt: %{public}d", objectId, this, atomicStrong_.load(std::memory_order_relaxed), - atomicWeak_.load(std::memory_order_relaxed), atomicRefCount_.load(std::memory_order_relaxed)); + this->domainId_ = domainId; + enableTrack = true; } #else void RefCounter::GetNewTrace(const void* objectId) @@ -151,21 +165,19 @@ void RefCounter::PrintTracker() void RefCounter::EnableTracker() { std::lock_guard lock(trackerMutex); -#ifdef PRINT_TRACK_AT_ONCE - UTILS_LOGI("%{public}p start tracking", this); -#endif +#ifndef PRINT_TRACK_AT_ONCE enableTrack = true; +#endif } #endif + #endif void RefCounter::DebugRefBase([[maybe_unused]]const void* objectId) { #ifdef DEBUG_REFBASE if (enableTrack) { -#ifdef PRINT_TRACK_AT_ONCE - PrintRefs(objectId); -#else +#ifndef PRINT_TRACK_AT_ONCE GetNewTrace(objectId); #endif } @@ -184,13 +196,22 @@ int RefCounter::GetRefCount() void RefCounter::IncRefCount() { +#if ((defined DEBUG_REFBASE) && (defined PRINT_TRACK_AT_ONCE)) + int curCount = atomicRefCount_.fetch_add(1, std::memory_order_relaxed); + RefBaseDebugPrint(curCount, __builtin_return_address(0), nullptr, "++", "atomicRefCount_"); +#else atomicRefCount_.fetch_add(1, std::memory_order_relaxed); +#endif } void RefCounter::DecRefCount() { if (atomicRefCount_.load(std::memory_order_relaxed) > 0) { - if (atomicRefCount_.fetch_sub(1, std::memory_order_release) == 1) { + int curCount = atomicRefCount_.fetch_sub(1, std::memory_order_release); +#if ((defined DEBUG_REFBASE) && (defined PRINT_TRACK_AT_ONCE)) + RefBaseDebugPrint(curCount, __builtin_return_address(0), nullptr, "++", "atomicRefCount_"); +#endif + if (curCount == 1) { delete (this); } } @@ -232,9 +253,7 @@ RefCounter::~RefCounter() { #ifdef DEBUG_REFBASE if (enableTrack) { -#ifdef PRINT_TRACK_AT_ONCE - UTILS_LOGI("%{public}p end tracking", this); -#else +#ifndef PRINT_TRACK_AT_ONCE PrintTracker(); #endif } @@ -247,8 +266,16 @@ int RefCounter::IncStrongRefCount(const void* objectId) int curCount = atomicStrong_.load(std::memory_order_relaxed); if (curCount >= 0) { curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed); +#if ((defined DEBUG_REFBASE) && (defined PRINT_TRACK_AT_ONCE)) + RefBaseDebugPrint(curCount, __builtin_return_address(0), objectId, "++", "atomicStrong_"); +#endif if (curCount == INITIAL_PRIMARY_VALUE) { +#if ((defined DEBUG_REFBASE) && (defined PRINT_TRACK_AT_ONCE)) + int newCurCount = atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release); + RefBaseDebugPrint(newCurCount, __builtin_return_address(0), objectId, "--", "atomicStrong_"); +#else atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release); +#endif } } @@ -266,6 +293,9 @@ int RefCounter::DecStrongRefCount(const void* objectId) // we should update the current count here. // it may be changed after last operation. curCount = atomicStrong_.fetch_sub(1, std::memory_order_release); +#if ((defined DEBUG_REFBASE) && (defined PRINT_TRACK_AT_ONCE)) + RefBaseDebugPrint(curCount, __builtin_return_address(0), objectId, "--", "atomicStrong_"); +#endif } return curCount; @@ -279,7 +309,11 @@ int RefCounter::GetStrongRefCount() int RefCounter::IncWeakRefCount(const void* objectId) { DebugRefBase(objectId); - return atomicWeak_.fetch_add(1, std::memory_order_relaxed); + int curCount = atomicWeak_.fetch_add(1, std::memory_order_relaxed); +#if ((defined DEBUG_REFBASE) && (defined PRINT_TRACK_AT_ONCE)) + RefBaseDebugPrint(curCount, __builtin_return_address(0), objectId, "++", "atomicWeak_"); +#endif + return curCount; } int RefCounter::DecWeakRefCount(const void* objectId) @@ -288,6 +322,9 @@ int RefCounter::DecWeakRefCount(const void* objectId) int curCount = GetWeakRefCount(); if (curCount > 0) { curCount = atomicWeak_.fetch_sub(1, std::memory_order_release); +#if ((defined DEBUG_REFBASE) && (defined PRINT_TRACK_AT_ONCE)) + RefBaseDebugPrint(curCount, __builtin_return_address(0), objectId, "--", "atomicWeak_"); +#endif } if (curCount != 1) { @@ -326,7 +363,12 @@ int RefCounter::GetAttemptAcquire() void RefCounter::SetAttemptAcquire() { +#if ((defined DEBUG_REFBASE) && (defined PRINT_TRACK_AT_ONCE)) + int curCount = atomicAttempt_.fetch_add(1, std::memory_order_relaxed); + RefBaseDebugPrint(curCount, __builtin_return_address(0), nullptr, "++", "atomicAttempt_"); +#else (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed); +#endif } bool RefCounter::IsAttemptAcquireSet() @@ -336,7 +378,12 @@ bool RefCounter::IsAttemptAcquireSet() void RefCounter::ClearAttemptAcquire() { +#if ((defined DEBUG_REFBASE) && (defined PRINT_TRACK_AT_ONCE)) + int curCount = atomicAttempt_.fetch_sub(1, std::memory_order_relaxed); + RefBaseDebugPrint(curCount, __builtin_return_address(0), nullptr, "--", "atomicAttempt_"); +#else atomicAttempt_.fetch_sub(1, std::memory_order_relaxed); +#endif } void RefCounter::ExtendObjectLifetime() @@ -353,10 +400,10 @@ bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount) { int curCount = GetStrongRefCount(); IncWeakRefCount(objectId); - // if the object already had strong references.just promoting it. while ((curCount > 0) && (curCount != INITIAL_PRIMARY_VALUE)) { if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) { + RefBaseDebugPrint(curCount, __builtin_return_address(0), objectId, "++", "atomicStrong_"); goto ATTEMPT_SUCCESS; } // someone else changed the counter.re-acquire the counter value. @@ -367,6 +414,7 @@ bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount) // this object has a "normal" life-time, while (curCount > 0) { if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) { + RefBaseDebugPrint(curCount, __builtin_return_address(0), objectId, "++", "atomicStrong_"); goto ATTEMPT_SUCCESS; } curCount = atomicStrong_.load(std::memory_order_relaxed); @@ -380,12 +428,17 @@ bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount) } #endif curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed); + RefBaseDebugPrint(curCount, __builtin_return_address(0), objectId, "++", "atomicStrong_"); } - ATTEMPT_SUCCESS: if (curCount == INITIAL_PRIMARY_VALUE) { outCount = curCount; +#if ((defined DEBUG_REFBASE) && (defined PRINT_TRACK_AT_ONCE)) + int newCurCount = atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release); + RefBaseDebugPrint(newCurCount, __builtin_return_address(0), objectId, "--", "atomicStrong_"); +#else atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release); +#endif return true; } @@ -394,7 +447,6 @@ ATTEMPT_SUCCESS: DecWeakRefCount(objectId); return false; } - return true; } @@ -404,6 +456,9 @@ bool RefCounter::AttemptIncStrong(const void *objectId) int curCount = GetStrongRefCount(); while (curCount > 0) { if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) { +#if ((defined DEBUG_REFBASE) && (defined PRINT_TRACK_AT_ONCE)) + RefBaseDebugPrint(curCount, __builtin_return_address(0), objectId, "++", "atomicStrong_"); +#endif break; } // curCount has been updated. @@ -693,4 +748,11 @@ void RefBase::EnableTracker() } #endif +void RefBase::EnableTrackerWithDomainId(unsigned int domainId) +{ +#if ((defined DEBUG_REFBASE) && (defined PRINT_TRACK_AT_ONCE)) + refs_->EnableTrackerWithDomainId(domainId); +#endif +} + } // namespace OHOS diff --git a/base/src/utils_log.h b/base/src/utils_log.h index 1b3efac5c6ad3826d170fdfc2613c9ea800d091c..4e186e51aa9473cdfc617a6cae447102bfc5cfa8 100644 --- a/base/src/utils_log.h +++ b/base/src/utils_log.h @@ -24,6 +24,7 @@ constexpr const char *UTILS_LOG_TAG = "utils_base"; #define UTILS_LOGE(...) (void)HiLogBasePrint(UTILS_LOG_TYPE, LOG_ERROR, UTILS_LOG_DOMAIN, UTILS_LOG_TAG, __VA_ARGS__) #define UTILS_LOGW(...) (void)HiLogBasePrint(UTILS_LOG_TYPE, LOG_WARN, UTILS_LOG_DOMAIN, UTILS_LOG_TAG, __VA_ARGS__) #define UTILS_LOGI(...) (void)HiLogBasePrint(UTILS_LOG_TYPE, LOG_INFO, UTILS_LOG_DOMAIN, UTILS_LOG_TAG, __VA_ARGS__) +#define UTILS_LOGT(DOMAIN, ...) (void)HiLogBasePrint(UTILS_LOG_TYPE, LOG_DEBUG, DOMAIN, UTILS_LOG_TAG, __VA_ARGS__) #ifdef DEBUG_UTILS #define UTILS_LOGD(...) (void)HiLogBasePrint(UTILS_LOG_TYPE, LOG_DEBUG, UTILS_LOG_DOMAIN, UTILS_LOG_TAG, __VA_ARGS__) #else diff --git a/base/test/unittest/common/utils_refbase_test.cpp b/base/test/unittest/common/utils_refbase_test.cpp index b6208804c9e22e54c43e79e2b09a44a5c991313b..272fb36d331c7a34e5211dae4181b1e92799568b 100644 --- a/base/test/unittest/common/utils_refbase_test.cpp +++ b/base/test/unittest/common/utils_refbase_test.cpp @@ -1157,6 +1157,44 @@ HWTEST_F(UtilsRefbaseTest, testRefbaseDebug002, TestSize.Level1) std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } +/* + * @tc.name: testRefbaseWithDomainIdDebug001 + * @tc.desc: Test for single thread. Tracker can be enabled after construction + * of sptr. + */ +HWTEST_F(UtilsRefbaseTest, testRefbaseWithDomainIdDebug001, TestSize.Level1) +{ + sptr testObject1(new RefBase()); + testObject1->EnableTrackerWithDomainId(0xD001651); + sptr testObject2(testObject1); + EXPECT_EQ(testObject2->GetSptrRefCount(), 2); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + wptr testObject3(testObject2); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + wptr testObject4(testObject3); + EXPECT_EQ(testObject4->GetWptrRefCount(), 3); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); +} + +/* + * @tc.name: testRefbaseWithDomainIdDebug002 + * @tc.desc: Test for single thread. Tracker can be enabled after construction + * of wptr. + */ +HWTEST_F(UtilsRefbaseTest, testRefbaseWithDomainIdDebug002, TestSize.Level1) +{ + wptr testObject1(new RefBase()); + testObject1->EnableTrackerWithDomainId(0xD001651); + sptr testObject2 = testObject1.promote(); + EXPECT_EQ(testObject2->GetSptrRefCount(), 1); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + wptr testObject3(testObject2); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + wptr testObject4(testObject3); + EXPECT_EQ(testObject4->GetWptrRefCount(), 3); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); +} + // This is a class which can be tracked when implemented. class TestDebug : public RefBase { public: @@ -1166,6 +1204,14 @@ public: } }; +class TestDebugWithDomainId : public RefBase { +public: + TestDebugWithDomainId() + { + EnableTrackerWithDomainId(0xD001651); + } +}; + /* * @tc.name: testRefbaseDebug003 * @tc.desc: Test for single thread. Tracker can be enabled with construction @@ -1209,5 +1255,49 @@ HWTEST_F(UtilsRefbaseTest, testRefbaseDebug004, TestSize.Level1) subThread.join(); EXPECT_EQ(testObject3->GetWptrRefCount(), 2); } + +/* + * @tc.name: testRefbaseWithDomainIdDebug003 + * @tc.desc: Test for single thread. Tracker can be enabled with construction + * of sptr. + */ +HWTEST_F(UtilsRefbaseTest, testRefbaseWithDomainIdDebug003, TestSize.Level1) +{ + sptr testObject1(new TestDebugWithDomainId()); + sptr testObject2(testObject1); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + sptr testObject3; + EXPECT_EQ(testObject2->GetSptrRefCount(), 2); + testObject3 = testObject2; + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + wptr testObject4(testObject3); + EXPECT_EQ(testObject4->GetWptrRefCount(), 4); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); +} + +/* + * @tc.name: testRefbaseWithDomainIdDebug004 + * @tc.desc: Test for mult-thread. + */ +HWTEST_F(UtilsRefbaseTest, testRefbaseWithDomainIdDebug004, TestSize.Level1) +{ + sptr testObject1(new TestDebugWithDomainId()); + std::thread subThread {[&testObject1]() { + sptr subTestObject1(testObject1); + EXPECT_EQ(testObject1->GetSptrRefCount(), 2); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + wptr subTestObject2(subTestObject1); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + wptr subTestObject3(subTestObject2); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + }}; + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + wptr testObject2(testObject1); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + wptr testObject3(testObject2); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + subThread.join(); + EXPECT_EQ(testObject3->GetWptrRefCount(), 2); +} } // namespace } // namespace OHOS