mirror of
https://github.com/python/cpython.git
synced 2025-07-18 16:55:20 +00:00
gh-76785: Handle Legacy Interpreters Properly (gh-117490)
This is similar to the situation with threading._DummyThread. The methods (incl. __del__()) of interpreters.Interpreter objects must be careful with interpreters not created by interpreters.create(). The simplest thing to start with is to disable any method that modifies or runs in the interpreter. As part of this, the runtime keeps track of where an interpreter was created. We also handle interpreter "refcounts" properly.
This commit is contained in:
parent
fd2bab9d28
commit
fd259fdabe
9 changed files with 454 additions and 200 deletions
|
@ -1822,7 +1822,7 @@ _PyXI_FiniTypes(PyInterpreterState *interp)
|
|||
/*************/
|
||||
|
||||
PyInterpreterState *
|
||||
_PyXI_NewInterpreter(PyInterpreterConfig *config,
|
||||
_PyXI_NewInterpreter(PyInterpreterConfig *config, long *maybe_whence,
|
||||
PyThreadState **p_tstate, PyThreadState **p_save_tstate)
|
||||
{
|
||||
PyThreadState *save_tstate = PyThreadState_Swap(NULL);
|
||||
|
@ -1845,7 +1845,11 @@ _PyXI_NewInterpreter(PyInterpreterConfig *config,
|
|||
assert(tstate != NULL);
|
||||
PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate);
|
||||
|
||||
_PyInterpreterState_SetWhence(interp, _PyInterpreterState_WHENCE_XI);
|
||||
long whence = _PyInterpreterState_WHENCE_XI;
|
||||
if (maybe_whence != NULL) {
|
||||
whence = *maybe_whence;
|
||||
}
|
||||
_PyInterpreterState_SetWhence(interp, whence);
|
||||
|
||||
if (p_tstate != NULL) {
|
||||
// We leave the new thread state as the current one.
|
||||
|
@ -1868,6 +1872,22 @@ void
|
|||
_PyXI_EndInterpreter(PyInterpreterState *interp,
|
||||
PyThreadState *tstate, PyThreadState **p_save_tstate)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
long whence = _PyInterpreterState_GetWhence(interp);
|
||||
#endif
|
||||
assert(whence != _PyInterpreterState_WHENCE_RUNTIME);
|
||||
|
||||
if (!_PyInterpreterState_IsReady(interp)) {
|
||||
assert(whence == _PyInterpreterState_WHENCE_UNKNOWN);
|
||||
// PyInterpreterState_Clear() requires the GIL,
|
||||
// which a not-ready does not have, so we don't clear it.
|
||||
// That means there may be leaks here until clearing the
|
||||
// interpreter is fixed.
|
||||
PyInterpreterState_Delete(interp);
|
||||
return;
|
||||
}
|
||||
assert(whence != _PyInterpreterState_WHENCE_UNKNOWN);
|
||||
|
||||
PyThreadState *save_tstate = NULL;
|
||||
PyThreadState *cur_tstate = PyThreadState_GET();
|
||||
if (tstate == NULL) {
|
||||
|
@ -1889,18 +1909,7 @@ _PyXI_EndInterpreter(PyInterpreterState *interp,
|
|||
}
|
||||
}
|
||||
|
||||
long whence = _PyInterpreterState_GetWhence(interp);
|
||||
assert(whence != _PyInterpreterState_WHENCE_RUNTIME);
|
||||
if (whence == _PyInterpreterState_WHENCE_UNKNOWN) {
|
||||
assert(!interp->_ready);
|
||||
PyThreadState *tstate = PyThreadState_New(interp);
|
||||
save_tstate = PyThreadState_Swap(tstate);
|
||||
_PyInterpreterState_Clear(tstate);
|
||||
PyInterpreterState_Delete(interp);
|
||||
}
|
||||
else {
|
||||
Py_EndInterpreter(tstate);
|
||||
}
|
||||
Py_EndInterpreter(tstate);
|
||||
|
||||
if (p_save_tstate != NULL) {
|
||||
save_tstate = *p_save_tstate;
|
||||
|
|
|
@ -1111,6 +1111,13 @@ _PyInterpreterState_ReinitRunningMain(PyThreadState *tstate)
|
|||
// accessors
|
||||
//----------
|
||||
|
||||
int
|
||||
_PyInterpreterState_IsReady(PyInterpreterState *interp)
|
||||
{
|
||||
return interp->_ready;
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
check_interpreter_whence(long whence)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue