|
|
|
|
@@ -37,9 +37,6 @@ to avoid the expense of doing their own locking).
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Forward declarations */
|
|
|
|
|
static void _PyThreadState_Delete(PyThreadState *tstate, int check_current);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************/
|
|
|
|
|
/* helpers for the current thread state */
|
|
|
|
|
@@ -81,69 +78,56 @@ current_fast_clear(_PyRuntimeState *runtime)
|
|
|
|
|
_Py_atomic_store_relaxed(&runtime->tstate_current, (uintptr_t)NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define tstate_verify_not_active(tstate) \
|
|
|
|
|
if (tstate == current_fast_get((tstate)->interp->runtime)) { \
|
|
|
|
|
_Py_FatalErrorFormat(__func__, "tstate %p is still current", tstate); \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------
|
|
|
|
|
// the thread state bound to the current OS thread
|
|
|
|
|
//------------------------------------------------
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
The stored thread state is set by bind_tstate() (AKA PyThreadState_Bind().
|
|
|
|
|
|
|
|
|
|
The GIL does no need to be held for these.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
current_tss_initialized(_PyRuntimeState *runtime)
|
|
|
|
|
static inline int
|
|
|
|
|
tstate_tss_initialized(Py_tss_t *key)
|
|
|
|
|
{
|
|
|
|
|
return PyThread_tss_is_created(&runtime->autoTSSkey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PyStatus
|
|
|
|
|
current_tss_init(_PyRuntimeState *runtime)
|
|
|
|
|
{
|
|
|
|
|
assert(!current_tss_initialized(runtime));
|
|
|
|
|
if (PyThread_tss_create(&runtime->autoTSSkey) != 0) {
|
|
|
|
|
return _PyStatus_NO_MEMORY();
|
|
|
|
|
}
|
|
|
|
|
return _PyStatus_OK();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
current_tss_fini(_PyRuntimeState *runtime)
|
|
|
|
|
{
|
|
|
|
|
assert(current_tss_initialized(runtime));
|
|
|
|
|
PyThread_tss_delete(&runtime->autoTSSkey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline PyThreadState *
|
|
|
|
|
current_tss_get(_PyRuntimeState *runtime)
|
|
|
|
|
{
|
|
|
|
|
assert(current_tss_initialized(runtime));
|
|
|
|
|
return (PyThreadState *)PyThread_tss_get(&runtime->autoTSSkey);
|
|
|
|
|
return PyThread_tss_is_created(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
|
_current_tss_set(_PyRuntimeState *runtime, PyThreadState *tstate)
|
|
|
|
|
tstate_tss_init(Py_tss_t *key)
|
|
|
|
|
{
|
|
|
|
|
assert(tstate != NULL);
|
|
|
|
|
assert(current_tss_initialized(runtime));
|
|
|
|
|
return PyThread_tss_set(&runtime->autoTSSkey, (void *)tstate);
|
|
|
|
|
}
|
|
|
|
|
static inline void
|
|
|
|
|
current_tss_set(_PyRuntimeState *runtime, PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
if (_current_tss_set(runtime, tstate) != 0) {
|
|
|
|
|
Py_FatalError("failed to set current tstate (TSS)");
|
|
|
|
|
}
|
|
|
|
|
assert(!tstate_tss_initialized(key));
|
|
|
|
|
return PyThread_tss_create(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
current_tss_clear(_PyRuntimeState *runtime)
|
|
|
|
|
tstate_tss_fini(Py_tss_t *key)
|
|
|
|
|
{
|
|
|
|
|
assert(current_tss_initialized(runtime));
|
|
|
|
|
if (PyThread_tss_set(&runtime->autoTSSkey, NULL) != 0) {
|
|
|
|
|
Py_FatalError("failed to clear current tstate (TSS)");
|
|
|
|
|
}
|
|
|
|
|
assert(tstate_tss_initialized(key));
|
|
|
|
|
PyThread_tss_delete(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline PyThreadState *
|
|
|
|
|
tstate_tss_get(Py_tss_t *key)
|
|
|
|
|
{
|
|
|
|
|
assert(tstate_tss_initialized(key));
|
|
|
|
|
return (PyThreadState *)PyThread_tss_get(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
|
tstate_tss_set(Py_tss_t *key, PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
assert(tstate != NULL);
|
|
|
|
|
assert(tstate_tss_initialized(key));
|
|
|
|
|
return PyThread_tss_set(key, (void *)tstate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
|
tstate_tss_clear(Py_tss_t *key)
|
|
|
|
|
{
|
|
|
|
|
assert(tstate_tss_initialized(key));
|
|
|
|
|
return PyThread_tss_set(key, (void *)NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_FORK
|
|
|
|
|
@@ -152,92 +136,178 @@ current_tss_clear(_PyRuntimeState *runtime)
|
|
|
|
|
* don't reset TSS upon fork(), see issue #10517.
|
|
|
|
|
*/
|
|
|
|
|
static PyStatus
|
|
|
|
|
current_tss_reinit(_PyRuntimeState *runtime)
|
|
|
|
|
tstate_tss_reinit(Py_tss_t *key)
|
|
|
|
|
{
|
|
|
|
|
if (!current_tss_initialized(runtime)) {
|
|
|
|
|
if (!tstate_tss_initialized(key)) {
|
|
|
|
|
return _PyStatus_OK();
|
|
|
|
|
}
|
|
|
|
|
PyThreadState *tstate = current_tss_get(runtime);
|
|
|
|
|
PyThreadState *tstate = tstate_tss_get(key);
|
|
|
|
|
|
|
|
|
|
current_tss_fini(runtime);
|
|
|
|
|
PyStatus status = current_tss_init(runtime);
|
|
|
|
|
if (_PyStatus_EXCEPTION(status)) {
|
|
|
|
|
return status;
|
|
|
|
|
tstate_tss_fini(key);
|
|
|
|
|
if (tstate_tss_init(key) != 0) {
|
|
|
|
|
return _PyStatus_NO_MEMORY();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the thread had an associated auto thread state, reassociate it with
|
|
|
|
|
* the new key. */
|
|
|
|
|
if (tstate && _current_tss_set(runtime, tstate) != 0) {
|
|
|
|
|
return _PyStatus_ERR("failed to set autoTSSkey");
|
|
|
|
|
if (tstate && tstate_tss_set(key, tstate) != 0) {
|
|
|
|
|
return _PyStatus_ERR("failed to re-set autoTSSkey");
|
|
|
|
|
}
|
|
|
|
|
return _PyStatus_OK();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
The stored thread state is set by bind_tstate() (AKA PyThreadState_Bind().
|
|
|
|
|
|
|
|
|
|
The GIL does no need to be held for these.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define gilstate_tss_initialized(runtime) \
|
|
|
|
|
tstate_tss_initialized(&(runtime)->autoTSSkey)
|
|
|
|
|
#define gilstate_tss_init(runtime) \
|
|
|
|
|
tstate_tss_init(&(runtime)->autoTSSkey)
|
|
|
|
|
#define gilstate_tss_fini(runtime) \
|
|
|
|
|
tstate_tss_fini(&(runtime)->autoTSSkey)
|
|
|
|
|
#define gilstate_tss_get(runtime) \
|
|
|
|
|
tstate_tss_get(&(runtime)->autoTSSkey)
|
|
|
|
|
#define _gilstate_tss_set(runtime, tstate) \
|
|
|
|
|
tstate_tss_set(&(runtime)->autoTSSkey, tstate)
|
|
|
|
|
#define _gilstate_tss_clear(runtime) \
|
|
|
|
|
tstate_tss_clear(&(runtime)->autoTSSkey)
|
|
|
|
|
#define gilstate_tss_reinit(runtime) \
|
|
|
|
|
tstate_tss_reinit(&(runtime)->autoTSSkey)
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
gilstate_tss_set(_PyRuntimeState *runtime, PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
assert(tstate != NULL && tstate->interp->runtime == runtime);
|
|
|
|
|
if (_gilstate_tss_set(runtime, tstate) != 0) {
|
|
|
|
|
Py_FatalError("failed to set current tstate (TSS)");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
gilstate_tss_clear(_PyRuntimeState *runtime)
|
|
|
|
|
{
|
|
|
|
|
if (_gilstate_tss_clear(runtime) != 0) {
|
|
|
|
|
Py_FatalError("failed to clear current tstate (TSS)");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline int tstate_is_alive(PyThreadState *tstate);
|
|
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
|
tstate_is_bound(PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
return tstate->_status.bound && !tstate->_status.unbound;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void bind_gilstate_tstate(PyThreadState *);
|
|
|
|
|
static void unbind_gilstate_tstate(PyThreadState *);
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bind_tstate(PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
assert(tstate != NULL);
|
|
|
|
|
assert(tstate->_status == PyThreadState_INITIALIZED);
|
|
|
|
|
assert(tstate_is_alive(tstate) && !tstate->_status.bound);
|
|
|
|
|
assert(!tstate->_status.unbound); // just in case
|
|
|
|
|
assert(!tstate->_status.bound_gilstate);
|
|
|
|
|
assert(tstate != gilstate_tss_get(tstate->interp->runtime));
|
|
|
|
|
assert(!tstate->_status.active);
|
|
|
|
|
assert(tstate->thread_id == 0);
|
|
|
|
|
assert(tstate->native_thread_id == 0);
|
|
|
|
|
_PyRuntimeState *runtime = tstate->interp->runtime;
|
|
|
|
|
|
|
|
|
|
/* Stick the thread state for this thread in thread specific storage.
|
|
|
|
|
|
|
|
|
|
The only situation where you can legitimately have more than one
|
|
|
|
|
thread state for an OS level thread is when there are multiple
|
|
|
|
|
interpreters.
|
|
|
|
|
|
|
|
|
|
You shouldn't really be using the PyGILState_ APIs anyway (see issues
|
|
|
|
|
#10915 and #15751).
|
|
|
|
|
|
|
|
|
|
The first thread state created for that given OS level thread will
|
|
|
|
|
"win", which seems reasonable behaviour.
|
|
|
|
|
*/
|
|
|
|
|
/* When a thread state is created for a thread by some mechanism
|
|
|
|
|
other than PyGILState_Ensure(), it's important that the GILState
|
|
|
|
|
machinery knows about it so it doesn't try to create another
|
|
|
|
|
thread state for the thread.
|
|
|
|
|
(This is a better fix for SF bug #1010677 than the first one attempted.)
|
|
|
|
|
*/
|
|
|
|
|
// XXX Skipping like this does not play nice with multiple interpreters.
|
|
|
|
|
if (current_tss_get(runtime) == NULL) {
|
|
|
|
|
current_tss_set(runtime, tstate);
|
|
|
|
|
}
|
|
|
|
|
// Currently we don't necessarily store the thread state
|
|
|
|
|
// in thread-local storage (e.g. per-interpreter).
|
|
|
|
|
|
|
|
|
|
tstate->thread_id = PyThread_get_thread_ident();
|
|
|
|
|
#ifdef PY_HAVE_THREAD_NATIVE_ID
|
|
|
|
|
tstate->native_thread_id = PyThread_get_thread_native_id();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
tstate->_status = PyThreadState_BOUND;
|
|
|
|
|
tstate->_status.bound = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
unbind_tstate(PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
assert(tstate != NULL);
|
|
|
|
|
assert(tstate->_status == PyThreadState_BOUND);
|
|
|
|
|
// XXX assert(tstate_is_alive(tstate));
|
|
|
|
|
assert(tstate_is_bound(tstate));
|
|
|
|
|
// XXX assert(!tstate->_status.active);
|
|
|
|
|
assert(tstate->thread_id > 0);
|
|
|
|
|
#ifdef PY_HAVE_THREAD_NATIVE_ID
|
|
|
|
|
assert(tstate->native_thread_id > 0);
|
|
|
|
|
#endif
|
|
|
|
|
_PyRuntimeState *runtime = tstate->interp->runtime;
|
|
|
|
|
|
|
|
|
|
if (current_tss_initialized(runtime) &&
|
|
|
|
|
tstate == current_tss_get(runtime))
|
|
|
|
|
{
|
|
|
|
|
current_tss_clear(runtime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We leave thread_id and native_thread_id alone
|
|
|
|
|
// since they can be useful for debugging.
|
|
|
|
|
// Check the `_status` field to know if these values
|
|
|
|
|
// are still valid.
|
|
|
|
|
|
|
|
|
|
tstate->_status = PyThreadState_UNBOUND;
|
|
|
|
|
// We leave tstate->_status.bound set to 1
|
|
|
|
|
// to indicate it was previously bound.
|
|
|
|
|
tstate->_status.unbound = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Stick the thread state for this thread in thread specific storage.
|
|
|
|
|
|
|
|
|
|
When a thread state is created for a thread by some mechanism
|
|
|
|
|
other than PyGILState_Ensure(), it's important that the GILState
|
|
|
|
|
machinery knows about it so it doesn't try to create another
|
|
|
|
|
thread state for the thread.
|
|
|
|
|
(This is a better fix for SF bug #1010677 than the first one attempted.)
|
|
|
|
|
|
|
|
|
|
The only situation where you can legitimately have more than one
|
|
|
|
|
thread state for an OS level thread is when there are multiple
|
|
|
|
|
interpreters.
|
|
|
|
|
|
|
|
|
|
The PyGILState_*() APIs don't work with multiple
|
|
|
|
|
interpreters (see bpo-10915 and bpo-15751), so this function
|
|
|
|
|
sets TSS only once. Thus, the first thread state created for that
|
|
|
|
|
given OS level thread will "win", which seems reasonable behaviour.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bind_gilstate_tstate(PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
assert(tstate != NULL);
|
|
|
|
|
assert(tstate_is_alive(tstate));
|
|
|
|
|
assert(tstate_is_bound(tstate));
|
|
|
|
|
// XXX assert(!tstate->_status.active);
|
|
|
|
|
assert(!tstate->_status.bound_gilstate);
|
|
|
|
|
|
|
|
|
|
_PyRuntimeState *runtime = tstate->interp->runtime;
|
|
|
|
|
PyThreadState *tcur = gilstate_tss_get(runtime);
|
|
|
|
|
assert(tstate != tcur);
|
|
|
|
|
|
|
|
|
|
if (tcur != NULL) {
|
|
|
|
|
// The original gilstate implementation only respects the
|
|
|
|
|
// first thread state set.
|
|
|
|
|
// XXX Skipping like this does not play nice with multiple interpreters.
|
|
|
|
|
return;
|
|
|
|
|
tcur->_status.bound_gilstate = 0;
|
|
|
|
|
}
|
|
|
|
|
gilstate_tss_set(runtime, tstate);
|
|
|
|
|
tstate->_status.bound_gilstate = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
unbind_gilstate_tstate(PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
assert(tstate != NULL);
|
|
|
|
|
// XXX assert(tstate_is_alive(tstate));
|
|
|
|
|
assert(tstate_is_bound(tstate));
|
|
|
|
|
// XXX assert(!tstate->_status.active);
|
|
|
|
|
assert(tstate->_status.bound_gilstate);
|
|
|
|
|
assert(tstate == gilstate_tss_get(tstate->interp->runtime));
|
|
|
|
|
|
|
|
|
|
gilstate_tss_clear(tstate->interp->runtime);
|
|
|
|
|
tstate->_status.bound_gilstate = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -261,7 +331,7 @@ holds_gil(PyThreadState *tstate)
|
|
|
|
|
assert(tstate != NULL);
|
|
|
|
|
_PyRuntimeState *runtime = tstate->interp->runtime;
|
|
|
|
|
/* Must be the tstate for this thread */
|
|
|
|
|
assert(tstate == current_tss_get(runtime));
|
|
|
|
|
assert(tstate == gilstate_tss_get(runtime));
|
|
|
|
|
return tstate == current_fast_get(runtime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -394,10 +464,9 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
|
|
|
|
|
memcpy(runtime, &initial, sizeof(*runtime));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyStatus status = current_tss_init(runtime);
|
|
|
|
|
if (_PyStatus_EXCEPTION(status)) {
|
|
|
|
|
if (gilstate_tss_init(runtime) != 0) {
|
|
|
|
|
_PyRuntimeState_Fini(runtime);
|
|
|
|
|
return status;
|
|
|
|
|
return _PyStatus_NO_MEMORY();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (PyThread_tss_create(&runtime->trashTSSkey) != 0) {
|
|
|
|
|
@@ -414,8 +483,8 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
|
|
|
|
|
void
|
|
|
|
|
_PyRuntimeState_Fini(_PyRuntimeState *runtime)
|
|
|
|
|
{
|
|
|
|
|
if (current_tss_initialized(runtime)) {
|
|
|
|
|
current_tss_fini(runtime);
|
|
|
|
|
if (gilstate_tss_initialized(runtime)) {
|
|
|
|
|
gilstate_tss_fini(runtime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (PyThread_tss_is_created(&runtime->trashTSSkey)) {
|
|
|
|
|
@@ -475,7 +544,7 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyStatus status = current_tss_reinit(runtime);
|
|
|
|
|
PyStatus status = gilstate_tss_reinit(runtime);
|
|
|
|
|
if (_PyStatus_EXCEPTION(status)) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
@@ -669,18 +738,38 @@ error:
|
|
|
|
|
static void
|
|
|
|
|
interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
assert(interp != NULL);
|
|
|
|
|
assert(tstate != NULL);
|
|
|
|
|
_PyRuntimeState *runtime = interp->runtime;
|
|
|
|
|
|
|
|
|
|
/* XXX Conditions we need to enforce:
|
|
|
|
|
|
|
|
|
|
* the GIL must be held by the current thread
|
|
|
|
|
* tstate must be the "current" thread state (current_fast_get())
|
|
|
|
|
* tstate->interp must be interp
|
|
|
|
|
* for the main interpreter, tstate must be the main thread
|
|
|
|
|
*/
|
|
|
|
|
// XXX Ideally, we would not rely on any thread state in this function
|
|
|
|
|
// (and we would drop the "tstate" argument).
|
|
|
|
|
|
|
|
|
|
if (_PySys_Audit(tstate, "cpython.PyInterpreterState_Clear", NULL) < 0) {
|
|
|
|
|
_PyErr_Clear(tstate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HEAD_LOCK(runtime);
|
|
|
|
|
// XXX Clear the current/main thread state last.
|
|
|
|
|
for (PyThreadState *p = interp->threads.head; p != NULL; p = p->next) {
|
|
|
|
|
PyThreadState_Clear(p);
|
|
|
|
|
}
|
|
|
|
|
HEAD_UNLOCK(runtime);
|
|
|
|
|
|
|
|
|
|
/* It is possible that any of the objects below have a finalizer
|
|
|
|
|
that runs Python code or otherwise relies on a thread state
|
|
|
|
|
or even the interpreter state. For now we trust that isn't
|
|
|
|
|
a problem.
|
|
|
|
|
*/
|
|
|
|
|
// XXX Make sure we properly deal with problematic finalizers.
|
|
|
|
|
|
|
|
|
|
Py_CLEAR(interp->audit_hooks);
|
|
|
|
|
|
|
|
|
|
PyConfig_Clear(&interp->config);
|
|
|
|
|
@@ -751,7 +840,6 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
|
|
|
|
|
// garbage. It can be different than the current Python thread state
|
|
|
|
|
// of 'interp'.
|
|
|
|
|
PyThreadState *current_tstate = current_fast_get(interp->runtime);
|
|
|
|
|
|
|
|
|
|
interpreter_clear(interp, current_tstate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -763,30 +851,26 @@ _PyInterpreterState_Clear(PyThreadState *tstate)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
zapthreads(PyInterpreterState *interp, int check_current)
|
|
|
|
|
{
|
|
|
|
|
PyThreadState *tstate;
|
|
|
|
|
/* No need to lock the mutex here because this should only happen
|
|
|
|
|
when the threads are all really dead (XXX famous last words). */
|
|
|
|
|
while ((tstate = interp->threads.head) != NULL) {
|
|
|
|
|
_PyThreadState_Delete(tstate, check_current);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void zapthreads(PyInterpreterState *interp);
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PyInterpreterState_Delete(PyInterpreterState *interp)
|
|
|
|
|
{
|
|
|
|
|
_PyRuntimeState *runtime = interp->runtime;
|
|
|
|
|
struct pyinterpreters *interpreters = &runtime->interpreters;
|
|
|
|
|
zapthreads(interp, 0);
|
|
|
|
|
|
|
|
|
|
// XXX Clearing the "current" thread state should happen before
|
|
|
|
|
// we start finalizing the interpreter (or the current thread state).
|
|
|
|
|
PyThreadState *tcur = current_fast_get(runtime);
|
|
|
|
|
if (tcur != NULL && interp == tcur->interp) {
|
|
|
|
|
/* Unset current thread. After this, many C API calls become crashy. */
|
|
|
|
|
_PyThreadState_Swap(runtime, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
zapthreads(interp);
|
|
|
|
|
|
|
|
|
|
_PyEval_FiniState(&interp->ceval);
|
|
|
|
|
|
|
|
|
|
/* Delete current thread. After this, many C API calls become crashy. */
|
|
|
|
|
_PyThreadState_Swap(runtime, NULL);
|
|
|
|
|
|
|
|
|
|
HEAD_LOCK(runtime);
|
|
|
|
|
PyInterpreterState **p;
|
|
|
|
|
for (p = &interpreters->head; ; p = &(*p)->next) {
|
|
|
|
|
@@ -843,8 +927,10 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// XXX Won't this fail since PyInterpreterState_Clear() requires
|
|
|
|
|
// the "current" tstate to be set?
|
|
|
|
|
PyInterpreterState_Clear(interp); // XXX must activate?
|
|
|
|
|
zapthreads(interp, 1);
|
|
|
|
|
zapthreads(interp);
|
|
|
|
|
if (interp->id_mutex != NULL) {
|
|
|
|
|
PyThread_free_lock(interp->id_mutex);
|
|
|
|
|
}
|
|
|
|
|
@@ -1062,6 +1148,16 @@ _PyInterpreterState_LookUpID(int64_t requested_id)
|
|
|
|
|
/* the per-thread runtime state */
|
|
|
|
|
/********************************/
|
|
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
|
tstate_is_alive(PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
return (tstate->_status.initialized &&
|
|
|
|
|
!tstate->_status.finalized &&
|
|
|
|
|
!tstate->_status.cleared &&
|
|
|
|
|
!tstate->_status.finalizing);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//----------
|
|
|
|
|
// lifecycle
|
|
|
|
|
//----------
|
|
|
|
|
@@ -1112,7 +1208,7 @@ init_threadstate(PyThreadState *tstate,
|
|
|
|
|
PyInterpreterState *interp, uint64_t id,
|
|
|
|
|
PyThreadState *next)
|
|
|
|
|
{
|
|
|
|
|
if (tstate->_status != PyThreadState_UNINITIALIZED) {
|
|
|
|
|
if (tstate->_status.initialized) {
|
|
|
|
|
Py_FatalError("thread state already initialized");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1148,7 +1244,7 @@ init_threadstate(PyThreadState *tstate,
|
|
|
|
|
tstate->datastack_top = NULL;
|
|
|
|
|
tstate->datastack_limit = NULL;
|
|
|
|
|
|
|
|
|
|
tstate->_status = PyThreadState_INITIALIZED;
|
|
|
|
|
tstate->_status.initialized = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PyThreadState *
|
|
|
|
|
@@ -1208,17 +1304,29 @@ PyThreadState_New(PyInterpreterState *interp)
|
|
|
|
|
PyThreadState *tstate = new_threadstate(interp);
|
|
|
|
|
if (tstate) {
|
|
|
|
|
bind_tstate(tstate);
|
|
|
|
|
// This makes sure there's a gilstate tstate bound
|
|
|
|
|
// as soon as possible.
|
|
|
|
|
if (gilstate_tss_get(tstate->interp->runtime) == NULL) {
|
|
|
|
|
bind_gilstate_tstate(tstate);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return tstate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This must be followed by a call to _PyThreadState_Bind();
|
|
|
|
|
PyThreadState *
|
|
|
|
|
_PyThreadState_Prealloc(PyInterpreterState *interp)
|
|
|
|
|
_PyThreadState_New(PyInterpreterState *interp)
|
|
|
|
|
{
|
|
|
|
|
return new_threadstate(interp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We keep this for stable ABI compabibility.
|
|
|
|
|
PyThreadState *
|
|
|
|
|
_PyThreadState_Prealloc(PyInterpreterState *interp)
|
|
|
|
|
{
|
|
|
|
|
return _PyThreadState_New(interp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We keep this around for (accidental) stable ABI compatibility.
|
|
|
|
|
// Realistically, no extensions are using it.
|
|
|
|
|
void
|
|
|
|
|
@@ -1230,6 +1338,17 @@ _PyThreadState_Init(PyThreadState *tstate)
|
|
|
|
|
void
|
|
|
|
|
PyThreadState_Clear(PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
assert(tstate->_status.initialized && !tstate->_status.cleared);
|
|
|
|
|
// XXX assert(!tstate->_status.bound || tstate->_status.unbound);
|
|
|
|
|
tstate->_status.finalizing = 1; // just in case
|
|
|
|
|
|
|
|
|
|
/* XXX Conditions we need to enforce:
|
|
|
|
|
|
|
|
|
|
* the GIL must be held by the current thread
|
|
|
|
|
* current_fast_get()->interp must match tstate->interp
|
|
|
|
|
* for the main interpreter, current_fast_get() must be the main thread
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int verbose = _PyInterpreterState_GetConfig(tstate->interp)->verbose;
|
|
|
|
|
|
|
|
|
|
if (verbose && tstate->cframe->current_frame != NULL) {
|
|
|
|
|
@@ -1244,6 +1363,17 @@ PyThreadState_Clear(PyThreadState *tstate)
|
|
|
|
|
"PyThreadState_Clear: warning: thread still has a frame\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* At this point tstate shouldn't be used any more,
|
|
|
|
|
neither to run Python code nor for other uses.
|
|
|
|
|
|
|
|
|
|
This is tricky when current_fast_get() == tstate, in the same way
|
|
|
|
|
as noted in interpreter_clear() above. The below finalizers
|
|
|
|
|
can possibly run Python code or otherwise use the partially
|
|
|
|
|
cleared thread state. For now we trust that isn't a problem
|
|
|
|
|
in practice.
|
|
|
|
|
*/
|
|
|
|
|
// XXX Deal with the possibility of problematic finalizers.
|
|
|
|
|
|
|
|
|
|
/* Don't clear tstate->pyframe: it is a borrowed reference */
|
|
|
|
|
|
|
|
|
|
Py_CLEAR(tstate->dict);
|
|
|
|
|
@@ -1274,6 +1404,11 @@ PyThreadState_Clear(PyThreadState *tstate)
|
|
|
|
|
if (tstate->on_delete != NULL) {
|
|
|
|
|
tstate->on_delete(tstate->on_delete_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tstate->_status.cleared = 1;
|
|
|
|
|
|
|
|
|
|
// XXX Call _PyThreadStateSwap(runtime, NULL) here if "current".
|
|
|
|
|
// XXX Do it as early in the function as possible.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1281,7 +1416,8 @@ PyThreadState_Clear(PyThreadState *tstate)
|
|
|
|
|
static void
|
|
|
|
|
tstate_delete_common(PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
_Py_EnsureTstateNotNULL(tstate);
|
|
|
|
|
assert(tstate->_status.cleared && !tstate->_status.finalized);
|
|
|
|
|
|
|
|
|
|
PyInterpreterState *interp = tstate->interp;
|
|
|
|
|
if (interp == NULL) {
|
|
|
|
|
Py_FatalError("NULL interpreter");
|
|
|
|
|
@@ -1300,7 +1436,11 @@ tstate_delete_common(PyThreadState *tstate)
|
|
|
|
|
}
|
|
|
|
|
HEAD_UNLOCK(runtime);
|
|
|
|
|
|
|
|
|
|
// XXX Do this in PyThreadState_Swap() (and assert not-equal here)?
|
|
|
|
|
// XXX Unbind in PyThreadState_Clear(), or earlier
|
|
|
|
|
// (and assert not-equal here)?
|
|
|
|
|
if (tstate->_status.bound_gilstate) {
|
|
|
|
|
unbind_gilstate_tstate(tstate);
|
|
|
|
|
}
|
|
|
|
|
unbind_tstate(tstate);
|
|
|
|
|
|
|
|
|
|
// XXX Move to PyThreadState_Clear()?
|
|
|
|
|
@@ -1311,25 +1451,32 @@ tstate_delete_common(PyThreadState *tstate)
|
|
|
|
|
_PyObject_VirtualFree(chunk, chunk->size);
|
|
|
|
|
chunk = prev;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tstate->_status.finalized = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_PyThreadState_Delete(PyThreadState *tstate, int check_current)
|
|
|
|
|
zapthreads(PyInterpreterState *interp)
|
|
|
|
|
{
|
|
|
|
|
if (check_current) {
|
|
|
|
|
if (tstate == current_fast_get(tstate->interp->runtime)) {
|
|
|
|
|
_Py_FatalErrorFormat(__func__, "tstate %p is still current", tstate);
|
|
|
|
|
}
|
|
|
|
|
PyThreadState *tstate;
|
|
|
|
|
/* No need to lock the mutex here because this should only happen
|
|
|
|
|
when the threads are all really dead (XXX famous last words). */
|
|
|
|
|
while ((tstate = interp->threads.head) != NULL) {
|
|
|
|
|
tstate_verify_not_active(tstate);
|
|
|
|
|
tstate_delete_common(tstate);
|
|
|
|
|
free_threadstate(tstate);
|
|
|
|
|
}
|
|
|
|
|
tstate_delete_common(tstate);
|
|
|
|
|
free_threadstate(tstate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PyThreadState_Delete(PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
_PyThreadState_Delete(tstate, 1);
|
|
|
|
|
_Py_EnsureTstateNotNULL(tstate);
|
|
|
|
|
tstate_verify_not_active(tstate);
|
|
|
|
|
tstate_delete_common(tstate);
|
|
|
|
|
free_threadstate(tstate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1359,9 +1506,11 @@ PyThreadState_DeleteCurrent(void)
|
|
|
|
|
* be kept in those other interpreters.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
_PyThreadState_DeleteExcept(_PyRuntimeState *runtime, PyThreadState *tstate)
|
|
|
|
|
_PyThreadState_DeleteExcept(PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
assert(tstate != NULL);
|
|
|
|
|
PyInterpreterState *interp = tstate->interp;
|
|
|
|
|
_PyRuntimeState *runtime = interp->runtime;
|
|
|
|
|
|
|
|
|
|
HEAD_LOCK(runtime);
|
|
|
|
|
/* Remove all thread states, except tstate, from the linked list of
|
|
|
|
|
@@ -1460,6 +1609,38 @@ PyThreadState_GetID(PyThreadState *tstate)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
tstate_activate(PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
assert(tstate != NULL);
|
|
|
|
|
// XXX assert(tstate_is_alive(tstate));
|
|
|
|
|
assert(tstate_is_bound(tstate));
|
|
|
|
|
assert(!tstate->_status.active);
|
|
|
|
|
|
|
|
|
|
assert(!tstate->_status.bound_gilstate ||
|
|
|
|
|
tstate == gilstate_tss_get((tstate->interp->runtime)));
|
|
|
|
|
if (!tstate->_status.bound_gilstate) {
|
|
|
|
|
bind_gilstate_tstate(tstate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tstate->_status.active = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
tstate_deactivate(PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
assert(tstate != NULL);
|
|
|
|
|
// XXX assert(tstate_is_alive(tstate));
|
|
|
|
|
assert(tstate_is_bound(tstate));
|
|
|
|
|
assert(tstate->_status.active);
|
|
|
|
|
|
|
|
|
|
tstate->_status.active = 0;
|
|
|
|
|
|
|
|
|
|
// We do not unbind the gilstate tstate here.
|
|
|
|
|
// It will still be used in PyGILState_Ensure().
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//----------
|
|
|
|
|
// other API
|
|
|
|
|
//----------
|
|
|
|
|
@@ -1535,31 +1716,43 @@ PyThreadState_Get(void)
|
|
|
|
|
PyThreadState *
|
|
|
|
|
_PyThreadState_Swap(_PyRuntimeState *runtime, PyThreadState *newts)
|
|
|
|
|
{
|
|
|
|
|
#if defined(Py_DEBUG)
|
|
|
|
|
/* This can be called from PyEval_RestoreThread(). Similar
|
|
|
|
|
to it, we need to ensure errno doesn't change.
|
|
|
|
|
*/
|
|
|
|
|
int err = errno;
|
|
|
|
|
#endif
|
|
|
|
|
PyThreadState *oldts = current_fast_get(runtime);
|
|
|
|
|
|
|
|
|
|
if (newts == NULL) {
|
|
|
|
|
current_fast_clear(runtime);
|
|
|
|
|
current_fast_clear(runtime);
|
|
|
|
|
|
|
|
|
|
if (oldts != NULL) {
|
|
|
|
|
// XXX assert(tstate_is_alive(oldts) && tstate_is_bound(oldts));
|
|
|
|
|
tstate_deactivate(oldts);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
|
|
if (newts != NULL) {
|
|
|
|
|
// XXX assert(tstate_is_alive(newts));
|
|
|
|
|
assert(tstate_is_bound(newts));
|
|
|
|
|
current_fast_set(runtime, newts);
|
|
|
|
|
tstate_activate(newts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* It should not be possible for more than one thread state
|
|
|
|
|
to be used for a thread. Check this the best we can in debug
|
|
|
|
|
builds.
|
|
|
|
|
*/
|
|
|
|
|
// XXX The above isn't true when multiple interpreters are involved.
|
|
|
|
|
#if defined(Py_DEBUG)
|
|
|
|
|
if (newts && current_tss_initialized(runtime)) {
|
|
|
|
|
/* This can be called from PyEval_RestoreThread(). Similar
|
|
|
|
|
to it, we need to ensure errno doesn't change.
|
|
|
|
|
*/
|
|
|
|
|
int err = errno;
|
|
|
|
|
PyThreadState *check = current_tss_get(runtime);
|
|
|
|
|
if (check && check->interp == newts->interp && check != newts) {
|
|
|
|
|
Py_FatalError("Invalid thread state for this thread");
|
|
|
|
|
if (newts && gilstate_tss_initialized(runtime)) {
|
|
|
|
|
PyThreadState *check = gilstate_tss_get(runtime);
|
|
|
|
|
if (check != newts) {
|
|
|
|
|
if (check && check->interp == newts->interp) {
|
|
|
|
|
Py_FatalError("Invalid thread state for this thread");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
errno = err;
|
|
|
|
|
}
|
|
|
|
|
errno = err;
|
|
|
|
|
#endif
|
|
|
|
|
return oldts;
|
|
|
|
|
}
|
|
|
|
|
@@ -1575,6 +1768,11 @@ void
|
|
|
|
|
_PyThreadState_Bind(PyThreadState *tstate)
|
|
|
|
|
{
|
|
|
|
|
bind_tstate(tstate);
|
|
|
|
|
// This makes sure there's a gilstate tstate bound
|
|
|
|
|
// as soon as possible.
|
|
|
|
|
if (gilstate_tss_get(tstate->interp->runtime) == NULL) {
|
|
|
|
|
bind_gilstate_tstate(tstate);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1863,7 +2061,7 @@ _PyGILState_Init(PyInterpreterState *interp)
|
|
|
|
|
return _PyStatus_OK();
|
|
|
|
|
}
|
|
|
|
|
_PyRuntimeState *runtime = interp->runtime;
|
|
|
|
|
assert(current_tss_get(runtime) == NULL);
|
|
|
|
|
assert(gilstate_tss_get(runtime) == NULL);
|
|
|
|
|
assert(runtime->gilstate.autoInterpreterState == NULL);
|
|
|
|
|
runtime->gilstate.autoInterpreterState = interp;
|
|
|
|
|
return _PyStatus_OK();
|
|
|
|
|
@@ -1899,7 +2097,7 @@ _PyGILState_SetTstate(PyThreadState *tstate)
|
|
|
|
|
_PyRuntimeState *runtime = tstate->interp->runtime;
|
|
|
|
|
|
|
|
|
|
assert(runtime->gilstate.autoInterpreterState == tstate->interp);
|
|
|
|
|
assert(current_tss_get(runtime) == tstate);
|
|
|
|
|
assert(gilstate_tss_get(runtime) == tstate);
|
|
|
|
|
assert(tstate->gilstate_counter == 1);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
@@ -1918,10 +2116,10 @@ PyThreadState *
|
|
|
|
|
PyGILState_GetThisThreadState(void)
|
|
|
|
|
{
|
|
|
|
|
_PyRuntimeState *runtime = &_PyRuntime;
|
|
|
|
|
if (!current_tss_initialized(runtime)) {
|
|
|
|
|
if (!gilstate_tss_initialized(runtime)) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return current_tss_get(runtime);
|
|
|
|
|
return gilstate_tss_get(runtime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
@@ -1932,7 +2130,7 @@ PyGILState_Check(void)
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!current_tss_initialized(runtime)) {
|
|
|
|
|
if (!gilstate_tss_initialized(runtime)) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1941,7 +2139,7 @@ PyGILState_Check(void)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (tstate == current_tss_get(runtime));
|
|
|
|
|
return (tstate == gilstate_tss_get(runtime));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyGILState_STATE
|
|
|
|
|
@@ -1957,17 +2155,19 @@ PyGILState_Ensure(void)
|
|
|
|
|
/* Ensure that _PyEval_InitThreads() and _PyGILState_Init() have been
|
|
|
|
|
called by Py_Initialize() */
|
|
|
|
|
assert(_PyEval_ThreadsInitialized(runtime));
|
|
|
|
|
assert(current_tss_initialized(runtime));
|
|
|
|
|
assert(gilstate_tss_initialized(runtime));
|
|
|
|
|
assert(runtime->gilstate.autoInterpreterState != NULL);
|
|
|
|
|
|
|
|
|
|
PyThreadState *tcur = current_tss_get(runtime);
|
|
|
|
|
PyThreadState *tcur = gilstate_tss_get(runtime);
|
|
|
|
|
int has_gil;
|
|
|
|
|
if (tcur == NULL) {
|
|
|
|
|
/* Create a new Python thread state for this thread */
|
|
|
|
|
tcur = PyThreadState_New(runtime->gilstate.autoInterpreterState);
|
|
|
|
|
tcur = new_threadstate(runtime->gilstate.autoInterpreterState);
|
|
|
|
|
if (tcur == NULL) {
|
|
|
|
|
Py_FatalError("Couldn't create thread-state for new thread");
|
|
|
|
|
}
|
|
|
|
|
bind_tstate(tcur);
|
|
|
|
|
bind_gilstate_tstate(tcur);
|
|
|
|
|
|
|
|
|
|
/* This is our thread state! We'll need to delete it in the
|
|
|
|
|
matching call to PyGILState_Release(). */
|
|
|
|
|
@@ -1997,7 +2197,7 @@ void
|
|
|
|
|
PyGILState_Release(PyGILState_STATE oldstate)
|
|
|
|
|
{
|
|
|
|
|
_PyRuntimeState *runtime = &_PyRuntime;
|
|
|
|
|
PyThreadState *tstate = current_tss_get(runtime);
|
|
|
|
|
PyThreadState *tstate = gilstate_tss_get(runtime);
|
|
|
|
|
if (tstate == NULL) {
|
|
|
|
|
Py_FatalError("auto-releasing thread-state, "
|
|
|
|
|
"but no thread-state for this thread");
|
|
|
|
|
@@ -2023,6 +2223,7 @@ PyGILState_Release(PyGILState_STATE oldstate)
|
|
|
|
|
if (tstate->gilstate_counter == 0) {
|
|
|
|
|
/* can't have been locked when we created it */
|
|
|
|
|
assert(oldstate == PyGILState_UNLOCKED);
|
|
|
|
|
// XXX Unbind tstate here.
|
|
|
|
|
PyThreadState_Clear(tstate);
|
|
|
|
|
/* Delete the thread-state. Note this releases the GIL too!
|
|
|
|
|
* It's vital that the GIL be held here, to avoid shutdown
|
|
|
|
|
|