00001
00002
00003
00004
00005 #include "PyROOT.h"
00006 #include "MemoryRegulator.h"
00007 #include "ObjectProxy.h"
00008
00009
00010 #include "TObject.h"
00011 #include "TClass.h"
00012
00013
00014 #include <assert.h>
00015 #include <string.h>
00016 #include <Riostream.h>
00017
00018
00019
00020 PyROOT::TMemoryRegulator::ObjectMap_t* PyROOT::TMemoryRegulator::fgObjectTable = 0;
00021 PyROOT::TMemoryRegulator::WeakRefMap_t* PyROOT::TMemoryRegulator::fgWeakRefTable = 0;
00022
00023
00024 namespace {
00025
00026
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
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
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
00096 return ! PyObject_RichCompareBool( other, Py_None, Py_EQ );
00097 #endif
00098 }
00099 };
00100
00101 }
00102
00103
00104
00105 PyROOT::TMemoryRegulator::TMemoryRegulator()
00106 {
00107
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
00121 delete fgWeakRefTable;
00122 fgWeakRefTable = 0;
00123
00124 delete fgObjectTable;
00125 fgObjectTable = 0;
00126 }
00127
00128
00129
00130 void PyROOT::TMemoryRegulator::RecursiveRemove( TObject* object )
00131 {
00132
00133 if ( ! object || ! fgObjectTable )
00134 return;
00135
00136
00137 ObjectMap_t::iterator ppo = fgObjectTable->find( object );
00138
00139 if ( ppo != fgObjectTable->end() ) {
00140 fgWeakRefTable->erase( fgWeakRefTable->find( ppo->second ) );
00141
00142
00143 ObjectProxy* pyobj = (ObjectProxy*)PyWeakref_GetObject( ppo->second );
00144 if ( ! pyobj ) {
00145 fgObjectTable->erase( ppo );
00146 return;
00147 }
00148
00149
00150 Py_DECREF( ppo->second );
00151
00152
00153 if ( ObjectProxy_Check( pyobj ) ) {
00154 if ( ! PyROOT_NoneType.tp_traverse ) {
00155
00156 Py_INCREF( Py_TYPE(pyobj) );
00157
00158
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
00167 return;
00168 }
00169
00170
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
00177 pyobj->Release();
00178 op_dealloc_nofree( pyobj );
00179
00180
00181 Py_INCREF( (PyObject*)(void*)&PyROOT_NoneType );
00182 Py_DECREF( Py_TYPE(pyobj) );
00183 ((PyObject*)pyobj)->ob_type = &PyROOT_NoneType;
00184 }
00185
00186
00187 fgObjectTable->erase( ppo );
00188 }
00189 }
00190
00191
00192 Bool_t PyROOT::TMemoryRegulator::RegisterObject( ObjectProxy* pyobj, TObject* object )
00193 {
00194
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;
00204 return kTRUE;
00205 }
00206
00207 return kFALSE;
00208 }
00209
00210
00211 Bool_t PyROOT::TMemoryRegulator::UnregisterObject( TObject* object )
00212 {
00213
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
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
00244 PyObject* PyROOT::TMemoryRegulator::ObjectEraseCallback( PyObject*, PyObject* pyref )
00245 {
00246
00247 ObjectProxy* pyobj = (ObjectProxy*)PyWeakref_GetObject( pyref );
00248
00249 if ( ObjectProxy_Check( pyobj ) && pyobj->GetObject() != 0 ) {
00250
00251 TObject* object = (TObject*)pyobj->ObjectIsA()->DynamicCast(
00252 TObject::Class(), pyobj->GetObject() );
00253
00254 if ( object != 0 ) {
00255
00256 ObjectMap_t::iterator ppo = fgObjectTable->find( object );
00257 if ( ppo != fgObjectTable->end() ) {
00258
00259 fgWeakRefTable->erase( fgWeakRefTable->find( ppo->second ) );
00260 Py_DECREF( ppo->second );
00261 fgObjectTable->erase( ppo );
00262 }
00263 }
00264 } else {
00265
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 }