Skip to content

Commit 62e9549

Browse files
committed
Add a test for PyThreadState_Ensure() across interpreters.
1 parent f7723c0 commit 62e9549

3 files changed

Lines changed: 42 additions & 3 deletions

File tree

Include/cpython/pystate.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,9 @@ PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Lookup(int64_t interp_id);
288288
/* Release a reference to an interpreter incremented by PyInterpreterState_Hold() */
289289
PyAPI_FUNC(void) PyInterpreterState_Release(PyInterpreterState *interp);
290290

291-
// Export for '_testcapi' shared extension
291+
// Exports for '_testcapi' shared extension
292292
PyAPI_FUNC(Py_ssize_t) _PyInterpreterState_Refcount(PyInterpreterState *interp);
293+
PyAPI_FUNC(void) _PyInterpreterState_Incref(PyInterpreterState *interp);
293294

294295
PyAPI_FUNC(int) PyThreadState_SetDaemon(int daemon);
295296

Modules/_testcapimodule.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2591,6 +2591,36 @@ test_interp_lookup(PyObject *self, PyObject *unused)
25912591
Py_RETURN_NONE;
25922592
}
25932593

2594+
static PyObject *
2595+
test_interp_ensure(PyObject *self, PyObject *unused)
2596+
{
2597+
PyInterpreterState *interp = PyInterpreterState_Get();
2598+
PyThreadState *save_tstate = PyThreadState_Swap(NULL);
2599+
PyThreadState *tstate = Py_NewInterpreter();
2600+
PyInterpreterState *subinterp = PyThreadState_GetInterpreter(tstate);
2601+
2602+
for (int i = 0; i < 10; ++i) {
2603+
_PyInterpreterState_Incref(interp);
2604+
int res = PyThreadState_Ensure(interp);
2605+
assert(res == 0);
2606+
assert(PyInterpreterState_Get() == interp);
2607+
}
2608+
2609+
for (int i = 0; i < 10; ++i) {
2610+
_PyInterpreterState_Incref(subinterp);
2611+
int res = PyThreadState_Ensure(subinterp);
2612+
assert(res == 0);
2613+
assert(PyInterpreterState_Get() == subinterp);
2614+
}
2615+
2616+
for (int i = 0; i < 20; ++i) {
2617+
PyThreadState_Release();
2618+
}
2619+
2620+
PyThreadState_Swap(save_tstate);
2621+
Py_RETURN_NONE;
2622+
}
2623+
25942624
static PyMethodDef TestMethods[] = {
25952625
{"set_errno", set_errno, METH_VARARGS},
25962626
{"test_config", test_config, METH_NOARGS},
@@ -2687,6 +2717,7 @@ static PyMethodDef TestMethods[] = {
26872717
{"toggle_reftrace_printer", toggle_reftrace_printer, METH_O},
26882718
{"test_interp_refcount", test_interp_refcount, METH_NOARGS},
26892719
{"test_interp_lookup", test_interp_lookup, METH_NOARGS},
2720+
{"test_interp_ensure", test_interp_ensure, METH_NOARGS},
26902721
{NULL, NULL} /* sentinel */
26912722
};
26922723

Python/pystate.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3230,12 +3230,19 @@ _PyInterpreterState_Refcount(PyInterpreterState *interp)
32303230
return refcount;
32313231
}
32323232

3233+
void
3234+
_PyInterpreterState_Incref(PyInterpreterState *interp)
3235+
{
3236+
assert(interp != NULL);
3237+
assert(_Py_atomic_load_ssize_relaxed(&interp->threads.finalizing.countdown) >= 0);
3238+
_Py_atomic_add_ssize(&interp->threads.finalizing.countdown, 1);
3239+
}
3240+
32333241
PyInterpreterState *
32343242
PyInterpreterState_Hold(void)
32353243
{
32363244
PyInterpreterState *interp = PyInterpreterState_Get();
3237-
assert(_Py_atomic_load_ssize_relaxed(&interp->threads.finalizing.countdown) >= 0);
3238-
_Py_atomic_add_ssize(&interp->threads.finalizing.countdown, 1);
3245+
_PyInterpreterState_Incref(interp);
32393246
return interp;
32403247
}
32413248

0 commit comments

Comments
 (0)