From 579f564ce490566d0462bc2138a4beefa7747b7e Mon Sep 17 00:00:00 2001 From: Thomas Grill Date: Wed, 23 Feb 2005 04:57:19 +0000 Subject: better cleanup behavior (shutdown hook method _del and garbage collection) - garbage collection at module scope update for flext build system - better handling of bang messages fixes for single-threaded compilation little restructuring svn path=/trunk/; revision=2573 --- externals/grill/py/readme.txt | 3 +-- externals/grill/py/source/main.cpp | 23 ++++++++++++++++++++ externals/grill/py/source/main.h | 12 +++++------ externals/grill/py/source/pyext.cpp | 42 +++++++++++++++---------------------- 4 files changed, 47 insertions(+), 33 deletions(-) diff --git a/externals/grill/py/readme.txt b/externals/grill/py/readme.txt index a39f529e..1aa18022 100644 --- a/externals/grill/py/readme.txt +++ b/externals/grill/py/readme.txt @@ -81,6 +81,7 @@ Version history: - FIX: __init__ wasn't called on reload - FIX: bound instance methods weren't correctly decref'd - ADD: Python symbol type +- ADD: _del method in pyext-derived class can be used to clean up things on exit 0.1.4: - ADD: better (and independent) handling of inlet and outlet count (as class variables or dynamically initialized in __init__) @@ -152,7 +153,5 @@ features: - stop individual threads - support named (keyword) arguments (like attributes for messages) -- shutdown hook for threaded Python apps - tests: - check for python threading support diff --git a/externals/grill/py/source/main.cpp b/externals/grill/py/source/main.cpp index 89696b46..bf7345d5 100644 --- a/externals/grill/py/source/main.cpp +++ b/externals/grill/py/source/main.cpp @@ -17,6 +17,7 @@ static PyMethodDef StdOut_Methods[] = { NULL, NULL, } }; +static PyObject *gcollect = NULL; #ifdef FLEXT_THREADS @@ -119,6 +120,13 @@ void py::lib_setup() py_out = Py_InitModule("stderr", StdOut_Methods); PySys_SetObject("stderr", py_out); + // get garbage collector function + PyObject *gcobj = PyImport_ImportModule("gc"); + if(gcobj) { + gcollect = PyObject_GetAttrString(gcobj,"collect"); + Py_DECREF(gcobj); + } + // ------------------------------------------------------------- FLEXT_SETUP(pyobj); @@ -548,6 +556,21 @@ short py::patcher_myvol(t_patcher *x) } #endif +void py::collect() +{ + if(gcollect) { + PyObject *args = PyTuple_New(0); + PyObject *ret = PyObject_Call(gcollect,args,NULL); + Py_DECREF(args); + if(ret) { +#ifdef FLEXT_DEBUG + int refs = PyInt_AsLong(ret); + if(refs) post("py/pyext - Garbage collector reports %i unreachable objects",refs); +#endif + Py_DECREF(ret); + } + } +} Fifo::~Fifo() { diff --git a/externals/grill/py/source/main.h b/externals/grill/py/source/main.h index 8671a87f..621c9eff 100644 --- a/externals/grill/py/source/main.h +++ b/externals/grill/py/source/main.h @@ -90,7 +90,7 @@ protected: void Respond(bool b); - static bool IsAnything(const t_symbol *s) { return s && s != sym_bang && s != sym_float && s != sym_int && s != sym_symbol && s != sym_list && s != sym_pointer; } + static bool IsAnything(const t_symbol *s) { return s && s != sym_float && s != sym_int && s != sym_symbol && s != sym_list && s != sym_pointer; } enum retval { nothing,atom,sequ }; @@ -132,6 +132,8 @@ protected: static short patcher_myvol(t_patcher *x); #endif + static void collect(); + private: void work_wrapper(void *data); @@ -142,16 +144,14 @@ private: Fifo qufifo; ThrCond qucond; + static PyThreadState *FindThreadState(); + static void FreeThreadState(); + FLEXT_THREAD_X(work_wrapper) #else FLEXT_CALLBACK_X(work_wrapper) #endif -#ifdef FLEXT_THREADS - static PyThreadState *FindThreadState(); - static void FreeThreadState(); -#endif - public: #ifdef FLEXT_THREADS diff --git a/externals/grill/py/source/pyext.cpp b/externals/grill/py/source/pyext.cpp index 4acafd60..de208aac 100644 --- a/externals/grill/py/source/pyext.cpp +++ b/externals/grill/py/source/pyext.cpp @@ -225,28 +225,26 @@ void pyext::DoExit() { ClearBinding(); + bool gcrun = false; if(pyobj) { - if(pyobj->ob_refcnt > 1) { - post("%s - Python object is still referenced",thisName()); - - // Force-quit object: - // call __del__ manually - // this is dangerous, because it could get called a second time - // if object really has no more references then - PyObject *meth = PyObject_GetAttrString(pyobj,"__del__"); // get ref - if(meth) { - if(PyMethod_Check(meth)) { - PyObject *res = PyObject_CallObject(meth,NULL); - if(!res) - PyErr_Print(); - else - Py_DECREF(res); - } - Py_DECREF(meth); - } + // try to run del to clean up the class instance + PyObject *objdel = PyObject_GetAttrString(pyobj,"_del"); + if(objdel) { + PyObject *args = PyTuple_New(0); + PyObject *ret = PyObject_Call(objdel,args,NULL); + if(!ret) + post("%s - Could not call _del method",thisName()); + else + Py_DECREF(ret); + Py_DECREF(args); + Py_DECREF(objdel); } + + gcrun = pyobj->ob_refcnt > 1; Py_DECREF(pyobj); // opposite of SetClssMeth } + + if(gcrun) collect(); } void pyext::InitInOut(int &inl,int &outl) @@ -542,13 +540,7 @@ bool pyext::work(int n,const t_symbol *s,int argc,const t_atom *argv) // try anything/inlet if(!ret) { sprintf(str,"_anything_%i",n); - if(s == sym_bang && !argc) { - t_atom argv; - SetSymbol(argv,sym__); - ret = call(str,0,s,1,&argv); - } - else - ret = call(str,0,s,argc,argv); + ret = call(str,0,s,argc,argv); } // try int at any inlet -- cgit v1.2.1