gh-109860: Use a New Thread State When Switching Interpreters, When Necessary (gh-110245)
In a few places we switch to another interpreter without knowing if it has a thread state associated with the current thread. For the main interpreter there wasn't much of a problem, but for subinterpreters we were *mostly* okay re-using the tstate created with the interpreter (located via PyInterpreterState_ThreadHead()). There was a good chance that tstate wasn't actually in use by another thread. However, there are no guarantees of that. Furthermore, re-using an already used tstate is currently fragile. To address this, now we create a new thread state in each of those places and use it. One consequence of this change is that PyInterpreterState_ThreadHead() may not return NULL (though that won't happen for the main interpreter).
This commit is contained in:
parent
4227bfa8b2
commit
f5198b09e1
@ -92,6 +92,15 @@ struct _ts {
|
|||||||
/* padding to align to 4 bytes */
|
/* padding to align to 4 bytes */
|
||||||
unsigned int :24;
|
unsigned int :24;
|
||||||
} _status;
|
} _status;
|
||||||
|
#ifdef Py_BUILD_CORE
|
||||||
|
# define _PyThreadState_WHENCE_NOTSET -1
|
||||||
|
# define _PyThreadState_WHENCE_UNKNOWN 0
|
||||||
|
# define _PyThreadState_WHENCE_INTERP 1
|
||||||
|
# define _PyThreadState_WHENCE_THREADING 2
|
||||||
|
# define _PyThreadState_WHENCE_GILSTATE 3
|
||||||
|
# define _PyThreadState_WHENCE_EXEC 4
|
||||||
|
#endif
|
||||||
|
int _whence;
|
||||||
|
|
||||||
int py_recursion_remaining;
|
int py_recursion_remaining;
|
||||||
int py_recursion_limit;
|
int py_recursion_limit;
|
||||||
|
@ -48,6 +48,7 @@ _Py_IsMainInterpreterFinalizing(PyInterpreterState *interp)
|
|||||||
PyAPI_FUNC(int) _PyInterpreterState_SetRunningMain(PyInterpreterState *);
|
PyAPI_FUNC(int) _PyInterpreterState_SetRunningMain(PyInterpreterState *);
|
||||||
PyAPI_FUNC(void) _PyInterpreterState_SetNotRunningMain(PyInterpreterState *);
|
PyAPI_FUNC(void) _PyInterpreterState_SetNotRunningMain(PyInterpreterState *);
|
||||||
PyAPI_FUNC(int) _PyInterpreterState_IsRunningMain(PyInterpreterState *);
|
PyAPI_FUNC(int) _PyInterpreterState_IsRunningMain(PyInterpreterState *);
|
||||||
|
PyAPI_FUNC(int) _PyInterpreterState_FailIfRunningMain(PyInterpreterState *);
|
||||||
|
|
||||||
|
|
||||||
static inline const PyConfig *
|
static inline const PyConfig *
|
||||||
@ -139,7 +140,9 @@ static inline PyInterpreterState* _PyInterpreterState_GET(void) {
|
|||||||
|
|
||||||
// PyThreadState functions
|
// PyThreadState functions
|
||||||
|
|
||||||
extern PyThreadState * _PyThreadState_New(PyInterpreterState *interp);
|
extern PyThreadState * _PyThreadState_New(
|
||||||
|
PyInterpreterState *interp,
|
||||||
|
int whence);
|
||||||
extern void _PyThreadState_Bind(PyThreadState *tstate);
|
extern void _PyThreadState_Bind(PyThreadState *tstate);
|
||||||
extern void _PyThreadState_DeleteExcept(PyThreadState *tstate);
|
extern void _PyThreadState_DeleteExcept(PyThreadState *tstate);
|
||||||
|
|
||||||
|
@ -185,6 +185,7 @@ extern PyTypeObject _PyExc_MemoryError;
|
|||||||
|
|
||||||
#define _PyThreadState_INIT \
|
#define _PyThreadState_INIT \
|
||||||
{ \
|
{ \
|
||||||
|
._whence = _PyThreadState_WHENCE_NOTSET, \
|
||||||
.py_recursion_limit = Py_DEFAULT_RECURSION_LIMIT, \
|
.py_recursion_limit = Py_DEFAULT_RECURSION_LIMIT, \
|
||||||
.context_ver = 1, \
|
.context_ver = 1, \
|
||||||
}
|
}
|
||||||
|
@ -1593,8 +1593,11 @@ def _shutdown():
|
|||||||
# The main thread isn't finished yet, so its thread state lock can't
|
# The main thread isn't finished yet, so its thread state lock can't
|
||||||
# have been released.
|
# have been released.
|
||||||
assert tlock is not None
|
assert tlock is not None
|
||||||
assert tlock.locked()
|
if tlock.locked():
|
||||||
tlock.release()
|
# It should have been released already by
|
||||||
|
# _PyInterpreterState_SetNotRunningMain(), but there may be
|
||||||
|
# embedders that aren't calling that yet.
|
||||||
|
tlock.release()
|
||||||
_main_thread._stop()
|
_main_thread._stop()
|
||||||
else:
|
else:
|
||||||
# bpo-1596321: _shutdown() must be called in the main thread.
|
# bpo-1596321: _shutdown() must be called in the main thread.
|
||||||
|
@ -1205,7 +1205,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
|
|||||||
if (boot == NULL) {
|
if (boot == NULL) {
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
}
|
}
|
||||||
boot->tstate = _PyThreadState_New(interp);
|
boot->tstate = _PyThreadState_New(interp, _PyThreadState_WHENCE_THREADING);
|
||||||
if (boot->tstate == NULL) {
|
if (boot->tstate == NULL) {
|
||||||
PyMem_RawFree(boot);
|
PyMem_RawFree(boot);
|
||||||
if (!PyErr_Occurred()) {
|
if (!PyErr_Occurred()) {
|
||||||
|
@ -242,6 +242,11 @@ _sharedns_apply(_sharedns *shared, PyObject *ns)
|
|||||||
// of the exception in the calling interpreter.
|
// of the exception in the calling interpreter.
|
||||||
|
|
||||||
typedef struct _sharedexception {
|
typedef struct _sharedexception {
|
||||||
|
PyInterpreterState *interp;
|
||||||
|
#define ERR_NOT_SET 0
|
||||||
|
#define ERR_NO_MEMORY 1
|
||||||
|
#define ERR_ALREADY_RUNNING 2
|
||||||
|
int code;
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *msg;
|
const char *msg;
|
||||||
} _sharedexception;
|
} _sharedexception;
|
||||||
@ -263,14 +268,26 @@ _sharedexception_clear(_sharedexception *exc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
_sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
|
_sharedexception_bind(PyObject *exc, int code, _sharedexception *sharedexc)
|
||||||
{
|
{
|
||||||
|
if (sharedexc->interp == NULL) {
|
||||||
|
sharedexc->interp = PyInterpreterState_Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code != ERR_NOT_SET) {
|
||||||
|
assert(exc == NULL);
|
||||||
|
assert(code > 0);
|
||||||
|
sharedexc->code = code;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
assert(exc != NULL);
|
assert(exc != NULL);
|
||||||
const char *failure = NULL;
|
const char *failure = NULL;
|
||||||
|
|
||||||
PyObject *nameobj = PyUnicode_FromString(Py_TYPE(exc)->tp_name);
|
PyObject *nameobj = PyUnicode_FromString(Py_TYPE(exc)->tp_name);
|
||||||
if (nameobj == NULL) {
|
if (nameobj == NULL) {
|
||||||
failure = "unable to format exception type name";
|
failure = "unable to format exception type name";
|
||||||
|
code = ERR_NO_MEMORY;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
sharedexc->name = _copy_raw_string(nameobj);
|
sharedexc->name = _copy_raw_string(nameobj);
|
||||||
@ -281,6 +298,7 @@ _sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
|
|||||||
} else {
|
} else {
|
||||||
failure = "unable to encode and copy exception type name";
|
failure = "unable to encode and copy exception type name";
|
||||||
}
|
}
|
||||||
|
code = ERR_NO_MEMORY;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,6 +306,7 @@ _sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
|
|||||||
PyObject *msgobj = PyUnicode_FromFormat("%S", exc);
|
PyObject *msgobj = PyUnicode_FromFormat("%S", exc);
|
||||||
if (msgobj == NULL) {
|
if (msgobj == NULL) {
|
||||||
failure = "unable to format exception message";
|
failure = "unable to format exception message";
|
||||||
|
code = ERR_NO_MEMORY;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
sharedexc->msg = _copy_raw_string(msgobj);
|
sharedexc->msg = _copy_raw_string(msgobj);
|
||||||
@ -298,6 +317,7 @@ _sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
|
|||||||
} else {
|
} else {
|
||||||
failure = "unable to encode and copy exception message";
|
failure = "unable to encode and copy exception message";
|
||||||
}
|
}
|
||||||
|
code = ERR_NO_MEMORY;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -308,7 +328,10 @@ error:
|
|||||||
assert(failure != NULL);
|
assert(failure != NULL);
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
_sharedexception_clear(sharedexc);
|
_sharedexception_clear(sharedexc);
|
||||||
*sharedexc = no_exception;
|
*sharedexc = (_sharedexception){
|
||||||
|
.interp = sharedexc->interp,
|
||||||
|
.code = code,
|
||||||
|
};
|
||||||
return failure;
|
return failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,6 +339,7 @@ static void
|
|||||||
_sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
|
_sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
|
||||||
{
|
{
|
||||||
if (exc->name != NULL) {
|
if (exc->name != NULL) {
|
||||||
|
assert(exc->code == ERR_NOT_SET);
|
||||||
if (exc->msg != NULL) {
|
if (exc->msg != NULL) {
|
||||||
PyErr_Format(wrapperclass, "%s: %s", exc->name, exc->msg);
|
PyErr_Format(wrapperclass, "%s: %s", exc->name, exc->msg);
|
||||||
}
|
}
|
||||||
@ -324,9 +348,19 @@ _sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (exc->msg != NULL) {
|
else if (exc->msg != NULL) {
|
||||||
|
assert(exc->code == ERR_NOT_SET);
|
||||||
PyErr_SetString(wrapperclass, exc->msg);
|
PyErr_SetString(wrapperclass, exc->msg);
|
||||||
}
|
}
|
||||||
|
else if (exc->code == ERR_NO_MEMORY) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
}
|
||||||
|
else if (exc->code == ERR_ALREADY_RUNNING) {
|
||||||
|
assert(exc->interp != NULL);
|
||||||
|
assert(_PyInterpreterState_IsRunningMain(exc->interp));
|
||||||
|
_PyInterpreterState_FailIfRunningMain(exc->interp);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
|
assert(exc->code == ERR_NOT_SET);
|
||||||
PyErr_SetNone(wrapperclass);
|
PyErr_SetNone(wrapperclass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -362,9 +396,16 @@ static int
|
|||||||
_run_script(PyInterpreterState *interp, const char *codestr,
|
_run_script(PyInterpreterState *interp, const char *codestr,
|
||||||
_sharedns *shared, _sharedexception *sharedexc)
|
_sharedns *shared, _sharedexception *sharedexc)
|
||||||
{
|
{
|
||||||
|
int errcode = ERR_NOT_SET;
|
||||||
|
|
||||||
if (_PyInterpreterState_SetRunningMain(interp) < 0) {
|
if (_PyInterpreterState_SetRunningMain(interp) < 0) {
|
||||||
// We skip going through the shared exception.
|
assert(PyErr_Occurred());
|
||||||
return -1;
|
// In the case where we didn't switch interpreters, it would
|
||||||
|
// be more efficient to leave the exception in place and return
|
||||||
|
// immediately. However, life is simpler if we don't.
|
||||||
|
PyErr_Clear();
|
||||||
|
errcode = ERR_ALREADY_RUNNING;
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *excval = NULL;
|
PyObject *excval = NULL;
|
||||||
@ -403,16 +444,17 @@ _run_script(PyInterpreterState *interp, const char *codestr,
|
|||||||
|
|
||||||
error:
|
error:
|
||||||
excval = PyErr_GetRaisedException();
|
excval = PyErr_GetRaisedException();
|
||||||
const char *failure = _sharedexception_bind(excval, sharedexc);
|
const char *failure = _sharedexception_bind(excval, errcode, sharedexc);
|
||||||
if (failure != NULL) {
|
if (failure != NULL) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"RunFailedError: script raised an uncaught exception (%s)",
|
"RunFailedError: script raised an uncaught exception (%s)",
|
||||||
failure);
|
failure);
|
||||||
PyErr_Clear();
|
|
||||||
}
|
}
|
||||||
Py_XDECREF(excval);
|
Py_XDECREF(excval);
|
||||||
|
if (errcode != ERR_ALREADY_RUNNING) {
|
||||||
|
_PyInterpreterState_SetNotRunningMain(interp);
|
||||||
|
}
|
||||||
assert(!PyErr_Occurred());
|
assert(!PyErr_Occurred());
|
||||||
_PyInterpreterState_SetNotRunningMain(interp);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,6 +463,7 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
|
|||||||
const char *codestr, PyObject *shareables)
|
const char *codestr, PyObject *shareables)
|
||||||
{
|
{
|
||||||
module_state *state = get_module_state(mod);
|
module_state *state = get_module_state(mod);
|
||||||
|
assert(state != NULL);
|
||||||
|
|
||||||
_sharedns *shared = _get_shared_ns(shareables);
|
_sharedns *shared = _get_shared_ns(shareables);
|
||||||
if (shared == NULL && PyErr_Occurred()) {
|
if (shared == NULL && PyErr_Occurred()) {
|
||||||
@ -429,50 +472,30 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
|
|||||||
|
|
||||||
// Switch to interpreter.
|
// Switch to interpreter.
|
||||||
PyThreadState *save_tstate = NULL;
|
PyThreadState *save_tstate = NULL;
|
||||||
|
PyThreadState *tstate = NULL;
|
||||||
if (interp != PyInterpreterState_Get()) {
|
if (interp != PyInterpreterState_Get()) {
|
||||||
// XXX gh-109860: Using the "head" thread isn't strictly correct.
|
tstate = PyThreadState_New(interp);
|
||||||
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
|
tstate->_whence = _PyThreadState_WHENCE_EXEC;
|
||||||
assert(tstate != NULL);
|
|
||||||
// Hack (until gh-109860): The interpreter's initial thread state
|
|
||||||
// is least likely to break.
|
|
||||||
while(tstate->next != NULL) {
|
|
||||||
tstate = tstate->next;
|
|
||||||
}
|
|
||||||
// We must do this check before switching interpreters, so any
|
|
||||||
// exception gets raised in the right one.
|
|
||||||
// XXX gh-109860: Drop this redundant check once we stop
|
|
||||||
// re-using tstates that might already be in use.
|
|
||||||
if (_PyInterpreterState_IsRunningMain(interp)) {
|
|
||||||
PyErr_SetString(PyExc_RuntimeError,
|
|
||||||
"interpreter already running");
|
|
||||||
if (shared != NULL) {
|
|
||||||
_sharedns_free(shared);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
// XXX Possible GILState issues?
|
// XXX Possible GILState issues?
|
||||||
save_tstate = PyThreadState_Swap(tstate);
|
save_tstate = PyThreadState_Swap(tstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the script.
|
// Run the script.
|
||||||
_sharedexception exc = {NULL, NULL};
|
_sharedexception exc = (_sharedexception){ .interp = interp };
|
||||||
int result = _run_script(interp, codestr, shared, &exc);
|
int result = _run_script(interp, codestr, shared, &exc);
|
||||||
|
|
||||||
// Switch back.
|
// Switch back.
|
||||||
if (save_tstate != NULL) {
|
if (save_tstate != NULL) {
|
||||||
|
PyThreadState_Clear(tstate);
|
||||||
PyThreadState_Swap(save_tstate);
|
PyThreadState_Swap(save_tstate);
|
||||||
|
PyThreadState_Delete(tstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Propagate any exception out to the caller.
|
// Propagate any exception out to the caller.
|
||||||
if (exc.name != NULL) {
|
if (result < 0) {
|
||||||
assert(state != NULL);
|
assert(!PyErr_Occurred());
|
||||||
_sharedexception_apply(&exc, state->RunFailedError);
|
_sharedexception_apply(&exc, state->RunFailedError);
|
||||||
}
|
assert(PyErr_Occurred());
|
||||||
else if (result != 0) {
|
|
||||||
if (!PyErr_Occurred()) {
|
|
||||||
// We were unable to allocate a shared exception.
|
|
||||||
PyErr_NoMemory();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shared != NULL) {
|
if (shared != NULL) {
|
||||||
@ -502,6 +525,7 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
|
|||||||
const PyInterpreterConfig config = isolated
|
const PyInterpreterConfig config = isolated
|
||||||
? (PyInterpreterConfig)_PyInterpreterConfig_INIT
|
? (PyInterpreterConfig)_PyInterpreterConfig_INIT
|
||||||
: (PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT;
|
: (PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT;
|
||||||
|
|
||||||
// XXX Possible GILState issues?
|
// XXX Possible GILState issues?
|
||||||
PyThreadState *tstate = NULL;
|
PyThreadState *tstate = NULL;
|
||||||
PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config);
|
PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config);
|
||||||
@ -517,6 +541,7 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
assert(tstate != NULL);
|
assert(tstate != NULL);
|
||||||
|
|
||||||
PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate);
|
PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate);
|
||||||
PyObject *idobj = PyInterpreterState_GetIDObject(interp);
|
PyObject *idobj = PyInterpreterState_GetIDObject(interp);
|
||||||
if (idobj == NULL) {
|
if (idobj == NULL) {
|
||||||
@ -526,6 +551,10 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
|
|||||||
PyThreadState_Swap(save_tstate);
|
PyThreadState_Swap(save_tstate);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyThreadState_Clear(tstate);
|
||||||
|
PyThreadState_Delete(tstate);
|
||||||
|
|
||||||
_PyInterpreterState_RequireIDRef(interp, 1);
|
_PyInterpreterState_RequireIDRef(interp, 1);
|
||||||
return idobj;
|
return idobj;
|
||||||
}
|
}
|
||||||
@ -573,14 +602,8 @@ interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Destroy the interpreter.
|
// Destroy the interpreter.
|
||||||
// XXX gh-109860: Using the "head" thread isn't strictly correct.
|
PyThreadState *tstate = PyThreadState_New(interp);
|
||||||
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
|
tstate->_whence = _PyThreadState_WHENCE_INTERP;
|
||||||
assert(tstate != NULL);
|
|
||||||
// Hack (until gh-109860): The interpreter's initial thread state
|
|
||||||
// is least likely to break.
|
|
||||||
while(tstate->next != NULL) {
|
|
||||||
tstate = tstate->next;
|
|
||||||
}
|
|
||||||
// XXX Possible GILState issues?
|
// XXX Possible GILState issues?
|
||||||
PyThreadState *save_tstate = PyThreadState_Swap(tstate);
|
PyThreadState *save_tstate = PyThreadState_Swap(tstate);
|
||||||
Py_EndInterpreter(tstate);
|
Py_EndInterpreter(tstate);
|
||||||
|
@ -655,7 +655,8 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyThreadState *tstate = _PyThreadState_New(interp);
|
PyThreadState *tstate = _PyThreadState_New(interp,
|
||||||
|
_PyThreadState_WHENCE_INTERP);
|
||||||
if (tstate == NULL) {
|
if (tstate == NULL) {
|
||||||
return _PyStatus_ERR("can't make first thread");
|
return _PyStatus_ERR("can't make first thread");
|
||||||
}
|
}
|
||||||
@ -2050,7 +2051,8 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config)
|
|||||||
return _PyStatus_OK();
|
return _PyStatus_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
PyThreadState *tstate = _PyThreadState_New(interp);
|
PyThreadState *tstate = _PyThreadState_New(interp,
|
||||||
|
_PyThreadState_WHENCE_INTERP);
|
||||||
if (tstate == NULL) {
|
if (tstate == NULL) {
|
||||||
PyInterpreterState_Delete(interp);
|
PyInterpreterState_Delete(interp);
|
||||||
*tstate_p = NULL;
|
*tstate_p = NULL;
|
||||||
|
@ -1094,9 +1094,7 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime)
|
|||||||
int
|
int
|
||||||
_PyInterpreterState_SetRunningMain(PyInterpreterState *interp)
|
_PyInterpreterState_SetRunningMain(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
if (interp->threads.main != NULL) {
|
if (_PyInterpreterState_FailIfRunningMain(interp) < 0) {
|
||||||
PyErr_SetString(PyExc_RuntimeError,
|
|
||||||
"interpreter already running");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
PyThreadState *tstate = current_fast_get(&_PyRuntime);
|
PyThreadState *tstate = current_fast_get(&_PyRuntime);
|
||||||
@ -1113,7 +1111,20 @@ _PyInterpreterState_SetRunningMain(PyInterpreterState *interp)
|
|||||||
void
|
void
|
||||||
_PyInterpreterState_SetNotRunningMain(PyInterpreterState *interp)
|
_PyInterpreterState_SetNotRunningMain(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
assert(interp->threads.main == current_fast_get(&_PyRuntime));
|
PyThreadState *tstate = interp->threads.main;
|
||||||
|
assert(tstate == current_fast_get(&_PyRuntime));
|
||||||
|
|
||||||
|
if (tstate->on_delete != NULL) {
|
||||||
|
// The threading module was imported for the first time in this
|
||||||
|
// thread, so it was set as threading._main_thread. (See gh-75698.)
|
||||||
|
// The thread has finished running the Python program so we mark
|
||||||
|
// the thread object as finished.
|
||||||
|
assert(tstate->_whence != _PyThreadState_WHENCE_THREADING);
|
||||||
|
tstate->on_delete(tstate->on_delete_data);
|
||||||
|
tstate->on_delete = NULL;
|
||||||
|
tstate->on_delete_data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
interp->threads.main = NULL;
|
interp->threads.main = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1123,6 +1134,17 @@ _PyInterpreterState_IsRunningMain(PyInterpreterState *interp)
|
|||||||
return (interp->threads.main != NULL);
|
return (interp->threads.main != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_PyInterpreterState_FailIfRunningMain(PyInterpreterState *interp)
|
||||||
|
{
|
||||||
|
if (interp->threads.main != NULL) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError,
|
||||||
|
"interpreter already running");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//----------
|
//----------
|
||||||
// accessors
|
// accessors
|
||||||
@ -1183,8 +1205,10 @@ _PyInterpreterState_IDDecref(PyInterpreterState *interp)
|
|||||||
PyThread_release_lock(interp->id_mutex);
|
PyThread_release_lock(interp->id_mutex);
|
||||||
|
|
||||||
if (refcount == 0 && interp->requires_idref) {
|
if (refcount == 0 && interp->requires_idref) {
|
||||||
// XXX Using the "head" thread isn't strictly correct.
|
PyThreadState *tstate = _PyThreadState_New(interp,
|
||||||
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
|
_PyThreadState_WHENCE_INTERP);
|
||||||
|
_PyThreadState_Bind(tstate);
|
||||||
|
|
||||||
// XXX Possible GILState issues?
|
// XXX Possible GILState issues?
|
||||||
PyThreadState *save_tstate = _PyThreadState_Swap(runtime, tstate);
|
PyThreadState *save_tstate = _PyThreadState_Swap(runtime, tstate);
|
||||||
Py_EndInterpreter(tstate);
|
Py_EndInterpreter(tstate);
|
||||||
@ -1338,7 +1362,14 @@ free_threadstate(PyThreadState *tstate)
|
|||||||
{
|
{
|
||||||
// The initial thread state of the interpreter is allocated
|
// The initial thread state of the interpreter is allocated
|
||||||
// as part of the interpreter state so should not be freed.
|
// as part of the interpreter state so should not be freed.
|
||||||
if (tstate != &tstate->interp->_initial_thread) {
|
if (tstate == &tstate->interp->_initial_thread) {
|
||||||
|
// Restore to _PyThreadState_INIT.
|
||||||
|
tstate = &tstate->interp->_initial_thread;
|
||||||
|
memcpy(tstate,
|
||||||
|
&initial._main_interpreter._initial_thread,
|
||||||
|
sizeof(*tstate));
|
||||||
|
}
|
||||||
|
else {
|
||||||
PyMem_RawFree(tstate);
|
PyMem_RawFree(tstate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1353,7 +1384,7 @@ free_threadstate(PyThreadState *tstate)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
init_threadstate(PyThreadState *tstate,
|
init_threadstate(PyThreadState *tstate,
|
||||||
PyInterpreterState *interp, uint64_t id)
|
PyInterpreterState *interp, uint64_t id, int whence)
|
||||||
{
|
{
|
||||||
if (tstate->_status.initialized) {
|
if (tstate->_status.initialized) {
|
||||||
Py_FatalError("thread state already initialized");
|
Py_FatalError("thread state already initialized");
|
||||||
@ -1366,6 +1397,10 @@ init_threadstate(PyThreadState *tstate,
|
|||||||
assert(tstate->next == NULL);
|
assert(tstate->next == NULL);
|
||||||
assert(tstate->prev == NULL);
|
assert(tstate->prev == NULL);
|
||||||
|
|
||||||
|
assert(tstate->_whence == _PyThreadState_WHENCE_NOTSET);
|
||||||
|
assert(whence >= 0 && whence <= _PyThreadState_WHENCE_EXEC);
|
||||||
|
tstate->_whence = whence;
|
||||||
|
|
||||||
assert(id > 0);
|
assert(id > 0);
|
||||||
tstate->id = id;
|
tstate->id = id;
|
||||||
|
|
||||||
@ -1395,8 +1430,6 @@ add_threadstate(PyInterpreterState *interp, PyThreadState *tstate,
|
|||||||
PyThreadState *next)
|
PyThreadState *next)
|
||||||
{
|
{
|
||||||
assert(interp->threads.head != tstate);
|
assert(interp->threads.head != tstate);
|
||||||
assert((next != NULL && tstate->id != 1) ||
|
|
||||||
(next == NULL && tstate->id == 1));
|
|
||||||
if (next != NULL) {
|
if (next != NULL) {
|
||||||
assert(next->prev == NULL || next->prev == tstate);
|
assert(next->prev == NULL || next->prev == tstate);
|
||||||
next->prev = tstate;
|
next->prev = tstate;
|
||||||
@ -1407,7 +1440,7 @@ add_threadstate(PyInterpreterState *interp, PyThreadState *tstate,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static PyThreadState *
|
static PyThreadState *
|
||||||
new_threadstate(PyInterpreterState *interp)
|
new_threadstate(PyInterpreterState *interp, int whence)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate;
|
PyThreadState *tstate;
|
||||||
_PyRuntimeState *runtime = interp->runtime;
|
_PyRuntimeState *runtime = interp->runtime;
|
||||||
@ -1430,10 +1463,10 @@ new_threadstate(PyInterpreterState *interp)
|
|||||||
PyThreadState *old_head = interp->threads.head;
|
PyThreadState *old_head = interp->threads.head;
|
||||||
if (old_head == NULL) {
|
if (old_head == NULL) {
|
||||||
// It's the interpreter's initial thread state.
|
// It's the interpreter's initial thread state.
|
||||||
assert(id == 1);
|
|
||||||
used_newtstate = 0;
|
used_newtstate = 0;
|
||||||
tstate = &interp->_initial_thread;
|
tstate = &interp->_initial_thread;
|
||||||
}
|
}
|
||||||
|
// XXX Re-use interp->_initial_thread if not in use?
|
||||||
else {
|
else {
|
||||||
// Every valid interpreter must have at least one thread.
|
// Every valid interpreter must have at least one thread.
|
||||||
assert(id > 1);
|
assert(id > 1);
|
||||||
@ -1446,7 +1479,7 @@ new_threadstate(PyInterpreterState *interp)
|
|||||||
sizeof(*tstate));
|
sizeof(*tstate));
|
||||||
}
|
}
|
||||||
|
|
||||||
init_threadstate(tstate, interp, id);
|
init_threadstate(tstate, interp, id, whence);
|
||||||
add_threadstate(interp, tstate, old_head);
|
add_threadstate(interp, tstate, old_head);
|
||||||
|
|
||||||
HEAD_UNLOCK(runtime);
|
HEAD_UNLOCK(runtime);
|
||||||
@ -1460,7 +1493,8 @@ new_threadstate(PyInterpreterState *interp)
|
|||||||
PyThreadState *
|
PyThreadState *
|
||||||
PyThreadState_New(PyInterpreterState *interp)
|
PyThreadState_New(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = new_threadstate(interp);
|
PyThreadState *tstate = new_threadstate(interp,
|
||||||
|
_PyThreadState_WHENCE_UNKNOWN);
|
||||||
if (tstate) {
|
if (tstate) {
|
||||||
bind_tstate(tstate);
|
bind_tstate(tstate);
|
||||||
// This makes sure there's a gilstate tstate bound
|
// This makes sure there's a gilstate tstate bound
|
||||||
@ -1474,16 +1508,16 @@ PyThreadState_New(PyInterpreterState *interp)
|
|||||||
|
|
||||||
// This must be followed by a call to _PyThreadState_Bind();
|
// This must be followed by a call to _PyThreadState_Bind();
|
||||||
PyThreadState *
|
PyThreadState *
|
||||||
_PyThreadState_New(PyInterpreterState *interp)
|
_PyThreadState_New(PyInterpreterState *interp, int whence)
|
||||||
{
|
{
|
||||||
return new_threadstate(interp);
|
return new_threadstate(interp, whence);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We keep this for stable ABI compabibility.
|
// We keep this for stable ABI compabibility.
|
||||||
PyAPI_FUNC(PyThreadState*)
|
PyAPI_FUNC(PyThreadState*)
|
||||||
_PyThreadState_Prealloc(PyInterpreterState *interp)
|
_PyThreadState_Prealloc(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
return _PyThreadState_New(interp);
|
return _PyThreadState_New(interp, _PyThreadState_WHENCE_UNKNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We keep this around for (accidental) stable ABI compatibility.
|
// We keep this around for (accidental) stable ABI compatibility.
|
||||||
@ -1580,6 +1614,12 @@ PyThreadState_Clear(PyThreadState *tstate)
|
|||||||
Py_CLEAR(tstate->context);
|
Py_CLEAR(tstate->context);
|
||||||
|
|
||||||
if (tstate->on_delete != NULL) {
|
if (tstate->on_delete != NULL) {
|
||||||
|
// For the "main" thread of each interpreter, this is meant
|
||||||
|
// to be done in _PyInterpreterState_SetNotRunningMain().
|
||||||
|
// That leaves threads created by the threading module,
|
||||||
|
// and any threads killed by forking.
|
||||||
|
// However, we also accommodate "main" threads that still
|
||||||
|
// don't call _PyInterpreterState_SetNotRunningMain() yet.
|
||||||
tstate->on_delete(tstate->on_delete_data);
|
tstate->on_delete(tstate->on_delete_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2240,7 +2280,9 @@ PyGILState_Ensure(void)
|
|||||||
int has_gil;
|
int has_gil;
|
||||||
if (tcur == NULL) {
|
if (tcur == NULL) {
|
||||||
/* Create a new Python thread state for this thread */
|
/* Create a new Python thread state for this thread */
|
||||||
tcur = new_threadstate(runtime->gilstate.autoInterpreterState);
|
// XXX Use PyInterpreterState_EnsureThreadState()?
|
||||||
|
tcur = new_threadstate(runtime->gilstate.autoInterpreterState,
|
||||||
|
_PyThreadState_WHENCE_GILSTATE);
|
||||||
if (tcur == NULL) {
|
if (tcur == NULL) {
|
||||||
Py_FatalError("Couldn't create thread-state for new thread");
|
Py_FatalError("Couldn't create thread-state for new thread");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user