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:
parent
b1dfbb7ad8
commit
b856768b04
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user