xbmc/xbmc — pull request #1224 by garbear (2012-07-27 22:33:27+00:00)
Title: Fixed crash of death when calling XBPyThread::stop() while inside a python dialog's doModal()

When XBPyThread::stop() is called, a SystemExit exception is raised in Python script's threads, but the Python window "misses the memo". It continues calling [PyXBMC_MakePendingCalls()](https://github.com/xbmc/xbmc/blob/master/xbmc/interfaces/python/xbmcmodule/window.cpp#L540), which XBMC continues populating with onAction events even though the event's thread has a SystemExit exception raised.

Eventually, as python objects are unloaded, the user-supplied onAction() will throw an exception. When this [is caught](https://github.com/xbmc/xbmc/blob/master/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.cpp#L281), a call to PyErr_Print() seems to go on an object-freeing spree, but the deallocation of something naughty causes python26.dll (Win32) to invoke a "crash of death" immediately terminating the entire XBMC application.

The fix is to have doModal() check if the exception has been raised; if so, hide the window and return control to the python script. By having XBPyThread::stop() invoke g_pythonParser.PulseGlobalEvent() we can force doModal() to wake up immediately instead of laying dormant until another onAction event.

Other considerations:
* Maybe _PyXBMC_MakePendingCalls() and _PyXBMC_AddPendingCall() should also check for PyExc_SystemExit?
* Is this the right way to check for a SystemExit exception?
* This wakes up the dialog, but I think an infinite loop in the Python script right after doModal() can still hang the thread