summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/Python/pylifecycle.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tools/python3/Python/pylifecycle.c')
-rw-r--r--contrib/tools/python3/Python/pylifecycle.c1013
1 files changed, 724 insertions, 289 deletions
diff --git a/contrib/tools/python3/Python/pylifecycle.c b/contrib/tools/python3/Python/pylifecycle.c
index ef4e6076570..8ba9b2bd006 100644
--- a/contrib/tools/python3/Python/pylifecycle.c
+++ b/contrib/tools/python3/Python/pylifecycle.c
@@ -2,10 +2,12 @@
#include "Python.h"
+#include "pycore_call.h" // _PyObject_CallMethod()
#include "pycore_ceval.h" // _PyEval_FiniGIL()
+#include "pycore_codecs.h" // _PyCodec_Lookup()
#include "pycore_context.h" // _PyContext_Init()
-#include "pycore_exceptions.h" // _PyExc_InitTypes()
#include "pycore_dict.h" // _PyDict_Fini()
+#include "pycore_exceptions.h" // _PyExc_InitTypes()
#include "pycore_fileutils.h" // _Py_ResetForceASCII()
#include "pycore_floatobject.h" // _PyFloat_InitTypes()
#include "pycore_genobject.h" // _PyAsyncGen_Fini()
@@ -15,26 +17,47 @@
#include "pycore_list.h" // _PyList_Fini()
#include "pycore_long.h" // _PyLong_InitTypes()
#include "pycore_object.h" // _PyDebug_PrintTotalRefs()
-#include "pycore_pathconfig.h" // _PyConfig_WritePathConfig()
+#include "pycore_pathconfig.h" // _PyPathConfig_UpdateGlobal()
#include "pycore_pyerrors.h" // _PyErr_Occurred()
#include "pycore_pylifecycle.h" // _PyErr_Print()
#include "pycore_pymem.h" // _PyObject_DebugMallocStats()
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_runtime.h" // _Py_ID()
#include "pycore_runtime_init.h" // _PyRuntimeState_INIT
+#include "pycore_setobject.h" // _PySet_NextEntry()
#include "pycore_sliceobject.h" // _PySlice_Fini()
#include "pycore_sysmodule.h" // _PySys_ClearAuditHooks()
#include "pycore_traceback.h" // _Py_DumpTracebackThreads()
#include "pycore_typeobject.h" // _PyTypes_InitTypes()
#include "pycore_typevarobject.h" // _Py_clear_generic_types()
#include "pycore_unicodeobject.h" // _PyUnicode_InitTypes()
+#include "pycore_weakref.h" // _PyWeakref_GET_REF()
+#include "pycore_obmalloc.h" // _PyMem_init_obmalloc()
+
#include "opcode.h"
#include <locale.h> // setlocale()
#include <stdlib.h> // getenv()
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> // isatty()
+#endif
#if defined(__APPLE__)
-#include <mach-o/loader.h>
+# include <AvailabilityMacros.h>
+# include <TargetConditionals.h>
+# include <mach-o/loader.h>
+// The os_log unified logging APIs were introduced in macOS 10.12, iOS 10.0,
+// tvOS 10.0, and watchOS 3.0; we enable the use of the system logger
+// automatically on non-macOS platforms.
+# if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+# define USE_APPLE_SYSTEM_LOG 1
+# else
+# define USE_APPLE_SYSTEM_LOG 0
+# endif
+
+# if USE_APPLE_SYSTEM_LOG
+# include <os/log.h>
+# endif
#endif
#ifdef HAVE_SIGNAL_H
@@ -53,12 +76,7 @@
# undef BYTE
#endif
-#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str))
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+#define PUTS(fd, str) (void)_Py_write_noraise(fd, str, (int)strlen(str))
/* Forward declarations */
@@ -66,7 +84,14 @@ static PyStatus add_main_module(PyInterpreterState *interp);
static PyStatus init_import_site(void);
static PyStatus init_set_builtins_open(void);
static PyStatus init_sys_streams(PyThreadState *tstate);
+#ifdef __ANDROID__
+static PyStatus init_android_streams(PyThreadState *tstate);
+#endif
+#if defined(__APPLE__) && USE_APPLE_SYSTEM_LOG
+static PyStatus init_apple_streams(PyThreadState *tstate);
+#endif
static void wait_for_thread_shutdown(PyThreadState *tstate);
+static void finalize_subinterpreters(void);
static void call_ll_exitfuncs(_PyRuntimeState *runtime);
/* The following places the `_PyRuntime` structure in a location that can be
@@ -95,7 +120,7 @@ _PyRuntimeState _PyRuntime
#if defined(__linux__) && (defined(__GNUC__) || defined(__clang__))
__attribute__ ((section (".PyRuntime")))
#endif
-= _PyRuntimeState_INIT(_PyRuntime);
+= _PyRuntimeState_INIT(_PyRuntime, _Py_Debug_Cookie);
_Py_COMP_DIAG_POP
static int runtime_initialized = 0;
@@ -125,7 +150,7 @@ _PyRuntime_Finalize(void)
}
int
-_Py_IsFinalizing(void)
+Py_IsFinalizing(void)
{
return _PyRuntimeState_GetFinalizing(&_PyRuntime) != NULL;
}
@@ -472,6 +497,7 @@ pyinit_core_reconfigure(_PyRuntimeState *runtime,
if (interp == NULL) {
return _PyStatus_ERR("can't make main interpreter");
}
+ assert(interp->_ready);
status = _PyConfig_Write(config, runtime);
if (_PyStatus_EXCEPTION(status)) {
@@ -525,11 +551,6 @@ pycore_init_runtime(_PyRuntimeState *runtime,
return status;
}
- status = _PyTime_Init();
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
-
status = _PyImport_Init();
if (_PyStatus_EXCEPTION(status)) {
return status;
@@ -558,6 +579,15 @@ init_interp_settings(PyInterpreterState *interp,
return _PyStatus_ERR("per-interpreter obmalloc does not support "
"single-phase init extension modules");
}
+#ifdef Py_GIL_DISABLED
+ if (!_Py_IsMainInterpreter(interp) &&
+ !config->check_multi_interp_extensions)
+ {
+ return _PyStatus_ERR("The free-threaded build does not support "
+ "single-phase init extension modules in "
+ "subinterpreters");
+ }
+#endif
if (config->allow_fork) {
interp->feature_flags |= Py_RTFLAGS_FORK;
@@ -578,46 +608,47 @@ init_interp_settings(PyInterpreterState *interp,
interp->feature_flags |= Py_RTFLAGS_MULTI_INTERP_EXTENSIONS;
}
- /* We check "gil" in init_interp_create_gil(). */
+ switch (config->gil) {
+ case PyInterpreterConfig_DEFAULT_GIL: break;
+ case PyInterpreterConfig_SHARED_GIL: break;
+ case PyInterpreterConfig_OWN_GIL: break;
+ default:
+ return _PyStatus_ERR("invalid interpreter config 'gil' value");
+ }
return _PyStatus_OK();
}
-static PyStatus
+static void
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 */
- status = _PyGILState_SetTstate(tstate);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
+ _PyGILState_SetTstate(tstate);
- 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");
- }
+ int own_gil = (gil == PyInterpreterConfig_OWN_GIL);
/* Create the GIL and take it */
- status = _PyEval_InitGIL(tstate, own_gil);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
-
- return _PyStatus_OK();
+ _PyEval_InitGIL(tstate, own_gil);
}
+static int
+builtins_dict_watcher(PyDict_WatchEvent event, PyObject *dict, PyObject *key, PyObject *new_value)
+{
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+#ifdef _Py_TIER2
+ if (interp->rare_events.builtin_dict < _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) {
+ _Py_Executors_InvalidateAll(interp, 1);
+ }
+#endif
+ RARE_EVENT_INTERP_INC(interp, builtin_dict);
+ return 0;
+}
static PyStatus
pycore_create_interpreter(_PyRuntimeState *runtime,
@@ -625,11 +656,15 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
PyThreadState **tstate_p)
{
PyStatus status;
- PyInterpreterState *interp = PyInterpreterState_New();
- if (interp == NULL) {
- return _PyStatus_ERR("can't make main interpreter");
+ PyInterpreterState *interp;
+ status = _PyInterpreterState_New(NULL, &interp);
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
}
+ assert(interp != NULL);
assert(_Py_IsMainInterpreter(interp));
+ _PyInterpreterState_SetWhence(interp, _PyInterpreterState_WHENCE_RUNTIME);
+ interp->_ready = 1;
status = _PyConfig_Copy(&interp->config, src_config);
if (_PyStatus_EXCEPTION(status)) {
@@ -643,8 +678,10 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
}
PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
- // The main interpreter always has its own GIL.
+ // The main interpreter always has its own GIL and supports single-phase
+ // init extensions.
config.gil = PyInterpreterConfig_OWN_GIL;
+ config.check_multi_interp_extensions = 0;
status = init_interp_settings(interp, &config);
if (_PyStatus_EXCEPTION(status)) {
return status;
@@ -652,25 +689,32 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
// This could be done in init_interpreter() (in pystate.c) if it
// didn't depend on interp->feature_flags being set already.
- _PyObject_InitState(interp);
+ status = _PyObject_InitState(interp);
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
+
+ // initialize the interp->obmalloc state. This must be done after
+ // the settings are loaded (so that feature_flags are set) but before
+ // any calls are made to obmalloc functions.
+ if (_PyMem_init_obmalloc(interp) < 0) {
+ return _PyStatus_NO_MEMORY();
+ }
status = _PyTraceMalloc_Init();
if (_PyStatus_EXCEPTION(status)) {
return status;
}
- PyThreadState *tstate = _PyThreadState_New(interp);
+ PyThreadState *tstate = _PyThreadState_New(interp,
+ _PyThreadState_WHENCE_INIT);
if (tstate == NULL) {
return _PyStatus_ERR("can't make first thread");
}
+ runtime->main_tstate = 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, config.gil);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
+ init_interp_create_gil(tstate, config.gil);
*tstate_p = tstate;
return _PyStatus_OK();
@@ -691,6 +735,10 @@ pycore_init_global_objects(PyInterpreterState *interp)
_PyUnicode_InitState(interp);
+ if (_Py_IsMainInterpreter(interp)) {
+ _Py_GetConstant_Init();
+ }
+
return _PyStatus_OK();
}
@@ -743,24 +791,14 @@ pycore_init_types(PyInterpreterState *interp)
if (_PyStatus_EXCEPTION(status)) {
return status;
}
- 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
-};
+ status = _PyXI_InitTypes(interp);
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
-static const _PyShimCodeDef INTERPRETER_TRAMPOLINE_CODEDEF = {
- INTERPRETER_TRAMPOLINE_INSTRUCTIONS,
- sizeof(INTERPRETER_TRAMPOLINE_INSTRUCTIONS),
- 1,
- "<interpreter trampoline>"
-};
+ return _PyStatus_OK();
+}
static PyStatus
pycore_init_builtins(PyThreadState *tstate)
@@ -773,7 +811,7 @@ pycore_init_builtins(PyThreadState *tstate)
}
PyObject *modules = _PyImport_GetModules(interp);
- if (_PyImport_FixupBuiltin(bimod, "builtins", modules) < 0) {
+ if (_PyImport_FixupBuiltin(tstate, bimod, "builtins", modules) < 0) {
goto error;
}
@@ -783,22 +821,30 @@ pycore_init_builtins(PyThreadState *tstate)
}
interp->builtins = Py_NewRef(builtins_dict);
- PyObject *isinstance = PyDict_GetItem(builtins_dict, &_Py_ID(isinstance));
- assert(isinstance);
+ PyObject *isinstance = PyDict_GetItemWithError(builtins_dict, &_Py_ID(isinstance));
+ if (!isinstance) {
+ goto error;
+ }
interp->callable_cache.isinstance = isinstance;
- PyObject *len = PyDict_GetItem(builtins_dict, &_Py_ID(len));
- assert(len);
+
+ PyObject *len = PyDict_GetItemWithError(builtins_dict, &_Py_ID(len));
+ if (!len) {
+ goto error;
+ }
interp->callable_cache.len = len;
+
PyObject *list_append = _PyType_Lookup(&PyList_Type, &_Py_ID(append));
- assert(list_append);
+ if (list_append == NULL) {
+ goto error;
+ }
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 (object__getattribute__ == NULL) {
+ goto error;
}
+ interp->callable_cache.object__getattribute__ = object__getattribute__;
+
if (_PyBuiltins_AddExceptions(bimod) < 0) {
return _PyStatus_ERR("failed to add exceptions to builtins");
}
@@ -837,20 +883,18 @@ pycore_interp_init(PyThreadState *tstate)
return status;
}
- // The GC must be initialized before the first GC collection.
- status = _PyGC_Init(interp);
+ status = _PyCode_Init(interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
- // Intern strings in deep-frozen modules first so that others
- // can use it instead of creating a heap allocated string.
- if (_Py_Deepfreeze_Init() < 0) {
- return _PyStatus_ERR("failed to initialize deep-frozen modules");
+
+ status = _PyDtoa_Init(interp);
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
}
- // Per-interpreter interned string dict is created after deep-frozen
- // modules have interned the global strings.
- status = _PyUnicode_InitInternDict(interp);
+ // The GC must be initialized before the first GC collection.
+ status = _PyGC_Init(interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
@@ -879,6 +923,11 @@ pycore_interp_init(PyThreadState *tstate)
goto done;
}
+ status = _PyXI_Init(interp);
+ if (_PyStatus_EXCEPTION(status)) {
+ goto done;
+ }
+
const PyConfig *config = _PyInterpreterState_GetConfig(interp);
status = _PyImport_InitCore(tstate, sysmod, config->_install_importlib);
@@ -1101,6 +1150,37 @@ pyinit_main_reconfigure(PyThreadState *tstate)
}
+#ifdef Py_DEBUG
+static void
+run_presite(PyThreadState *tstate)
+{
+ PyInterpreterState *interp = tstate->interp;
+ const PyConfig *config = _PyInterpreterState_GetConfig(interp);
+
+ if (!config->run_presite) {
+ return;
+ }
+
+ PyObject *presite_modname = PyUnicode_FromWideChar(
+ config->run_presite,
+ wcslen(config->run_presite)
+ );
+ if (presite_modname == NULL) {
+ fprintf(stderr, "Could not convert pre-site module name to unicode\n");
+ }
+ else {
+ PyObject *presite = PyImport_Import(presite_modname);
+ if (presite == NULL) {
+ fprintf(stderr, "pre-site import failed:\n");
+ _PyErr_Print(tstate);
+ }
+ Py_XDECREF(presite);
+ Py_DECREF(presite_modname);
+ }
+}
+#endif
+
+
static PyStatus
init_interp_main(PyThreadState *tstate)
{
@@ -1164,7 +1244,14 @@ init_interp_main(PyThreadState *tstate)
#ifdef PY_HAVE_PERF_TRAMPOLINE
if (config->perf_profiling) {
- if (_PyPerfTrampoline_SetCallbacks(&_Py_perfmap_callbacks) < 0 ||
+ _PyPerf_Callbacks *cur_cb;
+ if (config->perf_profiling == 1) {
+ cur_cb = &_Py_perfmap_callbacks;
+ }
+ else {
+ cur_cb = &_Py_perfmap_jit_callbacks;
+ }
+ if (_PyPerfTrampoline_SetCallbacks(cur_cb) < 0 ||
_PyPerfTrampoline_Init(config->perf_profiling) < 0) {
return _PyStatus_ERR("can't initialize the perf trampoline");
}
@@ -1182,6 +1269,23 @@ init_interp_main(PyThreadState *tstate)
return status;
}
+#ifdef __ANDROID__
+ status = init_android_streams(tstate);
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
+#endif
+#if defined(__APPLE__) && USE_APPLE_SYSTEM_LOG
+ status = init_apple_streams(tstate);
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
+#endif
+
+#ifdef Py_DEBUG
+ run_presite(tstate);
+#endif
+
status = add_main_module(interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
@@ -1189,8 +1293,12 @@ init_interp_main(PyThreadState *tstate)
if (is_main_interp) {
/* Initialize warnings. */
- PyObject *warnoptions = PySys_GetObject("warnoptions");
- if (warnoptions != NULL && PyList_Size(warnoptions) > 0)
+ PyObject *warnoptions;
+ if (_PySys_GetOptionalAttrString("warnoptions", &warnoptions) < 0) {
+ return _PyStatus_ERR("can't initialize warnings");
+ }
+ if (warnoptions != NULL && PyList_Check(warnoptions) &&
+ PyList_Size(warnoptions) > 0)
{
PyObject *warnings_module = PyImport_ImportModule("warnings");
if (warnings_module == NULL) {
@@ -1199,6 +1307,7 @@ init_interp_main(PyThreadState *tstate)
}
Py_XDECREF(warnings_module);
}
+ Py_XDECREF(warnoptions);
interp->runtime->initialized = 1;
}
@@ -1216,11 +1325,36 @@ init_interp_main(PyThreadState *tstate)
#endif
}
+ // Turn on experimental tier 2 (uops-based) optimizer
+ // This is also needed when the JIT is enabled
+#ifdef _Py_TIER2
+ if (is_main_interp) {
+ int enabled = 1;
+#if _Py_TIER2 & 2
+ enabled = 0;
+#endif
+ char *env = Py_GETENV("PYTHON_JIT");
+ if (env && *env != '\0') {
+ // PYTHON_JIT=0|1 overrides the default
+ enabled = *env != '0';
+ }
+ if (enabled) {
+ PyObject *opt = _PyOptimizer_NewUOpOptimizer();
+ if (opt == NULL) {
+ return _PyStatus_ERR("can't initialize optimizer");
+ }
+ if (_Py_SetTier2Optimizer((_PyOptimizerObject *)opt)) {
+ return _PyStatus_ERR("can't install optimizer");
+ }
+ Py_DECREF(opt);
+ }
+ }
+#endif
+
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 (config->sys_path_0 != NULL) {
+ PyObject *path0 = PyUnicode_FromWideChar(config->sys_path_0, -1);
if (path0 == NULL) {
return _PyStatus_ERR("can't initialize sys.path[0]");
}
@@ -1242,6 +1376,12 @@ init_interp_main(PyThreadState *tstate)
}
}
+
+ interp->dict_state.watchers[0] = &builtins_dict_watcher;
+ if (PyDict_Watch(0, interp->builtins) != 0) {
+ return _PyStatus_ERR("failed to set builtin dict watcher");
+ }
+
assert(!_PyErr_Occurred(tstate));
return _PyStatus_OK();
@@ -1386,13 +1526,13 @@ finalize_modules_delete_special(PyThreadState *tstate, int verbose)
PySys_WriteStderr("# clear builtins._\n");
}
if (PyDict_SetItemString(interp->builtins, "_", Py_None) < 0) {
- PyErr_WriteUnraisable(NULL);
+ PyErr_FormatUnraisable("Exception ignored on setting builtin variable _");
}
const char * const *p;
for (p = sys_deletes; *p != NULL; p++) {
if (_PySys_ClearAttrString(interp, *p, verbose) < 0) {
- PyErr_WriteUnraisable(NULL);
+ PyErr_FormatUnraisable("Exception ignored on clearing sys.%s", *p);
}
}
for (p = sys_files; *p != NULL; p+=2) {
@@ -1401,17 +1541,17 @@ finalize_modules_delete_special(PyThreadState *tstate, int verbose)
if (verbose) {
PySys_WriteStderr("# restore sys.%s\n", name);
}
- PyObject *value = _PyDict_GetItemStringWithError(interp->sysdict,
- orig_name);
+ PyObject *value;
+ if (PyDict_GetItemStringRef(interp->sysdict, orig_name, &value) < 0) {
+ PyErr_FormatUnraisable("Exception ignored on restoring sys.%s", name);
+ }
if (value == NULL) {
- if (_PyErr_Occurred(tstate)) {
- PyErr_WriteUnraisable(NULL);
- }
- value = Py_None;
+ value = Py_NewRef(Py_None);
}
if (PyDict_SetItemString(interp->sysdict, name, value) < 0) {
- PyErr_WriteUnraisable(NULL);
+ PyErr_FormatUnraisable("Exception ignored on restoring sys.%s", name);
}
+ Py_DECREF(value);
}
}
@@ -1421,7 +1561,7 @@ finalize_remove_modules(PyObject *modules, int verbose)
{
PyObject *weaklist = PyList_New(0);
if (weaklist == NULL) {
- PyErr_WriteUnraisable(NULL);
+ PyErr_FormatUnraisable("Exception ignored on removing modules");
}
#define STORE_MODULE_WEAKREF(name, mod) \
@@ -1430,13 +1570,13 @@ finalize_remove_modules(PyObject *modules, int verbose)
if (wr) { \
PyObject *tup = PyTuple_Pack(2, name, wr); \
if (!tup || PyList_Append(weaklist, tup) < 0) { \
- PyErr_WriteUnraisable(NULL); \
+ PyErr_FormatUnraisable("Exception ignored on removing modules"); \
} \
Py_XDECREF(tup); \
Py_DECREF(wr); \
} \
else { \
- PyErr_WriteUnraisable(NULL); \
+ PyErr_FormatUnraisable("Exception ignored on removing modules"); \
} \
}
@@ -1447,7 +1587,7 @@ finalize_remove_modules(PyObject *modules, int verbose)
} \
STORE_MODULE_WEAKREF(name, mod); \
if (PyObject_SetItem(modules, name, Py_None) < 0) { \
- PyErr_WriteUnraisable(NULL); \
+ PyErr_FormatUnraisable("Exception ignored on removing modules"); \
} \
}
@@ -1461,14 +1601,15 @@ finalize_remove_modules(PyObject *modules, int verbose)
else {
PyObject *iterator = PyObject_GetIter(modules);
if (iterator == NULL) {
- PyErr_WriteUnraisable(NULL);
+ PyErr_FormatUnraisable("Exception ignored on removing modules");
}
else {
PyObject *key;
while ((key = PyIter_Next(iterator))) {
PyObject *value = PyObject_GetItem(modules, key);
if (value == NULL) {
- PyErr_WriteUnraisable(NULL);
+ PyErr_FormatUnraisable("Exception ignored on removing modules");
+ Py_DECREF(key);
continue;
}
CLEAR_MODULE(key, value);
@@ -1476,7 +1617,7 @@ finalize_remove_modules(PyObject *modules, int verbose)
Py_DECREF(key);
}
if (PyErr_Occurred()) {
- PyErr_WriteUnraisable(NULL);
+ PyErr_FormatUnraisable("Exception ignored on removing modules");
}
Py_DECREF(iterator);
}
@@ -1496,7 +1637,7 @@ finalize_clear_modules_dict(PyObject *modules)
}
else {
if (PyObject_CallMethodNoArgs(modules, &_Py_ID(clear)) == NULL) {
- PyErr_WriteUnraisable(NULL);
+ PyErr_FormatUnraisable("Exception ignored on clearing sys.modules");
}
}
}
@@ -1508,11 +1649,11 @@ finalize_restore_builtins(PyThreadState *tstate)
PyInterpreterState *interp = tstate->interp;
PyObject *dict = PyDict_Copy(interp->builtins);
if (dict == NULL) {
- PyErr_WriteUnraisable(NULL);
+ PyErr_FormatUnraisable("Exception ignored on restoring builtins");
}
PyDict_Clear(interp->builtins);
if (PyDict_Update(interp->builtins, interp->builtins_copy)) {
- PyErr_WriteUnraisable(NULL);
+ PyErr_FormatUnraisable("Exception ignored on restoring builtins");
}
Py_XDECREF(dict);
}
@@ -1526,16 +1667,16 @@ finalize_modules_clear_weaklist(PyInterpreterState *interp,
for (Py_ssize_t i = PyList_GET_SIZE(weaklist) - 1; i >= 0; i--) {
PyObject *tup = PyList_GET_ITEM(weaklist, i);
PyObject *name = PyTuple_GET_ITEM(tup, 0);
- PyObject *mod = PyWeakref_GET_OBJECT(PyTuple_GET_ITEM(tup, 1));
- if (mod == Py_None) {
+ PyObject *mod = _PyWeakref_GET_REF(PyTuple_GET_ITEM(tup, 1));
+ if (mod == NULL) {
continue;
}
assert(PyModule_Check(mod));
- PyObject *dict = PyModule_GetDict(mod);
+ PyObject *dict = _PyModule_GetDict(mod); // borrowed reference
if (dict == interp->builtins || dict == interp->sysdict) {
+ Py_DECREF(mod);
continue;
}
- Py_INCREF(mod);
if (verbose && PyUnicode_Check(name)) {
PySys_FormatStderr("# cleanup[3] wiping %U\n", name);
}
@@ -1568,6 +1709,19 @@ static void
finalize_modules(PyThreadState *tstate)
{
PyInterpreterState *interp = tstate->interp;
+
+#ifdef _Py_TIER2
+ // Invalidate all executors and turn off tier 2 optimizer
+ _Py_Executors_InvalidateAll(interp, 0);
+ _PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL);
+ Py_XDECREF(old);
+#endif
+
+ // Stop watching __builtin__ modifications
+ if (PyDict_Unwatch(0, interp->builtins) < 0) {
+ // might happen if interp is cleared before watching the __builtin__
+ PyErr_Clear();
+ }
PyObject *modules = _PyImport_GetModules(interp);
if (modules == NULL) {
// Already done
@@ -1667,31 +1821,33 @@ file_is_closed(PyObject *fobj)
static int
flush_std_files(void)
{
- PyThreadState *tstate = _PyThreadState_GET();
- PyObject *fout = _PySys_GetAttr(tstate, &_Py_ID(stdout));
- PyObject *ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr));
- PyObject *tmp;
+ PyObject *file;
int status = 0;
- if (fout != NULL && fout != Py_None && !file_is_closed(fout)) {
- tmp = PyObject_CallMethodNoArgs(fout, &_Py_ID(flush));
- if (tmp == NULL) {
- PyErr_WriteUnraisable(fout);
+ if (_PySys_GetOptionalAttr(&_Py_ID(stdout), &file) < 0) {
+ status = -1;
+ }
+ else if (file != NULL && file != Py_None && !file_is_closed(file)) {
+ if (_PyFile_Flush(file) < 0) {
status = -1;
}
- else
- Py_DECREF(tmp);
}
+ if (status < 0) {
+ PyErr_FormatUnraisable("Exception ignored on flushing sys.stdout");
+ }
+ Py_XDECREF(file);
- if (ferr != NULL && ferr != Py_None && !file_is_closed(ferr)) {
- tmp = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush));
- if (tmp == NULL) {
+ if (_PySys_GetOptionalAttr(&_Py_ID(stderr), &file) < 0) {
+ PyErr_Clear();
+ status = -1;
+ }
+ else if (file != NULL && file != Py_None && !file_is_closed(file)) {
+ if (_PyFile_Flush(file) < 0) {
PyErr_Clear();
status = -1;
}
- else
- Py_DECREF(tmp);
}
+ Py_XDECREF(file);
return status;
}
@@ -1714,11 +1870,11 @@ flush_std_files(void)
static void
finalize_interp_types(PyInterpreterState *interp)
{
+ _PyTypes_FiniExtTypes(interp);
_PyUnicode_FiniTypes(interp);
_PySys_FiniTypes(interp);
+ _PyXI_FiniTypes(interp);
_PyExc_Fini(interp);
- _PyAsyncGen_Fini(interp);
- _PyContext_Fini(interp);
_PyFloat_FiniType(interp);
_PyLong_FiniTypes(interp);
_PyThread_FiniType(interp);
@@ -1729,18 +1885,21 @@ finalize_interp_types(PyInterpreterState *interp)
_PyTypes_Fini(interp);
+ _PyCode_Fini(interp);
+
// Call _PyUnicode_ClearInterned() before _PyDict_Fini() since it uses
// a dict internally.
_PyUnicode_ClearInterned(interp);
- _PyDict_Fini(interp);
- _PyList_Fini(interp);
- _PyTuple_Fini(interp);
+ _PyUnicode_Fini(interp);
- _PySlice_Fini(interp);
+#ifndef Py_GIL_DISABLED
+ // With Py_GIL_DISABLED:
+ // the freelists for the current thread state have already been cleared.
+ struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
+ _PyObject_ClearFreeLists(freelists, 1);
+#endif
- _PyUnicode_Fini(interp);
- _PyFloat_Fini(interp);
#ifdef Py_DEBUG
_PyStaticObjects_CheckRefcnt(interp);
#endif
@@ -1752,6 +1911,7 @@ finalize_interp_clear(PyThreadState *tstate)
{
int is_main_interp = _Py_IsMainInterpreter(tstate->interp);
+ _PyXI_Fini(tstate->interp);
_PyExc_ClearExceptionGroupType(tstate->interp);
_Py_clear_generic_types(tstate->interp);
@@ -1769,12 +1929,20 @@ finalize_interp_clear(PyThreadState *tstate)
_Py_HashRandomization_Fini();
_PyArg_Fini();
_Py_ClearFileSystemEncoding();
- _Py_Deepfreeze_Fini();
_PyPerfTrampoline_Fini();
- _PyPerfTrampoline_FreeArenas();
}
finalize_interp_types(tstate->interp);
+
+ /* Finalize dtoa at last so that finalizers calling repr of float doesn't crash */
+ _PyDtoa_Fini(tstate->interp);
+
+ /* Free any delayed free requests immediately */
+ _PyMem_FiniDelayed(tstate->interp);
+
+ /* finalize_interp_types may allocate Python objects so we may need to
+ abandon mimalloc segments again */
+ _PyThreadState_ClearMimallocHeaps(tstate);
}
@@ -1794,20 +1962,73 @@ finalize_interp_delete(PyInterpreterState *interp)
}
-int
-Py_FinalizeEx(void)
+/* Conceptually, there isn't a good reason for Py_Finalize()
+ to be called in any other thread than the one where Py_Initialize()
+ was called. Consequently, it would make sense to fail if the thread
+ or thread state (or interpreter) don't match. However, such
+ constraints have never been enforced, and, as unlikely as it may be,
+ there may be users relying on the unconstrained behavior. Thus,
+ we do our best here to accommodate that possibility. */
+
+static PyThreadState *
+resolve_final_tstate(_PyRuntimeState *runtime)
+{
+ PyThreadState *main_tstate = runtime->main_tstate;
+ assert(main_tstate != NULL);
+ assert(main_tstate->thread_id == runtime->main_thread);
+ PyInterpreterState *main_interp = _PyInterpreterState_Main();
+ assert(main_tstate->interp == main_interp);
+
+ PyThreadState *tstate = _PyThreadState_GET();
+ if (_Py_IsMainThread()) {
+ if (tstate != main_tstate) {
+ /* This implies that Py_Finalize() was called while
+ a non-main interpreter was active or while the main
+ tstate was temporarily swapped out with another.
+ Neither case should be allowed, but, until we get around
+ to fixing that (and Py_Exit()), we're letting it go. */
+ (void)PyThreadState_Swap(main_tstate);
+ }
+ }
+ else {
+ /* This is another unfortunate case where Py_Finalize() was
+ called when it shouldn't have been. We can't simply switch
+ over to the main thread. At the least, however, we can make
+ sure the main interpreter is active. */
+ if (!_Py_IsMainInterpreter(tstate->interp)) {
+ /* We don't go to the trouble of updating runtime->main_tstate
+ since it will be dead soon anyway. */
+ main_tstate =
+ _PyThreadState_New(main_interp, _PyThreadState_WHENCE_FINI);
+ if (main_tstate != NULL) {
+ _PyThreadState_Bind(main_tstate);
+ (void)PyThreadState_Swap(main_tstate);
+ }
+ else {
+ /* Fall back to the current tstate. It's better than nothing. */
+ main_tstate = tstate;
+ }
+ }
+ }
+ assert(main_tstate != NULL);
+
+ /* We might want to warn if main_tstate->current_frame != NULL. */
+
+ return main_tstate;
+}
+
+static int
+_Py_Finalize(_PyRuntimeState *runtime)
{
int status = 0;
- _PyRuntimeState *runtime = &_PyRuntime;
+ /* Bail out early if already finalized (or never initialized). */
if (!runtime->initialized) {
return status;
}
- /* Get current thread state and interpreter pointer */
- PyThreadState *tstate = _PyThreadState_GET();
- // XXX assert(_Py_IsMainInterpreter(tstate->interp));
- // XXX assert(_Py_IsMainThread());
+ /* Get final thread state pointer. */
+ PyThreadState *tstate = resolve_final_tstate(runtime);
// Block some operations.
tstate->interp->finalizing = 1;
@@ -1830,6 +2051,8 @@ Py_FinalizeEx(void)
_PyAtExit_Call(tstate->interp);
+ assert(_PyThreadState_GET() == tstate);
+
/* Copy the core config, PyInterpreterState_Delete() free
the core config memory */
#ifdef Py_REF_DEBUG
@@ -1843,7 +2066,10 @@ Py_FinalizeEx(void)
int malloc_stats = tstate->interp->config.malloc_stats;
#endif
- /* Remaining daemon threads will automatically exit
+ /* Ensure that remaining threads are detached */
+ _PyEval_StopTheWorldAll(runtime);
+
+ /* Remaining daemon threads will be trapped in PyThread_hang_thread
when they attempt to take the GIL (ex: PyEval_RestoreThread()). */
_PyInterpreterState_SetFinalizing(tstate->interp, tstate);
_PyRuntimeState_SetFinalizing(runtime, tstate);
@@ -1859,8 +2085,11 @@ Py_FinalizeEx(void)
will be called in the current Python thread. Since
_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(tstate);
+ immediately. We start the world once we are the only thread state left,
+ before we call destructors. */
+ PyThreadState *list = _PyThreadState_RemoveExcept(tstate);
+ _PyEval_StartTheWorldAll(runtime);
+ _PyThreadState_DeleteList(list);
/* At this point no Python code should be running at all.
The only thread state left should be the main thread of the main
@@ -1904,6 +2133,9 @@ Py_FinalizeEx(void)
_PyImport_FiniExternal(tstate->interp);
finalize_modules(tstate);
+ /* Clean up any lingering subinterpreters. */
+ finalize_subinterpreters();
+
/* Print debug stats if any */
_PyEval_Fini();
@@ -1988,6 +2220,19 @@ Py_FinalizeEx(void)
_PyTraceMalloc_Fini();
+#ifdef Py_TRACE_REFS
+ /* Display addresses (& refcnts) of all objects still alive.
+ * An address can be used to find the repr of the object, printed
+ * above by _Py_PrintReferences. */
+ if (dump_refs) {
+ _Py_PrintReferenceAddresses(tstate->interp, stderr);
+ }
+ if (dump_refs_fp != NULL) {
+ _Py_PrintReferenceAddresses(tstate->interp, dump_refs_fp);
+ fclose(dump_refs_fp);
+ }
+#endif /* Py_TRACE_REFS */
+
#ifdef WITH_PYMALLOC
if (malloc_stats) {
_PyObject_DebugMallocStats(stderr);
@@ -2004,32 +2249,22 @@ Py_FinalizeEx(void)
#endif
_Py_FinalizeAllocatedBlocks(runtime);
-#ifdef Py_TRACE_REFS
- /* Display addresses (& refcnts) of all objects still alive.
- * An address can be used to find the repr of the object, printed
- * above by _Py_PrintReferences.
- */
-
- if (dump_refs) {
- _Py_PrintReferenceAddresses(tstate->interp, stderr);
- }
-
- if (dump_refs_fp != NULL) {
- _Py_PrintReferenceAddresses(tstate->interp, dump_refs_fp);
- fclose(dump_refs_fp);
- }
-#endif /* Py_TRACE_REFS */
-
call_ll_exitfuncs(runtime);
_PyRuntime_Finalize();
return status;
}
+int
+Py_FinalizeEx(void)
+{
+ return _Py_Finalize(&_PyRuntime);
+}
+
void
Py_Finalize(void)
{
- Py_FinalizeEx();
+ (void)_Py_Finalize(&_PyRuntime);
}
@@ -2047,7 +2282,8 @@ Py_Finalize(void)
*/
static PyStatus
-new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config)
+new_interpreter(PyThreadState **tstate_p,
+ const PyInterpreterConfig *config, long whence)
{
PyStatus status;
@@ -2065,34 +2301,28 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config)
interpreters: disable PyGILState_Check(). */
runtime->gilstate.check_enabled = 0;
- PyInterpreterState *interp = PyInterpreterState_New();
+ // XXX Might new_interpreter() have been called without the GIL held?
+ PyThreadState *save_tstate = _PyThreadState_GET();
+ PyThreadState *tstate = NULL;
+ PyInterpreterState *interp;
+ status = _PyInterpreterState_New(save_tstate, &interp);
if (interp == NULL) {
- *tstate_p = NULL;
- return _PyStatus_OK();
+ goto error;
}
-
- PyThreadState *tstate = _PyThreadState_New(interp);
- if (tstate == NULL) {
- PyInterpreterState_Delete(interp);
- *tstate_p = NULL;
- return _PyStatus_OK();
- }
- _PyThreadState_Bind(tstate);
-
- // XXX For now we do this before the GIL is created.
- PyThreadState *save_tstate = _PyThreadState_SwapNoGIL(tstate);
- int has_gil = 0;
+ _PyInterpreterState_SetWhence(interp, whence);
+ interp->_ready = 1;
/* 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). */
+ if (save_tstate != NULL) {
+ _PyThreadState_Detach(save_tstate);
+ }
/* Copy the current interpreter config into the new interpreter */
const PyConfig *src_config;
if (save_tstate != NULL) {
- // 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
@@ -2116,13 +2346,27 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config)
// This could be done in init_interpreter() (in pystate.c) if it
// didn't depend on interp->feature_flags being set already.
- _PyObject_InitState(interp);
-
- status = init_interp_create_gil(tstate, config->gil);
+ status = _PyObject_InitState(interp);
if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
+
+ // initialize the interp->obmalloc state. This must be done after
+ // the settings are loaded (so that feature_flags are set) but before
+ // any calls are made to obmalloc functions.
+ if (_PyMem_init_obmalloc(interp) < 0) {
+ status = _PyStatus_NO_MEMORY();
+ goto error;
+ }
+
+ tstate = _PyThreadState_New(interp, _PyThreadState_WHENCE_INIT);
+ if (tstate == NULL) {
+ status = _PyStatus_NO_MEMORY();
goto error;
}
- has_gil = 1;
+
+ _PyThreadState_Bind(tstate);
+ init_interp_create_gil(tstate, config->gil);
/* No objects have been created yet. */
@@ -2141,19 +2385,14 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config)
error:
*tstate_p = NULL;
-
- /* Oops, it didn't work. Undo it all. */
- PyErr_PrintEx(0);
- if (has_gil) {
- PyThreadState_Swap(save_tstate);
+ if (tstate != NULL) {
+ Py_EndInterpreter(tstate);
+ } else if (interp != NULL) {
+ PyInterpreterState_Delete(interp);
}
- else {
- _PyThreadState_SwapNoGIL(save_tstate);
+ if (save_tstate != NULL) {
+ _PyThreadState_Attach(save_tstate);
}
- PyThreadState_Clear(tstate);
- PyThreadState_Delete(tstate);
- PyInterpreterState_Delete(interp);
-
return status;
}
@@ -2161,15 +2400,17 @@ PyStatus
Py_NewInterpreterFromConfig(PyThreadState **tstate_p,
const PyInterpreterConfig *config)
{
- return new_interpreter(tstate_p, config);
+ long whence = _PyInterpreterState_WHENCE_CAPI;
+ return new_interpreter(tstate_p, config, whence);
}
PyThreadState *
Py_NewInterpreter(void)
{
PyThreadState *tstate = NULL;
+ long whence = _PyInterpreterState_WHENCE_LEGACY_CAPI;
const PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
- PyStatus status = new_interpreter(&tstate, &config);
+ PyStatus status = new_interpreter(&tstate, &config, whence);
if (_PyStatus_EXCEPTION(status)) {
Py_ExitStatusException(status);
}
@@ -2196,7 +2437,7 @@ Py_EndInterpreter(PyThreadState *tstate)
if (tstate != _PyThreadState_GET()) {
Py_FatalError("thread is not current");
}
- if (tstate->cframe->current_frame != NULL) {
+ if (tstate->current_frame != NULL) {
Py_FatalError("thread still has a frame");
}
interp->finalizing = 1;
@@ -2239,13 +2480,86 @@ _Py_IsInterpreterFinalizing(PyInterpreterState *interp)
return finalizing != NULL;
}
+static void
+finalize_subinterpreters(void)
+{
+ PyThreadState *final_tstate = _PyThreadState_GET();
+ PyInterpreterState *main_interp = _PyInterpreterState_Main();
+ assert(final_tstate->interp == main_interp);
+ _PyRuntimeState *runtime = main_interp->runtime;
+ struct pyinterpreters *interpreters = &runtime->interpreters;
+
+ /* Get the first interpreter in the list. */
+ HEAD_LOCK(runtime);
+ PyInterpreterState *interp = interpreters->head;
+ if (interp == main_interp) {
+ interp = interp->next;
+ }
+ HEAD_UNLOCK(runtime);
+
+ /* Bail out if there are no subinterpreters left. */
+ if (interp == NULL) {
+ return;
+ }
+
+ /* Warn the user if they forgot to clean up subinterpreters. */
+ (void)PyErr_WarnEx(
+ PyExc_RuntimeWarning,
+ "remaining subinterpreters; "
+ "destroy them with _interpreters.destroy()",
+ 0);
+
+ /* Swap out the current tstate, which we know must belong
+ to the main interpreter. */
+ _PyThreadState_Detach(final_tstate);
+
+ /* Clean up all remaining subinterpreters. */
+ while (interp != NULL) {
+ assert(!_PyInterpreterState_IsRunningMain(interp));
+
+ /* Find the tstate to use for fini. We assume the interpreter
+ will have at most one tstate at this point. */
+ PyThreadState *tstate = interp->threads.head;
+ if (tstate != NULL) {
+ /* Ideally we would be able to use tstate as-is, and rely
+ on it being in a ready state: no exception set, not
+ running anything (tstate->current_frame), matching the
+ current thread ID (tstate->thread_id). To play it safe,
+ we always delete it and use a fresh tstate instead. */
+ assert(tstate != final_tstate);
+ _PyThreadState_Attach(tstate);
+ PyThreadState_Clear(tstate);
+ _PyThreadState_Detach(tstate);
+ PyThreadState_Delete(tstate);
+ }
+ tstate = _PyThreadState_NewBound(interp, _PyThreadState_WHENCE_FINI);
+
+ /* Destroy the subinterpreter. */
+ _PyThreadState_Attach(tstate);
+ Py_EndInterpreter(tstate);
+ assert(_PyThreadState_GET() == NULL);
+
+ /* Advance to the next interpreter. */
+ HEAD_LOCK(runtime);
+ interp = interpreters->head;
+ if (interp == main_interp) {
+ interp = interp->next;
+ }
+ HEAD_UNLOCK(runtime);
+ }
+
+ /* Switch back to the main interpreter. */
+ _PyThreadState_Attach(final_tstate);
+}
+
+
/* Add the __main__ module */
static PyStatus
add_main_module(PyInterpreterState *interp)
{
- PyObject *m, *d, *loader, *ann_dict;
- m = PyImport_AddModule("__main__");
+ PyObject *m, *d, *ann_dict;
+ m = PyImport_AddModuleObject(&_Py_ID(__main__));
if (m == NULL)
return _PyStatus_ERR("can't create __main__ module");
@@ -2257,10 +2571,11 @@ add_main_module(PyInterpreterState *interp)
}
Py_DECREF(ann_dict);
- if (_PyDict_GetItemStringWithError(d, "__builtins__") == NULL) {
- if (PyErr_Occurred()) {
- return _PyStatus_ERR("Failed to test __main__.__builtins__");
- }
+ int has_builtins = PyDict_ContainsString(d, "__builtins__");
+ if (has_builtins < 0) {
+ return _PyStatus_ERR("Failed to test __main__.__builtins__");
+ }
+ if (!has_builtins) {
PyObject *bimod = PyImport_ImportModule("builtins");
if (bimod == NULL) {
return _PyStatus_ERR("Failed to retrieve builtins module");
@@ -2276,11 +2591,13 @@ add_main_module(PyInterpreterState *interp)
* will be set if __main__ gets further initialized later in the startup
* process.
*/
- loader = _PyDict_GetItemStringWithError(d, "__loader__");
- if (loader == NULL || loader == Py_None) {
- if (PyErr_Occurred()) {
- return _PyStatus_ERR("Failed to test __main__.__loader__");
- }
+ PyObject *loader;
+ if (PyDict_GetItemStringRef(d, "__loader__", &loader) < 0) {
+ return _PyStatus_ERR("Failed to test __main__.__loader__");
+ }
+ int has_loader = !(loader == NULL || loader == Py_None);
+ Py_XDECREF(loader);
+ if (!has_loader) {
PyObject *loader = _PyImport_GetImportlibLoader(interp,
"BuiltinImporter");
if (loader == NULL) {
@@ -2308,54 +2625,6 @@ init_import_site(void)
return _PyStatus_OK();
}
-/* Check if a file descriptor is valid or not.
- Return 0 if the file descriptor is invalid, return non-zero otherwise. */
-static int
-is_valid_fd(int fd)
-{
-/* dup() is faster than fstat(): fstat() can require input/output operations,
- whereas dup() doesn't. There is a low risk of EMFILE/ENFILE at Python
- startup. Problem: dup() doesn't check if the file descriptor is valid on
- some platforms.
-
- fcntl(fd, F_GETFD) is even faster, because it only checks the process table.
- It is preferred over dup() when available, since it cannot fail with the
- "too many open files" error (EMFILE).
-
- bpo-30225: On macOS Tiger, when stdout is redirected to a pipe and the other
- side of the pipe is closed, dup(1) succeed, whereas fstat(1, &st) fails with
- EBADF. FreeBSD has similar issue (bpo-32849).
-
- Only use dup() on Linux where dup() is enough to detect invalid FD
- (bpo-32849).
-*/
- if (fd < 0) {
- return 0;
- }
-#if defined(F_GETFD) && ( \
- defined(__linux__) || \
- defined(__APPLE__) || \
- defined(__wasm__))
- return fcntl(fd, F_GETFD) >= 0;
-#elif defined(__linux__)
- int fd2 = dup(fd);
- if (fd2 >= 0) {
- close(fd2);
- }
- return (fd2 >= 0);
-#elif defined(MS_WINDOWS)
- HANDLE hfile;
- _Py_BEGIN_SUPPRESS_IPH
- hfile = (HANDLE)_get_osfhandle(fd);
- _Py_END_SUPPRESS_IPH
- return (hfile != INVALID_HANDLE_VALUE
- && GetFileType(hfile) != FILE_TYPE_UNKNOWN);
-#else
- struct stat st;
- return (fstat(fd, &st) == 0);
-#endif
-}
-
/* returns Py_None if the fd is not valid */
static PyObject*
create_stdio(const PyConfig *config, PyObject* io,
@@ -2369,8 +2638,9 @@ create_stdio(const PyConfig *config, PyObject* io,
int buffering, isatty;
const int buffered_stdio = config->buffered_stdio;
- if (!is_valid_fd(fd))
+ if (!_Py_IsValidFD(fd)) {
Py_RETURN_NONE;
+ }
/* stdin is always opened in buffered mode, first because it shouldn't
make a difference in common use cases, second because TextIOWrapper
@@ -2486,9 +2756,9 @@ error:
Py_XDECREF(text);
Py_XDECREF(raw);
- if (PyErr_ExceptionMatches(PyExc_OSError) && !is_valid_fd(fd)) {
+ if (PyErr_ExceptionMatches(PyExc_OSError) && !_Py_IsValidFD(fd)) {
/* Issue #24891: the file descriptor was closed after the first
- is_valid_fd() check was called. Ignore the OSError and set the
+ _Py_IsValidFD() check was called. Ignore the OSError and set the
stream to None. */
PyErr_Clear();
Py_RETURN_NONE;
@@ -2622,12 +2892,141 @@ error:
res = _PyStatus_ERR("can't initialize sys standard streams");
done:
- _Py_ClearStandardStreamEncoding();
Py_XDECREF(iomod);
return res;
}
+#ifdef __ANDROID__
+#include <android/log.h>
+
+static PyObject *
+android_log_write_impl(PyObject *self, PyObject *args)
+{
+ int prio = 0;
+ const char *tag = NULL;
+ const char *text = NULL;
+ if (!PyArg_ParseTuple(args, "isy", &prio, &tag, &text)) {
+ return NULL;
+ }
+
+ // Despite its name, this function is part of the public API
+ // (https://developer.android.com/ndk/reference/group/logging).
+ __android_log_write(prio, tag, text);
+ Py_RETURN_NONE;
+}
+
+
+static PyMethodDef android_log_write_method = {
+ "android_log_write", android_log_write_impl, METH_VARARGS
+};
+
+
+static PyStatus
+init_android_streams(PyThreadState *tstate)
+{
+ PyStatus status = _PyStatus_OK();
+ PyObject *_android_support = NULL;
+ PyObject *android_log_write = NULL;
+ PyObject *result = NULL;
+
+ _android_support = PyImport_ImportModule("_android_support");
+ if (_android_support == NULL) {
+ goto error;
+ }
+
+ android_log_write = PyCFunction_New(&android_log_write_method, NULL);
+ if (android_log_write == NULL) {
+ goto error;
+ }
+
+ // These log priorities match those used by Java's System.out and System.err.
+ result = PyObject_CallMethod(
+ _android_support, "init_streams", "Oii",
+ android_log_write, ANDROID_LOG_INFO, ANDROID_LOG_WARN);
+ if (result == NULL) {
+ goto error;
+ }
+
+ goto done;
+
+error:
+ _PyErr_Print(tstate);
+ status = _PyStatus_ERR("failed to initialize Android streams");
+
+done:
+ Py_XDECREF(result);
+ Py_XDECREF(android_log_write);
+ Py_XDECREF(_android_support);
+ return status;
+}
+
+#endif // __ANDROID__
+
+#if defined(__APPLE__) && USE_APPLE_SYSTEM_LOG
+
+static PyObject *
+apple_log_write_impl(PyObject *self, PyObject *args)
+{
+ int logtype = 0;
+ const char *text = NULL;
+ if (!PyArg_ParseTuple(args, "iy", &logtype, &text)) {
+ return NULL;
+ }
+
+ // Pass the user-provided text through explicit %s formatting
+ // to avoid % literals being interpreted as a formatting directive.
+ os_log_with_type(OS_LOG_DEFAULT, logtype, "%s", text);
+ Py_RETURN_NONE;
+}
+
+
+static PyMethodDef apple_log_write_method = {
+ "apple_log_write", apple_log_write_impl, METH_VARARGS
+};
+
+
+static PyStatus
+init_apple_streams(PyThreadState *tstate)
+{
+ PyStatus status = _PyStatus_OK();
+ PyObject *_apple_support = NULL;
+ PyObject *apple_log_write = NULL;
+ PyObject *result = NULL;
+
+ _apple_support = PyImport_ImportModule("_apple_support");
+ if (_apple_support == NULL) {
+ goto error;
+ }
+
+ apple_log_write = PyCFunction_New(&apple_log_write_method, NULL);
+ if (apple_log_write == NULL) {
+ goto error;
+ }
+
+ // Initialize the logging streams, sending stdout -> Default; stderr -> Error
+ result = PyObject_CallMethod(
+ _apple_support, "init_streams", "Oii",
+ apple_log_write, OS_LOG_TYPE_DEFAULT, OS_LOG_TYPE_ERROR);
+ if (result == NULL) {
+ goto error;
+ }
+ goto done;
+
+error:
+ _PyErr_Print(tstate);
+ status = _PyStatus_ERR("failed to initialize Apple log streams");
+
+done:
+ Py_XDECREF(result);
+ Py_XDECREF(apple_log_write);
+ Py_XDECREF(_apple_support);
+ return status;
+}
+
+#endif // __APPLE__ && USE_APPLE_SYSTEM_LOG
+
+
static void
_Py_FatalError_DumpTracebacks(int fd, PyInterpreterState *interp,
PyThreadState *tstate)
@@ -2655,10 +3054,14 @@ _Py_FatalError_PrintExc(PyThreadState *tstate)
return 0;
}
- PyObject *ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr));
+ PyObject *ferr;
+ if (_PySys_GetOptionalAttr(&_Py_ID(stderr), &ferr) < 0) {
+ _PyErr_Clear(tstate);
+ }
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_XDECREF(ferr);
Py_DECREF(exc);
return 0;
}
@@ -2671,13 +3074,10 @@ _Py_FatalError_PrintExc(PyThreadState *tstate)
Py_DECREF(exc);
/* sys.stderr may be buffered: call sys.stderr.flush() */
- PyObject *res = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush));
- if (res == NULL) {
+ if (_PyFile_Flush(ferr) < 0) {
_PyErr_Clear(tstate);
}
- else {
- Py_DECREF(res);
- }
+ Py_DECREF(ferr);
return has_tb;
}
@@ -2763,6 +3163,30 @@ fatal_error_exit(int status)
}
}
+static inline int
+acquire_dict_lock_for_dump(PyObject *obj)
+{
+#ifdef Py_GIL_DISABLED
+ PyMutex *mutex = &obj->ob_mutex;
+ if (_PyMutex_LockTimed(mutex, 0, 0) == PY_LOCK_ACQUIRED) {
+ return 1;
+ }
+ return 0;
+#else
+ return 1;
+#endif
+}
+
+static inline void
+release_dict_lock_for_dump(PyObject *obj)
+{
+#ifdef Py_GIL_DISABLED
+ PyMutex *mutex = &obj->ob_mutex;
+ // We can not call PyMutex_Unlock because it's not async-signal-safe.
+ // So not to wake up other threads, we just use a simple atomic store in here.
+ _Py_atomic_store_uint8(&mutex->_bits, _Py_UNLOCKED);
+#endif
+}
// Dump the list of extension modules of sys.modules, excluding stdlib modules
// (sys.stdlib_module_names), into fd file descriptor.
@@ -2790,13 +3214,18 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
PyObject *stdlib_module_names = NULL;
if (interp->sysdict != NULL) {
pos = 0;
- while (PyDict_Next(interp->sysdict, &pos, &key, &value)) {
+ if (!acquire_dict_lock_for_dump(interp->sysdict)) {
+ // If we cannot acquire the lock, just don't dump the list of extension modules.
+ return;
+ }
+ while (_PyDict_Next(interp->sysdict, &pos, &key, &value, NULL)) {
if (PyUnicode_Check(key)
&& PyUnicode_CompareWithASCIIString(key, "stdlib_module_names") == 0) {
stdlib_module_names = value;
break;
}
}
+ release_dict_lock_for_dump(interp->sysdict);
}
// If we failed to get sys.stdlib_module_names or it's not a frozenset,
// don't exclude stdlib modules.
@@ -2808,7 +3237,11 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
int header = 1;
Py_ssize_t count = 0;
pos = 0;
- while (PyDict_Next(modules, &pos, &key, &value)) {
+ if (!acquire_dict_lock_for_dump(modules)) {
+ // If we cannot acquire the lock, just don't dump the list of extension modules.
+ return;
+ }
+ while (_PyDict_Next(modules, &pos, &key, &value, NULL)) {
if (!PyUnicode_Check(key)) {
continue;
}
@@ -2823,6 +3256,7 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
Py_ssize_t i = 0;
PyObject *item;
Py_hash_t hash;
+ // if stdlib_module_names is not NULL, it is always a frozenset.
while (_PySet_NextEntry(stdlib_module_names, &i, &item, &hash)) {
if (PyUnicode_Check(item)
&& PyUnicode_Compare(key, item) == 0)
@@ -2848,6 +3282,7 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
_Py_DumpASCII(fd, key);
count++;
}
+ release_dict_lock_for_dump(modules);
if (count) {
PUTS(fd, " (total: ");
@@ -3023,14 +3458,14 @@ wait_for_thread_shutdown(PyThreadState *tstate)
PyObject *threading = PyImport_GetModule(&_Py_ID(threading));
if (threading == NULL) {
if (_PyErr_Occurred(tstate)) {
- PyErr_WriteUnraisable(NULL);
+ PyErr_FormatUnraisable("Exception ignored on threading shutdown");
}
/* else: threading not imported */
return;
}
result = PyObject_CallMethodNoArgs(threading, &_Py_ID(_shutdown));
if (result == NULL) {
- PyErr_WriteUnraisable(threading);
+ PyErr_FormatUnraisable("Exception ignored on threading shutdown");
}
else {
Py_DECREF(result);
@@ -3041,13 +3476,13 @@ wait_for_thread_shutdown(PyThreadState *tstate)
int Py_AtExit(void (*func)(void))
{
struct _atexit_runtime_state *state = &_PyRuntime.atexit;
- PyThread_acquire_lock(state->mutex, WAIT_LOCK);
+ PyMutex_Lock(&state->mutex);
if (state->ncallbacks >= NEXITFUNCS) {
- PyThread_release_lock(state->mutex);
+ PyMutex_Unlock(&state->mutex);
return -1;
}
state->callbacks[state->ncallbacks++] = func;
- PyThread_release_lock(state->mutex);
+ PyMutex_Unlock(&state->mutex);
return 0;
}
@@ -3057,18 +3492,18 @@ call_ll_exitfuncs(_PyRuntimeState *runtime)
atexit_callbackfunc exitfunc;
struct _atexit_runtime_state *state = &runtime->atexit;
- PyThread_acquire_lock(state->mutex, WAIT_LOCK);
+ PyMutex_Lock(&state->mutex);
while (state->ncallbacks > 0) {
/* pop last function from the list */
state->ncallbacks--;
exitfunc = state->callbacks[state->ncallbacks];
state->callbacks[state->ncallbacks] = NULL;
- PyThread_release_lock(state->mutex);
+ PyMutex_Unlock(&state->mutex);
exitfunc();
- PyThread_acquire_lock(state->mutex, WAIT_LOCK);
+ PyMutex_Lock(&state->mutex);
}
- PyThread_release_lock(state->mutex);
+ PyMutex_Unlock(&state->mutex);
fflush(stdout);
fflush(stderr);
@@ -3077,7 +3512,11 @@ call_ll_exitfuncs(_PyRuntimeState *runtime)
void _Py_NO_RETURN
Py_Exit(int sts)
{
- if (Py_FinalizeEx() < 0) {
+ PyThreadState *tstate = _PyThreadState_GET();
+ if (tstate != NULL && _PyThreadState_IsRunningMain(tstate)) {
+ _PyInterpreterState_SetNotRunningMain(tstate->interp);
+ }
+ if (_Py_Finalize(&_PyRuntime) < 0) {
sts = 120;
}
@@ -3159,7 +3598,7 @@ PyOS_getsig(int sig)
/*
* All of the code in this function must only use async-signal-safe functions,
- * listed at `man 7 signal` or
+ * listed at `man 7 signal-safety` or
* http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html.
*/
PyOS_sighandler_t
@@ -3189,7 +3628,3 @@ PyOS_setsig(int sig, PyOS_sighandler_t handler)
return oldhandler;
#endif
}
-
-#ifdef __cplusplus
-}
-#endif