diff --git a/Include/ceval.h b/Include/ceval.h index 68c59774e9d..2336ed31f45 100644 --- a/Include/ceval.h +++ b/Include/ceval.h @@ -100,13 +100,16 @@ int Py_MakePendingCalls Py_PROTO((void)); */ extern void PyEval_InitThreads Py_PROTO((void)); -extern PyObject *PyEval_SaveThread Py_PROTO((void)); -extern void PyEval_RestoreThread Py_PROTO((PyObject *)); +extern PyThreadState *PyEval_SaveThread Py_PROTO((void)); +extern void PyEval_RestoreThread Py_PROTO((PyThreadState *)); #ifdef WITH_THREAD +extern void PyEval_AcquireThread Py_PROTO((PyThreadState *tstate)); +extern void PyEval_ReleaseThread Py_PROTO((PyThreadState *tstate)); + #define Py_BEGIN_ALLOW_THREADS { \ - PyObject *_save; \ + PyThreadState *_save; \ _save = PyEval_SaveThread(); #define Py_BLOCK_THREADS PyEval_RestoreThread(_save); #define Py_UNBLOCK_THREADS _save = PyEval_SaveThread(); diff --git a/Python/ceval.c b/Python/ceval.c index ab1e90f2a9c..be4ffec6547 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -135,35 +135,57 @@ PyEval_InitThreads() dynamically loaded modules needn't be compiled separately for use with and without threads: */ -PyObject * +PyThreadState * PyEval_SaveThread() { #ifdef WITH_THREAD if (interpreter_lock) { PyThreadState *tstate = PyThreadState_Swap(NULL); - PyObject *res = tstate ? (PyObject *) (tstate->frame) : NULL; + if (tstate == NULL) + Py_FatalError("PyEval_SaveThread: NULL tstate"); release_lock(interpreter_lock); - return res; + return tstate; } #endif return NULL; } void -PyEval_RestoreThread(x) - PyObject *x; +PyEval_RestoreThread(tstate) + PyThreadState *tstate; { #ifdef WITH_THREAD if (interpreter_lock) { int err; err = errno; + if (tstate == NULL) + Py_FatalError("PyEval_RestoreThread: NULL tstate"); acquire_lock(interpreter_lock, 1); + PyThreadState_Swap(tstate); errno = err; - PyThreadState_Swap(x ? ((PyFrameObject *)x)->f_tstate : NULL); } #endif } +#ifdef WITH_THREAD +void +PyEval_AcquireThread(tstate) + PyThreadState *tstate; +{ + acquire_lock(interpreter_lock, 1); + if (PyThreadState_Swap(tstate) != NULL) + Py_FatalError("PyEval_AcquireThread: non-NULL old state"); +} + +void +PyEval_ReleaseThread(tstate) + PyThreadState *tstate; +{ + if (PyThreadState_Swap(NULL) != tstate) + Py_FatalError("PyEval_ReleaseThread: wrong thread state"); + release_lock(interpreter_lock); +} +#endif /* Mechanism whereby asynchronously executing callbacks (e.g. UNIX signal handlers or Mac I/O completion routines) can schedule calls