diff options
-rw-r--r-- | Modules/posixmodule.c | 58 |
1 files changed, 57 insertions, 1 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index d5290f6..42bde97 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -2685,6 +2685,21 @@ _PyPopen(char *cmdstring, int mode, int n) * files to be closed in any order - it is always the close() of the * final handle that will return the exit code. */ + + /* RED_FLAG 31-Aug-2000 Tim + * This is always called (today!) between a pair of + * Py_BEGIN_ALLOW_THREADS/ Py_END_ALLOW_THREADS + * macros. So the thread running this has no valid thread state, as + * far as Python is concerned. However, this calls some Python API + * functions that cannot be called safely without a valid thread + * state, in particular PyDict_GetItem. + * As a temporary hack (although it may last for years ...), we + * *rely* on not having a valid thread state in this function, in + * order to create our own "from scratch". + * This will deadlock if _PyPclose is ever called by a thread + * holding the global lock. + */ + static int _PyPclose(FILE *file) { int result; @@ -2692,12 +2707,41 @@ static int _PyPclose(FILE *file) HANDLE hProcess; PyObject *procObj, *hProcessObj, *intObj, *fileObj; long file_count; - +#ifdef WITH_THREAD + PyInterpreterState* pInterpreterState; + PyThreadState* pThreadState; +#endif + /* Close the file handle first, to ensure it can't block the * child from exiting if it's the last handle. */ result = fclose(file); +#ifdef WITH_THREAD + /* Bootstrap a valid thread state into existence. */ + pInterpreterState = PyInterpreterState_New(); + if (!pInterpreterState) { + /* Well, we're hosed now! We don't have a thread + * state, so can't call a nice error routine, or raise + * an exception. Just die. + */ + Py_FatalError("unable to allocate interpreter state " + " when closing popen object."); + return -1; /* unreachable */ + } + pThreadState = PyThreadState_New(pInterpreterState); + if (!pThreadState) { + Py_FatalError("unable to allocate thread state " + " when closing popen object."); + return -1; /* unreachable */ + } + /* Grab the global lock. Note that this will deadlock if the + * current thread already has the lock! (see RED_FLAG comments + * before this function) + */ + PyEval_RestoreThread(pThreadState); +#endif + if (_PyPopenProcs) { if ((fileObj = PyLong_FromVoidPtr(file)) != NULL && (procObj = PyDict_GetItem(_PyPopenProcs, @@ -2755,6 +2799,18 @@ static int _PyPclose(FILE *file) Py_XDECREF(fileObj); } /* if _PyPopenProcs */ +#ifdef WITH_THREAD + /* Tear down the thread & interpreter states. + * Note that interpreter state clear & delete functions automatically + * call the thread & clear functions, and * indeed insist on doing + * that themselves. The lock must be held during the clear, but need + * not be held during the delete. + */ + PyInterpreterState_Clear(pInterpreterState); + PyEval_ReleaseThread(pThreadState); + PyInterpreterState_Delete(pInterpreterState); +#endif + return result; } #else |