bpo-32604: Clean up created subinterpreters before runtime finalization. (gh-5710)

(cherry picked from commit 4c6955e2b0ccf88c705f8d1fac685a8e65f9699e)

Co-authored-by: Eric Snow <ericsnowcurrently@gmail.com>
diff --git a/Python/pystate.c b/Python/pystate.c
index 8dbda73..8cbf1fa 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -125,7 +125,8 @@
         return NULL;
     }
 
-
+    interp->id_refcount = -1;
+    interp->id_mutex = NULL;
     interp->modules = NULL;
     interp->modules_by_index = NULL;
     interp->sysdict = NULL;
@@ -247,6 +248,9 @@
             Py_FatalError("PyInterpreterState_Delete: remaining subinterpreters");
     }
     HEAD_UNLOCK();
+    if (interp->id_mutex != NULL) {
+        PyThread_free_lock(interp->id_mutex);
+    }
     PyMem_RawFree(interp);
 }
 
@@ -284,6 +288,58 @@
     return NULL;
 }
 
+
+int
+_PyInterpreterState_IDInitref(PyInterpreterState *interp)
+{
+    if (interp->id_mutex != NULL) {
+        return 0;
+    }
+    interp->id_mutex = PyThread_allocate_lock();
+    if (interp->id_mutex == NULL) {
+        PyErr_SetString(PyExc_RuntimeError,
+                        "failed to create init interpreter ID mutex");
+        return -1;
+    }
+    interp->id_refcount = 0;
+    return 0;
+}
+
+
+void
+_PyInterpreterState_IDIncref(PyInterpreterState *interp)
+{
+    if (interp->id_mutex == NULL) {
+        return;
+    }
+    PyThread_acquire_lock(interp->id_mutex, WAIT_LOCK);
+    interp->id_refcount += 1;
+    PyThread_release_lock(interp->id_mutex);
+}
+
+
+void
+_PyInterpreterState_IDDecref(PyInterpreterState *interp)
+{
+    if (interp->id_mutex == NULL) {
+        return;
+    }
+    PyThread_acquire_lock(interp->id_mutex, WAIT_LOCK);
+    assert(interp->id_refcount != 0);
+    interp->id_refcount -= 1;
+    int64_t refcount = interp->id_refcount;
+    PyThread_release_lock(interp->id_mutex);
+
+    if (refcount == 0) {
+        PyThreadState *tstate, *save_tstate;
+        tstate = PyInterpreterState_ThreadHead(interp);
+        save_tstate = PyThreadState_Swap(tstate);
+        Py_EndInterpreter(tstate);
+        PyThreadState_Swap(save_tstate);
+    }
+}
+
+
 /* Default implementation for _PyThreadState_GetFrame */
 static struct _frame *
 threadstate_getframe(PyThreadState *self)