self.assertFalse(
self.interp_exists(interpid))
+ with self.subTest('basic C-API'):
+ interpid = _testinternalcapi.create_interpreter()
+ self.assertTrue(
+ self.interp_exists(interpid))
+ _testinternalcapi.destroy_interpreter(interpid, basic=True)
+ self.assertFalse(
+ self.interp_exists(interpid))
+
def test_get_config(self):
# This test overlaps with
# test.test_capi.test_misc.InterpreterConfigTests.
static PyObject *
destroy_interpreter(PyObject *self, PyObject *args, PyObject *kwargs)
{
- static char *kwlist[] = {"id", NULL};
+ static char *kwlist[] = {"id", "basic", NULL};
PyObject *idobj = NULL;
+ int basic = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
- "O:destroy_interpreter", kwlist,
- &idobj))
+ "O|p:destroy_interpreter", kwlist,
+ &idobj, &basic))
{
return NULL;
}
return NULL;
}
- _PyXI_EndInterpreter(interp, NULL, NULL);
+ if (basic)
+ {
+ // Test the basic Py_EndInterpreter with weird out of order thread states
+ PyThreadState *t1, *t2;
+ PyThreadState *prev;
+ t1 = interp->threads.head;
+ if (t1 == NULL) {
+ t1 = PyThreadState_New(interp);
+ }
+ t2 = PyThreadState_New(interp);
+ prev = PyThreadState_Swap(t2);
+ PyThreadState_Clear(t1);
+ PyThreadState_Delete(t1);
+ Py_EndInterpreter(t2);
+ PyThreadState_Swap(prev);
+ }
+ else
+ {
+ // use the cross interpreter _PyXI_EndInterpreter normally
+ _PyXI_EndInterpreter(interp, NULL, NULL);
+ }
Py_RETURN_NONE;
}
static void
zapthreads(PyInterpreterState *interp)
{
+ PyThreadState *tstate;
/* No need to lock the mutex here because this should only happen
- when the threads are all really dead (XXX famous last words). */
- _Py_FOR_EACH_TSTATE_UNLOCKED(interp, tstate) {
+ when the threads are all really dead (XXX famous last words).
+
+ Cannot use _Py_FOR_EACH_TSTATE_UNLOCKED because we are freeing
+ the thread states here.
+ */
+ while ((tstate = interp->threads.head) != NULL) {
tstate_verify_not_active(tstate);
tstate_delete_common(tstate, 0);
free_threadstate((_PyThreadStateImpl *)tstate);