diff --git a/src/pya/pya/pya.cc b/src/pya/pya/pya.cc index 5f177fa56..0de6ea55c 100644 --- a/src/pya/pya/pya.cc +++ b/src/pya/pya/pya.cc @@ -360,6 +360,10 @@ PythonInterpreter::PythonInterpreter (bool embedded) PythonInterpreter::~PythonInterpreter () { + for (auto m = m_modules.begin (); m != m_modules.end (); ++m) { + (*m)->cleanup (); + } + m_stdout_channel = PythonRef (); m_stderr_channel = PythonRef (); m_stdout = PythonPtr (); @@ -370,6 +374,23 @@ PythonInterpreter::~PythonInterpreter () if (m_embedded) { Py_Finalize (); } + + for (auto m = m_modules.begin (); m != m_modules.end (); ++m) { + delete *m; + } + m_modules.clear (); +} + +void +PythonInterpreter::register_module (pya::PythonModule *module) +{ + for (auto m = m_modules.begin (); m != m_modules.end (); ++m) { + if (*m == module) { + return; // already registered + } + } + + m_modules.push_back (module); } char * diff --git a/src/pya/pya/pya.h b/src/pya/pya/pya.h index ee8d35381..76838f4f0 100644 --- a/src/pya/pya/pya.h +++ b/src/pya/pya/pya.h @@ -105,6 +105,14 @@ class PYA_PUBLIC PythonInterpreter */ ~PythonInterpreter (); + /** + * @brief Registers a module + * + * The registered modules are cleaned up before the interpreter shuts down. The interpreter takes + * ownership of the module object. + */ + void register_module (pya::PythonModule *module); + /** * @brief Add the given path to the search path */ @@ -279,7 +287,7 @@ class PYA_PUBLIC PythonInterpreter std::map m_file_id_map; std::wstring mp_py3_app_name; bool m_embedded; - std::unique_ptr m_pya_module; + std::vector m_modules; }; } diff --git a/src/pya/pya/pyaCallables.cc b/src/pya/pya/pyaCallables.cc index 5dfc3e4f1..d12ea6905 100644 --- a/src/pya/pya/pyaCallables.cc +++ b/src/pya/pya/pyaCallables.cc @@ -51,6 +51,9 @@ pya_object_deallocate (PyObject *self) // we better work around it. ++self->ob_refcnt; + // Mute Python warnings in debug case + PyObject_GC_UnTrack (self); + PYAObjectBase *p = PYAObjectBase::from_pyobject (self); p->~PYAObjectBase (); Py_TYPE (self)->tp_free (self); diff --git a/src/pya/pya/pyaModule.cc b/src/pya/pya/pyaModule.cc index 30452d669..62e6bacde 100644 --- a/src/pya/pya/pyaModule.cc +++ b/src/pya/pya/pyaModule.cc @@ -71,12 +71,6 @@ PythonModule::PythonModule () PythonModule::~PythonModule () { - PYAObjectBase::clear_callbacks_cache (); - - // the Python objects were probably deleted by Python itself as it exited - - // don't try to delete them again. - mp_module.release (); - while (!m_methods_heap.empty ()) { delete m_methods_heap.back (); m_methods_heap.pop_back (); @@ -93,6 +87,16 @@ PythonModule::~PythonModule () } } +void +PythonModule::cleanup () +{ + // the Python objects are probably deleted by Python itself as it exits - + // don't try to delete them again in the destructor. + mp_module.release (); + + PYAObjectBase::clear_callbacks_cache (); +} + PyObject * PythonModule::module () { diff --git a/src/pya/pya/pyaModule.h b/src/pya/pya/pyaModule.h index 0adcc9586..b543ae02b 100644 --- a/src/pya/pya/pyaModule.h +++ b/src/pya/pya/pyaModule.h @@ -65,6 +65,12 @@ class PYA_PUBLIC PythonModule */ ~PythonModule (); + /** + * @brief Clean up the module + * This method is called by the interpreter before Py_Finalize + */ + void cleanup (); + /** * @brief Initializes the module * This entry point is for external use where the module has not been created yet diff --git a/src/pymod/pymodHelper.h b/src/pymod/pymodHelper.h index 55bc56185..6d116e234 100644 --- a/src/pymod/pymodHelper.h +++ b/src/pymod/pymodHelper.h @@ -34,6 +34,7 @@ #include "pyaModule.h" #include "pyaUtils.h" +#include "pya.h" #include "gsi.h" #include "gsiExpression.h" @@ -41,7 +42,12 @@ static PyObject * module_init (const char *pymod_name, const char *mod_name, const char *mod_description) { - static pya::PythonModule module; + if (! pya::PythonInterpreter::instance ()) { + return 0; + } + + pya::PythonModule *module = new pya::PythonModule (); + pya::PythonInterpreter::instance ()->register_module (module); PYA_TRY @@ -50,10 +56,10 @@ module_init (const char *pymod_name, const char *mod_name, const char *mod_descr // required for the tiling processor for example gsi::initialize_expressions (); - module.init (pymod_name, mod_description); - module.make_classes (mod_name); + module->init (pymod_name, mod_description); + module->make_classes (mod_name); - return module.take_module (); + return module->take_module (); PYA_CATCH_ANYWHERE