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:
Robin Dunn 2004-01-15 01:06:39 +00:00
parent b1dfbb7ad8
commit b856768b04

View File

@ -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();
} }