diff options
author | Tim Peters <tim.peters@gmail.com> | 2000-09-01 06:51:24 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2000-09-01 06:51:24 (GMT) |
commit | 736aa32a39d1c7afb5f3298fd0e13c51754546c7 (patch) | |
tree | 89af20c495ce16d813223955201418b7503980d0 /Modules | |
parent | 5bf94a0b772276548781ec6c29c3bd1cc96115d7 (diff) | |
download | cpython-736aa32a39d1c7afb5f3298fd0e13c51754546c7.zip cpython-736aa32a39d1c7afb5f3298fd0e13c51754546c7.tar.gz cpython-736aa32a39d1c7afb5f3298fd0e13c51754546c7.tar.bz2 |
Fix test_popen2 on Windows, recently broken by changes to the dict(!)
implementation. You don't want to know. I've asked Guido to give this
a critical review (we agreed on the approach, but the implementation
proved more ... interesting ... than anticipated). This will almost
certainly be the highlight of Mark Hammond's day <wink>.
Diffstat (limited to 'Modules')
-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 |