nuclear@0: /************************************************************************************ nuclear@0: nuclear@0: PublicHeader: Kernel nuclear@0: Filename : OVR_RefCount.h nuclear@0: Content : Reference counting implementation headers nuclear@0: Created : September 19, 2012 nuclear@0: Notes : nuclear@0: nuclear@0: Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. nuclear@0: nuclear@0: Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); nuclear@0: you may not use the Oculus VR Rift SDK except in compliance with the License, nuclear@0: which is provided at the time of installation or download, or which nuclear@0: otherwise accompanies this software in either electronic or hard copy form. nuclear@0: nuclear@0: You may obtain a copy of the License at nuclear@0: nuclear@0: http://www.oculusvr.com/licenses/LICENSE-3.2 nuclear@0: nuclear@0: Unless required by applicable law or agreed to in writing, the Oculus VR SDK nuclear@0: distributed under the License is distributed on an "AS IS" BASIS, nuclear@0: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. nuclear@0: See the License for the specific language governing permissions and nuclear@0: limitations under the License. nuclear@0: nuclear@0: ************************************************************************************/ nuclear@0: nuclear@0: #ifndef OVR_RefCount_h nuclear@0: #define OVR_RefCount_h nuclear@0: nuclear@0: #include "OVR_Types.h" nuclear@0: #include "OVR_Allocator.h" nuclear@0: nuclear@0: namespace OVR { nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** Reference Counting nuclear@0: nuclear@0: // There are three types of reference counting base classes: nuclear@0: // nuclear@0: // RefCountBase - Provides thread-safe reference counting (Default). nuclear@0: // RefCountBaseNTS - Non Thread Safe version of reference counting. nuclear@0: nuclear@0: nuclear@0: // ***** Declared classes nuclear@0: nuclear@0: template nuclear@0: class RefCountBase; nuclear@0: template nuclear@0: class RefCountBaseNTS; nuclear@0: nuclear@0: class RefCountImpl; nuclear@0: class RefCountNTSImpl; nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** Implementation For Reference Counting nuclear@0: nuclear@0: // RefCountImplCore holds RefCount value and defines a few utility nuclear@0: // functions shared by all implementations. nuclear@0: nuclear@0: class RefCountImplCore nuclear@0: { nuclear@0: protected: nuclear@0: volatile int RefCount; nuclear@0: nuclear@0: public: nuclear@0: // RefCountImpl constructor always initializes RefCount to 1 by default. nuclear@0: OVR_FORCE_INLINE RefCountImplCore() : RefCount(1) { } nuclear@0: nuclear@0: // Need virtual destructor nuclear@0: // This: 1. Makes sure the right destructor's called. nuclear@0: // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem() nuclear@0: virtual ~RefCountImplCore(); nuclear@0: nuclear@0: // Debug method only. nuclear@0: int GetRefCount() const { return RefCount; } nuclear@0: nuclear@0: // This logic is used to detect invalid 'delete' calls of reference counted nuclear@0: // objects. Direct delete calls are not allowed on them unless they come in nuclear@0: // internally from Release. nuclear@0: #ifdef OVR_BUILD_DEBUG nuclear@0: static void OVR_CDECL reportInvalidDelete(void *pmem); nuclear@0: inline static void checkInvalidDelete(RefCountImplCore *pmem) nuclear@0: { nuclear@0: if (pmem->RefCount != 0) nuclear@0: reportInvalidDelete(pmem); nuclear@0: } nuclear@0: #else nuclear@0: inline static void checkInvalidDelete(RefCountImplCore *) { } nuclear@0: #endif nuclear@0: nuclear@0: // Base class ref-count content should not be copied. nuclear@0: void operator = (const RefCountImplCore &) { } nuclear@0: }; nuclear@0: nuclear@0: class RefCountNTSImplCore nuclear@0: { nuclear@0: protected: nuclear@0: mutable int RefCount; nuclear@0: nuclear@0: public: nuclear@0: // RefCountImpl constructor always initializes RefCount to 1 by default. nuclear@0: OVR_FORCE_INLINE RefCountNTSImplCore() : RefCount(1) { } nuclear@0: nuclear@0: // Need virtual destructor nuclear@0: // This: 1. Makes sure the right destructor's called. nuclear@0: // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem() nuclear@0: virtual ~RefCountNTSImplCore(); nuclear@0: nuclear@0: // Debug method only. nuclear@0: int GetRefCount() const { return RefCount; } nuclear@0: nuclear@0: // This logic is used to detect invalid 'delete' calls of reference counted nuclear@0: // objects. Direct delete calls are not allowed on them unless they come in nuclear@0: // internally from Release. nuclear@0: #ifdef OVR_BUILD_DEBUG nuclear@0: static void OVR_CDECL reportInvalidDelete(void *pmem); nuclear@0: OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *pmem) nuclear@0: { nuclear@0: if (pmem->RefCount != 0) nuclear@0: reportInvalidDelete(pmem); nuclear@0: } nuclear@0: #else nuclear@0: OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *) { } nuclear@0: #endif nuclear@0: nuclear@0: // Base class ref-count content should not be copied. nuclear@0: void operator = (const RefCountNTSImplCore &) { } nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: nuclear@0: // RefCountImpl provides Thread-Safe implementation of reference counting, so nuclear@0: // it should be used by default in most places. nuclear@0: nuclear@0: class RefCountImpl : public RefCountImplCore nuclear@0: { nuclear@0: public: nuclear@0: // Thread-Safe Ref-Count Implementation. nuclear@0: void AddRef(); nuclear@0: void Release(); nuclear@0: }; nuclear@0: nuclear@0: // RefCountVImpl provides Thread-Safe implementation of reference counting, plus, nuclear@0: // virtual AddRef and Release. nuclear@0: nuclear@0: class RefCountVImpl : virtual public RefCountImplCore nuclear@0: { nuclear@0: public: nuclear@0: // Thread-Safe Ref-Count Implementation. nuclear@0: virtual void AddRef(); nuclear@0: virtual void Release(); nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: // RefCountImplNTS provides Non-Thread-Safe implementation of reference counting, nuclear@0: // which is slightly more efficient since it doesn't use atomics. nuclear@0: nuclear@0: class RefCountNTSImpl : public RefCountNTSImplCore nuclear@0: { nuclear@0: public: nuclear@0: OVR_FORCE_INLINE void AddRef() const { RefCount++; } nuclear@0: void Release() const; nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: nuclear@0: // RefCountBaseStatImpl<> is a common class that adds new/delete override with Stat tracking nuclear@0: // to the reference counting implementation. Base must be one of the RefCountImpl classes. nuclear@0: nuclear@0: template nuclear@0: class RefCountBaseStatImpl : public Base nuclear@0: { nuclear@0: public: nuclear@0: RefCountBaseStatImpl() { } nuclear@0: nuclear@0: // *** Override New and Delete nuclear@0: nuclear@0: // DOM-IGNORE-BEGIN nuclear@0: // Undef new temporarily if it is being redefined nuclear@0: #ifdef OVR_DEFINE_NEW nuclear@0: #undef new nuclear@0: #endif nuclear@0: nuclear@0: #ifdef OVR_BUILD_DEBUG nuclear@0: // Custom check used to detect incorrect calls of 'delete' on ref-counted objects. nuclear@0: #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) \ nuclear@0: do {if (p) Base::checkInvalidDelete((class_name*)p); } while(0) nuclear@0: #else nuclear@0: #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) nuclear@0: #endif nuclear@0: nuclear@0: // Redefine all new & delete operators. nuclear@0: OVR_MEMORY_REDEFINE_NEW_IMPL(Base, OVR_REFCOUNTALLOC_CHECK_DELETE) nuclear@0: nuclear@0: #undef OVR_REFCOUNTALLOC_CHECK_DELETE nuclear@0: nuclear@0: #ifdef OVR_DEFINE_NEW nuclear@0: #define new OVR_DEFINE_NEW nuclear@0: #endif nuclear@0: // OVR_BUILD_DEFINE_NEW nuclear@0: // DOM-IGNORE-END nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: template nuclear@0: class RefCountBaseStatVImpl : virtual public Base nuclear@0: { nuclear@0: public: nuclear@0: RefCountBaseStatVImpl() { } nuclear@0: nuclear@0: // *** Override New and Delete nuclear@0: nuclear@0: // DOM-IGNORE-BEGIN nuclear@0: // Undef new temporarily if it is being redefined nuclear@0: #ifdef OVR_DEFINE_NEW nuclear@0: #undef new nuclear@0: #endif nuclear@0: nuclear@0: #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) nuclear@0: nuclear@0: // Redefine all new & delete operators. nuclear@0: OVR_MEMORY_REDEFINE_NEW_IMPL(Base, OVR_REFCOUNTALLOC_CHECK_DELETE) nuclear@0: nuclear@0: #undef OVR_REFCOUNTALLOC_CHECK_DELETE nuclear@0: nuclear@0: #ifdef OVR_DEFINE_NEW nuclear@0: #define new OVR_DEFINE_NEW nuclear@0: #endif nuclear@0: // OVR_BUILD_DEFINE_NEW nuclear@0: // DOM-IGNORE-END nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // *** End user RefCountBase<> classes nuclear@0: nuclear@0: nuclear@0: // RefCountBase is a base class for classes that require thread-safe reference nuclear@0: // counting; it also overrides the new and delete operators to use MemoryHeap. nuclear@0: // nuclear@0: // Reference counted objects start out with RefCount value of 1. Further lifetime nuclear@0: // management is done through the AddRef() and Release() methods, typically nuclear@0: // hidden by Ptr<>. nuclear@0: nuclear@0: template nuclear@0: class RefCountBase : public RefCountBaseStatImpl nuclear@0: { nuclear@0: public: nuclear@0: // Constructor. nuclear@0: OVR_FORCE_INLINE RefCountBase() : RefCountBaseStatImpl() { } nuclear@0: }; nuclear@0: nuclear@0: // RefCountBaseV is the same as RefCountBase but with virtual AddRef/Release nuclear@0: nuclear@0: template nuclear@0: class RefCountBaseV : virtual public RefCountBaseStatVImpl nuclear@0: { nuclear@0: public: nuclear@0: // Constructor. nuclear@0: OVR_FORCE_INLINE RefCountBaseV() : RefCountBaseStatVImpl() { } nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: // RefCountBaseNTS is a base class for classes that require Non-Thread-Safe reference nuclear@0: // counting; it also overrides the new and delete operators to use MemoryHeap. nuclear@0: // This class should only be used if all pointers to it are known to be assigned, nuclear@0: // destroyed and manipulated within one thread. nuclear@0: // nuclear@0: // Reference counted objects start out with RefCount value of 1. Further lifetime nuclear@0: // management is done through the AddRef() and Release() methods, typically nuclear@0: // hidden by Ptr<>. nuclear@0: nuclear@0: template nuclear@0: class RefCountBaseNTS : public RefCountBaseStatImpl nuclear@0: { nuclear@0: public: nuclear@0: // Constructor. nuclear@0: OVR_FORCE_INLINE RefCountBaseNTS() : RefCountBaseStatImpl() { } nuclear@0: }; nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** Pickable template pointer nuclear@0: enum PickType { PickValue }; nuclear@0: nuclear@0: template nuclear@0: class Pickable nuclear@0: { nuclear@0: public: nuclear@0: Pickable() : pV(NULL) {} nuclear@0: explicit Pickable(T* p) : pV(p) {} nuclear@0: Pickable(T* p, PickType) : pV(p) nuclear@0: { nuclear@0: OVR_ASSERT(pV); nuclear@0: if (pV) nuclear@0: pV->AddRef(); nuclear@0: } nuclear@0: template nuclear@0: Pickable(const Pickable& other) : pV(other.GetPtr()) {} nuclear@0: nuclear@0: public: nuclear@0: Pickable& operator =(const Pickable& other) nuclear@0: { nuclear@0: OVR_ASSERT(pV == NULL); nuclear@0: pV = other.pV; nuclear@0: // Extra check. nuclear@0: //other.pV = NULL; nuclear@0: return *this; nuclear@0: } nuclear@0: nuclear@0: public: nuclear@0: T* GetPtr() const { return pV; } nuclear@0: T* operator->() const nuclear@0: { nuclear@0: return pV; nuclear@0: } nuclear@0: T& operator*() const nuclear@0: { nuclear@0: OVR_ASSERT(pV); nuclear@0: return *pV; nuclear@0: } nuclear@0: nuclear@0: private: nuclear@0: T* pV; nuclear@0: }; nuclear@0: nuclear@0: template nuclear@0: OVR_FORCE_INLINE nuclear@0: Pickable MakePickable(T* p) nuclear@0: { nuclear@0: return Pickable(p); nuclear@0: } nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** Ref-Counted template pointer nuclear@0: nuclear@0: // Automatically AddRefs and Releases interfaces nuclear@0: nuclear@0: void* ReturnArg0(void* p); nuclear@0: nuclear@0: template nuclear@0: class Ptr nuclear@0: { nuclear@0: #ifdef OVR_CC_ARM nuclear@0: static C* ReturnArg(void* p) { return (C*)ReturnArg0(p); } nuclear@0: #endif nuclear@0: nuclear@0: protected: nuclear@0: C *pObject; nuclear@0: nuclear@0: public: nuclear@0: nuclear@0: // Constructors nuclear@0: OVR_FORCE_INLINE Ptr() : pObject(0) nuclear@0: { } nuclear@0: #ifdef OVR_CC_ARM nuclear@0: OVR_FORCE_INLINE Ptr(C &robj) : pObject(ReturnArg(&robj)) nuclear@0: #else nuclear@0: OVR_FORCE_INLINE Ptr(C &robj) : pObject(&robj) nuclear@0: #endif nuclear@0: { } nuclear@0: OVR_FORCE_INLINE Ptr(Pickable v) : pObject(v.GetPtr()) nuclear@0: { nuclear@0: // No AddRef() on purpose. nuclear@0: } nuclear@0: OVR_FORCE_INLINE Ptr(Ptr& other, PickType) : pObject(other.pObject) nuclear@0: { nuclear@0: other.pObject = NULL; nuclear@0: // No AddRef() on purpose. nuclear@0: } nuclear@0: OVR_FORCE_INLINE Ptr(C *pobj) nuclear@0: { nuclear@0: if (pobj) pobj->AddRef(); nuclear@0: pObject = pobj; nuclear@0: } nuclear@0: OVR_FORCE_INLINE Ptr(const Ptr &src) nuclear@0: { nuclear@0: if (src.pObject) src.pObject->AddRef(); nuclear@0: pObject = src.pObject; nuclear@0: } nuclear@0: nuclear@0: template nuclear@0: OVR_FORCE_INLINE Ptr(Ptr &src) nuclear@0: { nuclear@0: if (src) src->AddRef(); nuclear@0: pObject = src; nuclear@0: } nuclear@0: template nuclear@0: OVR_FORCE_INLINE Ptr(Pickable v) : pObject(v.GetPtr()) nuclear@0: { nuclear@0: // No AddRef() on purpose. nuclear@0: } nuclear@0: nuclear@0: // Destructor nuclear@0: OVR_FORCE_INLINE ~Ptr() nuclear@0: { nuclear@0: if (pObject) pObject->Release(); nuclear@0: } nuclear@0: nuclear@0: // Compares nuclear@0: OVR_FORCE_INLINE bool operator == (const Ptr &other) const { return pObject == other.pObject; } nuclear@0: OVR_FORCE_INLINE bool operator != (const Ptr &other) const { return pObject != other.pObject; } nuclear@0: nuclear@0: OVR_FORCE_INLINE bool operator == (C *pother) const { return pObject == pother; } nuclear@0: OVR_FORCE_INLINE bool operator != (C *pother) const { return pObject != pother; } nuclear@0: nuclear@0: nuclear@0: OVR_FORCE_INLINE bool operator < (const Ptr &other) const { return pObject < other.pObject; } nuclear@0: nuclear@0: // Assignment nuclear@0: template nuclear@0: OVR_FORCE_INLINE const Ptr& operator = (const Ptr &src) nuclear@0: { nuclear@0: // By design we don't check for src == pObject, as we don't expect that to be the case the large majority of the time. nuclear@0: if (src) src->AddRef(); nuclear@0: if (pObject) pObject->Release(); nuclear@0: pObject = src; nuclear@0: return *this; nuclear@0: } nuclear@0: // Specialization nuclear@0: OVR_FORCE_INLINE const Ptr& operator = (const Ptr &src) nuclear@0: { nuclear@0: if (src) src->AddRef(); nuclear@0: if (pObject) pObject->Release(); nuclear@0: pObject = src; nuclear@0: return *this; nuclear@0: } nuclear@0: nuclear@0: OVR_FORCE_INLINE const Ptr& operator = (C *psrc) nuclear@0: { nuclear@0: if (psrc) psrc->AddRef(); nuclear@0: if (pObject) pObject->Release(); nuclear@0: pObject = psrc; nuclear@0: return *this; nuclear@0: } nuclear@0: OVR_FORCE_INLINE const Ptr& operator = (C &src) nuclear@0: { nuclear@0: if (pObject) pObject->Release(); nuclear@0: pObject = &src; nuclear@0: return *this; nuclear@0: } nuclear@0: OVR_FORCE_INLINE Ptr& operator = (Pickable src) nuclear@0: { nuclear@0: return Pick(src); nuclear@0: } nuclear@0: template nuclear@0: OVR_FORCE_INLINE Ptr& operator = (Pickable src) nuclear@0: { nuclear@0: return Pick(src); nuclear@0: } nuclear@0: nuclear@0: // Set Assignment nuclear@0: template nuclear@0: OVR_FORCE_INLINE Ptr& SetPtr(const Ptr &src) nuclear@0: { nuclear@0: if (src) src->AddRef(); nuclear@0: if (pObject) pObject->Release(); nuclear@0: pObject = src; nuclear@0: return *this; nuclear@0: } nuclear@0: // Specialization nuclear@0: OVR_FORCE_INLINE Ptr& SetPtr(const Ptr &src) nuclear@0: { nuclear@0: if (src) src->AddRef(); nuclear@0: if (pObject) pObject->Release(); nuclear@0: pObject = src; nuclear@0: return *this; nuclear@0: } nuclear@0: nuclear@0: OVR_FORCE_INLINE Ptr& SetPtr(C *psrc) nuclear@0: { nuclear@0: if (psrc) psrc->AddRef(); nuclear@0: if (pObject) pObject->Release(); nuclear@0: pObject = psrc; nuclear@0: return *this; nuclear@0: } nuclear@0: OVR_FORCE_INLINE Ptr& SetPtr(C &src) nuclear@0: { nuclear@0: if (pObject) pObject->Release(); nuclear@0: pObject = &src; nuclear@0: return *this; nuclear@0: } nuclear@0: OVR_FORCE_INLINE Ptr& SetPtr(Pickable src) nuclear@0: { nuclear@0: return Pick(src); nuclear@0: } nuclear@0: nuclear@0: // Nulls ref-counted pointer without decrement nuclear@0: OVR_FORCE_INLINE void NullWithoutRelease() nuclear@0: { nuclear@0: pObject = 0; nuclear@0: } nuclear@0: nuclear@0: // Clears the pointer to the object nuclear@0: OVR_FORCE_INLINE void Clear() nuclear@0: { nuclear@0: if (pObject) pObject->Release(); nuclear@0: pObject = 0; nuclear@0: } nuclear@0: nuclear@0: // Obtain pointer reference directly, for D3D interfaces nuclear@0: OVR_FORCE_INLINE C*& GetRawRef() { return pObject; } nuclear@0: nuclear@0: // Access Operators nuclear@0: OVR_FORCE_INLINE C* GetPtr() const { return pObject; } nuclear@0: OVR_FORCE_INLINE C& operator * () const { return *pObject; } nuclear@0: OVR_FORCE_INLINE C* operator -> () const { return pObject; } nuclear@0: // Conversion nuclear@0: OVR_FORCE_INLINE operator C* () const { return pObject; } nuclear@0: nuclear@0: // Pickers. nuclear@0: nuclear@0: // Pick a value. nuclear@0: OVR_FORCE_INLINE Ptr& Pick(Ptr& other) nuclear@0: { nuclear@0: if (&other != this) nuclear@0: { nuclear@0: if (pObject) pObject->Release(); nuclear@0: pObject = other.pObject; nuclear@0: other.pObject = 0; nuclear@0: } nuclear@0: nuclear@0: return *this; nuclear@0: } nuclear@0: nuclear@0: OVR_FORCE_INLINE Ptr& Pick(Pickable v) nuclear@0: { nuclear@0: if (v.GetPtr() != pObject) nuclear@0: { nuclear@0: if (pObject) pObject->Release(); nuclear@0: pObject = v.GetPtr(); nuclear@0: } nuclear@0: nuclear@0: return *this; nuclear@0: } nuclear@0: nuclear@0: template nuclear@0: OVR_FORCE_INLINE Ptr& Pick(Pickable v) nuclear@0: { nuclear@0: if (v.GetPtr() != pObject) nuclear@0: { nuclear@0: if (pObject) pObject->Release(); nuclear@0: pObject = v.GetPtr(); nuclear@0: } nuclear@0: nuclear@0: return *this; nuclear@0: } nuclear@0: nuclear@0: OVR_FORCE_INLINE Ptr& Pick(C* p) nuclear@0: { nuclear@0: if (p != pObject) nuclear@0: { nuclear@0: if (pObject) pObject->Release(); nuclear@0: pObject = p; nuclear@0: } nuclear@0: nuclear@0: return *this; nuclear@0: } nuclear@0: }; nuclear@0: nuclear@0: } // OVR nuclear@0: nuclear@0: #endif