Skip to content

Commit d6c82bd

Browse files
committed
Only delete thread states created by PyThreadState_Ensure()
1 parent 02f93bc commit d6c82bd

2 files changed

Lines changed: 26 additions & 13 deletions

File tree

Include/cpython/pystate.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -207,11 +207,19 @@ struct _ts {
207207
PyObject *threading_local_sentinel;
208208
_PyRemoteDebuggerSupport remote_debugger_support;
209209

210-
/* Number of nested PyThreadState_Ensure() calls on this thread state */
211-
Py_ssize_t ensure_counter;
210+
struct {
211+
/* Number of nested PyThreadState_Ensure() calls on this thread state */
212+
Py_ssize_t counter;
213+
214+
/* Thread state that was active before PyThreadState_Ensure() was called. */
215+
PyThreadState *prior_tstate;
216+
217+
/* Should this thread state be deleted upon calling
218+
PyThreadState_Release() (with the counter at 1)?
212219
213-
/* Thread state that was active before PyThreadState_Ensure() was called. */
214-
PyThreadState *prior_ensure;
220+
This is only true for thread states created by PyThreadState_Ensure() */
221+
int delete_on_release;
222+
} ensure;
215223
};
216224

217225
/* other API */

Python/pystate.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3320,15 +3320,15 @@ PyThreadState_Ensure(PyInterpreterRef interp_ref)
33203320
PyThreadState *attached_tstate = current_fast_get();
33213321
if (attached_tstate != NULL && attached_tstate->interp == interp) {
33223322
/* Yay! We already have an attached thread state that matches. */
3323-
++attached_tstate->ensure_counter;
3323+
++attached_tstate->ensure.counter;
33243324
return 0;
33253325
}
33263326

33273327
PyThreadState *detached_gilstate = gilstate_get();
33283328
if (detached_gilstate != NULL && detached_gilstate->interp == interp) {
33293329
/* There's a detached thread state that works. */
33303330
assert(attached_tstate == NULL);
3331-
++detached_gilstate->ensure_counter;
3331+
++detached_gilstate->ensure.counter;
33323332
_PyThreadState_Attach(detached_gilstate);
33333333
return 0;
33343334
}
@@ -3338,10 +3338,11 @@ PyThreadState_Ensure(PyInterpreterRef interp_ref)
33383338
if (fresh_tstate == NULL) {
33393339
return -1;
33403340
}
3341-
fresh_tstate->ensure_counter = 1;
3341+
fresh_tstate->ensure.counter = 1;
3342+
fresh_tstate->ensure.delete_on_release = 1;
33423343

33433344
if (attached_tstate != NULL) {
3344-
fresh_tstate->prior_ensure = PyThreadState_Swap(fresh_tstate);
3345+
fresh_tstate->ensure.prior_tstate = PyThreadState_Swap(fresh_tstate);
33453346
} else {
33463347
_PyThreadState_Attach(fresh_tstate);
33473348
}
@@ -3354,15 +3355,19 @@ PyThreadState_Release(void)
33543355
{
33553356
PyThreadState *tstate = current_fast_get();
33563357
_Py_EnsureTstateNotNULL(tstate);
3357-
Py_ssize_t remaining = --tstate->ensure_counter;
3358+
Py_ssize_t remaining = --tstate->ensure.counter;
33583359
if (remaining < 0) {
33593360
Py_FatalError("PyThreadState_Release() called more times than PyThreadState_Ensure()");
33603361
}
3362+
PyThreadState *to_restore = tstate->ensure.prior_tstate;
33613363
if (remaining == 0) {
3362-
PyThreadState *to_restore = tstate->prior_ensure;
3363-
PyThreadState_Clear(tstate);
3364-
PyThreadState_Swap(to_restore);
3365-
PyThreadState_Delete(tstate);
3364+
if (tstate->ensure.delete_on_release) {
3365+
PyThreadState_Clear(tstate);
3366+
PyThreadState_Swap(to_restore);
3367+
PyThreadState_Delete(tstate);
3368+
} else {
3369+
PyThreadState_Swap(to_restore);
3370+
}
33663371
}
33673372

33683373
return;

0 commit comments

Comments
 (0)