mirror of https://github.com/python/cpython
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>.
This commit is contained in:
parent
5bf94a0b77
commit
736aa32a39
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue