aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Python/pylifecycle.c
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.com>2024-02-12 07:53:52 +0300
committershadchin <shadchin@yandex-team.com>2024-02-12 08:07:36 +0300
commitce1b7ca3171f9158180640c6a02a74b4afffedea (patch)
treee47c1e8391b1b0128262c1e9b1e6ed4c8fff2348 /contrib/tools/python3/src/Python/pylifecycle.c
parent57350d96f030db90f220ce50ee591d5c5d403df7 (diff)
downloadydb-ce1b7ca3171f9158180640c6a02a74b4afffedea.tar.gz
Update Python from 3.11.8 to 3.12.2
Diffstat (limited to 'contrib/tools/python3/src/Python/pylifecycle.c')
-rw-r--r--contrib/tools/python3/src/Python/pylifecycle.c614
1 files changed, 362 insertions, 252 deletions
diff --git a/contrib/tools/python3/src/Python/pylifecycle.c b/contrib/tools/python3/src/Python/pylifecycle.c
index 4a6787d36d..a0130fde15 100644
--- a/contrib/tools/python3/src/Python/pylifecycle.c
+++ b/contrib/tools/python3/src/Python/pylifecycle.c
@@ -2,7 +2,6 @@
#include "Python.h"
-#include "pycore_bytesobject.h" // _PyBytes_InitTypes()
#include "pycore_ceval.h" // _PyEval_FiniGIL()
#include "pycore_context.h" // _PyContext_Init()
#include "pycore_exceptions.h" // _PyExc_InitTypes()
@@ -10,6 +9,7 @@
#include "pycore_fileutils.h" // _Py_ResetForceASCII()
#include "pycore_floatobject.h" // _PyFloat_InitTypes()
#include "pycore_genobject.h" // _PyAsyncGen_Fini()
+#include "pycore_global_objects_fini_generated.h" // "_PyStaticObjects_CheckRefcnt()
#include "pycore_import.h" // _PyImport_BootstrapImp()
#include "pycore_initconfig.h" // _PyStatus_OK()
#include "pycore_list.h" // _PyList_Fini()
@@ -25,11 +25,10 @@
#include "pycore_sliceobject.h" // _PySlice_Fini()
#include "pycore_sysmodule.h" // _PySys_ClearAuditHooks()
#include "pycore_traceback.h" // _Py_DumpTracebackThreads()
-#include "pycore_tuple.h" // _PyTuple_InitTypes()
#include "pycore_typeobject.h" // _PyTypes_InitTypes()
+#include "pycore_typevarobject.h" // _Py_clear_generic_types()
#include "pycore_unicodeobject.h" // _PyUnicode_InitTypes()
-
-extern void _PyIO_Fini(void);
+#include "opcode.h"
#include <locale.h> // setlocale()
#include <stdlib.h> // getenv()
@@ -52,11 +51,6 @@ extern void _PyIO_Fini(void);
#ifdef MS_WINDOWS
# undef BYTE
-# include "windows.h"
-
- extern PyTypeObject PyWindowsConsoleIO_Type;
-# define PyWindowsConsoleIO_Check(op) \
- (PyObject_TypeCheck((op), &PyWindowsConsoleIO_Type))
#endif
#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str))
@@ -75,8 +69,6 @@ static PyStatus init_sys_streams(PyThreadState *tstate);
static void wait_for_thread_shutdown(PyThreadState *tstate);
static void call_ll_exitfuncs(_PyRuntimeState *runtime);
-int _Py_UnhandledKeyboardInterrupt = 0;
-
/* The following places the `_PyRuntime` structure in a location that can be
* found without any external information. This is meant to ease access to the
* interpreter state for various runtime debugging tools, but is *not* an
@@ -103,7 +95,7 @@ _PyRuntimeState _PyRuntime
#if defined(__linux__) && (defined(__GNUC__) || defined(__clang__))
__attribute__ ((section (".PyRuntime")))
#endif
-= _PyRuntimeState_INIT;
+= _PyRuntimeState_INIT(_PyRuntime);
_Py_COMP_DIAG_POP
static int runtime_initialized = 0;
@@ -161,87 +153,6 @@ Py_IsInitialized(void)
}
-/* Global initializations. Can be undone by Py_FinalizeEx(). Don't
- call this twice without an intervening Py_FinalizeEx() call. When
- initializations fail, a fatal error is issued and the function does
- not return. On return, the first thread and interpreter state have
- been created.
-
- Locking: you must hold the interpreter lock while calling this.
- (If the lock has not yet been initialized, that's equivalent to
- having the lock, but you cannot use multiple threads.)
-
-*/
-static int
-init_importlib(PyThreadState *tstate, PyObject *sysmod)
-{
- assert(!_PyErr_Occurred(tstate));
-
- PyInterpreterState *interp = tstate->interp;
- int verbose = _PyInterpreterState_GetConfig(interp)->verbose;
-
- // Import _importlib through its frozen version, _frozen_importlib.
- if (verbose) {
- PySys_FormatStderr("import _frozen_importlib # frozen\n");
- }
- if (PyImport_ImportFrozenModule("_frozen_importlib") <= 0) {
- return -1;
- }
- PyObject *importlib = PyImport_AddModule("_frozen_importlib"); // borrowed
- if (importlib == NULL) {
- return -1;
- }
- interp->importlib = Py_NewRef(importlib);
-
- // Import the _imp module
- if (verbose) {
- PySys_FormatStderr("import _imp # builtin\n");
- }
- PyObject *imp_mod = _PyImport_BootstrapImp(tstate);
- if (imp_mod == NULL) {
- return -1;
- }
- if (_PyImport_SetModuleString("_imp", imp_mod) < 0) {
- Py_DECREF(imp_mod);
- return -1;
- }
-
- // Install importlib as the implementation of import
- PyObject *value = PyObject_CallMethod(importlib, "_install",
- "OO", sysmod, imp_mod);
- Py_DECREF(imp_mod);
- if (value == NULL) {
- return -1;
- }
- Py_DECREF(value);
-
- assert(!_PyErr_Occurred(tstate));
- return 0;
-}
-
-
-static PyStatus
-init_importlib_external(PyThreadState *tstate)
-{
- PyObject *value;
- value = PyObject_CallMethod(tstate->interp->importlib,
- "_install_external_importers", "");
- if (value == NULL) {
- _PyErr_Print(tstate);
- return _PyStatus_ERR("external importer setup failed");
- }
- Py_DECREF(value);
-
- value = PyImport_ImportModule("__res");
- if (value == NULL) {
- PyErr_Print();
- return _PyStatus_ERR("can't import __res");
- }
- Py_DECREF(value);
-
- return _PyImportZip_Init(tstate);
-}
-
/* Helper functions to better handle the legacy C locale
*
* The legacy C locale assumes ASCII as the default text encoding, which
@@ -489,6 +400,8 @@ interpreter_update_config(PyThreadState *tstate, int only_update_path_config)
}
}
+ tstate->interp->long_state.max_str_digits = config->int_max_str_digits;
+
// Update the sys module for the new configuration
if (_PySys_UpdateConfig(tstate) < 0) {
return -1;
@@ -605,11 +518,23 @@ pycore_init_runtime(_PyRuntimeState *runtime,
*/
_PyRuntimeState_SetFinalizing(runtime, NULL);
+ _Py_InitVersion();
+
status = _Py_HashRandomization_Init(config);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
+ status = _PyTime_Init();
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
+
+ status = _PyImport_Init();
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
+
status = _PyInterpreterState_Enable(runtime);
if (_PyStatus_EXCEPTION(status)) {
return status;
@@ -619,12 +544,54 @@ pycore_init_runtime(_PyRuntimeState *runtime,
static PyStatus
-init_interp_create_gil(PyThreadState *tstate)
+init_interp_settings(PyInterpreterState *interp,
+ const PyInterpreterConfig *config)
+{
+ assert(interp->feature_flags == 0);
+
+ if (config->use_main_obmalloc) {
+ interp->feature_flags |= Py_RTFLAGS_USE_MAIN_OBMALLOC;
+ }
+ else if (!config->check_multi_interp_extensions) {
+ /* The reason: PyModuleDef.m_base.m_copy leaks objects between
+ interpreters. */
+ return _PyStatus_ERR("per-interpreter obmalloc does not support "
+ "single-phase init extension modules");
+ }
+
+ if (config->allow_fork) {
+ interp->feature_flags |= Py_RTFLAGS_FORK;
+ }
+ if (config->allow_exec) {
+ interp->feature_flags |= Py_RTFLAGS_EXEC;
+ }
+ // Note that fork+exec is always allowed.
+
+ if (config->allow_threads) {
+ interp->feature_flags |= Py_RTFLAGS_THREADS;
+ }
+ if (config->allow_daemon_threads) {
+ interp->feature_flags |= Py_RTFLAGS_DAEMON_THREADS;
+ }
+
+ if (config->check_multi_interp_extensions) {
+ interp->feature_flags |= Py_RTFLAGS_MULTI_INTERP_EXTENSIONS;
+ }
+
+ /* We check "gil" in init_interp_create_gil(). */
+
+ return _PyStatus_OK();
+}
+
+
+static PyStatus
+init_interp_create_gil(PyThreadState *tstate, int gil)
{
PyStatus status;
/* finalize_interp_delete() comment explains why _PyEval_FiniGIL() is
only called here. */
+ // XXX This is broken with a per-interpreter GIL.
_PyEval_FiniGIL(tstate->interp);
/* Auto-thread-state API */
@@ -633,8 +600,17 @@ init_interp_create_gil(PyThreadState *tstate)
return status;
}
+ int own_gil;
+ switch (gil) {
+ case PyInterpreterConfig_DEFAULT_GIL: own_gil = 0; break;
+ case PyInterpreterConfig_SHARED_GIL: own_gil = 0; break;
+ case PyInterpreterConfig_OWN_GIL: own_gil = 1; break;
+ default:
+ return _PyStatus_ERR("invalid interpreter config 'gil' value");
+ }
+
/* Create the GIL and take it */
- status = _PyEval_InitGIL(tstate);
+ status = _PyEval_InitGIL(tstate, own_gil);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
@@ -645,33 +621,44 @@ init_interp_create_gil(PyThreadState *tstate)
static PyStatus
pycore_create_interpreter(_PyRuntimeState *runtime,
- const PyConfig *config,
+ const PyConfig *src_config,
PyThreadState **tstate_p)
{
- /* Auto-thread-state API */
- PyStatus status = _PyGILState_Init(runtime);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
-
+ PyStatus status;
PyInterpreterState *interp = PyInterpreterState_New();
if (interp == NULL) {
return _PyStatus_ERR("can't make main interpreter");
}
assert(_Py_IsMainInterpreter(interp));
- status = _PyConfig_Copy(&interp->config, config);
+ status = _PyConfig_Copy(&interp->config, src_config);
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
+
+ /* Auto-thread-state API */
+ status = _PyGILState_Init(interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
- PyThreadState *tstate = PyThreadState_New(interp);
+ PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
+ // The main interpreter always has its own GIL.
+ config.gil = PyInterpreterConfig_OWN_GIL;
+ status = init_interp_settings(interp, &config);
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
+
+ PyThreadState *tstate = _PyThreadState_New(interp);
if (tstate == NULL) {
return _PyStatus_ERR("can't make first thread");
}
- (void) PyThreadState_Swap(tstate);
+ _PyThreadState_Bind(tstate);
+ // XXX For now we do this before the GIL is created.
+ (void) _PyThreadState_SwapNoGIL(tstate);
- status = init_interp_create_gil(tstate);
+ status = init_interp_create_gil(tstate, config.gil);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
@@ -704,21 +691,11 @@ pycore_init_types(PyInterpreterState *interp)
{
PyStatus status;
- status = _PyTypes_InitState(interp);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
-
status = _PyTypes_InitTypes(interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
- status = _PyBytes_InitTypes(interp);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
-
status = _PyLong_InitTypes(interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
@@ -734,11 +711,6 @@ pycore_init_types(PyInterpreterState *interp)
return status;
}
- status = _PyTuple_InitTypes(interp);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
-
if (_PyExc_InitTypes(interp) < 0) {
return _PyStatus_ERR("failed to initialize an exception type");
}
@@ -765,6 +737,21 @@ pycore_init_types(PyInterpreterState *interp)
return _PyStatus_OK();
}
+static const uint8_t INTERPRETER_TRAMPOLINE_INSTRUCTIONS[] = {
+ /* Put a NOP at the start, so that the IP points into
+ * the code, rather than before it */
+ NOP, 0,
+ INTERPRETER_EXIT, 0,
+ /* RESUME at end makes sure that the frame appears incomplete */
+ RESUME, 0
+};
+
+static const _PyShimCodeDef INTERPRETER_TRAMPOLINE_CODEDEF = {
+ INTERPRETER_TRAMPOLINE_INSTRUCTIONS,
+ sizeof(INTERPRETER_TRAMPOLINE_INSTRUCTIONS),
+ 1,
+ "<interpreter trampoline>"
+};
static PyStatus
pycore_init_builtins(PyThreadState *tstate)
@@ -776,7 +763,8 @@ pycore_init_builtins(PyThreadState *tstate)
goto error;
}
- if (_PyImport_FixupBuiltin(bimod, "builtins", interp->modules) < 0) {
+ PyObject *modules = _PyImport_GetModules(interp);
+ if (_PyImport_FixupBuiltin(bimod, "builtins", modules) < 0) {
goto error;
}
@@ -784,8 +772,7 @@ pycore_init_builtins(PyThreadState *tstate)
if (builtins_dict == NULL) {
goto error;
}
- Py_INCREF(builtins_dict);
- interp->builtins = builtins_dict;
+ interp->builtins = Py_NewRef(builtins_dict);
PyObject *isinstance = PyDict_GetItem(builtins_dict, &_Py_ID(isinstance));
assert(isinstance);
@@ -796,7 +783,13 @@ pycore_init_builtins(PyThreadState *tstate)
PyObject *list_append = _PyType_Lookup(&PyList_Type, &_Py_ID(append));
assert(list_append);
interp->callable_cache.list_append = list_append;
-
+ PyObject *object__getattribute__ = _PyType_Lookup(&PyBaseObject_Type, &_Py_ID(__getattribute__));
+ assert(object__getattribute__);
+ interp->callable_cache.object__getattribute__ = object__getattribute__;
+ interp->interpreter_trampoline = _Py_MakeShimCode(&INTERPRETER_TRAMPOLINE_CODEDEF);
+ if (interp->interpreter_trampoline == NULL) {
+ return _PyStatus_ERR("failed to create interpreter trampoline.");
+ }
if (_PyBuiltins_AddExceptions(bimod) < 0) {
return _PyStatus_ERR("failed to add exceptions to builtins");
}
@@ -807,13 +800,9 @@ pycore_init_builtins(PyThreadState *tstate)
}
Py_DECREF(bimod);
- // Get the __import__ function
- PyObject *import_func = _PyDict_GetItemStringWithError(interp->builtins,
- "__import__");
- if (import_func == NULL) {
+ if (_PyImport_InitDefaultImportFunc(interp) < 0) {
goto error;
}
- interp->import_func = Py_NewRef(import_func);
assert(!_PyErr_Occurred(tstate));
return _PyStatus_OK();
@@ -875,11 +864,10 @@ pycore_interp_init(PyThreadState *tstate)
}
const PyConfig *config = _PyInterpreterState_GetConfig(interp);
- if (config->_install_importlib) {
- /* This call sets up builtin and frozen import support */
- if (init_importlib(tstate, sysmod) < 0) {
- return _PyStatus_ERR("failed to initialize importlib");
- }
+
+ status = _PyImport_InitCore(tstate, sysmod, config->_install_importlib);
+ if (_PyStatus_EXCEPTION(status)) {
+ goto done;
}
done:
@@ -1100,8 +1088,6 @@ pyinit_main_reconfigure(PyThreadState *tstate)
static PyStatus
init_interp_main(PyThreadState *tstate)
{
- extern void _PyThread_debug_deprecation(void);
-
assert(!_PyErr_Occurred(tstate));
PyStatus status;
@@ -1131,7 +1117,7 @@ init_interp_main(PyThreadState *tstate)
return _PyStatus_ERR("failed to update the Python config");
}
- status = init_importlib_external(tstate);
+ status = _PyImport_InitExternal(tstate);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
@@ -1154,9 +1140,20 @@ init_interp_main(PyThreadState *tstate)
return _PyStatus_ERR("can't initialize signals");
}
- if (_PyTraceMalloc_Init(config->tracemalloc) < 0) {
- return _PyStatus_ERR("can't initialize tracemalloc");
+ if (config->tracemalloc) {
+ if (_PyTraceMalloc_Start(config->tracemalloc) < 0) {
+ return _PyStatus_ERR("can't start tracemalloc");
+ }
+ }
+
+#ifdef PY_HAVE_PERF_TRAMPOLINE
+ if (config->perf_profiling) {
+ if (_PyPerfTrampoline_SetCallbacks(&_Py_perfmap_callbacks) < 0 ||
+ _PyPerfTrampoline_Init(config->perf_profiling) < 0) {
+ return _PyStatus_ERR("can't initialize the perf trampoline");
+ }
}
+#endif
}
status = init_sys_streams(tstate);
@@ -1203,8 +1200,31 @@ init_interp_main(PyThreadState *tstate)
#endif
}
- // Warn about PYTHONTHREADDEBUG deprecation
- _PyThread_debug_deprecation();
+ if (!is_main_interp) {
+ // The main interpreter is handled in Py_Main(), for now.
+ wchar_t *sys_path_0 = interp->runtime->sys_path_0;
+ if (sys_path_0 != NULL) {
+ PyObject *path0 = PyUnicode_FromWideChar(sys_path_0, -1);
+ if (path0 == NULL) {
+ return _PyStatus_ERR("can't initialize sys.path[0]");
+ }
+ PyObject *sysdict = interp->sysdict;
+ if (sysdict == NULL) {
+ Py_DECREF(path0);
+ return _PyStatus_ERR("can't initialize sys.path[0]");
+ }
+ PyObject *sys_path = PyDict_GetItemWithError(sysdict, &_Py_ID(path));
+ if (sys_path == NULL) {
+ Py_DECREF(path0);
+ return _PyStatus_ERR("can't initialize sys.path[0]");
+ }
+ int res = PyList_Insert(sys_path, 0, path0);
+ Py_DECREF(path0);
+ if (res) {
+ return _PyStatus_ERR("can't initialize sys.path[0]");
+ }
+ }
+ }
assert(!_PyErr_Occurred(tstate));
@@ -1318,8 +1338,7 @@ _Py_InitializeMain(void)
if (_PyStatus_EXCEPTION(status)) {
return status;
}
- _PyRuntimeState *runtime = &_PyRuntime;
- PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
+ PyThreadState *tstate = _PyThreadState_GET();
return pyinit_main(tstate);
}
@@ -1329,10 +1348,13 @@ finalize_modules_delete_special(PyThreadState *tstate, int verbose)
{
// List of names to clear in sys
static const char * const sys_deletes[] = {
- "path", "argv", "ps1", "ps2",
+ "path", "argv", "ps1", "ps2", "last_exc",
"last_type", "last_value", "last_traceback",
- "path_hooks", "path_importer_cache", "meta_path",
"__interactivehook__",
+ // path_hooks and path_importer_cache are cleared
+ // by _PyImport_FiniExternal().
+ // XXX Clear meta_path in _PyImport_FiniCore().
+ "meta_path",
NULL
};
@@ -1353,10 +1375,7 @@ finalize_modules_delete_special(PyThreadState *tstate, int verbose)
const char * const *p;
for (p = sys_deletes; *p != NULL; p++) {
- if (verbose) {
- PySys_WriteStderr("# clear sys.%s\n", *p);
- }
- if (PyDict_SetItemString(interp->sysdict, *p, Py_None) < 0) {
+ if (_PySys_ClearAttrString(interp, *p, verbose) < 0) {
PyErr_WriteUnraisable(NULL);
}
}
@@ -1477,7 +1496,7 @@ finalize_restore_builtins(PyThreadState *tstate)
}
PyDict_Clear(interp->builtins);
if (PyDict_Update(interp->builtins, interp->builtins_copy)) {
- _PyErr_Clear(tstate);
+ PyErr_WriteUnraisable(NULL);
}
Py_XDECREF(dict);
}
@@ -1528,11 +1547,12 @@ finalize_clear_sys_builtins_dict(PyInterpreterState *interp, int verbose)
/* Clear modules, as good as we can */
+// XXX Move most of this to import.c.
static void
finalize_modules(PyThreadState *tstate)
{
PyInterpreterState *interp = tstate->interp;
- PyObject *modules = interp->modules;
+ PyObject *modules = _PyImport_GetModules(interp);
if (modules == NULL) {
// Already done
return;
@@ -1597,12 +1617,12 @@ finalize_modules(PyThreadState *tstate)
// clear PyInterpreterState.modules_by_index and
// clear PyModuleDef.m_base.m_copy (of extensions not using the multi-phase
// initialization API)
- _PyInterpreterState_ClearModules(interp);
+ _PyImport_ClearModulesByIndex(interp);
// Clear and delete the modules directory. Actual modules will
// still be there only if imported during the execution of some
// destructor.
- Py_SETREF(interp->modules, NULL);
+ _PyImport_ClearModules(interp);
// Collect garbage once more
_PyGC_CollectNoFail(tstate);
@@ -1679,17 +1699,20 @@ static void
finalize_interp_types(PyInterpreterState *interp)
{
_PyUnicode_FiniTypes(interp);
- _PySys_Fini(interp);
+ _PySys_FiniTypes(interp);
_PyExc_Fini(interp);
_PyAsyncGen_Fini(interp);
_PyContext_Fini(interp);
_PyFloat_FiniType(interp);
_PyLong_FiniTypes(interp);
_PyThread_FiniType(interp);
+ // XXX fini collections module static types (_PyStaticType_Dealloc())
+ // XXX fini IO module static types (_PyStaticType_Dealloc())
_PyErr_FiniTypes(interp);
- _PyTypes_Fini(interp);
_PyTypes_FiniTypes(interp);
+ _PyTypes_Fini(interp);
+
// Call _PyUnicode_ClearInterned() before _PyDict_Fini() since it uses
// a dict internally.
_PyUnicode_ClearInterned(interp);
@@ -1702,6 +1725,9 @@ finalize_interp_types(PyInterpreterState *interp)
_PyUnicode_Fini(interp);
_PyFloat_Fini(interp);
+#ifdef Py_DEBUG
+ _PyStaticObjects_CheckRefcnt(interp);
+#endif
}
@@ -1711,14 +1737,11 @@ finalize_interp_clear(PyThreadState *tstate)
int is_main_interp = _Py_IsMainInterpreter(tstate->interp);
_PyExc_ClearExceptionGroupType(tstate->interp);
+ _Py_clear_generic_types(tstate->interp);
/* Clear interpreter state and all thread states */
_PyInterpreterState_Clear(tstate);
- if (is_main_interp) {
- _PyIO_Fini();
- }
-
/* Clear all loghooks */
/* Both _PySys_Audit function and users still need PyObject, such as tuple.
Call _PySys_ClearAuditHooks when PyObject available. */
@@ -1731,6 +1754,8 @@ finalize_interp_clear(PyThreadState *tstate)
_PyArg_Fini();
_Py_ClearFileSystemEncoding();
_Py_Deepfreeze_Fini();
+ _PyPerfTrampoline_Fini();
+ _PyPerfTrampoline_FreeArenas();
}
finalize_interp_types(tstate->interp);
@@ -1740,10 +1765,8 @@ finalize_interp_clear(PyThreadState *tstate)
static void
finalize_interp_delete(PyInterpreterState *interp)
{
- if (_Py_IsMainInterpreter(interp)) {
- /* Cleanup auto-thread-state */
- _PyGILState_Fini(interp);
- }
+ /* Cleanup auto-thread-state */
+ _PyGILState_Fini(interp);
/* We can't call _PyEval_FiniGIL() here because destroying the GIL lock can
fail when it is being awaited by another running daemon thread (see
@@ -1766,7 +1789,12 @@ Py_FinalizeEx(void)
}
/* Get current thread state and interpreter pointer */
- PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
+ PyThreadState *tstate = _PyThreadState_GET();
+ // XXX assert(_Py_IsMainInterpreter(tstate->interp));
+ // XXX assert(_Py_IsMainThread());
+
+ // Block some operations.
+ tstate->interp->finalizing = 1;
// Wrap up existing "threading"-module-created, non-daemon threads.
wait_for_thread_shutdown(tstate);
@@ -1801,10 +1829,13 @@ Py_FinalizeEx(void)
/* Remaining daemon threads will automatically exit
when they attempt to take the GIL (ex: PyEval_RestoreThread()). */
+ _PyInterpreterState_SetFinalizing(tstate->interp, tstate);
_PyRuntimeState_SetFinalizing(runtime, tstate);
runtime->initialized = 0;
runtime->core_initialized = 0;
+ // XXX Call something like _PyImport_Disable() here?
+
/* Destroy the state of all threads of the interpreter, except of the
current thread. In practice, only daemon threads should still be alive,
except if wait_for_thread_shutdown() has been cancelled by CTRL+C.
@@ -1813,7 +1844,23 @@ Py_FinalizeEx(void)
_PyRuntimeState_SetFinalizing() has been called, no other Python thread
can take the GIL at this point: if they try, they will exit
immediately. */
- _PyThreadState_DeleteExcept(runtime, tstate);
+ _PyThreadState_DeleteExcept(tstate);
+
+ /* At this point no Python code should be running at all.
+ The only thread state left should be the main thread of the main
+ interpreter (AKA tstate), in which this code is running right now.
+ There may be other OS threads running but none of them will have
+ thread states associated with them, nor will be able to create
+ new thread states.
+
+ Thus tstate is the only possible thread state from here on out.
+ It may still be used during finalization to run Python code as
+ needed or provide runtime state (e.g. sys.modules) but that will
+ happen sparingly. Furthermore, the order of finalization aims
+ to not need a thread (or interpreter) state as soon as possible.
+ */
+ // XXX Make sure we are preventing the creating of any new thread states
+ // (or interpreters).
/* Flush sys.stdout and sys.stderr */
if (flush_std_files() < 0) {
@@ -1838,6 +1885,7 @@ Py_FinalizeEx(void)
PyGC_Collect();
/* Destroy all modules */
+ _PyImport_FiniExternal(tstate->interp);
finalize_modules(tstate);
/* Print debug stats if any */
@@ -1871,7 +1919,9 @@ Py_FinalizeEx(void)
so it is possible to use tracemalloc in objects destructor. */
_PyTraceMalloc_Fini();
- /* Destroy the database used by _PyImport_{Fixup,Find}Extension */
+ /* Finalize any remaining import state */
+ // XXX Move these up to where finalize_modules() is currently.
+ _PyImport_FiniCore(tstate->interp);
_PyImport_Fini();
/* unload faulthandler module */
@@ -1896,14 +1946,28 @@ Py_FinalizeEx(void)
}
if (dump_refs) {
- _Py_PrintReferences(stderr);
+ _Py_PrintReferences(tstate->interp, stderr);
}
if (dump_refs_fp != NULL) {
- _Py_PrintReferences(dump_refs_fp);
+ _Py_PrintReferences(tstate->interp, dump_refs_fp);
}
#endif /* Py_TRACE_REFS */
+ /* At this point there's almost no other Python code that will run,
+ nor interpreter state needed. The only possibility is the
+ finalizers of the objects stored on tstate (and tstate->interp),
+ which are triggered via finalize_interp_clear().
+
+ For now we operate as though none of those finalizers actually
+ need an operational thread state or interpreter. In reality,
+ those finalizers may rely on some part of tstate or
+ tstate->interp, and/or may raise exceptions
+ or otherwise fail.
+ */
+ // XXX Do this sooner during finalization.
+ // XXX Ensure finalizer errors are handled properly.
+
finalize_interp_clear(tstate);
finalize_interp_delete(tstate->interp);
@@ -1911,7 +1975,9 @@ Py_FinalizeEx(void)
if (show_ref_count) {
_PyDebug_PrintTotalRefs();
}
+ _Py_FinalizeRefTotal(runtime);
#endif
+ _Py_FinalizeAllocatedBlocks(runtime);
#ifdef Py_TRACE_REFS
/* Display addresses (& refcnts) of all objects still alive.
@@ -1920,11 +1986,11 @@ Py_FinalizeEx(void)
*/
if (dump_refs) {
- _Py_PrintReferenceAddresses(stderr);
+ _Py_PrintReferenceAddresses(tstate->interp, stderr);
}
if (dump_refs_fp != NULL) {
- _Py_PrintReferenceAddresses(dump_refs_fp);
+ _Py_PrintReferenceAddresses(tstate->interp, dump_refs_fp);
fclose(dump_refs_fp);
}
#endif /* Py_TRACE_REFS */
@@ -1961,7 +2027,7 @@ Py_Finalize(void)
*/
static PyStatus
-new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter)
+new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config)
{
PyStatus status;
@@ -1985,38 +2051,56 @@ new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter)
return _PyStatus_OK();
}
- PyThreadState *tstate = PyThreadState_New(interp);
+ PyThreadState *tstate = _PyThreadState_New(interp);
if (tstate == NULL) {
PyInterpreterState_Delete(interp);
*tstate_p = NULL;
return _PyStatus_OK();
}
+ _PyThreadState_Bind(tstate);
- PyThreadState *save_tstate = PyThreadState_Swap(tstate);
+ // XXX For now we do this before the GIL is created.
+ PyThreadState *save_tstate = _PyThreadState_SwapNoGIL(tstate);
+ int has_gil = 0;
+
+ /* From this point until the init_interp_create_gil() call,
+ we must not do anything that requires that the GIL be held
+ (or otherwise exist). That applies whether or not the new
+ interpreter has its own GIL (e.g. the main interpreter). */
/* Copy the current interpreter config into the new interpreter */
- const PyConfig *config;
+ const PyConfig *src_config;
if (save_tstate != NULL) {
- config = _PyInterpreterState_GetConfig(save_tstate->interp);
+ // XXX Might new_interpreter() have been called without the GIL held?
+ _PyEval_ReleaseLock(save_tstate->interp, save_tstate);
+ src_config = _PyInterpreterState_GetConfig(save_tstate->interp);
}
else
{
/* No current thread state, copy from the main interpreter */
PyInterpreterState *main_interp = _PyInterpreterState_Main();
- config = _PyInterpreterState_GetConfig(main_interp);
+ src_config = _PyInterpreterState_GetConfig(main_interp);
}
+ /* This does not require that the GIL be held. */
+ status = _PyConfig_Copy(&interp->config, src_config);
+ if (_PyStatus_EXCEPTION(status)) {
+ goto error;
+ }
- status = _PyConfig_Copy(&interp->config, config);
+ /* This does not require that the GIL be held. */
+ status = init_interp_settings(interp, config);
if (_PyStatus_EXCEPTION(status)) {
goto error;
}
- interp->config._isolated_interpreter = isolated_subinterpreter;
- status = init_interp_create_gil(tstate);
+ status = init_interp_create_gil(tstate, config->gil);
if (_PyStatus_EXCEPTION(status)) {
goto error;
}
+ has_gil = 1;
+
+ /* No objects have been created yet. */
status = pycore_interp_init(tstate);
if (_PyStatus_EXCEPTION(status)) {
@@ -2036,7 +2120,12 @@ error:
/* Oops, it didn't work. Undo it all. */
PyErr_PrintEx(0);
- PyThreadState_Swap(save_tstate);
+ if (has_gil) {
+ PyThreadState_Swap(save_tstate);
+ }
+ else {
+ _PyThreadState_SwapNoGIL(save_tstate);
+ }
PyThreadState_Clear(tstate);
PyThreadState_Delete(tstate);
PyInterpreterState_Delete(interp);
@@ -2044,22 +2133,23 @@ error:
return status;
}
+PyStatus
+Py_NewInterpreterFromConfig(PyThreadState **tstate_p,
+ const PyInterpreterConfig *config)
+{
+ return new_interpreter(tstate_p, config);
+}
+
PyThreadState *
-_Py_NewInterpreter(int isolated_subinterpreter)
+Py_NewInterpreter(void)
{
PyThreadState *tstate = NULL;
- PyStatus status = new_interpreter(&tstate, isolated_subinterpreter);
+ const PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
+ PyStatus status = new_interpreter(&tstate, &config);
if (_PyStatus_EXCEPTION(status)) {
Py_ExitStatusException(status);
}
return tstate;
-
-}
-
-PyThreadState *
-Py_NewInterpreter(void)
-{
- return _Py_NewInterpreter(0);
}
/* Delete an interpreter and its last thread. This requires that the
@@ -2090,18 +2180,41 @@ Py_EndInterpreter(PyThreadState *tstate)
// Wrap up existing "threading"-module-created, non-daemon threads.
wait_for_thread_shutdown(tstate);
+ // Make any remaining pending calls.
+ _Py_FinishPendingCalls(tstate);
+
_PyAtExit_Call(tstate->interp);
if (tstate != interp->threads.head || tstate->next != NULL) {
Py_FatalError("not the last thread");
}
+ /* Remaining daemon threads will automatically exit
+ when they attempt to take the GIL (ex: PyEval_RestoreThread()). */
+ _PyInterpreterState_SetFinalizing(interp, tstate);
+
+ // XXX Call something like _PyImport_Disable() here?
+
+ _PyImport_FiniExternal(tstate->interp);
finalize_modules(tstate);
+ _PyImport_FiniCore(tstate->interp);
finalize_interp_clear(tstate);
finalize_interp_delete(tstate->interp);
}
+int
+_Py_IsInterpreterFinalizing(PyInterpreterState *interp)
+{
+ /* We check the runtime first since, in a daemon thread,
+ interp might be dangling pointer. */
+ PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(&_PyRuntime);
+ if (finalizing == NULL) {
+ finalizing = _PyInterpreterState_GetFinalizing(interp);
+ }
+ return finalizing != NULL;
+}
+
/* Add the __main__ module */
static PyStatus
@@ -2134,10 +2247,9 @@ add_main_module(PyInterpreterState *interp)
Py_DECREF(bimod);
}
- /* Main is a little special - imp.is_builtin("__main__") will return
- * False, but BuiltinImporter is still the most appropriate initial
- * setting for its __loader__ attribute. A more suitable value will
- * be set if __main__ gets further initialized later in the startup
+ /* Main is a little special - BuiltinImporter is the most appropriate
+ * initial setting for its __loader__ attribute. A more suitable value
+ * will be set if __main__ gets further initialized later in the startup
* process.
*/
loader = _PyDict_GetItemStringWithError(d, "__loader__");
@@ -2145,8 +2257,8 @@ add_main_module(PyInterpreterState *interp)
if (PyErr_Occurred()) {
return _PyStatus_ERR("Failed to test __main__.__loader__");
}
- PyObject *loader = PyObject_GetAttrString(interp->importlib,
- "BuiltinImporter");
+ PyObject *loader = _PyImport_GetImportlibLoader(interp,
+ "BuiltinImporter");
if (loader == NULL) {
return _PyStatus_ERR("Failed to retrieve BuiltinImporter");
}
@@ -2262,14 +2374,21 @@ create_stdio(const PyConfig *config, PyObject* io,
goto error;
}
else {
- raw = buf;
- Py_INCREF(raw);
+ raw = Py_NewRef(buf);
}
-#ifdef MS_WINDOWS
+#ifdef HAVE_WINDOWS_CONSOLE_IO
/* Windows console IO is always UTF-8 encoded */
- if (PyWindowsConsoleIO_Check(raw))
+ PyTypeObject *winconsoleio_type = (PyTypeObject *)_PyImport_GetModuleAttr(
+ &_Py_ID(_io), &_Py_ID(_WindowsConsoleIO));
+ if (winconsoleio_type == NULL) {
+ goto error;
+ }
+ int is_subclass = PyObject_TypeCheck(raw, winconsoleio_type);
+ Py_DECREF(winconsoleio_type);
+ if (is_subclass) {
encoding = L"utf-8";
+ }
#endif
text = PyUnicode_FromString(name);
@@ -2357,19 +2476,15 @@ error:
static PyStatus
init_set_builtins_open(void)
{
- PyObject *iomod = NULL, *wrapper;
+ PyObject *wrapper;
PyObject *bimod = NULL;
PyStatus res = _PyStatus_OK();
- if (!(iomod = PyImport_ImportModule("io"))) {
- goto error;
- }
-
if (!(bimod = PyImport_ImportModule("builtins"))) {
goto error;
}
- if (!(wrapper = PyObject_GetAttrString(iomod, "open"))) {
+ if (!(wrapper = _PyImport_GetModuleAttrString("io", "open"))) {
goto error;
}
@@ -2386,7 +2501,6 @@ error:
done:
Py_XDECREF(bimod);
- Py_XDECREF(iomod);
return res;
}
@@ -2511,42 +2625,29 @@ _Py_FatalError_DumpTracebacks(int fd, PyInterpreterState *interp,
static int
_Py_FatalError_PrintExc(PyThreadState *tstate)
{
- PyObject *ferr, *res;
- PyObject *exception, *v, *tb;
- int has_tb;
-
- _PyErr_Fetch(tstate, &exception, &v, &tb);
- if (exception == NULL) {
+ PyObject *exc = _PyErr_GetRaisedException(tstate);
+ if (exc == NULL) {
/* No current exception */
return 0;
}
- ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr));
+ PyObject *ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr));
if (ferr == NULL || ferr == Py_None) {
/* sys.stderr is not set yet or set to None,
no need to try to display the exception */
+ Py_DECREF(exc);
return 0;
}
- _PyErr_NormalizeException(tstate, &exception, &v, &tb);
- if (tb == NULL) {
- tb = Py_None;
- Py_INCREF(tb);
- }
- PyException_SetTraceback(v, tb);
- if (exception == NULL) {
- /* PyErr_NormalizeException() failed */
- return 0;
- }
+ PyErr_DisplayException(exc);
- has_tb = (tb != Py_None);
- PyErr_Display(exception, v, tb);
- Py_XDECREF(exception);
- Py_XDECREF(v);
+ PyObject *tb = PyException_GetTraceback(exc);
+ int has_tb = (tb != NULL) && (tb != Py_None);
Py_XDECREF(tb);
+ Py_DECREF(exc);
/* sys.stderr may be buffered: call sys.stderr.flush() */
- res = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush));
+ PyObject *res = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush));
if (res == NULL) {
_PyErr_Clear(tstate);
}
@@ -2651,7 +2752,7 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
if (interp == NULL) {
return;
}
- PyObject *modules = interp->modules;
+ PyObject *modules = _PyImport_GetModules(interp);
if (modules == NULL || !PyDict_Check(modules)) {
return;
}
@@ -2772,7 +2873,7 @@ fatal_error(int fd, int header, const char *prefix, const char *msg,
tss_tstate != tstate if the current Python thread does not hold the GIL.
*/
- PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
+ PyThreadState *tstate = _PyThreadState_GET();
PyInterpreterState *interp = NULL;
PyThreadState *tss_tstate = PyGILState_GetThisThreadState();
if (tstate != NULL) {
@@ -2851,11 +2952,7 @@ _Py_FatalErrorFormat(const char *func, const char *format, ...)
}
va_list vargs;
-#ifdef HAVE_STDARG_PROTOTYPES
va_start(vargs, format);
-#else
- va_start(vargs);
-#endif
vfprintf(stream, format, vargs);
va_end(vargs);
@@ -2917,26 +3014,37 @@ wait_for_thread_shutdown(PyThreadState *tstate)
Py_DECREF(threading);
}
-#define NEXITFUNCS 32
int Py_AtExit(void (*func)(void))
{
- if (_PyRuntime.nexitfuncs >= NEXITFUNCS)
+ struct _atexit_runtime_state *state = &_PyRuntime.atexit;
+ PyThread_acquire_lock(state->mutex, WAIT_LOCK);
+ if (state->ncallbacks >= NEXITFUNCS) {
+ PyThread_release_lock(state->mutex);
return -1;
- _PyRuntime.exitfuncs[_PyRuntime.nexitfuncs++] = func;
+ }
+ state->callbacks[state->ncallbacks++] = func;
+ PyThread_release_lock(state->mutex);
return 0;
}
static void
call_ll_exitfuncs(_PyRuntimeState *runtime)
{
- while (runtime->nexitfuncs > 0) {
+ atexit_callbackfunc exitfunc;
+ struct _atexit_runtime_state *state = &runtime->atexit;
+
+ PyThread_acquire_lock(state->mutex, WAIT_LOCK);
+ while (state->ncallbacks > 0) {
/* pop last function from the list */
- runtime->nexitfuncs--;
- void (*exitfunc)(void) = runtime->exitfuncs[runtime->nexitfuncs];
- runtime->exitfuncs[runtime->nexitfuncs] = NULL;
+ state->ncallbacks--;
+ exitfunc = state->callbacks[state->ncallbacks];
+ state->callbacks[state->ncallbacks] = NULL;
+ PyThread_release_lock(state->mutex);
exitfunc();
+ PyThread_acquire_lock(state->mutex, WAIT_LOCK);
}
+ PyThread_release_lock(state->mutex);
fflush(stdout);
fflush(stderr);
@@ -2962,28 +3070,30 @@ Py_Exit(int sts)
int
Py_FdIsInteractive(FILE *fp, const char *filename)
{
- if (isatty((int)fileno(fp)))
+ if (isatty(fileno(fp))) {
return 1;
- if (!Py_InteractiveFlag)
+ }
+ if (!_Py_GetConfig()->interactive) {
return 0;
- return (filename == NULL) ||
- (strcmp(filename, "<stdin>") == 0) ||
- (strcmp(filename, "???") == 0);
+ }
+ return ((filename == NULL)
+ || (strcmp(filename, "<stdin>") == 0)
+ || (strcmp(filename, "???") == 0));
}
int
_Py_FdIsInteractive(FILE *fp, PyObject *filename)
{
- if (isatty((int)fileno(fp))) {
+ if (isatty(fileno(fp))) {
return 1;
}
- if (!Py_InteractiveFlag) {
+ if (!_Py_GetConfig()->interactive) {
return 0;
}
- return (filename == NULL) ||
- (PyUnicode_CompareWithASCIIString(filename, "<stdin>") == 0) ||
- (PyUnicode_CompareWithASCIIString(filename, "???") == 0);
+ return ((filename == NULL)
+ || (PyUnicode_CompareWithASCIIString(filename, "<stdin>") == 0)
+ || (PyUnicode_CompareWithASCIIString(filename, "???") == 0));
}