Skip to content

Commit 082fd69

Browse files
committed
Add a test for crossinterpreter ensures.
1 parent d6c82bd commit 082fd69

1 file changed

Lines changed: 53 additions & 0 deletions

File tree

Modules/_testcapimodule.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2650,6 +2650,58 @@ test_thread_state_ensure_nested(PyObject *self, PyObject *unused)
26502650
Py_RETURN_NONE;
26512651
}
26522652

2653+
static PyObject *
2654+
test_thread_state_ensure_crossinterp(PyObject *self, PyObject *unused)
2655+
{
2656+
PyInterpreterRef ref = get_strong_ref();
2657+
PyThreadState *save_tstate = PyThreadState_Swap(NULL);
2658+
PyThreadState *interp_tstate = Py_NewInterpreter();
2659+
2660+
/* This should create a new thread state for the calling interpreter, *not*
2661+
reactivate the old one. In a real-world scenario, this would arise in
2662+
something like this:
2663+
2664+
def some_func():
2665+
import something
2666+
# This re-enters the main interpreter, but we
2667+
# shouldn't have access to prior thread-locals.
2668+
something.call_something()
2669+
2670+
interp = interpreters.create()
2671+
interp.exec(some_func)
2672+
*/
2673+
if (PyThreadState_Ensure(ref) < 0) {
2674+
PyInterpreterRef_Close(ref);
2675+
return PyErr_NoMemory();
2676+
}
2677+
2678+
PyThreadState *ensured_tstate = PyThreadState_Get();
2679+
assert(ensured_tstate != save_tstate);
2680+
assert(PyInterpreterState_Get() == PyInterpreterRef_AsInterpreter(ref));
2681+
assert(PyGILState_GetThisThreadState() == ensured_tstate);
2682+
2683+
// Now though, we should reactivate the thread state
2684+
if (PyThreadState_Ensure(ref) < 0) {
2685+
PyInterpreterRef_Close(ref);
2686+
return PyErr_NoMemory();
2687+
}
2688+
2689+
assert(PyThreadState_Get() == ensured_tstate);
2690+
PyThreadState_Release();
2691+
2692+
// Ensure that we're restoring the prior thread state
2693+
PyThreadState_Release();
2694+
assert(PyThreadState_Get() == interp_tstate);
2695+
assert(PyGILState_GetThisThreadState() == interp_tstate);
2696+
2697+
PyThreadState_Swap(interp_tstate);
2698+
Py_EndInterpreter(interp_tstate);
2699+
2700+
PyInterpreterRef_Close(ref);
2701+
PyThreadState_Swap(save_tstate);
2702+
Py_RETURN_NONE;
2703+
}
2704+
26532705
static PyMethodDef TestMethods[] = {
26542706
{"set_errno", set_errno, METH_VARARGS},
26552707
{"test_config", test_config, METH_NOARGS},
@@ -2746,6 +2798,7 @@ static PyMethodDef TestMethods[] = {
27462798
{"toggle_reftrace_printer", toggle_reftrace_printer, METH_O},
27472799
{"test_interpreter_refs", test_interpreter_refs, METH_NOARGS},
27482800
{"test_thread_state_ensure_nested", test_thread_state_ensure_nested, METH_NOARGS},
2801+
{"test_thread_state_ensure_crossinterp", test_thread_state_ensure_crossinterp, METH_NOARGS},
27492802
{NULL, NULL} /* sentinel */
27502803
};
27512804

0 commit comments

Comments
 (0)