Panda3D
|
00001 // Filename: copyOnWritePointer.cxx 00002 // Created by: drose (09Apr07) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "copyOnWritePointer.h" 00016 #include "mutexHolder.h" 00017 #include "config_util.h" 00018 #include "config_pipeline.h" 00019 00020 #ifdef COW_THREADED 00021 //////////////////////////////////////////////////////////////////// 00022 // Function: CopyOnWritePointer::get_read_pointer 00023 // Access: Public 00024 // Description: Returns a pointer locked for read. Until this 00025 // pointer dereferences, calls to get_write_pointer() 00026 // will force a copy. 00027 // 00028 // This flavor of the method is written for the threaded 00029 // case. 00030 //////////////////////////////////////////////////////////////////// 00031 CPT(CopyOnWriteObject) CopyOnWritePointer:: 00032 get_read_pointer() const { 00033 if (_object == (CopyOnWriteObject *)NULL) { 00034 return NULL; 00035 } 00036 00037 Thread *current_thread = Thread::get_current_thread(); 00038 00039 MutexHolder holder(_object->_lock_mutex); 00040 while (_object->_lock_status == CopyOnWriteObject::LS_locked_write) { 00041 if (_object->_locking_thread == current_thread) { 00042 return _object; 00043 } 00044 if (util_cat.is_debug()) { 00045 util_cat.debug() 00046 << *current_thread << " waiting on " << _object->get_type() 00047 << " " << _object << ", held by " << *_object->_locking_thread 00048 << "\n"; 00049 } 00050 _object->_lock_cvar.wait(); 00051 } 00052 00053 _object->_lock_status = CopyOnWriteObject::LS_locked_read; 00054 _object->_locking_thread = current_thread; 00055 return _object; 00056 } 00057 #endif // COW_THREADED 00058 00059 #ifdef COW_THREADED 00060 //////////////////////////////////////////////////////////////////// 00061 // Function: CopyOnWritePointer::get_write_pointer 00062 // Access: Public 00063 // Description: Returns a pointer locked for write. If another 00064 // thread or threads already hold the pointer locked for 00065 // read, then this will force a copy. 00066 // 00067 // Until this pointer dereferences, calls to 00068 // get_read_pointer() or get_write_pointer() will block. 00069 // 00070 // This flavor of the method is written for the threaded 00071 // case. 00072 //////////////////////////////////////////////////////////////////// 00073 PT(CopyOnWriteObject) CopyOnWritePointer:: 00074 get_write_pointer() { 00075 if (_object == (CopyOnWriteObject *)NULL) { 00076 return NULL; 00077 } 00078 00079 Thread *current_thread = Thread::get_current_thread(); 00080 00081 MutexHolder holder(_object->_lock_mutex); 00082 while (_object->_lock_status == CopyOnWriteObject::LS_locked_write && 00083 _object->_locking_thread != current_thread) { 00084 if (util_cat.is_debug()) { 00085 util_cat.debug() 00086 << *current_thread << " waiting on " << _object->get_type() 00087 << " " << _object << ", held by " << *_object->_locking_thread 00088 << "\n"; 00089 } 00090 _object->_lock_cvar.wait(); 00091 } 00092 00093 if (_object->_lock_status == CopyOnWriteObject::LS_locked_read) { 00094 nassertr(_object->get_ref_count() > _object->get_cache_ref_count(), NULL); 00095 00096 if (util_cat.is_debug()) { 00097 util_cat.debug() 00098 << "Making copy of " << _object->get_type() 00099 << " because it is locked in read mode.\n"; 00100 } 00101 PT(CopyOnWriteObject) new_object = _object->make_cow_copy(); 00102 cache_unref_delete(_object); 00103 _object = new_object; 00104 _object->cache_ref(); 00105 00106 } else if (_object->get_cache_ref_count() > 1) { 00107 // No one else has it specifically read-locked, but there are 00108 // other CopyOnWritePointers holding the same object, so we should 00109 // make our own writable copy anyway. 00110 if (util_cat.is_debug()) { 00111 util_cat.debug() 00112 << "Making copy of " << _object->get_type() 00113 << " because it is shared by " << _object->get_ref_count() 00114 << " pointers.\n"; 00115 } 00116 00117 PT(CopyOnWriteObject) new_object = _object->make_cow_copy(); 00118 cache_unref_delete(_object); 00119 _object = new_object; 00120 _object->cache_ref(); 00121 00122 } else { 00123 // No other thread has the pointer locked, and we're the only 00124 // CopyOnWritePointer with this object. We can safely write to it 00125 // without making a copy. 00126 00127 // We can't assert that there are no outstanding ordinary 00128 // references to it, though, since the creator of the object might 00129 // have saved himself a reference. 00130 } 00131 _object->_lock_status = CopyOnWriteObject::LS_locked_write; 00132 _object->_locking_thread = current_thread; 00133 00134 return _object; 00135 } 00136 #endif // COW_THREADED