PyEval_SaveThread() and PyEval_RestoreThread() now return/take a

PyThreadState pointer instead of a (frame) PyObject pointer.  This
makes much more sense.  It is backward incompatible, but that's no
problem, because (a) the heaviest users are the Py_{BEGIN,END}_
ALLOW_THREADS macros here, which have been fixed too; (b) there are
very few direct users; (c) those who use it are there will probably
appreciate the change.

Also, added new functions PyEval_AcquireThread() and
PyEval_ReleaseThread() which allows the threads created by the thread
module as well threads created by others (!) to set/reset the current
thread, and at the same time acquire/release the interpreter lock.

Much saner.
This commit is contained in:
Guido van Rossum 1997-07-18 23:56:58 +00:00
parent c864ad695f
commit 2fca21f762
2 changed files with 34 additions and 9 deletions

View file

@ -100,13 +100,16 @@ int Py_MakePendingCalls Py_PROTO((void));
*/ */
extern void PyEval_InitThreads Py_PROTO((void)); extern void PyEval_InitThreads Py_PROTO((void));
extern PyObject *PyEval_SaveThread Py_PROTO((void)); extern PyThreadState *PyEval_SaveThread Py_PROTO((void));
extern void PyEval_RestoreThread Py_PROTO((PyObject *)); extern void PyEval_RestoreThread Py_PROTO((PyThreadState *));
#ifdef WITH_THREAD #ifdef WITH_THREAD
extern void PyEval_AcquireThread Py_PROTO((PyThreadState *tstate));
extern void PyEval_ReleaseThread Py_PROTO((PyThreadState *tstate));
#define Py_BEGIN_ALLOW_THREADS { \ #define Py_BEGIN_ALLOW_THREADS { \
PyObject *_save; \ PyThreadState *_save; \
_save = PyEval_SaveThread(); _save = PyEval_SaveThread();
#define Py_BLOCK_THREADS PyEval_RestoreThread(_save); #define Py_BLOCK_THREADS PyEval_RestoreThread(_save);
#define Py_UNBLOCK_THREADS _save = PyEval_SaveThread(); #define Py_UNBLOCK_THREADS _save = PyEval_SaveThread();

View file

@ -135,35 +135,57 @@ PyEval_InitThreads()
dynamically loaded modules needn't be compiled separately for use dynamically loaded modules needn't be compiled separately for use
with and without threads: */ with and without threads: */
PyObject * PyThreadState *
PyEval_SaveThread() PyEval_SaveThread()
{ {
#ifdef WITH_THREAD #ifdef WITH_THREAD
if (interpreter_lock) { if (interpreter_lock) {
PyThreadState *tstate = PyThreadState_Swap(NULL); 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); release_lock(interpreter_lock);
return res; return tstate;
} }
#endif #endif
return NULL; return NULL;
} }
void void
PyEval_RestoreThread(x) PyEval_RestoreThread(tstate)
PyObject *x; PyThreadState *tstate;
{ {
#ifdef WITH_THREAD #ifdef WITH_THREAD
if (interpreter_lock) { if (interpreter_lock) {
int err; int err;
err = errno; err = errno;
if (tstate == NULL)
Py_FatalError("PyEval_RestoreThread: NULL tstate");
acquire_lock(interpreter_lock, 1); acquire_lock(interpreter_lock, 1);
PyThreadState_Swap(tstate);
errno = err; errno = err;
PyThreadState_Swap(x ? ((PyFrameObject *)x)->f_tstate : NULL);
} }
#endif #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 /* Mechanism whereby asynchronously executing callbacks (e.g. UNIX
signal handlers or Mac I/O completion routines) can schedule calls signal handlers or Mac I/O completion routines) can schedule calls