Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

FIX: GilSafeSingleLock is causing UI freeze when it cannot get the GIL back... #1204

Closed
wants to merge 1 commit into from

4 participants

@koying
Collaborator

... while having already locked the graphic context.

This happens (for me), for instance, during lengthy mysql operations in python while another script tries a simple "window.setProperty".

Removing it and using the separate ad-hoc locking mechanisms. Reference: Pull Request #797

@koying koying FIX: GilSafeSingleLock is causing UI freeze when it cannot get the GI…
…L back while having already locked the graphic context. Removing it.
1ad325a
@garbear

cosmetic (two little spaces thought they could come along for the ride :))

@jmarshallnz

Above this you call PyThreadState_Get() when setting the callback. What implications (if any) does this have while you're not holding the GIL?

Collaborator

ACK, You need the GIL for PyThreadState_Get.

@jmarshallnz

above this you're accessing python functions without the GIL?

Collaborator

ACK

@jmarshallnz
Owner

@jimfcarroll a review would be good - a few places we're calling python routines while in the scope of CPyThreadState that I'm not sure about.

@koying
Collaborator

Actually, looks like all CGUIWindowManager functions are already locking the graphic context, so I wonder if it is even necessary to recurse lock it in the windows.cpp functions... Will test...

@jimfcarroll
Collaborator

My concern here is whether or not you considered that calls made from these methods assume the GIL is held and not just what's visible here. For example, you are now calling "new CGUIPythonWindowXMLDialog" without holding the GIL. Did you check that all possible call stacks resulting from all calls where you no longer are holding the GIL nowhere assume you were holding the GIL?

This is why I did it the way I did in the first place. Not that I think it was the right answer (The right answer is in my PR).

@koying
Collaborator

I checked as far as possible that called functions were not calling python.

But my problem is actually related to the graphic context lock, not the GIL. As far as my problem is concerned, the functions can have the GIL as long as the UI is not locked while we are waiting to obtain it, as was done with GilSafeSingleLock.

So, if someone could confirm the "CSingleLock lock(g_graphicsContext);"'s are not needed because the locking is properly done in the xbmc window functions, that would solve the original problem, the windows.cpp could keep the GIL and no "CPyThreadState" would even be necessary.

@koying koying closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 22, 2012
  1. @koying

    FIX: GilSafeSingleLock is causing UI freeze when it cannot get the GI…

    koying authored
    …L back while having already locked the graphic context. Removing it.
This page is out of date. Refresh to see the latest.
Showing with 64 additions and 24 deletions.
  1. +64 −24 xbmc/interfaces/python/xbmcmodule/window.cpp
View
88 xbmc/interfaces/python/xbmcmodule/window.cpp
@@ -41,17 +41,7 @@ using namespace std;
#define ACTIVE_WINDOW g_windowManager.GetActiveWindow()
-/**
- * A CSingleLock that will relinquish the GIL during the time
- * it takes to obtain the CriticalSection
- */
-class GilSafeSingleLock : public CPyThreadState, public CSingleLock
-{
-public:
- GilSafeSingleLock(const CCriticalSection& critSec) : CPyThreadState(true), CSingleLock(critSec) { CPyThreadState::Restore(); }
-};
-
-#ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
#endif
@@ -62,8 +52,9 @@ namespace PYXBMC
// used by Dialog to to create a new dialogWindow
bool Window_CreateNewWindow(Window* pWindow, bool bAsDialog)
{
- GilSafeSingleLock lock(g_graphicsContext);
-
+ CPyThreadState state;
+
+ CSingleLock lock(g_graphicsContext);
if (pWindow->iWindowId != -1)
{
// user specified window id, use this one if it exists
@@ -71,6 +62,8 @@ namespace PYXBMC
pWindow->pWindow = g_windowManager.GetWindow(pWindow->iWindowId);
if (!pWindow->pWindow)
{
+ lock.Leave();
+ state.Restore();
PyErr_SetString(PyExc_ValueError, "Window id does not exist");
return false;
}
@@ -84,6 +77,8 @@ namespace PYXBMC
// if window 13099 is in use it means python can't create more windows
if (g_windowManager.GetWindow(WINDOW_PYTHON_END))
{
+ lock.Leave();
+ state.Restore();
PyErr_SetString(PyExc_Exception, "maximum number of windows reached");
return false;
}
@@ -111,6 +106,9 @@ namespace PYXBMC
g_windowManager.Add(pWindow->pWindow);
}
+ lock.Leave();
+ state.Restore();
+
pWindow->iOldWindowId = 0;
pWindow->bModal = false;
pWindow->iCurrentControlId = 3000;
@@ -139,13 +137,16 @@ namespace PYXBMC
}
// lock xbmc GUI before accessing data from it
- GilSafeSingleLock lock(g_graphicsContext);
+ CPyThreadState state;
+ CSingleLock lock(g_graphicsContext);
// check if control exists
CGUIControl* pGUIControl = (CGUIControl*)self->pWindow->GetControl(iControlId);
if (!pGUIControl)
{
// control does not exist.
+ lock.Leave();
+ state.Restore();
CStdString error;
error.Format("Non-Existent Control %d",iControlId);
PyErr_SetString(PyExc_TypeError, error.c_str());
@@ -282,6 +283,9 @@ namespace PYXBMC
break;
}
+ lock.Leave();
+ state.Restore();
+
if (!pControl)
{
// throw an exeption
@@ -342,7 +346,9 @@ namespace PYXBMC
void Window_Dealloc(Window* self)
{
- GilSafeSingleLock lock(g_graphicsContext);
+ CPyThreadState state;
+
+ CSingleLock lock(g_graphicsContext);
if (self->bIsPythonWindow)
{
// first change to an existing window
@@ -399,6 +405,8 @@ namespace PYXBMC
}
lock.Leave();
+ state.Restore();
+
self->vecControls.clear();
self->vecControls.~vector();
self->sFallBackPath.~string();
@@ -632,9 +640,13 @@ namespace PYXBMC
pControl->iParentId = self->iWindowId;
{ // assign control id, if id is already in use, try next id
- GilSafeSingleLock lock(g_graphicsContext);
+ CPyThreadState state;
+
+ CSingleLock lock(g_graphicsContext);
do pControl->iControlId = ++self->iCurrentControlId;
while (self->pWindow->GetControl(pControl->iControlId));
+ lock.Leave();
+ state.Restore();
}
// Control Label
@@ -830,15 +842,18 @@ namespace PYXBMC
PyObject* Window_GetFocus(Window *self, PyObject *args)
{
- GilSafeSingleLock lock(g_graphicsContext);
-
+ CPyThreadState state;
+
+ CSingleLock lock(g_graphicsContext);
int iControlId = self->pWindow->GetFocusedControlID();
+ lock.Leave();
+
+ state.Restore();
if(iControlId == -1)
{
PyErr_SetString(PyExc_RuntimeError, "No control in this window has focus");
return NULL;
}
- lock.Leave();
return (PyObject*)Window_GetControlById(self, iControlId);
}
@@ -851,8 +866,13 @@ namespace PYXBMC
PyObject* Window_GetFocusId(Window *self, PyObject *args)
{
- GilSafeSingleLock lock(g_graphicsContext);
+ CPyThreadState state;
+
+ CSingleLock lock(g_graphicsContext);
int iControlId = self->pWindow->GetFocusedControlID();
+ lock.Leave();
+
+ state.Restore();
if(iControlId == -1)
{
PyErr_SetString(PyExc_RuntimeError, "No control in this window has focus");
@@ -972,8 +992,13 @@ namespace PYXBMC
return NULL;
}
- GilSafeSingleLock lock(g_graphicsContext);
+ CPyThreadState state;
+
+ CSingleLock lock(g_graphicsContext);
self->pWindow->SetCoordsRes(g_settings.m_ResInfo[res]);
+ lock.Leave();
+
+ state.Restore();
Py_INCREF(Py_None);
return Py_None;
@@ -1056,9 +1081,14 @@ namespace PYXBMC
return NULL; }
if (!key) return NULL;
- GilSafeSingleLock lock(g_graphicsContext);
+ CPyThreadState state;
+
+ CSingleLock lock(g_graphicsContext);
CStdString lowerKey = key;
string value = self->pWindow->GetProperty(lowerKey.ToLower()).asString();
+ lock.Leave();
+
+ state.Restore();
return Py_BuildValue((char*)"s", value.c_str());
}
@@ -1091,10 +1121,15 @@ namespace PYXBMC
return NULL;
}
if (!key) return NULL;
- GilSafeSingleLock lock(g_graphicsContext);
+ CPyThreadState state;
+
+ CSingleLock lock(g_graphicsContext);
CStdString lowerKey = key;
self->pWindow->SetProperty(lowerKey.ToLower(), "");
+ lock.Leave();
+
+ state.Restore();
Py_INCREF(Py_None);
return Py_None;
@@ -1109,8 +1144,13 @@ namespace PYXBMC
PyObject* Window_ClearProperties(Window *self, PyObject *args)
{
- GilSafeSingleLock lock(g_graphicsContext);
+ CPyThreadState state;
+
+ CSingleLock lock(g_graphicsContext);
self->pWindow->ClearProperties();
+ lock.Leave();
+
+ state.Restore();
Py_INCREF(Py_None);
return Py_None;
Something went wrong with that request. Please try again.