/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_REF_BASE_H #define ANDROID_REF_BASE_H #include #include #include #include #include #include #include // --------------------------------------------------------------------------- namespace android { class TextOutput; TextOutput& printWeakPointer(TextOutput& to, const void* val); // --------------------------------------------------------------------------- #define COMPARE_WEAK(_op_) \ inline bool operator _op_ (const sp& o) const { \ return m_ptr _op_ o.m_ptr; \ } \ inline bool operator _op_ (const T* o) const { \ return m_ptr _op_ o; \ } \ template \ inline bool operator _op_ (const sp& o) const { \ return m_ptr _op_ o.m_ptr; \ } \ template \ inline bool operator _op_ (const U* o) const { \ return m_ptr _op_ o; \ } // --------------------------------------------------------------------------- class ReferenceRenamer { protected: // destructor is purposedly not virtual so we avoid code overhead from // subclasses; we have to make it protected to guarantee that it // cannot be called from this base class (and to make strict compilers // happy). ~ReferenceRenamer() { } public: virtual void operator()(size_t i) const = 0; }; // --------------------------------------------------------------------------- class RefBase { public: void incStrong(const void* id) const; void decStrong(const void* id) const; void forceIncStrong(const void* id) const; //! DEBUGGING ONLY: Get current strong ref count. int32_t getStrongCount() const; class weakref_type { public: RefBase* refBase() const; void incWeak(const void* id); void decWeak(const void* id); // acquires a strong reference if there is already one. bool attemptIncStrong(const void* id); // 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. int32_t getWeakCount() const; //! DEBUGGING ONLY: Print references held on object. void printRefs() const; //! DEBUGGING ONLY: Enable tracking for this object. // enable -- enable/disable tracking // retain -- when tracking is enable, if true, then we save a stack trace // for each reference and dereference; when retain == false, we // match up references and dereferences and keep only the // outstanding ones. void trackMe(bool enable, bool retain); }; weakref_type* createWeak(const void* id) const; weakref_type* getWeakRefs() const; //! DEBUGGING ONLY: Print references held on object. inline void printRefs() const { getWeakRefs()->printRefs(); } //! DEBUGGING ONLY: Enable tracking of object. inline void trackMe(bool enable, bool retain) { getWeakRefs()->trackMe(enable, retain); } typedef RefBase basetype; protected: RefBase(); virtual ~RefBase(); //! Flags for extendObjectLifetime() enum { OBJECT_LIFETIME_STRONG = 0x0000, OBJECT_LIFETIME_WEAK = 0x0001, OBJECT_LIFETIME_MASK = 0x0001 }; void extendObjectLifetime(int32_t mode); //! Flags for onIncStrongAttempted() enum { FIRST_INC_STRONG = 0x0001 }; virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); virtual bool onIncStrongAttempted(uint32_t flags, const void* id); virtual void onLastWeakRef(const void* id); private: friend class weakref_type; class weakref_impl; RefBase(const RefBase& o); RefBase& operator=(const RefBase& o); private: friend class ReferenceMover; static void renameRefs(size_t n, const ReferenceRenamer& renamer); static void renameRefId(weakref_type* ref, const void* old_id, const void* new_id); static void renameRefId(RefBase* ref, const void* old_id, const void* new_id); weakref_impl* const mRefs; }; // --------------------------------------------------------------------------- template class LightRefBase { public: inline LightRefBase() : mCount(0) { } inline void incStrong(__attribute__((unused)) const void* id) const { android_atomic_inc(&mCount); } inline void decStrong(__attribute__((unused)) const void* id) const { if (android_atomic_dec(&mCount) == 1) { delete static_cast(this); } } //! DEBUGGING ONLY: Get current strong ref count. inline int32_t getStrongCount() const { return mCount; } typedef LightRefBase basetype; protected: inline ~LightRefBase() { } private: friend class ReferenceMover; inline static void renameRefs(size_t n, const ReferenceRenamer& renamer) { } inline static void renameRefId(T* ref, const void* old_id, const void* new_id) { } private: mutable volatile int32_t mCount; }; // This is a wrapper around LightRefBase that simply enforces a virtual // destructor to eliminate the template requirement of LightRefBase class VirtualLightRefBase : public LightRefBase { public: virtual ~VirtualLightRefBase() {} }; // --------------------------------------------------------------------------- template class wp { public: typedef typename RefBase::weakref_type weakref_type; inline wp() : m_ptr(0) { } wp(T* other); wp(const wp& other); wp(const sp& other); template wp(U* other); template wp(const sp& other); template wp(const wp& other); ~wp(); // Assignment wp& operator = (T* other); wp& operator = (const wp& other); wp& operator = (const sp& other); template wp& operator = (U* other); template wp& operator = (const wp& other); template wp& operator = (const sp& other); void set_object_and_refs(T* other, weakref_type* refs); // promotion to sp sp promote() const; // Reset void clear(); // Accessors inline weakref_type* get_refs() const { return m_refs; } inline T* unsafe_get() const { return m_ptr; } // Operators COMPARE_WEAK(==) COMPARE_WEAK(!=) COMPARE_WEAK(>) COMPARE_WEAK(<) COMPARE_WEAK(<=) COMPARE_WEAK(>=) inline bool operator == (const wp& o) const { return (m_ptr == o.m_ptr) && (m_refs == o.m_refs); } template inline bool operator == (const wp& o) const { return m_ptr == o.m_ptr; } inline bool operator > (const wp& o) const { return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr); } template inline bool operator > (const wp& o) const { return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr); } inline bool operator < (const wp& o) const { return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr); } template inline bool operator < (const wp& o) const { return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr); } inline bool operator != (const wp& o) const { return m_refs != o.m_refs; } template inline bool operator != (const wp& o) const { return !operator == (o); } inline bool operator <= (const wp& o) const { return !operator > (o); } template inline bool operator <= (const wp& o) const { return !operator > (o); } inline bool operator >= (const wp& o) const { return !operator < (o); } template inline bool operator >= (const wp& o) const { return !operator < (o); } private: template friend class sp; template friend class wp; T* m_ptr; weakref_type* m_refs; }; template TextOutput& operator<<(TextOutput& to, const wp& val); #undef COMPARE_WEAK // --------------------------------------------------------------------------- // No user serviceable parts below here. template wp::wp(T* other) : m_ptr(other) { if (other) m_refs = other->createWeak(this); } template wp::wp(const wp& other) : m_ptr(other.m_ptr), m_refs(other.m_refs) { if (m_ptr) m_refs->incWeak(this); } template wp::wp(const sp& other) : m_ptr(other.m_ptr) { if (m_ptr) { m_refs = m_ptr->createWeak(this); } } template template wp::wp(U* other) : m_ptr(other) { if (other) m_refs = other->createWeak(this); } template template wp::wp(const wp& other) : m_ptr(other.m_ptr) { if (m_ptr) { m_refs = other.m_refs; m_refs->incWeak(this); } } template template wp::wp(const sp& other) : m_ptr(other.m_ptr) { if (m_ptr) { m_refs = m_ptr->createWeak(this); } } template wp::~wp() { if (m_ptr) m_refs->decWeak(this); } template wp& wp::operator = (T* other) { weakref_type* newRefs = other ? other->createWeak(this) : 0; if (m_ptr) m_refs->decWeak(this); m_ptr = other; m_refs = newRefs; return *this; } template wp& wp::operator = (const wp& other) { weakref_type* otherRefs(other.m_refs); T* otherPtr(other.m_ptr); if (otherPtr) otherRefs->incWeak(this); if (m_ptr) m_refs->decWeak(this); m_ptr = otherPtr; m_refs = otherRefs; return *this; } template wp& wp::operator = (const sp& other) { weakref_type* newRefs = other != NULL ? other->createWeak(this) : 0; T* otherPtr(other.m_ptr); if (m_ptr) m_refs->decWeak(this); m_ptr = otherPtr; m_refs = newRefs; return *this; } template template wp& wp::operator = (U* other) { weakref_type* newRefs = other ? other->createWeak(this) : 0; if (m_ptr) m_refs->decWeak(this); m_ptr = other; m_refs = newRefs; return *this; } template template wp& wp::operator = (const wp& other) { weakref_type* otherRefs(other.m_refs); U* otherPtr(other.m_ptr); if (otherPtr) otherRefs->incWeak(this); if (m_ptr) m_refs->decWeak(this); m_ptr = otherPtr; m_refs = otherRefs; return *this; } template template wp& wp::operator = (const sp& other) { weakref_type* newRefs = other != NULL ? other->createWeak(this) : 0; U* otherPtr(other.m_ptr); if (m_ptr) m_refs->decWeak(this); m_ptr = otherPtr; m_refs = newRefs; return *this; } template void wp::set_object_and_refs(T* other, weakref_type* refs) { if (other) refs->incWeak(this); if (m_ptr) m_refs->decWeak(this); m_ptr = other; m_refs = refs; } template sp wp::promote() const { sp result; if (m_ptr && m_refs->attemptIncStrong(&result)) { result.set_pointer(m_ptr); } return result; } template void wp::clear() { if (m_ptr) { m_refs->decWeak(this); m_ptr = 0; } } template inline TextOutput& operator<<(TextOutput& to, const wp& val) { return printWeakPointer(to, val.unsafe_get()); } // --------------------------------------------------------------------------- // this class just serves as a namespace so TYPE::moveReferences can stay // private. class ReferenceMover { public: // it would be nice if we could make sure no extra code is generated // for sp or wp when TYPE is a descendant of RefBase: // Using a sp override doesn't work; it's a bit like we wanted // a template template... template static inline void move_references(sp* d, sp const* s, size_t n) { class Renamer : public ReferenceRenamer { sp* d; sp const* s; virtual void operator()(size_t i) const { // The id are known to be the sp<>'s this pointer TYPE::renameRefId(d[i].get(), &s[i], &d[i]); } public: Renamer(sp* d, sp const* s) : d(d), s(s) { } virtual ~Renamer() { } }; memmove(d, s, n*sizeof(sp)); TYPE::renameRefs(n, Renamer(d, s)); } template static inline void move_references(wp* d, wp const* s, size_t n) { class Renamer : public ReferenceRenamer { wp* d; wp const* s; virtual void operator()(size_t i) const { // The id are known to be the wp<>'s this pointer TYPE::renameRefId(d[i].get_refs(), &s[i], &d[i]); } public: Renamer(wp* d, wp const* s) : d(d), s(s) { } virtual ~Renamer() { } }; memmove(d, s, n*sizeof(wp)); TYPE::renameRefs(n, Renamer(d, s)); } }; // specialization for moving sp<> and wp<> types. // these are used by the [Sorted|Keyed]Vector<> implementations // sp<> and wp<> need to be handled specially, because they do not // have trivial copy operation in the general case (see RefBase.cpp // when DEBUG ops are enabled), but can be implemented very // efficiently in most cases. template inline void move_forward_type(sp* d, sp const* s, size_t n) { ReferenceMover::move_references(d, s, n); } template inline void move_backward_type(sp* d, sp const* s, size_t n) { ReferenceMover::move_references(d, s, n); } template inline void move_forward_type(wp* d, wp const* s, size_t n) { ReferenceMover::move_references(d, s, n); } template inline void move_backward_type(wp* d, wp const* s, size_t n) { ReferenceMover::move_references(d, s, n); } }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_REF_BASE_H