Panda3D
 All Classes Functions Variables Enumerations
copyOnWritePointer.cxx
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
 All Classes Functions Variables Enumerations