aboutsummaryrefslogtreecommitdiff
path: root/xbmc/interfaces/python/XBPyThread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/interfaces/python/XBPyThread.cpp')
-rw-r--r--xbmc/interfaces/python/XBPyThread.cpp54
1 files changed, 53 insertions, 1 deletions
diff --git a/xbmc/interfaces/python/XBPyThread.cpp b/xbmc/interfaces/python/XBPyThread.cpp
index 1ffad6d49a..82ca80f782 100644
--- a/xbmc/interfaces/python/XBPyThread.cpp
+++ b/xbmc/interfaces/python/XBPyThread.cpp
@@ -42,6 +42,7 @@
#include "XBPyThread.h"
#include "XBPython.h"
+#include "LanguageHook.h"
#include "interfaces/legacy/Exception.h"
#include "interfaces/legacy/CallbackHandler.h"
@@ -158,6 +159,9 @@ void XBPyThread::Process()
// swap in my thread state
PyThreadState_Swap(state);
+ XBMCAddon::AddonClass::Ref<XBMCAddon::Python::LanguageHook> languageHook(new XBMCAddon::Python::LanguageHook(state->interp));
+ languageHook->RegisterMe();
+
m_pExecuter->InitializeInterpreter(addon);
CLog::Log(LOGDEBUG, "%s - The source file to load is %s", __FUNCTION__, m_source);
@@ -369,8 +373,56 @@ void XBPyThread::Process()
m_pExecuter->DeInitializeInterpreter();
Py_EndInterpreter(state);
- PyThreadState_Swap(NULL);
+ // This is a total hack. Python doesn't necessarily release
+ // all of the objects associated with the interpreter when
+ // you end the interpreter. As a result there are objects
+ // managed by the windowing system that still receive events
+ // until python decides to clean them up. Python will eventually
+ // clean them up on the creation or ending of a subsequent
+ // interpreter. So we are going to keep creating and ending
+ // interpreters until we have no more python objects hanging
+ // around.
+ int countLimit;
+ for (countLimit = 0; languageHook->HasRegisteredAddonClasses() && countLimit < 10; countLimit++)
+ {
+ PyThreadState* tmpstate = Py_NewInterpreter();
+ Py_EndInterpreter(tmpstate);
+ }
+
+ // If necessary and successfull, debug log the results.
+ if (countLimit > 0 && !languageHook->HasRegisteredAddonClasses())
+ CLog::Log(LOGDEBUG,"It took %d Py_NewInterpreter/Py_EndInterpreter calls"
+ " to clean up the classes leftover from running \"%s.\"",
+ countLimit,m_source);
+
+ // If not successful, produce an error message detailing what's been left behind
+ if (languageHook->HasRegisteredAddonClasses())
+ {
+ CStdString message;
+ message.Format("The python script \"%s\" has left several "
+ "classes in memory that should have been cleaned up. The classes include: ",
+ m_source);
+
+ { XBMCAddon::AddonClass::Synchronize l(*(languageHook.get()));
+ std::set<XBMCAddon::AddonClass*>& acs = languageHook->GetRegisteredAddonClasses();
+ bool firstTime = true;
+ for (std::set<XBMCAddon::AddonClass*>::iterator iter = acs.begin();
+ iter != acs.end(); iter++)
+ {
+ if (!firstTime) message += ",";
+ else firstTime = false;
+ message += (*iter)->GetClassname().c_str();
+ }
+ }
+
+ CLog::Log(LOGERROR, "%s", message.c_str());
+ }
+
+ // unregister the language hook
+ languageHook->UnregisterMe();
+
+ PyThreadState_Swap(NULL);
PyEval_ReleaseLock();
}