MemoryRegulator.cxx

Go to the documentation of this file.
00001 // @(#)root/pyroot:$Id: MemoryRegulator.cxx 36609 2010-11-11 18:49:41Z wlav $
00002 // Author: Wim Lavrijsen, Apr 2004
00003 
00004 // Bindings
00005 #include "PyROOT.h"
00006 #include "MemoryRegulator.h"
00007 #include "ObjectProxy.h"
00008 
00009 // ROOT
00010 #include "TObject.h"
00011 #include "TClass.h"
00012 
00013 // Standard
00014 #include <assert.h>
00015 #include <string.h>
00016 #include <Riostream.h>
00017 
00018 
00019 //- static data --------------------------------------------------------------
00020 PyROOT::TMemoryRegulator::ObjectMap_t*  PyROOT::TMemoryRegulator::fgObjectTable  = 0;
00021 PyROOT::TMemoryRegulator::WeakRefMap_t* PyROOT::TMemoryRegulator::fgWeakRefTable = 0;
00022 
00023 
00024 namespace {
00025 
00026 // memory regulater callback for deletion of registered objects
00027    PyMethodDef methoddef_ = {
00028       const_cast< char* >( "TMemoryRegulator_internal_ObjectEraseCallback" ),
00029       (PyCFunction) PyROOT::TMemoryRegulator::ObjectEraseCallback,
00030       METH_O,
00031       NULL
00032    };
00033 
00034    PyObject* gObjectEraseCallback = PyCFunction_New( &methoddef_, NULL );
00035 
00036 
00037 // pseudo-None type for masking out objects on the python side
00038    PyTypeObject PyROOT_NoneType;
00039 
00040 //____________________________________________________________________________
00041    Py_ssize_t AlwaysNullLength( PyObject* )
00042    {
00043       return 0;
00044    }
00045 
00046 //____________________________________________________________________________
00047    PyMappingMethods PyROOT_NoneType_mapping = {
00048         AlwaysNullLength,
00049         (binaryfunc)             0,
00050         (objobjargproc)          0
00051    };
00052 
00053 //____________________________________________________________________________
00054    struct InitPyROOT_NoneType_t {
00055       InitPyROOT_NoneType_t()
00056       {
00057          memset( &PyROOT_NoneType, 0, sizeof( PyROOT_NoneType ) );
00058 
00059          ((PyObject&)PyROOT_NoneType).ob_type    = &PyType_Type;
00060          ((PyObject&)PyROOT_NoneType).ob_refcnt  = 1;
00061          ((PyVarObject&)PyROOT_NoneType).ob_size = 0;
00062 
00063          PyROOT_NoneType.tp_name        = const_cast< char* >( "PyROOT_NoneType" );
00064          PyROOT_NoneType.tp_flags       = Py_TPFLAGS_HAVE_RICHCOMPARE | Py_TPFLAGS_HAVE_GC;
00065 
00066          PyROOT_NoneType.tp_traverse    = (traverseproc) 0;
00067          PyROOT_NoneType.tp_clear       = (inquiry) 0;
00068          PyROOT_NoneType.tp_dealloc     = (destructor)  &InitPyROOT_NoneType_t::DeAlloc;
00069          PyROOT_NoneType.tp_repr        = Py_TYPE(Py_None)->tp_repr;
00070          PyROOT_NoneType.tp_richcompare = (richcmpfunc) &InitPyROOT_NoneType_t::RichCompare;
00071 #if PY_VERSION_HEX < 0x03000000
00072 // tp_compare has become tp_reserved (place holder only) in p3
00073          PyROOT_NoneType.tp_compare     = (cmpfunc) &InitPyROOT_NoneType_t::Compare;
00074 #endif
00075          PyROOT_NoneType.tp_hash        = (hashfunc) &InitPyROOT_NoneType_t::PtrHash;
00076 
00077          PyROOT_NoneType.tp_as_mapping  = &PyROOT_NoneType_mapping;
00078 
00079          PyType_Ready( &PyROOT_NoneType );
00080       }
00081 
00082       static void DeAlloc( PyObject* obj ) { Py_TYPE(obj)->tp_free( obj ); }
00083       static int PtrHash( PyObject* obj ) { return (int)Long_t(obj); }
00084 
00085       static PyObject* RichCompare( PyObject*, PyObject* other, int opid )
00086       {
00087          return PyObject_RichCompare( other, Py_None, opid );
00088       }
00089 
00090       static int Compare( PyObject*, PyObject* other )
00091       {
00092 #if PY_VERSION_HEX < 0x03000000
00093          return PyObject_Compare( other, Py_None );
00094 #else
00095 // TODO the following isn't correct as it doens't order, but will do for now ...
00096          return ! PyObject_RichCompareBool( other, Py_None, Py_EQ );
00097 #endif
00098       }
00099    };
00100 
00101 } // unnamed namespace
00102 
00103 
00104 //- ctor/dtor ----------------------------------------------------------------
00105 PyROOT::TMemoryRegulator::TMemoryRegulator()
00106 {
00107 // setup NoneType for referencing and create weakref cache
00108    static InitPyROOT_NoneType_t initPyROOT_NoneType;
00109 
00110    assert( fgObjectTable == 0 );
00111    fgObjectTable = new ObjectMap_t;
00112 
00113    assert( fgWeakRefTable == 0 );
00114    fgWeakRefTable = new WeakRefMap_t;
00115 }
00116 
00117 //____________________________________________________________________________
00118 PyROOT::TMemoryRegulator::~TMemoryRegulator()
00119 {
00120 // cleanup weakref cache
00121    delete fgWeakRefTable;
00122    fgWeakRefTable = 0;
00123 
00124    delete fgObjectTable;
00125    fgObjectTable = 0;
00126 }
00127 
00128 
00129 //- public members -----------------------------------------------------------
00130 void PyROOT::TMemoryRegulator::RecursiveRemove( TObject* object )
00131 {
00132 // called whenever a TObject gets destroyed
00133    if ( ! object || ! fgObjectTable )   // table can be deleted before libCore is done
00134       return;
00135 
00136 // see whether we're tracking this object
00137    ObjectMap_t::iterator ppo = fgObjectTable->find( object );
00138 
00139    if ( ppo != fgObjectTable->end() ) {
00140       fgWeakRefTable->erase( fgWeakRefTable->find( ppo->second ) );
00141  
00142    // get the tracked object
00143       ObjectProxy* pyobj = (ObjectProxy*)PyWeakref_GetObject( ppo->second );
00144       if ( ! pyobj ) {
00145          fgObjectTable->erase( ppo );
00146          return;
00147       }
00148 
00149    // clean up the weak reference.
00150       Py_DECREF( ppo->second );
00151 
00152    // nullify the object
00153       if ( ObjectProxy_Check( pyobj ) ) {
00154          if ( ! PyROOT_NoneType.tp_traverse ) {
00155          // take a reference as we're copying its function pointers
00156             Py_INCREF( Py_TYPE(pyobj) );
00157 
00158          // all object that arrive here are expected to be of the same type ("instance")
00159             PyROOT_NoneType.tp_traverse   = Py_TYPE(pyobj)->tp_traverse;
00160             PyROOT_NoneType.tp_clear      = Py_TYPE(pyobj)->tp_clear;
00161             PyROOT_NoneType.tp_free       = Py_TYPE(pyobj)->tp_free;
00162          } else if ( PyROOT_NoneType.tp_traverse != Py_TYPE(pyobj)->tp_traverse ) {
00163             std::cerr << "in PyROOT::TMemoryRegulater, unexpected object of type: "
00164                       << Py_TYPE(pyobj)->tp_name << std::endl;
00165 
00166          // leave before too much damage is done
00167             return;
00168          }
00169 
00170       // notify any other weak referents by playing dead
00171          int refcnt = ((PyObject*)pyobj)->ob_refcnt;
00172          ((PyObject*)pyobj)->ob_refcnt = 0;
00173          PyObject_ClearWeakRefs( (PyObject*)pyobj );
00174          ((PyObject*)pyobj)->ob_refcnt = refcnt;
00175 
00176       // cleanup object internals
00177          pyobj->Release();              // held object is out of scope now anyway
00178          op_dealloc_nofree( pyobj );    // normal object cleanup, while keeping memory
00179 
00180       // reset type object
00181          Py_INCREF( (PyObject*)(void*)&PyROOT_NoneType );
00182          Py_DECREF( Py_TYPE(pyobj) );
00183          ((PyObject*)pyobj)->ob_type = &PyROOT_NoneType;
00184       }
00185 
00186    // erase the object from tracking (weakref table already cleared, above)
00187       fgObjectTable->erase( ppo );
00188    }
00189 }
00190 
00191 //____________________________________________________________________________
00192 Bool_t PyROOT::TMemoryRegulator::RegisterObject( ObjectProxy* pyobj, TObject* object )
00193 {
00194 // start tracking <object> proxied by <pyobj>
00195    if ( ! ( pyobj && object ) )
00196       return kFALSE;
00197 
00198    ObjectMap_t::iterator ppo = fgObjectTable->find( object );
00199    if ( ppo == fgObjectTable->end() ) {
00200       object->SetBit( TObject::kMustCleanup );
00201       PyObject* pyref = PyWeakref_NewRef( (PyObject*)pyobj, gObjectEraseCallback );
00202       ObjectMap_t::iterator newppo = fgObjectTable->insert( std::make_pair( object, pyref ) ).first;
00203       (*fgWeakRefTable)[ pyref ] = newppo;  // no Py_INCREF on pyref, as object table has one
00204       return kTRUE;
00205    }
00206 
00207    return kFALSE;
00208 }
00209 
00210 //____________________________________________________________________________
00211 Bool_t PyROOT::TMemoryRegulator::UnregisterObject( TObject* object )
00212 {
00213 // stop tracking <object>, without notification
00214    ObjectMap_t::iterator ppo = fgObjectTable->find( object );
00215 
00216    if ( ppo != fgObjectTable->end() ) {
00217       fgWeakRefTable->erase( fgWeakRefTable->find( ppo->second ) );
00218       fgObjectTable->erase( ppo );
00219       return kTRUE;
00220    }
00221 
00222    return kFALSE;
00223 }
00224 
00225 //____________________________________________________________________________
00226 PyObject* PyROOT::TMemoryRegulator::RetrieveObject( TObject* object )
00227 {
00228 // lookup <object>, return old proxy if tracked
00229    if ( ! object )
00230       return 0;
00231 
00232    ObjectMap_t::iterator ppo = fgObjectTable->find( object );
00233    if ( ppo != fgObjectTable->end() ) {
00234       PyObject* pyobj = PyWeakref_GetObject( ppo->second );
00235       Py_XINCREF( pyobj );
00236       return pyobj;
00237    }
00238 
00239    return 0;
00240 }
00241 
00242 
00243 //- private static members ------------------------------------------------------
00244 PyObject* PyROOT::TMemoryRegulator::ObjectEraseCallback( PyObject*, PyObject* pyref )
00245 {
00246 // called when one of the python objects we've registered is going away
00247    ObjectProxy* pyobj = (ObjectProxy*)PyWeakref_GetObject( pyref );
00248 
00249    if ( ObjectProxy_Check( pyobj ) && pyobj->GetObject() != 0 ) {
00250    // get TObject pointer to the object
00251       TObject* object = (TObject*)pyobj->ObjectIsA()->DynamicCast(
00252          TObject::Class(), pyobj->GetObject() );
00253 
00254       if ( object != 0 ) {
00255       // erase if tracked
00256          ObjectMap_t::iterator ppo = fgObjectTable->find( object );
00257          if ( ppo != fgObjectTable->end() ) {
00258          // cleanup table entries and weak reference
00259             fgWeakRefTable->erase( fgWeakRefTable->find( ppo->second ) );
00260             Py_DECREF( ppo->second );
00261             fgObjectTable->erase( ppo );
00262          }
00263       }
00264    } else {
00265    // object already dead; need to clean up the weak ref from the table
00266       WeakRefMap_t::iterator wri = fgWeakRefTable->find( pyref );
00267       if ( wri != fgWeakRefTable->end() ) {
00268          fgObjectTable->erase( wri->second );
00269          fgWeakRefTable->erase( wri );
00270          Py_DECREF( pyref );
00271       }
00272    }
00273 
00274    Py_INCREF( Py_None );
00275    return Py_None;
00276 }

Generated on Tue Jul 5 14:10:12 2011 for ROOT_528-00b_version by  doxygen 1.5.1