/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * * All use of this software is subject to the terms of the revised BSD * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * * @file copyOnWriteObject.h * @author drose * @date 2007-04-09 */ #ifndef COPYONWRITEOBJECT_H #define COPYONWRITEOBJECT_H #include "pandabase.h" #include "cachedTypedWritableReferenceCount.h" #include "pmutex.h" #include "conditionVar.h" #include "mutexHolder.h" // Should we implement full thread protection for CopyOnWritePointer? If we // can be assured that no other thread will interrupt while a write pointer is // held, we don't need thread protection. // Nowadays, this is the same thing as asking if HAVE_THREADS is defined. // Maybe we'll just replace COW_THREADED with HAVE_THREADS in the future. #ifdef HAVE_THREADS #define COW_THREADED 1 #else #undef COW_THREADED #endif /** * This base class provides basic reference counting, but also can be used * with a CopyOnWritePointer to provide get_read_pointer() and * get_write_pointer(). */ class EXPCL_PANDA_PUTIL CopyOnWriteObject : public CachedTypedWritableReferenceCount { public: INLINE CopyOnWriteObject(); INLINE CopyOnWriteObject(const CopyOnWriteObject ©); INLINE void operator = (const CopyOnWriteObject ©); PUBLISHED: #ifdef COW_THREADED virtual bool unref() const; INLINE void cache_ref() const; INLINE bool cache_unref() const; public: void cache_ref_only() const; #endif // COW_THREADED protected: virtual PT(CopyOnWriteObject) make_cow_copy()=0; private: #ifdef COW_THREADED enum LockStatus { LS_unlocked, LS_locked_read, LS_locked_write, }; Mutex _lock_mutex; ConditionVar _lock_cvar; LockStatus _lock_status; Thread *_locking_thread; #endif // COW_THREADED public: virtual TypeHandle get_type() const { return get_class_type(); } virtual TypeHandle force_init_type() {init_type(); return get_class_type();} PUBLISHED: static TypeHandle get_class_type() { return _type_handle; } public: static void init_type() { CachedTypedWritableReferenceCount::init_type(); register_type(_type_handle, "CopyOnWriteObject", CachedTypedWritableReferenceCount::get_class_type()); } private: static TypeHandle _type_handle; friend class CopyOnWritePointer; }; /** * This is similar to RefCountObj, but it implements a CopyOnWriteObject * inheritance instead of a ReferenceCount inheritance. */ template class CopyOnWriteObj : public CopyOnWriteObject, public Base { public: INLINE CopyOnWriteObj(); INLINE CopyOnWriteObj(const Base ©); INLINE CopyOnWriteObj(const CopyOnWriteObj ©); ALLOC_DELETED_CHAIN(CopyOnWriteObj); protected: virtual PT(CopyOnWriteObject) make_cow_copy(); public: virtual TypeHandle get_type() const { return get_class_type(); } virtual TypeHandle force_init_type() {init_type(); return get_class_type();} PUBLISHED: static TypeHandle get_class_type() { return _type_handle; } public: static void init_type(); private: static TypeHandle _type_handle; }; /** * For objects (e.g. pvectors) whose constructor takes a single parameter. */ template class CopyOnWriteObj1 : public CopyOnWriteObject, public Base { public: INLINE CopyOnWriteObj1(Param1 p1); INLINE CopyOnWriteObj1(const Base ©); INLINE CopyOnWriteObj1(const CopyOnWriteObj1 ©); typedef CopyOnWriteObj1 ThisClass; ALLOC_DELETED_CHAIN(ThisClass) protected: virtual PT(CopyOnWriteObject) make_cow_copy(); public: virtual TypeHandle get_type() const { return get_class_type(); } virtual TypeHandle force_init_type() {init_type(); return get_class_type();} PUBLISHED: static TypeHandle get_class_type() { return _type_handle; } public: static void init_type(); private: static TypeHandle _type_handle; }; // We can safely redefine this as a no-op. template<> INLINE void PointerToBase::update_type(To *ptr) {} #include "copyOnWriteObject.I" #endif