@@ -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+
26532705static 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