Allow nested calls to wxPy[Begin|End]BlockThreads instead of
deadlocking when the nested calls try to aquire the Python GIL. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@25176 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
		@@ -49,9 +49,10 @@ bool wxPyDoingCleanup = False;
 | 
				
			|||||||
struct wxPyThreadState {
 | 
					struct wxPyThreadState {
 | 
				
			||||||
    unsigned long  tid;
 | 
					    unsigned long  tid;
 | 
				
			||||||
    PyThreadState* tstate;
 | 
					    PyThreadState* tstate;
 | 
				
			||||||
 | 
					    int            blocked;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wxPyThreadState(unsigned long _tid=0, PyThreadState* _tstate=NULL)
 | 
					    wxPyThreadState(unsigned long _tid=0, PyThreadState* _tstate=NULL)
 | 
				
			||||||
        : tid(_tid), tstate(_tstate) {}
 | 
					        : tid(_tid), tstate(_tstate), blocked(1) {}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <wx/dynarray.h>
 | 
					#include <wx/dynarray.h>
 | 
				
			||||||
@@ -895,21 +896,21 @@ unsigned long wxPyGetCurrentThreadId() {
 | 
				
			|||||||
    return wxThread::GetCurrentId();
 | 
					    return wxThread::GetCurrentId();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static PyThreadState* gs_shutdownTState;
 | 
					static wxPyThreadState gs_shutdownTState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static
 | 
					static
 | 
				
			||||||
PyThreadState* wxPyGetThreadState() {
 | 
					wxPyThreadState* wxPyGetThreadState() {
 | 
				
			||||||
    if (wxPyTMutex == NULL) // Python is shutting down...
 | 
					    if (wxPyTMutex == NULL) // Python is shutting down...
 | 
				
			||||||
        return gs_shutdownTState;
 | 
					        return &gs_shutdownTState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unsigned long ctid = wxPyGetCurrentThreadId();
 | 
					    unsigned long ctid = wxPyGetCurrentThreadId();
 | 
				
			||||||
    PyThreadState* tstate = NULL;
 | 
					    wxPyThreadState* tstate = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wxPyTMutex->Lock();
 | 
					    wxPyTMutex->Lock();
 | 
				
			||||||
    for(size_t i=0; i < wxPyTStates->GetCount(); i++) {
 | 
					    for(size_t i=0; i < wxPyTStates->GetCount(); i++) {
 | 
				
			||||||
        wxPyThreadState& info = wxPyTStates->Item(i);
 | 
					        wxPyThreadState& info = wxPyTStates->Item(i);
 | 
				
			||||||
        if (info.tid == ctid) {
 | 
					        if (info.tid == ctid) {
 | 
				
			||||||
            tstate = info.tstate;
 | 
					            tstate = &info;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -918,10 +919,11 @@ PyThreadState* wxPyGetThreadState() {
 | 
				
			|||||||
    return tstate;
 | 
					    return tstate;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static
 | 
					static
 | 
				
			||||||
void wxPySaveThreadState(PyThreadState* tstate) {
 | 
					void wxPySaveThreadState(PyThreadState* tstate) {
 | 
				
			||||||
    if (wxPyTMutex == NULL) { // Python is shutting down, assume a single thread...
 | 
					    if (wxPyTMutex == NULL) { // Python is shutting down, assume a single thread...
 | 
				
			||||||
        gs_shutdownTState = tstate;
 | 
					        gs_shutdownTState.tstate = tstate;
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    unsigned long ctid = wxPyGetCurrentThreadId();
 | 
					    unsigned long ctid = wxPyGetCurrentThreadId();
 | 
				
			||||||
@@ -950,6 +952,7 @@ void wxPySaveThreadState(PyThreadState* tstate) {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Calls from Python to wxWindows code are wrapped in calls to these
 | 
					// Calls from Python to wxWindows code are wrapped in calls to these
 | 
				
			||||||
// functions:
 | 
					// functions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -957,6 +960,7 @@ PyThreadState* wxPyBeginAllowThreads() {
 | 
				
			|||||||
#ifdef WXP_WITH_THREAD
 | 
					#ifdef WXP_WITH_THREAD
 | 
				
			||||||
    PyThreadState* saved = PyEval_SaveThread();  // Py_BEGIN_ALLOW_THREADS;
 | 
					    PyThreadState* saved = PyEval_SaveThread();  // Py_BEGIN_ALLOW_THREADS;
 | 
				
			||||||
    wxPySaveThreadState(saved);
 | 
					    wxPySaveThreadState(saved);
 | 
				
			||||||
 | 
					    wxPyGetThreadState()->blocked -= 1;
 | 
				
			||||||
    return saved;
 | 
					    return saved;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    return NULL;
 | 
					    return NULL;
 | 
				
			||||||
@@ -965,6 +969,7 @@ PyThreadState* wxPyBeginAllowThreads() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void wxPyEndAllowThreads(PyThreadState* saved) {
 | 
					void wxPyEndAllowThreads(PyThreadState* saved) {
 | 
				
			||||||
#ifdef WXP_WITH_THREAD
 | 
					#ifdef WXP_WITH_THREAD
 | 
				
			||||||
 | 
					    wxPyGetThreadState()->blocked += 1;
 | 
				
			||||||
    PyEval_RestoreThread(saved);   // Py_END_ALLOW_THREADS;
 | 
					    PyEval_RestoreThread(saved);   // Py_END_ALLOW_THREADS;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -976,17 +981,21 @@ void wxPyEndAllowThreads(PyThreadState* saved) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void wxPyBeginBlockThreads() {
 | 
					void wxPyBeginBlockThreads() {
 | 
				
			||||||
#ifdef WXP_WITH_THREAD
 | 
					#ifdef WXP_WITH_THREAD
 | 
				
			||||||
    PyThreadState* tstate = wxPyGetThreadState();
 | 
					    wxPyThreadState* tstate = wxPyGetThreadState();
 | 
				
			||||||
    PyEval_RestoreThread(tstate);
 | 
					    if (tstate->blocked++ == 0) {  // if nested calls then do nothing
 | 
				
			||||||
 | 
					        PyEval_RestoreThread(tstate->tstate);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wxPyEndBlockThreads() {
 | 
					void wxPyEndBlockThreads() {
 | 
				
			||||||
#ifdef WXP_WITH_THREAD
 | 
					#ifdef WXP_WITH_THREAD
 | 
				
			||||||
    // Is there any need to save it again?
 | 
					    wxPyThreadState* tstate = wxPyGetThreadState();
 | 
				
			||||||
    // PyThreadState* tstate =
 | 
					    tstate->blocked -= 1;
 | 
				
			||||||
    PyEval_SaveThread();
 | 
					    if ( tstate->blocked == 0) {  // if nested calls then do nothing
 | 
				
			||||||
 | 
					        PyEval_SaveThread();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1336,31 +1345,34 @@ void wxPyCallback::EventThunker(wxEvent& event) {
 | 
				
			|||||||
        arg = wxPyConstructObject((void*)&event, className);
 | 
					        arg = wxPyConstructObject((void*)&event, className);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Call the event handler, passing the event object
 | 
					    if (!arg) {
 | 
				
			||||||
    tuple = PyTuple_New(1);
 | 
					 | 
				
			||||||
    PyTuple_SET_ITEM(tuple, 0, arg);  // steals ref to arg
 | 
					 | 
				
			||||||
    result = PyEval_CallObject(func, tuple);
 | 
					 | 
				
			||||||
    if ( result ) {
 | 
					 | 
				
			||||||
        Py_DECREF(result);   // result is ignored, but we still need to decref it
 | 
					 | 
				
			||||||
        PyErr_Clear();       // Just in case...
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        PyErr_Print();
 | 
					        PyErr_Print();
 | 
				
			||||||
    }
 | 
					    } else {
 | 
				
			||||||
 | 
					        // Call the event handler, passing the event object
 | 
				
			||||||
    if ( checkSkip ) {
 | 
					        tuple = PyTuple_New(1);
 | 
				
			||||||
        // if the event object was one of our special types and
 | 
					        PyTuple_SET_ITEM(tuple, 0, arg);  // steals ref to arg
 | 
				
			||||||
        // it had been cloned, then we need to extract the Skipped
 | 
					        result = PyEval_CallObject(func, tuple);
 | 
				
			||||||
        // value from the original and set it in the clone.
 | 
					 | 
				
			||||||
        result = PyObject_CallMethod(arg, "GetSkipped", "");
 | 
					 | 
				
			||||||
        if ( result ) {
 | 
					        if ( result ) {
 | 
				
			||||||
            event.Skip(PyInt_AsLong(result));
 | 
					            Py_DECREF(result);   // result is ignored, but we still need to decref it
 | 
				
			||||||
            Py_DECREF(result);
 | 
					            PyErr_Clear();       // Just in case...
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            PyErr_Print();
 | 
					            PyErr_Print();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Py_DECREF(tuple);
 | 
					        if ( checkSkip ) {
 | 
				
			||||||
 | 
					            // if the event object was one of our special types and
 | 
				
			||||||
 | 
					            // it had been cloned, then we need to extract the Skipped
 | 
				
			||||||
 | 
					            // value from the original and set it in the clone.
 | 
				
			||||||
 | 
					            result = PyObject_CallMethod(arg, "GetSkipped", "");
 | 
				
			||||||
 | 
					            if ( result ) {
 | 
				
			||||||
 | 
					                event.Skip(PyInt_AsLong(result));
 | 
				
			||||||
 | 
					                Py_DECREF(result);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                PyErr_Print();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Py_DECREF(tuple);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    wxPyEndBlockThreads();
 | 
					    wxPyEndBlockThreads();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user