diff options
Diffstat (limited to 'contrib/tools/python3/Python/pylifecycle.c')
| -rw-r--r-- | contrib/tools/python3/Python/pylifecycle.c | 1013 |
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 |
