python-cffi/87f514b.patch
2023-06-14 09:08:44 +02:00

104 lines
3.9 KiB
Diff

From 87f514b8a4fc6b29df8febf1176ad846007a5b56 Mon Sep 17 00:00:00 2001
From: Armin Rigo <arigo@tunes.org>
Date: Thu, 8 Jun 2023 18:34:20 +0200
Subject: [PATCH] Fix for what may be a CPython 3.12 bug, or just me abusing
the API
---
c/misc_thread_common.h | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/c/misc_thread_common.h b/c/misc_thread_common.h
index 66e28354..9e9a818d 100644
--- a/c/misc_thread_common.h
+++ b/c/misc_thread_common.h
@@ -102,6 +102,7 @@ thread_canary_dealloc(ThreadCanaryObj *ob)
'local_thread_canary' accesses need to be protected with
the TLS_ZOM_LOCK.
*/
+ //fprintf(stderr, "entering dealloc(%p)\n", ob);
TLS_ZOM_LOCK();
if (ob->zombie_next != NULL) {
//fprintf(stderr, "thread_canary_dealloc(%p): ZOMBIE\n", ob);
@@ -136,6 +137,7 @@ thread_canary_make_zombie(ThreadCanaryObj *ob)
ob->zombie_prev = last;
last->zombie_next = ob;
cffi_zombie_head.zombie_prev = ob;
+ //fprintf(stderr, "thread_canary_make_zombie(%p) DONE\n", ob);
}
static void
@@ -164,6 +166,15 @@ thread_canary_free_zombies(void)
break;
PyThreadState_Clear(tstate); /* calls thread_canary_dealloc on 'ob',
but now ob->zombie_next == NULL. */
+#if PY_HEX_VERSION >= 0x030C0000
+ /* this might be a bug introduced in 3.12, or just me abusing the
+ API around there. The issue is that PyThreadState_Delete()
+ called on a random old tstate will clear the *current* thread
+ notion of what PyGILState_GetThisThreadState() should be, at
+ least if the internal 'bound_gilstate' flag is set in the old
+ tstate. Workaround: clear that flag. */
+ tstate->_status.bound_gilstate = 0;
+#endif
PyThreadState_Delete(tstate);
//fprintf(stderr, "thread_canary_free_zombie: cleared and deleted tstate=%p\n", tstate);
}
@@ -213,9 +224,11 @@ thread_canary_register(PyThreadState *tstate)
tstate->gilstate_counter++;
/* ^^^ this means 'tstate' will never be automatically freed by
PyGILState_Release() */
+ //fprintf(stderr, "CANARY: ready, tstate=%p, tls=%p, canary=%p\n", tstate, tls, canary);
return;
ignore_error:
+ //fprintf(stderr, "CANARY: IGNORED ERROR\n");
PyErr_Clear();
}
@@ -334,6 +347,7 @@ static PyGILState_STATE gil_ensure(void)
*/
PyGILState_STATE result;
PyThreadState *ts = PyGILState_GetThisThreadState();
+ //fprintf(stderr, "%p: gil_ensure(), tstate=%p, tls=%p\n", get_cffi_tls(), ts, get_cffi_tls());
if (ts != NULL) {
ts->gilstate_counter++;
@@ -341,9 +355,11 @@ static PyGILState_STATE gil_ensure(void)
/* common case: 'ts' is our non-current thread state and
we have to make it current and acquire the GIL */
PyEval_RestoreThread(ts);
+ //fprintf(stderr, "%p: gil_ensure(), tstate=%p MADE CURRENT\n", get_cffi_tls(), ts);
return PyGILState_UNLOCKED;
}
else {
+ //fprintf(stderr, "%p: gil_ensure(), tstate=%p ALREADY CURRENT\n", get_cffi_tls(), ts);
return PyGILState_LOCKED;
}
}
@@ -353,6 +369,7 @@ static PyGILState_STATE gil_ensure(void)
assert(result == PyGILState_UNLOCKED);
ts = PyGILState_GetThisThreadState();
+ //fprintf(stderr, "%p: gil_ensure(), made a new tstate=%p\n", get_cffi_tls(), ts);
assert(ts != NULL);
assert(ts == get_current_ts());
assert(ts->gilstate_counter >= 1);
@@ -361,11 +378,13 @@ static PyGILState_STATE gil_ensure(void)
thread really shuts down */
thread_canary_register(ts);
+ assert(ts == PyGILState_GetThisThreadState());
return result;
}
}
static void gil_release(PyGILState_STATE oldstate)
{
+ //fprintf(stderr, "%p: gil_release(%d), tls=%p\n", get_cffi_tls(), (int)oldstate, get_cffi_tls());
PyGILState_Release(oldstate);
}
--
GitLab