bpo-31404: Revert "remove modules from Py_InterpreterState (#1638)" (#3565)

PR #1638, for bpo-28411, causes problems in some (very) edge cases. Until that gets sorted out, we're reverting the merge. PR #3506, a fix on top of #1638, is also getting reverted.
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 3265d70..0700569 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -42,7 +42,6 @@
 _Py_IDENTIFIER(stdin);
 _Py_IDENTIFIER(stdout);
 _Py_IDENTIFIER(stderr);
-_Py_IDENTIFIER(threading);
 
 #ifdef __cplusplus
 extern "C" {
@@ -284,6 +283,7 @@
 {
     PyObject *importlib;
     PyObject *impmod;
+    PyObject *sys_modules;
     PyObject *value;
 
     /* Import _importlib through its frozen version, _frozen_importlib. */
@@ -314,7 +314,11 @@
     else if (Py_VerboseFlag) {
         PySys_FormatStderr("import _imp # builtin\n");
     }
-    if (_PyImport_SetModuleString("_imp", impmod) < 0) {
+    sys_modules = PyImport_GetModuleDict();
+    if (Py_VerboseFlag) {
+        PySys_FormatStderr("import sys # builtin\n");
+    }
+    if (PyDict_SetItemString(sys_modules, "_imp", impmod) < 0) {
         Py_FatalError("Py_Initialize: can't save _imp to sys.modules");
     }
 
@@ -671,20 +675,10 @@
     if (!_PyFloat_Init())
         Py_FatalError("Py_InitializeCore: can't init float");
 
-    PyObject *modules = PyDict_New();
-    if (modules == NULL)
+    interp->modules = PyDict_New();
+    if (interp->modules == NULL)
         Py_FatalError("Py_InitializeCore: can't make modules dictionary");
 
-    sysmod = _PySys_BeginInit();
-    if (sysmod == NULL)
-        Py_FatalError("Py_InitializeCore: can't initialize sys");
-    interp->sysdict = PyModule_GetDict(sysmod);
-    if (interp->sysdict == NULL)
-        Py_FatalError("Py_InitializeCore: can't initialize sys dict");
-    Py_INCREF(interp->sysdict);
-    PyDict_SetItemString(interp->sysdict, "modules", modules);
-    _PyImport_FixupBuiltin(sysmod, "sys", modules);
-
     /* Init Unicode implementation; relies on the codec registry */
     if (_PyUnicode_Init() < 0)
         Py_FatalError("Py_InitializeCore: can't initialize unicode");
@@ -695,7 +689,7 @@
     bimod = _PyBuiltin_Init();
     if (bimod == NULL)
         Py_FatalError("Py_InitializeCore: can't initialize builtins modules");
-    _PyImport_FixupBuiltin(bimod, "builtins", modules);
+    _PyImport_FixupBuiltin(bimod, "builtins");
     interp->builtins = PyModule_GetDict(bimod);
     if (interp->builtins == NULL)
         Py_FatalError("Py_InitializeCore: can't initialize builtins dict");
@@ -704,6 +698,17 @@
     /* initialize builtin exceptions */
     _PyExc_Init(bimod);
 
+    sysmod = _PySys_BeginInit();
+    if (sysmod == NULL)
+        Py_FatalError("Py_InitializeCore: can't initialize sys");
+    interp->sysdict = PyModule_GetDict(sysmod);
+    if (interp->sysdict == NULL)
+        Py_FatalError("Py_InitializeCore: can't initialize sys dict");
+    Py_INCREF(interp->sysdict);
+    _PyImport_FixupBuiltin(sysmod, "sys");
+    PyDict_SetItemString(interp->sysdict, "modules",
+                         interp->modules);
+
     /* Set up a preliminary stderr printer until we have enough
        infrastructure for the io module in place. */
     pstderr = PyFile_NewStdPrinter(fileno(stderr));
@@ -1006,11 +1011,6 @@
     while (_PyGC_CollectIfEnabled() > 0)
         /* nothing */;
 #endif
-
-#ifdef Py_REF_DEBUG
-    PyObject *showrefcount = _PyDebug_XOptionShowRefCount();
-#endif
-
     /* Destroy all modules */
     PyImport_Cleanup();
 
@@ -1058,10 +1058,7 @@
     /* dump hash stats */
     _PyHash_Fini();
 
-#ifdef Py_REF_DEBUG
-        if (showrefcount == Py_True)
-            _PyDebug_PrintTotalRefs();
-#endif
+    _PY_DEBUG_PRINT_TOTAL_REFS();
 
 #ifdef Py_TRACE_REFS
     /* Display all objects still alive -- this can invoke arbitrary
@@ -1206,22 +1203,9 @@
 
     /* XXX The following is lax in error checking */
 
-    PyObject *modules = PyDict_New();
-    if (modules == NULL)
-        Py_FatalError("Py_NewInterpreter: can't make modules dictionary");
+    interp->modules = PyDict_New();
 
-    sysmod = _PyImport_FindBuiltin("sys", modules);
-    if (sysmod != NULL) {
-        interp->sysdict = PyModule_GetDict(sysmod);
-        if (interp->sysdict == NULL)
-            goto handle_error;
-        Py_INCREF(interp->sysdict);
-        PyDict_SetItemString(interp->sysdict, "modules", modules);
-        PySys_SetPath(Py_GetPath());
-        _PySys_EndInit(interp->sysdict);
-    }
-
-    bimod = _PyImport_FindBuiltin("builtins", modules);
+    bimod = _PyImport_FindBuiltin("builtins");
     if (bimod != NULL) {
         interp->builtins = PyModule_GetDict(bimod);
         if (interp->builtins == NULL)
@@ -1232,9 +1216,18 @@
     /* initialize builtin exceptions */
     _PyExc_Init(bimod);
 
+    sysmod = _PyImport_FindBuiltin("sys");
     if (bimod != NULL && sysmod != NULL) {
         PyObject *pstderr;
 
+        interp->sysdict = PyModule_GetDict(sysmod);
+        if (interp->sysdict == NULL)
+            goto handle_error;
+        Py_INCREF(interp->sysdict);
+        _PySys_EndInit(interp->sysdict);
+        PySys_SetPath(Py_GetPath());
+        PyDict_SetItemString(interp->sysdict, "modules",
+                             interp->modules);
         /* Set up a preliminary stderr printer until we have enough
            infrastructure for the io module in place. */
         pstderr = PyFile_NewStdPrinter(fileno(stderr));
@@ -1910,13 +1903,14 @@
 {
     _Py_IDENTIFIER(_shutdown);
     PyObject *result;
-    PyObject *threading = _PyImport_GetModuleId(&PyId_threading);
+    PyThreadState *tstate = PyThreadState_GET();
+    PyObject *threading = PyMapping_GetItemString(tstate->interp->modules,
+                                                  "threading");
     if (threading == NULL) {
         /* threading not imported */
         PyErr_Clear();
         return;
     }
-    Py_INCREF(threading);
     result = _PyObject_CallMethodId(threading, &PyId__shutdown, NULL);
     if (result == NULL) {
         PyErr_WriteUnraisable(threading);