diff --git a/panda/src/putil/copyOnWriteObject.I b/panda/src/putil/copyOnWriteObject.I index 3ad239c47a..ee0d5a01b7 100644 --- a/panda/src/putil/copyOnWriteObject.I +++ b/panda/src/putil/copyOnWriteObject.I @@ -83,6 +83,17 @@ cache_ref() const { MutexHolder holder(_lock_mutex); CachedTypedWritableReferenceCount::cache_ref(); } + +//////////////////////////////////////////////////////////////////// +// Function: CopyOnWriteObject::cache_unref +// Access: Published +// Description: See CachedTypedWritableReferenceCount::cache_unref(). +//////////////////////////////////////////////////////////////////// +INLINE bool CopyOnWriteObject:: +cache_unref() const { + MutexHolder holder(_lock_mutex); + return CachedTypedWritableReferenceCount::cache_unref(); +} #endif // COW_THREADED //////////////////////////////////////////////////////////////////// diff --git a/panda/src/putil/copyOnWriteObject.h b/panda/src/putil/copyOnWriteObject.h index e7d1ca7be9..633bbfc08a 100644 --- a/panda/src/putil/copyOnWriteObject.h +++ b/panda/src/putil/copyOnWriteObject.h @@ -51,6 +51,7 @@ PUBLISHED: #ifdef COW_THREADED virtual bool unref() const; INLINE void cache_ref() const; + INLINE bool cache_unref() const; #endif // COW_THREADED protected: diff --git a/panda/src/putil/copyOnWritePointer.cxx b/panda/src/putil/copyOnWritePointer.cxx index 38ba2d63a5..c323cb76c0 100644 --- a/panda/src/putil/copyOnWritePointer.cxx +++ b/panda/src/putil/copyOnWritePointer.cxx @@ -13,7 +13,6 @@ //////////////////////////////////////////////////////////////////// #include "copyOnWritePointer.h" -#include "mutexHolder.h" #include "config_util.h" #include "config_pipeline.h" @@ -78,7 +77,7 @@ get_write_pointer() { Thread *current_thread = Thread::get_current_thread(); - MutexHolder holder(_cow_object->_lock_mutex); + _cow_object->_lock_mutex.acquire(); while (_cow_object->_lock_status == CopyOnWriteObject::LS_locked_write && _cow_object->_locking_thread != current_thread) { if (util_cat.is_debug()) { @@ -98,10 +97,20 @@ get_write_pointer() { << "Making copy of " << _cow_object->get_type() << " because it is locked in read mode.\n"; } + PT(CopyOnWriteObject) new_object = _cow_object->make_cow_copy(); - cache_unref_delete(_cow_object); + + // We can't call cache_unref_delete, because we hold the lock. + if (!_cow_object->CachedTypedWritableReferenceCount::cache_unref()) { + _cow_object->_lock_mutex.release(); + delete _cow_object; + } else { + _cow_object->_lock_mutex.release(); + } _cow_object = new_object; _cow_object->cache_ref(); + _cow_object->_lock_status = CopyOnWriteObject::LS_locked_write; + _cow_object->_locking_thread = current_thread; } else if (_cow_object->get_cache_ref_count() > 1) { // No one else has it specifically read-locked, but there are @@ -115,9 +124,18 @@ get_write_pointer() { } PT(CopyOnWriteObject) new_object = _cow_object->make_cow_copy(); - cache_unref_delete(_cow_object); + + // We can't call cache_unref_delete, because we hold the lock. + if (!_cow_object->CachedTypedWritableReferenceCount::cache_unref()) { + _cow_object->_lock_mutex.release(); + delete _cow_object; + } else { + _cow_object->_lock_mutex.release(); + } _cow_object = new_object; _cow_object->cache_ref(); + _cow_object->_lock_status = CopyOnWriteObject::LS_locked_write; + _cow_object->_locking_thread = current_thread; } else { // No other thread has the pointer locked, and we're the only @@ -127,9 +145,10 @@ get_write_pointer() { // We can't assert that there are no outstanding ordinary // references to it, though, since the creator of the object might // have saved himself a reference. + _cow_object->_lock_status = CopyOnWriteObject::LS_locked_write; + _cow_object->_locking_thread = current_thread; + _cow_object->_lock_mutex.release(); } - _cow_object->_lock_status = CopyOnWriteObject::LS_locked_write; - _cow_object->_locking_thread = current_thread; return _cow_object; }