diff options
-rw-r--r-- | include/utils/RefBase.h | 10 | ||||
-rw-r--r-- | libs/utils/RefBase.cpp | 264 |
2 files changed, 187 insertions, 87 deletions
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h index e81cd00..51eff5a 100644 --- a/include/utils/RefBase.h +++ b/include/utils/RefBase.h @@ -80,9 +80,12 @@ public: void incWeak(const void* id); void decWeak(const void* id); + // acquires a strong reference if there is already one. bool attemptIncStrong(const void* id); - //! This is only safe if you have set OBJECT_LIFETIME_FOREVER. + // acquires a weak reference if there is already one. + // This is not always safe. see ProcessState.cpp and BpBinder.cpp + // for proper use. bool attemptIncWeak(const void* id); //! DEBUGGING ONLY: Get current weak ref count. @@ -122,8 +125,9 @@ protected: //! Flags for extendObjectLifetime() enum { + OBJECT_LIFETIME_STRONG = 0x0000, OBJECT_LIFETIME_WEAK = 0x0001, - OBJECT_LIFETIME_FOREVER = 0x0003 + OBJECT_LIFETIME_MASK = 0x0001 }; void extendObjectLifetime(int32_t mode); @@ -149,7 +153,7 @@ private: RefBase(const RefBase& o); RefBase& operator=(const RefBase& o); - + weakref_impl* const mRefs; }; diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp index 32e900a..37d061c 100644 --- a/libs/utils/RefBase.cpp +++ b/libs/utils/RefBase.cpp @@ -20,9 +20,9 @@ #include <utils/Atomic.h> #include <utils/CallStack.h> -#include <utils/KeyedVector.h> #include <utils/Log.h> #include <utils/threads.h> +#include <utils/TextOutput.h> #include <stdlib.h> #include <stdio.h> @@ -34,6 +34,7 @@ // compile with refcounting debugging enabled #define DEBUG_REFS 0 +#define DEBUG_REFS_FATAL_SANITY_CHECKS 0 #define DEBUG_REFS_ENABLED_BY_DEFAULT 1 #define DEBUG_REFS_CALLSTACK_ENABLED 1 @@ -56,7 +57,6 @@ public: RefBase* const mBase; volatile int32_t mFlags; - #if !DEBUG_REFS weakref_impl(RefBase* base) @@ -69,8 +69,10 @@ public: void addStrongRef(const void* /*id*/) { } void removeStrongRef(const void* /*id*/) { } + void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { } void addWeakRef(const void* /*id*/) { } void removeWeakRef(const void* /*id*/) { } + void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { } void printRefs() const { } void trackMe(bool, bool) { } @@ -86,39 +88,91 @@ public: , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT) , mRetain(false) { - //LOGI("NEW weakref_impl %p for RefBase %p", this, base); } ~weakref_impl() { - LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!"); - LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!"); + bool dumpStack = false; + if (!mRetain && mStrongRefs != NULL) { + dumpStack = true; +#if DEBUG_REFS_FATAL_SANITY_CHECKS + LOG_ALWAYS_FATAL("Strong references remain!"); +#else + LOGE("Strong references remain:"); +#endif + ref_entry* refs = mStrongRefs; + while (refs) { + char inc = refs->ref >= 0 ? '+' : '-'; + LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref); +#if DEBUG_REFS_CALLSTACK_ENABLED + refs->stack.dump(); +#endif + refs = refs->next; + } + } + + if (!mRetain && mWeakRefs != NULL) { + dumpStack = true; +#if DEBUG_REFS_FATAL_SANITY_CHECKS + LOG_ALWAYS_FATAL("Weak references remain:"); +#else + LOGE("Weak references remain!"); +#endif + ref_entry* refs = mWeakRefs; + while (refs) { + char inc = refs->ref >= 0 ? '+' : '-'; + LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref); +#if DEBUG_REFS_CALLSTACK_ENABLED + refs->stack.dump(); +#endif + refs = refs->next; + } + } + if (dumpStack) { + LOGE("above errors at:"); + CallStack stack; + stack.update(); + stack.dump(); + } } - void addStrongRef(const void* id) - { + void addStrongRef(const void* id) { + //LOGD_IF(mTrackEnabled, + // "addStrongRef: RefBase=%p, id=%p", mBase, id); addRef(&mStrongRefs, id, mStrong); } - void removeStrongRef(const void* id) - { - if (!mRetain) + void removeStrongRef(const void* id) { + //LOGD_IF(mTrackEnabled, + // "removeStrongRef: RefBase=%p, id=%p", mBase, id); + if (!mRetain) { removeRef(&mStrongRefs, id); - else + } else { addRef(&mStrongRefs, id, -mStrong); + } } - void addWeakRef(const void* id) - { + void renameStrongRefId(const void* old_id, const void* new_id) { + //LOGD_IF(mTrackEnabled, + // "renameStrongRefId: RefBase=%p, oid=%p, nid=%p", + // mBase, old_id, new_id); + renameRefsId(mStrongRefs, old_id, new_id); + } + + void addWeakRef(const void* id) { addRef(&mWeakRefs, id, mWeak); } - void removeWeakRef(const void* id) - { - if (!mRetain) + void removeWeakRef(const void* id) { + if (!mRetain) { removeRef(&mWeakRefs, id); - else + } else { addRef(&mWeakRefs, id, -mWeak); + } + } + + void renameWeakRefId(const void* old_id, const void* new_id) { + renameRefsId(mWeakRefs, old_id, new_id); } void trackMe(bool track, bool retain) @@ -132,8 +186,7 @@ public: String8 text; { - AutoMutex _l(const_cast<weakref_impl*>(this)->mMutex); - + Mutex::Autolock _l(mMutex); char buf[128]; sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this); text.append(buf); @@ -172,6 +225,7 @@ private: { if (mTrackEnabled) { AutoMutex _l(mMutex); + ref_entry* ref = new ref_entry; // Reference count at the time of the snapshot, but before the // update. Positive value means we increment, negative--we @@ -181,7 +235,6 @@ private: #if DEBUG_REFS_CALLSTACK_ENABLED ref->stack.update(2); #endif - ref->next = *refs; *refs = ref; } @@ -192,20 +245,52 @@ private: if (mTrackEnabled) { AutoMutex _l(mMutex); - ref_entry* ref = *refs; + ref_entry* const head = *refs; + ref_entry* ref = head; while (ref != NULL) { if (ref->id == id) { *refs = ref->next; delete ref; return; } - refs = &ref->next; ref = *refs; } - - LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!", - id, mBase, this); + +#if DEBUG_REFS_FATAL_SANITY_CHECKS + LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p" + "(weakref_type %p) that doesn't exist!", + id, mBase, this); +#endif + + LOGE("RefBase: removing id %p on RefBase %p" + "(weakref_type %p) that doesn't exist!", + id, mBase, this); + + ref = head; + while (ref) { + char inc = ref->ref >= 0 ? '+' : '-'; + LOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref); + ref = ref->next; + } + + CallStack stack; + stack.update(); + stack.dump(); + } + } + + void renameRefsId(ref_entry* r, const void* old_id, const void* new_id) + { + if (mTrackEnabled) { + AutoMutex _l(mMutex); + ref_entry* ref = r; + while (ref != NULL) { + if (ref->id == old_id) { + ref->id = new_id; + } + ref = ref->next; + } } } @@ -226,7 +311,7 @@ private: } } - Mutex mMutex; + mutable Mutex mMutex; ref_entry* mStrongRefs; ref_entry* mWeakRefs; @@ -235,44 +320,6 @@ private: // on removeref that match the address ones. bool mRetain; -#if 0 - void addRef(KeyedVector<const void*, int32_t>* refs, const void* id) - { - AutoMutex _l(mMutex); - ssize_t i = refs->indexOfKey(id); - if (i >= 0) { - ++(refs->editValueAt(i)); - } else { - i = refs->add(id, 1); - } - } - - void removeRef(KeyedVector<const void*, int32_t>* refs, const void* id) - { - AutoMutex _l(mMutex); - ssize_t i = refs->indexOfKey(id); - LOG_ALWAYS_FATAL_IF(i < 0, "RefBase: removing id %p that doesn't exist!", id); - if (i >= 0) { - int32_t val = --(refs->editValueAt(i)); - if (val == 0) { - refs->removeItemsAt(i); - } - } - } - - void printRefs(const KeyedVector<const void*, int32_t>& refs) - { - const size_t N=refs.size(); - for (size_t i=0; i<N; i++) { - printf("\tID %p: %d remain\n", refs.keyAt(i), refs.valueAt(i)); - } - } - - mutable Mutex mMutex; - KeyedVector<const void*, int32_t> mStrongRefs; - KeyedVector<const void*, int32_t> mWeakRefs; -#endif - #endif }; @@ -281,7 +328,6 @@ private: void RefBase::incStrong(const void* id) const { weakref_impl* const refs = mRefs; - refs->addWeakRef(id); refs->incWeak(id); refs->addStrongRef(id); @@ -295,7 +341,7 @@ void RefBase::incStrong(const void* id) const } android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); - const_cast<RefBase*>(this)->onFirstRef(); + refs->mBase->onFirstRef(); } void RefBase::decStrong(const void* id) const @@ -308,19 +354,17 @@ void RefBase::decStrong(const void* id) const #endif LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs); if (c == 1) { - const_cast<RefBase*>(this)->onLastStrongRef(id); - if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { + refs->mBase->onLastStrongRef(id); + if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { delete this; } } - refs->removeWeakRef(id); refs->decWeak(id); } void RefBase::forceIncStrong(const void* id) const { weakref_impl* const refs = mRefs; - refs->addWeakRef(id); refs->incWeak(id); refs->addStrongRef(id); @@ -336,7 +380,7 @@ void RefBase::forceIncStrong(const void* id) const android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); // fall through... case 0: - const_cast<RefBase*>(this)->onFirstRef(); + refs->mBase->onFirstRef(); } } @@ -345,8 +389,6 @@ int32_t RefBase::getStrongCount() const return mRefs->mStrong; } - - RefBase* RefBase::weakref_type::refBase() const { return static_cast<const weakref_impl*>(this)->mBase; @@ -360,6 +402,7 @@ void RefBase::weakref_type::incWeak(const void* id) LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this); } + void RefBase::weakref_type::decWeak(const void* id) { weakref_impl* const impl = static_cast<weakref_impl*>(this); @@ -367,17 +410,26 @@ void RefBase::weakref_type::decWeak(const void* id) const int32_t c = android_atomic_dec(&impl->mWeak); LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this); if (c != 1) return; - - if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { - if (impl->mStrong == INITIAL_STRONG_VALUE) + + if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) { + // This is the regular lifetime case. The object is destroyed + // when the last strong reference goes away. Since weakref_impl + // outlive the object, it is not destroyed in the dtor, and + // we'll have to do it here. + if (impl->mStrong == INITIAL_STRONG_VALUE) { + // Special case: we never had a strong reference, so we need to + // destroy the object now. delete impl->mBase; - else { + } else { // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase); delete impl; } } else { + // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER} impl->mBase->onLastWeakRef(id); - if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) { + if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) { + // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference + // is gone, we can destroy the object. delete impl->mBase; } } @@ -432,7 +484,6 @@ bool RefBase::weakref_type::attemptIncStrong(const void* id) } } - impl->addWeakRef(id); impl->addStrongRef(id); #if PRINT_REFS @@ -450,7 +501,7 @@ bool RefBase::weakref_type::attemptIncStrong(const void* id) bool RefBase::weakref_type::attemptIncWeak(const void* id) { weakref_impl* const impl = static_cast<weakref_impl*>(this); - + int32_t curCount = impl->mWeak; LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow", this); @@ -480,7 +531,7 @@ void RefBase::weakref_type::printRefs() const void RefBase::weakref_type::trackMe(bool enable, bool retain) { - static_cast<const weakref_impl*>(this)->trackMe(enable, retain); + static_cast<weakref_impl*>(this)->trackMe(enable, retain); } RefBase::weakref_type* RefBase::createWeak(const void* id) const @@ -497,14 +548,27 @@ RefBase::weakref_type* RefBase::getWeakRefs() const RefBase::RefBase() : mRefs(new weakref_impl(this)) { -// LOGV("Creating refs %p with RefBase %p\n", mRefs, this); } RefBase::~RefBase() { - if (mRefs->mWeak == 0) { + if (mRefs->mStrong == INITIAL_STRONG_VALUE) { + // we never acquired a strong (and/or weak) reference on this object. delete mRefs; + } else { + // life-time of this object is extended to WEAK or FOREVER, in + // which case weakref_impl doesn't out-live the object and we + // can free it now. + if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) { + // It's possible that the weak count is not 0 if the object + // re-acquired a weak reference in its destructor + if (mRefs->mWeak == 0) { + delete mRefs; + } + } } + // for debugging purposes, clear this. + const_cast<weakref_impl*&>(mRefs) = NULL; } void RefBase::extendObjectLifetime(int32_t mode) @@ -528,5 +592,37 @@ bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id) void RefBase::onLastWeakRef(const void* /*id*/) { } - + +// --------------------------------------------------------------------------- + +void RefBase::moveReferences(void* dst, void const* src, size_t n, + const ReferenceConverterBase& caster) +{ +#if DEBUG_REFS + const size_t itemSize = caster.getReferenceTypeSize(); + for (size_t i=0 ; i<n ; i++) { + void* d = reinterpret_cast<void *>(intptr_t(dst) + i*itemSize); + void const* s = reinterpret_cast<void const*>(intptr_t(src) + i*itemSize); + RefBase* ref(reinterpret_cast<RefBase*>(caster.getReferenceBase(d))); + ref->mRefs->renameStrongRefId(s, d); + ref->mRefs->renameWeakRefId(s, d); + } +#endif +} + +// --------------------------------------------------------------------------- + +TextOutput& printStrongPointer(TextOutput& to, const void* val) +{ + to << "sp<>(" << val << ")"; + return to; +} + +TextOutput& printWeakPointer(TextOutput& to, const void* val) +{ + to << "wp<>(" << val << ")"; + return to; +} + + }; // namespace android |