diff --git a/Include/ceval.h b/Include/ceval.h
index 62c6489ed1..3bae89ae62 100644
--- a/Include/ceval.h
+++ b/Include/ceval.h
@@ -138,12 +138,20 @@ Py_DEPRECATED(3.2) PyAPI_FUNC(void) PyEval_AcquireLock(void);
PyAPI_FUNC(void) PyEval_AcquireThread(PyThreadState *tstate);
PyAPI_FUNC(void) PyEval_ReleaseThread(PyThreadState *tstate);
+#define Py_BLOCK_THREADS \
+ if (_wrapper.ts == NULL) PyThread_exit_thread(); \
+ PyEval_RestoreThread(_wrapper.ts);
+#define Py_UNBLOCK_THREADS \
+ _ts = PyThreadState_GET(); \
+ _ts->wrapper = &_wrapper; \
+ _wrapper.ts = _ts; \
+ (void)PyEval_SaveThread();
#define Py_BEGIN_ALLOW_THREADS { \
- PyThreadState *_save; \
- _save = PyEval_SaveThread();
-#define Py_BLOCK_THREADS PyEval_RestoreThread(_save);
-#define Py_UNBLOCK_THREADS _save = PyEval_SaveThread();
-#define Py_END_ALLOW_THREADS PyEval_RestoreThread(_save); \
+ PyThreadStateWrapper _wrapper; \
+ PyThreadState *_ts; \
+ Py_UNBLOCK_THREADS
+#define Py_END_ALLOW_THREADS \
+ Py_BLOCK_THREADS \
}
/* Masks and values used by FORMAT_VALUE opcode. */
diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h
index 6c8d2ae041..61c714ea42 100644
--- a/Include/cpython/pystate.h
+++ b/Include/cpython/pystate.h
@@ -135,10 +135,20 @@ struct _ts {
/* Unique thread state id. */
uint64_t id;
+ /* (Optional) wrapper that will survive this thread state being freed, used
+ * by daemon threads that wake up after interpreter finalization.
+ */
+ struct _ts_wrapper *wrapper;
+
/* XXX signal handlers should also be here */
};
+// The PyThreadStateWrapper typedef is in Include/pystate.h.
+struct _ts_wrapper {
+ PyThreadState *ts;
+};
+
/* Get the current interpreter state.
Issue a fatal error if there no current Python thread state or no current
diff --git a/Include/pystate.h b/Include/pystate.h
index 1cb2305696..413e1dc4da 100644
--- a/Include/pystate.h
+++ b/Include/pystate.h
@@ -17,10 +17,12 @@ removed (with effort). */
and PyInterpreterState */
struct _frame;
struct _ts;
+struct _ts_wrapper;
struct _is;
/* struct _ts is defined in cpython/pystate.h */
typedef struct _ts PyThreadState;
+typedef struct _ts_wrapper PyThreadStateWrapper;
/* struct _is is defined in internal/pycore_pystate.h */
typedef struct _is PyInterpreterState;
diff --git a/Python/pystate.c b/Python/pystate.c
index 0a6d035836..56e39470c3 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -826,6 +826,10 @@ tstate_delete_common(PyThreadState *tstate,
if (tstate->on_delete != NULL) {
tstate->on_delete(tstate->on_delete_data);
}
+ if (tstate->wrapper != NULL) {
+ assert(tstate->wrapper->ts == tstate);
+ tstate->wrapper->ts = NULL;
+ }
PyMem_RawFree(tstate);
if (gilstate->autoInterpreterState &&