Skip to content

Commit 16d79de

Browse files
committed
Implement new version of PyThreadState_Ensure() and PyThreadState_Release()
1 parent 0a15beb commit 16d79de

2 files changed

Lines changed: 57 additions & 11 deletions

File tree

Include/cpython/pystate.h

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,6 @@ typedef struct _stack_chunk {
6161
PyObject * data[1]; /* Variable sized */
6262
} _PyStackChunk;
6363

64-
typedef struct _ensured_tstate {
65-
struct _ensured_tstate *next;
66-
PyThreadState *prior_tstate;
67-
uint8_t was_daemon;
68-
} _Py_ensured_tstate;
69-
7064
struct _ts {
7165
/* See Python/ceval.c for comments explaining most fields */
7266

@@ -213,10 +207,11 @@ struct _ts {
213207
PyObject *threading_local_sentinel;
214208
_PyRemoteDebuggerSupport remote_debugger_support;
215209

216-
/* Whether this thread hangs when the interpreter is finalizing. */
217-
uint8_t daemon;
210+
/* Number of nested PyThreadState_Ensure() calls on this thread state */
211+
Py_ssize_t ensure_counter;
218212

219-
_Py_ensured_tstate *ensured;
213+
/* Thread state that was active before PyThreadState_Ensure() was called. */
214+
PyThreadState *prior_ensure;
220215
};
221216

222217
/* other API */
@@ -279,6 +274,7 @@ PyAPI_FUNC(PyInterpreterRef) PyInterpreterRef_Get(void);
279274
PyAPI_FUNC(PyInterpreterRef) PyInterpreterRef_Dup(PyInterpreterRef ref);
280275
PyAPI_FUNC(int) PyInterpreterState_AsStrong(PyInterpreterState *interp, PyInterpreterRef *strong_ptr);
281276
PyAPI_FUNC(void) PyInterpreterRef_Close(PyInterpreterRef ref);
277+
PyAPI_FUNC(PyInterpreterState *) PyInterpreterRef_AsInterpreter(PyInterpreterRef ref);
282278

283279
#define PyInterpreterRef_Close(ref) do { \
284280
PyInterpreterRef_Close(ref); \
@@ -301,6 +297,6 @@ PyAPI_FUNC(void) PyInterpreterWeakRef_Close(PyInterpreterWeakRef wref);
301297
PyAPI_FUNC(Py_ssize_t) _PyInterpreterState_Refcount(PyInterpreterState *interp);
302298
PyAPI_FUNC(void) _PyInterpreterState_Incref(PyInterpreterState *interp);
303299

304-
PyAPI_FUNC(int) PyThreadState_Ensure(PyInterpreterState *interp);
300+
PyAPI_FUNC(int) PyThreadState_Ensure(PyInterpreterRef interp_ref);
305301

306302
PyAPI_FUNC(void) PyThreadState_Release(void);

Python/pystate.c

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3188,6 +3188,13 @@ PyInterpreterRef_Close(PyInterpreterRef ref)
31883188
decref_interpreter(interp);
31893189
}
31903190

3191+
PyInterpreterState *
3192+
PyInterpreterRef_AsInterpreter(PyInterpreterRef ref)
3193+
{
3194+
PyInterpreterState *interp = ref_as_interp(ref);
3195+
return interp;
3196+
}
3197+
31913198
PyInterpreterWeakRef
31923199
PyInterpreterWeakRef_Get(void)
31933200
{
@@ -3260,13 +3267,56 @@ PyInterpreterState_AsStrong(PyInterpreterState *interp, PyInterpreterRef *strong
32603267
}
32613268

32623269
int
3263-
PyThreadState_Ensure(PyInterpreterState *interp)
3270+
PyThreadState_Ensure(PyInterpreterRef interp_ref)
32643271
{
3272+
PyInterpreterState *interp = ref_as_interp(interp_ref);
3273+
PyThreadState *attached_tstate = current_fast_get();
3274+
if (attached_tstate != NULL && attached_tstate->interp == interp) {
3275+
/* Yay! We already have an attached thread state that matches. */
3276+
++attached_tstate->ensure_counter;
3277+
return 0;
3278+
}
3279+
3280+
PyThreadState *detached_gilstate = gilstate_get();
3281+
if (detached_gilstate != NULL && detached_gilstate->interp == interp) {
3282+
/* There's a detached thread state that works. */
3283+
assert(attached_tstate == NULL);
3284+
++detached_gilstate->ensure_counter;
3285+
_PyThreadState_Attach(detached_gilstate);
3286+
return 0;
3287+
}
3288+
3289+
PyThreadState *fresh_tstate = _PyThreadState_NewBound(interp,
3290+
_PyThreadState_WHENCE_GILSTATE);
3291+
if (fresh_tstate == NULL) {
3292+
return -1;
3293+
}
3294+
3295+
if (attached_tstate != NULL) {
3296+
fresh_tstate->ensure_counter = 1;
3297+
fresh_tstate->prior_ensure = PyThreadState_Swap(fresh_tstate);
3298+
} else {
3299+
_PyThreadState_Attach(fresh_tstate);
3300+
}
3301+
32653302
return 0;
32663303
}
32673304

32683305
void
32693306
PyThreadState_Release(void)
32703307
{
3308+
PyThreadState *tstate = current_fast_get();
3309+
_Py_EnsureTstateNotNULL(tstate);
3310+
Py_ssize_t remaining = --tstate->ensure_counter;
3311+
if (remaining < 0) {
3312+
Py_FatalError("PyThreadState_Release() called more times than PyThreadState_Ensure()");
3313+
}
3314+
if (remaining == 0) {
3315+
PyThreadState *to_restore = tstate->prior_ensure;
3316+
PyThreadState_Clear(tstate);
3317+
PyThreadState_Swap(to_restore);
3318+
PyThreadState_Delete(tstate);
3319+
}
3320+
32713321
return;
32723322
}

0 commit comments

Comments
 (0)