| /* Python interpreter top-level routines, including init/exit */ |
| |
| #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_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() |
| #include "pycore_global_objects_fini_generated.h" // "_PyStaticObjects_CheckRefcnt() |
| #include "pycore_import.h" // _PyImport_BootstrapImp() |
| #include "pycore_initconfig.h" // _PyStatus_OK() |
| #include "pycore_list.h" // _PyList_Fini() |
| #include "pycore_long.h" // _PyLong_InitTypes() |
| #include "pycore_object.h" // _PyDebug_PrintTotalRefs() |
| #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 <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 |
| # include <signal.h> // SIG_IGN |
| #endif |
| |
| #ifdef HAVE_LANGINFO_H |
| # include <langinfo.h> // nl_langinfo(CODESET) |
| #endif |
| |
| #ifdef HAVE_FCNTL_H |
| # include <fcntl.h> // F_GETFD |
| #endif |
| |
| #ifdef MS_WINDOWS |
| # undef BYTE |
| #endif |
| |
| #define PUTS(fd, str) (void)_Py_write_noraise(fd, str, (int)strlen(str)) |
| |
| |
| /* Forward declarations */ |
| 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 |
| * found without any external information. This is meant to ease access to the |
| * interpreter state for various runtime debugging tools, but is *not* an |
| * officially supported feature */ |
| |
| /* Suppress deprecation warning for PyBytesObject.ob_shash */ |
| _Py_COMP_DIAG_PUSH |
| _Py_COMP_DIAG_IGNORE_DEPR_DECLS |
| |
| #if defined(MS_WINDOWS) |
| |
| #pragma section("PyRuntime", read, write) |
| __declspec(allocate("PyRuntime")) |
| |
| #elif defined(__APPLE__) |
| |
| __attribute__(( |
| section(SEG_DATA ",PyRuntime") |
| )) |
| |
| #endif |
| |
| _PyRuntimeState _PyRuntime |
| #if defined(__linux__) && (defined(__GNUC__) || defined(__clang__)) |
| __attribute__ ((section (".PyRuntime"))) |
| #endif |
| = _PyRuntimeState_INIT(_PyRuntime, _Py_Debug_Cookie); |
| _Py_COMP_DIAG_POP |
| |
| static int runtime_initialized = 0; |
| |
| PyStatus |
| _PyRuntime_Initialize(void) |
| { |
| /* XXX We only initialize once in the process, which aligns with |
| the static initialization of the former globals now found in |
| _PyRuntime. However, _PyRuntime *should* be initialized with |
| every Py_Initialize() call, but doing so breaks the runtime. |
| This is because the runtime state is not properly finalized |
| currently. */ |
| if (runtime_initialized) { |
| return _PyStatus_OK(); |
| } |
| runtime_initialized = 1; |
| |
| return _PyRuntimeState_Init(&_PyRuntime); |
| } |
| |
| void |
| _PyRuntime_Finalize(void) |
| { |
| _PyRuntimeState_Fini(&_PyRuntime); |
| runtime_initialized = 0; |
| } |
| |
| int |
| Py_IsFinalizing(void) |
| { |
| return _PyRuntimeState_GetFinalizing(&_PyRuntime) != NULL; |
| } |
| |
| /* Hack to force loading of object files */ |
| int (*_PyOS_mystrnicmp_hack)(const char *, const char *, Py_ssize_t) = \ |
| PyOS_mystrnicmp; /* Python/pystrcmp.o */ |
| |
| |
| /* APIs to access the initialization flags |
| * |
| * Can be called prior to Py_Initialize. |
| */ |
| |
| int |
| _Py_IsCoreInitialized(void) |
| { |
| return _PyRuntime.core_initialized; |
| } |
| |
| int |
| Py_IsInitialized(void) |
| { |
| return _PyRuntime.initialized; |
| } |
| |
| |
| /* Helper functions to better handle the legacy C locale |
| * |
| * The legacy C locale assumes ASCII as the default text encoding, which |
| * causes problems not only for the CPython runtime, but also other |
| * components like GNU readline. |
| * |
| * Accordingly, when the CLI detects it, it attempts to coerce it to a |
| * more capable UTF-8 based alternative as follows: |
| * |
| * if (_Py_LegacyLocaleDetected()) { |
| * _Py_CoerceLegacyLocale(); |
| * } |
| * |
| * See the documentation of the PYTHONCOERCECLOCALE setting for more details. |
| * |
| * Locale coercion also impacts the default error handler for the standard |
| * streams: while the usual default is "strict", the default for the legacy |
| * C locale and for any of the coercion target locales is "surrogateescape". |
| */ |
| |
| int |
| _Py_LegacyLocaleDetected(int warn) |
| { |
| #ifndef MS_WINDOWS |
| if (!warn) { |
| const char *locale_override = getenv("LC_ALL"); |
| if (locale_override != NULL && *locale_override != '\0') { |
| /* Don't coerce C locale if the LC_ALL environment variable |
| is set */ |
| return 0; |
| } |
| } |
| |
| /* On non-Windows systems, the C locale is considered a legacy locale */ |
| /* XXX (ncoghlan): some platforms (notably Mac OS X) don't appear to treat |
| * the POSIX locale as a simple alias for the C locale, so |
| * we may also want to check for that explicitly. |
| */ |
| const char *ctype_loc = setlocale(LC_CTYPE, NULL); |
| return ctype_loc != NULL && strcmp(ctype_loc, "C") == 0; |
| #else |
| /* Windows uses code pages instead of locales, so no locale is legacy */ |
| return 0; |
| #endif |
| } |
| |
| #ifndef MS_WINDOWS |
| static const char *_C_LOCALE_WARNING = |
| "Python runtime initialized with LC_CTYPE=C (a locale with default ASCII " |
| "encoding), which may cause Unicode compatibility problems. Using C.UTF-8, " |
| "C.utf8, or UTF-8 (if available) as alternative Unicode-compatible " |
| "locales is recommended.\n"; |
| |
| static void |
| emit_stderr_warning_for_legacy_locale(_PyRuntimeState *runtime) |
| { |
| const PyPreConfig *preconfig = &runtime->preconfig; |
| if (preconfig->coerce_c_locale_warn && _Py_LegacyLocaleDetected(1)) { |
| PySys_FormatStderr("%s", _C_LOCALE_WARNING); |
| } |
| } |
| #endif /* !defined(MS_WINDOWS) */ |
| |
| typedef struct _CandidateLocale { |
| const char *locale_name; /* The locale to try as a coercion target */ |
| } _LocaleCoercionTarget; |
| |
| static _LocaleCoercionTarget _TARGET_LOCALES[] = { |
| {"C.UTF-8"}, |
| {"C.utf8"}, |
| {"UTF-8"}, |
| {NULL} |
| }; |
| |
| |
| int |
| _Py_IsLocaleCoercionTarget(const char *ctype_loc) |
| { |
| const _LocaleCoercionTarget *target = NULL; |
| for (target = _TARGET_LOCALES; target->locale_name; target++) { |
| if (strcmp(ctype_loc, target->locale_name) == 0) { |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| |
| #ifdef PY_COERCE_C_LOCALE |
| static const char C_LOCALE_COERCION_WARNING[] = |
| "Python detected LC_CTYPE=C: LC_CTYPE coerced to %.20s (set another locale " |
| "or PYTHONCOERCECLOCALE=0 to disable this locale coercion behavior).\n"; |
| |
| static int |
| _coerce_default_locale_settings(int warn, const _LocaleCoercionTarget *target) |
| { |
| const char *newloc = target->locale_name; |
| |
| /* Reset locale back to currently configured defaults */ |
| _Py_SetLocaleFromEnv(LC_ALL); |
| |
| /* Set the relevant locale environment variable */ |
| if (setenv("LC_CTYPE", newloc, 1)) { |
| fprintf(stderr, |
| "Error setting LC_CTYPE, skipping C locale coercion\n"); |
| return 0; |
| } |
| if (warn) { |
| fprintf(stderr, C_LOCALE_COERCION_WARNING, newloc); |
| } |
| |
| /* Reconfigure with the overridden environment variables */ |
| _Py_SetLocaleFromEnv(LC_ALL); |
| return 1; |
| } |
| #endif |
| |
| int |
| _Py_CoerceLegacyLocale(int warn) |
| { |
| int coerced = 0; |
| #ifdef PY_COERCE_C_LOCALE |
| char *oldloc = NULL; |
| |
| oldloc = _PyMem_RawStrdup(setlocale(LC_CTYPE, NULL)); |
| if (oldloc == NULL) { |
| return coerced; |
| } |
| |
| const char *locale_override = getenv("LC_ALL"); |
| if (locale_override == NULL || *locale_override == '\0') { |
| /* LC_ALL is also not set (or is set to an empty string) */ |
| const _LocaleCoercionTarget *target = NULL; |
| for (target = _TARGET_LOCALES; target->locale_name; target++) { |
| const char *new_locale = setlocale(LC_CTYPE, |
| target->locale_name); |
| if (new_locale != NULL) { |
| #if !defined(_Py_FORCE_UTF8_LOCALE) && defined(HAVE_LANGINFO_H) && defined(CODESET) |
| /* Also ensure that nl_langinfo works in this locale */ |
| char *codeset = nl_langinfo(CODESET); |
| if (!codeset || *codeset == '\0') { |
| /* CODESET is not set or empty, so skip coercion */ |
| new_locale = NULL; |
| _Py_SetLocaleFromEnv(LC_CTYPE); |
| continue; |
| } |
| #endif |
| /* Successfully configured locale, so make it the default */ |
| coerced = _coerce_default_locale_settings(warn, target); |
| goto done; |
| } |
| } |
| } |
| /* No C locale warning here, as Py_Initialize will emit one later */ |
| |
| setlocale(LC_CTYPE, oldloc); |
| |
| done: |
| PyMem_RawFree(oldloc); |
| #endif |
| return coerced; |
| } |
| |
| /* _Py_SetLocaleFromEnv() is a wrapper around setlocale(category, "") to |
| * isolate the idiosyncrasies of different libc implementations. It reads the |
| * appropriate environment variable and uses its value to select the locale for |
| * 'category'. */ |
| char * |
| _Py_SetLocaleFromEnv(int category) |
| { |
| char *res; |
| #ifdef __ANDROID__ |
| const char *locale; |
| const char **pvar; |
| #ifdef PY_COERCE_C_LOCALE |
| const char *coerce_c_locale; |
| #endif |
| const char *utf8_locale = "C.UTF-8"; |
| const char *env_var_set[] = { |
| "LC_ALL", |
| "LC_CTYPE", |
| "LANG", |
| NULL, |
| }; |
| |
| /* Android setlocale(category, "") doesn't check the environment variables |
| * and incorrectly sets the "C" locale at API 24 and older APIs. We only |
| * check the environment variables listed in env_var_set. */ |
| for (pvar=env_var_set; *pvar; pvar++) { |
| locale = getenv(*pvar); |
| if (locale != NULL && *locale != '\0') { |
| if (strcmp(locale, utf8_locale) == 0 || |
| strcmp(locale, "en_US.UTF-8") == 0) { |
| return setlocale(category, utf8_locale); |
| } |
| return setlocale(category, "C"); |
| } |
| } |
| |
| /* Android uses UTF-8, so explicitly set the locale to C.UTF-8 if none of |
| * LC_ALL, LC_CTYPE, or LANG is set to a non-empty string. |
| * Quote from POSIX section "8.2 Internationalization Variables": |
| * "4. If the LANG environment variable is not set or is set to the empty |
| * string, the implementation-defined default locale shall be used." */ |
| |
| #ifdef PY_COERCE_C_LOCALE |
| coerce_c_locale = getenv("PYTHONCOERCECLOCALE"); |
| if (coerce_c_locale == NULL || strcmp(coerce_c_locale, "0") != 0) { |
| /* Some other ported code may check the environment variables (e.g. in |
| * extension modules), so we make sure that they match the locale |
| * configuration */ |
| if (setenv("LC_CTYPE", utf8_locale, 1)) { |
| fprintf(stderr, "Warning: failed setting the LC_CTYPE " |
| "environment variable to %s\n", utf8_locale); |
| } |
| } |
| #endif |
| res = setlocale(category, utf8_locale); |
| #else /* !defined(__ANDROID__) */ |
| res = setlocale(category, ""); |
| #endif |
| _Py_ResetForceASCII(); |
| return res; |
| } |
| |
| |
| static int |
| interpreter_update_config(PyThreadState *tstate, int only_update_path_config) |
| { |
| const PyConfig *config = &tstate->interp->config; |
| |
| if (!only_update_path_config) { |
| PyStatus status = _PyConfig_Write(config, tstate->interp->runtime); |
| if (_PyStatus_EXCEPTION(status)) { |
| _PyErr_SetFromPyStatus(status); |
| return -1; |
| } |
| } |
| |
| if (_Py_IsMainInterpreter(tstate->interp)) { |
| PyStatus status = _PyPathConfig_UpdateGlobal(config); |
| if (_PyStatus_EXCEPTION(status)) { |
| _PyErr_SetFromPyStatus(status); |
| return -1; |
| } |
| } |
| |
| tstate->interp->long_state.max_str_digits = config->int_max_str_digits; |
| |
| // Update the sys module for the new configuration |
| if (_PySys_UpdateConfig(tstate) < 0) { |
| return -1; |
| } |
| return 0; |
| } |
| |
| |
| int |
| _PyInterpreterState_SetConfig(const PyConfig *src_config) |
| { |
| PyThreadState *tstate = _PyThreadState_GET(); |
| int res = -1; |
| |
| PyConfig config; |
| PyConfig_InitPythonConfig(&config); |
| PyStatus status = _PyConfig_Copy(&config, src_config); |
| if (_PyStatus_EXCEPTION(status)) { |
| _PyErr_SetFromPyStatus(status); |
| goto done; |
| } |
| |
| status = _PyConfig_Read(&config, 1); |
| if (_PyStatus_EXCEPTION(status)) { |
| _PyErr_SetFromPyStatus(status); |
| goto done; |
| } |
| |
| status = _PyConfig_Copy(&tstate->interp->config, &config); |
| if (_PyStatus_EXCEPTION(status)) { |
| _PyErr_SetFromPyStatus(status); |
| goto done; |
| } |
| |
| res = interpreter_update_config(tstate, 0); |
| |
| done: |
| PyConfig_Clear(&config); |
| return res; |
| } |
| |
| |
| /* Global initializations. Can be undone by Py_Finalize(). Don't |
| call this twice without an intervening Py_Finalize() call. |
| |
| Every call to Py_InitializeFromConfig, Py_Initialize or Py_InitializeEx |
| must have a corresponding call to Py_Finalize. |
| |
| Locking: you must hold the interpreter lock while calling these APIs. |
| (If the lock has not yet been initialized, that's equivalent to |
| having the lock, but you cannot use multiple threads.) |
| |
| */ |
| |
| static PyStatus |
| pyinit_core_reconfigure(_PyRuntimeState *runtime, |
| PyThreadState **tstate_p, |
| const PyConfig *config) |
| { |
| PyStatus status; |
| PyThreadState *tstate = _PyThreadState_GET(); |
| if (!tstate) { |
| return _PyStatus_ERR("failed to read thread state"); |
| } |
| *tstate_p = tstate; |
| |
| PyInterpreterState *interp = tstate->interp; |
| if (interp == NULL) { |
| return _PyStatus_ERR("can't make main interpreter"); |
| } |
| assert(interp->_ready); |
| |
| status = _PyConfig_Write(config, runtime); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PyConfig_Copy(&interp->config, config); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| config = _PyInterpreterState_GetConfig(interp); |
| |
| if (config->_install_importlib) { |
| status = _PyPathConfig_UpdateGlobal(config); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| } |
| return _PyStatus_OK(); |
| } |
| |
| |
| static PyStatus |
| pycore_init_runtime(_PyRuntimeState *runtime, |
| const PyConfig *config) |
| { |
| if (runtime->initialized) { |
| return _PyStatus_ERR("main interpreter already initialized"); |
| } |
| |
| PyStatus status = _PyConfig_Write(config, runtime); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| /* Py_Finalize leaves _Py_Finalizing set in order to help daemon |
| * threads behave a little more gracefully at interpreter shutdown. |
| * We clobber it here so the new interpreter can start with a clean |
| * slate. |
| * |
| * However, this may still lead to misbehaviour if there are daemon |
| * threads still hanging around from a previous Py_Initialize/Finalize |
| * pair :( |
| */ |
| _PyRuntimeState_SetFinalizing(runtime, NULL); |
| |
| _Py_InitVersion(); |
| |
| status = _Py_HashRandomization_Init(config); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PyImport_Init(); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PyInterpreterState_Enable(runtime); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| return _PyStatus_OK(); |
| } |
| |
| |
| static PyStatus |
| init_interp_settings(PyInterpreterState *interp, |
| const PyInterpreterConfig *config) |
| { |
| assert(interp->feature_flags == 0); |
| |
| if (config->use_main_obmalloc) { |
| interp->feature_flags |= Py_RTFLAGS_USE_MAIN_OBMALLOC; |
| } |
| else if (!config->check_multi_interp_extensions) { |
| /* The reason: PyModuleDef.m_base.m_copy leaks objects between |
| interpreters. */ |
| return _PyStatus_ERR("per-interpreter obmalloc does not support " |
| "single-phase init extension modules"); |
| } |
| #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; |
| } |
| if (config->allow_exec) { |
| interp->feature_flags |= Py_RTFLAGS_EXEC; |
| } |
| // Note that fork+exec is always allowed. |
| |
| if (config->allow_threads) { |
| interp->feature_flags |= Py_RTFLAGS_THREADS; |
| } |
| if (config->allow_daemon_threads) { |
| interp->feature_flags |= Py_RTFLAGS_DAEMON_THREADS; |
| } |
| |
| if (config->check_multi_interp_extensions) { |
| interp->feature_flags |= Py_RTFLAGS_MULTI_INTERP_EXTENSIONS; |
| } |
| |
| 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 void |
| init_interp_create_gil(PyThreadState *tstate, int gil) |
| { |
| /* 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 */ |
| _PyGILState_SetTstate(tstate); |
| |
| int own_gil = (gil == PyInterpreterConfig_OWN_GIL); |
| |
| /* Create the GIL and take it */ |
| _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, |
| const PyConfig *src_config, |
| PyThreadState **tstate_p) |
| { |
| PyStatus status; |
| 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)) { |
| return status; |
| } |
| |
| /* Auto-thread-state API */ |
| status = _PyGILState_Init(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; |
| // 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; |
| } |
| |
| // This could be done in init_interpreter() (in pystate.c) if it |
| // didn't depend on interp->feature_flags being set already. |
| 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_WHENCE_INIT); |
| if (tstate == NULL) { |
| return _PyStatus_ERR("can't make first thread"); |
| } |
| runtime->main_tstate = tstate; |
| _PyThreadState_Bind(tstate); |
| |
| init_interp_create_gil(tstate, config.gil); |
| |
| *tstate_p = tstate; |
| return _PyStatus_OK(); |
| } |
| |
| |
| static PyStatus |
| pycore_init_global_objects(PyInterpreterState *interp) |
| { |
| PyStatus status; |
| |
| _PyFloat_InitState(interp); |
| |
| status = _PyUnicode_InitGlobalObjects(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| _PyUnicode_InitState(interp); |
| |
| if (_Py_IsMainInterpreter(interp)) { |
| _Py_GetConstant_Init(); |
| } |
| |
| return _PyStatus_OK(); |
| } |
| |
| |
| static PyStatus |
| pycore_init_types(PyInterpreterState *interp) |
| { |
| PyStatus status; |
| |
| status = _PyTypes_InitTypes(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PyLong_InitTypes(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PyUnicode_InitTypes(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PyFloat_InitTypes(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| if (_PyExc_InitTypes(interp) < 0) { |
| return _PyStatus_ERR("failed to initialize an exception type"); |
| } |
| |
| status = _PyExc_InitGlobalObjects(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PyExc_InitState(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PyErr_InitTypes(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PyContext_Init(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PyXI_InitTypes(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| return _PyStatus_OK(); |
| } |
| |
| static PyStatus |
| pycore_init_builtins(PyThreadState *tstate) |
| { |
| PyInterpreterState *interp = tstate->interp; |
| |
| PyObject *bimod = _PyBuiltin_Init(interp); |
| if (bimod == NULL) { |
| goto error; |
| } |
| |
| PyObject *modules = _PyImport_GetModules(interp); |
| if (_PyImport_FixupBuiltin(tstate, bimod, "builtins", modules) < 0) { |
| goto error; |
| } |
| |
| PyObject *builtins_dict = PyModule_GetDict(bimod); |
| if (builtins_dict == NULL) { |
| goto error; |
| } |
| interp->builtins = Py_NewRef(builtins_dict); |
| |
| PyObject *isinstance = PyDict_GetItemWithError(builtins_dict, &_Py_ID(isinstance)); |
| if (!isinstance) { |
| goto error; |
| } |
| interp->callable_cache.isinstance = isinstance; |
| |
| 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)); |
| if (list_append == NULL) { |
| goto error; |
| } |
| interp->callable_cache.list_append = list_append; |
| |
| PyObject *object__getattribute__ = _PyType_Lookup(&PyBaseObject_Type, &_Py_ID(__getattribute__)); |
| 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"); |
| } |
| |
| interp->builtins_copy = PyDict_Copy(interp->builtins); |
| if (interp->builtins_copy == NULL) { |
| goto error; |
| } |
| Py_DECREF(bimod); |
| |
| if (_PyImport_InitDefaultImportFunc(interp) < 0) { |
| goto error; |
| } |
| |
| assert(!_PyErr_Occurred(tstate)); |
| return _PyStatus_OK(); |
| |
| error: |
| Py_XDECREF(bimod); |
| return _PyStatus_ERR("can't initialize builtins module"); |
| } |
| |
| |
| static PyStatus |
| pycore_interp_init(PyThreadState *tstate) |
| { |
| PyInterpreterState *interp = tstate->interp; |
| PyStatus status; |
| PyObject *sysmod = NULL; |
| |
| // Create singletons before the first PyType_Ready() call, since |
| // PyType_Ready() uses singletons like the Unicode empty string (tp_doc) |
| // and the empty tuple singletons (tp_bases). |
| status = pycore_init_global_objects(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PyCode_Init(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PyDtoa_Init(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| // The GC must be initialized before the first GC collection. |
| status = _PyGC_Init(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = pycore_init_types(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| goto done; |
| } |
| |
| if (_PyWarnings_InitState(interp) < 0) { |
| return _PyStatus_ERR("can't initialize warnings"); |
| } |
| |
| status = _PyAtExit_Init(interp); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PySys_Create(tstate, &sysmod); |
| if (_PyStatus_EXCEPTION(status)) { |
| goto done; |
| } |
| |
| status = pycore_init_builtins(tstate); |
| if (_PyStatus_EXCEPTION(status)) { |
| 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); |
| if (_PyStatus_EXCEPTION(status)) { |
| goto done; |
| } |
| |
| done: |
| /* sys.modules['sys'] contains a strong reference to the module */ |
| Py_XDECREF(sysmod); |
| return status; |
| } |
| |
| |
| static PyStatus |
| pyinit_config(_PyRuntimeState *runtime, |
| PyThreadState **tstate_p, |
| const PyConfig *config) |
| { |
| PyStatus status = pycore_init_runtime(runtime, config); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| PyThreadState *tstate; |
| status = pycore_create_interpreter(runtime, config, &tstate); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| *tstate_p = tstate; |
| |
| status = pycore_interp_init(tstate); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| /* Only when we get here is the runtime core fully initialized */ |
| runtime->core_initialized = 1; |
| return _PyStatus_OK(); |
| } |
| |
| |
| PyStatus |
| _Py_PreInitializeFromPyArgv(const PyPreConfig *src_config, const _PyArgv *args) |
| { |
| PyStatus status; |
| |
| if (src_config == NULL) { |
| return _PyStatus_ERR("preinitialization config is NULL"); |
| } |
| |
| status = _PyRuntime_Initialize(); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| _PyRuntimeState *runtime = &_PyRuntime; |
| |
| if (runtime->preinitialized) { |
| /* If it's already configured: ignored the new configuration */ |
| return _PyStatus_OK(); |
| } |
| |
| /* Note: preinitialized remains 1 on error, it is only set to 0 |
| at exit on success. */ |
| runtime->preinitializing = 1; |
| |
| PyPreConfig config; |
| |
| status = _PyPreConfig_InitFromPreConfig(&config, src_config); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PyPreConfig_Read(&config, args); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = _PyPreConfig_Write(&config); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| runtime->preinitializing = 0; |
| runtime->preinitialized = 1; |
| return _PyStatus_OK(); |
| } |
| |
| |
| PyStatus |
| Py_PreInitializeFromBytesArgs(const PyPreConfig *src_config, Py_ssize_t argc, char **argv) |
| { |
| _PyArgv args = {.use_bytes_argv = 1, .argc = argc, .bytes_argv = argv}; |
| return _Py_PreInitializeFromPyArgv(src_config, &args); |
| } |
| |
| |
| PyStatus |
| Py_PreInitializeFromArgs(const PyPreConfig *src_config, Py_ssize_t argc, wchar_t **argv) |
| { |
| _PyArgv args = {.use_bytes_argv = 0, .argc = argc, .wchar_argv = argv}; |
| return _Py_PreInitializeFromPyArgv(src_config, &args); |
| } |
| |
| |
| PyStatus |
| Py_PreInitialize(const PyPreConfig *src_config) |
| { |
| return _Py_PreInitializeFromPyArgv(src_config, NULL); |
| } |
| |
| |
| PyStatus |
| _Py_PreInitializeFromConfig(const PyConfig *config, |
| const _PyArgv *args) |
| { |
| assert(config != NULL); |
| |
| PyStatus status = _PyRuntime_Initialize(); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| _PyRuntimeState *runtime = &_PyRuntime; |
| |
| if (runtime->preinitialized) { |
| /* Already initialized: do nothing */ |
| return _PyStatus_OK(); |
| } |
| |
| PyPreConfig preconfig; |
| |
| _PyPreConfig_InitFromConfig(&preconfig, config); |
| |
| if (!config->parse_argv) { |
| return Py_PreInitialize(&preconfig); |
| } |
| else if (args == NULL) { |
| _PyArgv config_args = { |
| .use_bytes_argv = 0, |
| .argc = config->argv.length, |
| .wchar_argv = config->argv.items}; |
| return _Py_PreInitializeFromPyArgv(&preconfig, &config_args); |
| } |
| else { |
| return _Py_PreInitializeFromPyArgv(&preconfig, args); |
| } |
| } |
| |
| |
| /* Begin interpreter initialization |
| * |
| * On return, the first thread and interpreter state have been created, |
| * but the compiler, signal handling, multithreading and |
| * multiple interpreter support, and codec infrastructure are not yet |
| * available. |
| * |
| * The import system will support builtin and frozen modules only. |
| * The only supported io is writing to sys.stderr |
| * |
| * If any operation invoked by this function fails, a fatal error is |
| * issued and the function does not return. |
| * |
| * Any code invoked from this function should *not* assume it has access |
| * to the Python C API (unless the API is explicitly listed as being |
| * safe to call without calling Py_Initialize first) |
| */ |
| static PyStatus |
| pyinit_core(_PyRuntimeState *runtime, |
| const PyConfig *src_config, |
| PyThreadState **tstate_p) |
| { |
| PyStatus status; |
| |
| status = _Py_PreInitializeFromConfig(src_config, NULL); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| PyConfig config; |
| PyConfig_InitPythonConfig(&config); |
| |
| status = _PyConfig_Copy(&config, src_config); |
| if (_PyStatus_EXCEPTION(status)) { |
| goto done; |
| } |
| |
| // Read the configuration, but don't compute the path configuration |
| // (it is computed in the main init). |
| status = _PyConfig_Read(&config, 0); |
| if (_PyStatus_EXCEPTION(status)) { |
| goto done; |
| } |
| |
| if (!runtime->core_initialized) { |
| status = pyinit_config(runtime, tstate_p, &config); |
| } |
| else { |
| status = pyinit_core_reconfigure(runtime, tstate_p, &config); |
| } |
| if (_PyStatus_EXCEPTION(status)) { |
| goto done; |
| } |
| |
| done: |
| PyConfig_Clear(&config); |
| return status; |
| } |
| |
| |
| /* Py_Initialize() has already been called: update the main interpreter |
| configuration. Example of bpo-34008: Py_Main() called after |
| Py_Initialize(). */ |
| static PyStatus |
| pyinit_main_reconfigure(PyThreadState *tstate) |
| { |
| if (interpreter_update_config(tstate, 0) < 0) { |
| return _PyStatus_ERR("fail to reconfigure Python"); |
| } |
| return _PyStatus_OK(); |
| } |
| |
| |
| #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) |
| { |
| assert(!_PyErr_Occurred(tstate)); |
| |
| PyStatus status; |
| int is_main_interp = _Py_IsMainInterpreter(tstate->interp); |
| PyInterpreterState *interp = tstate->interp; |
| const PyConfig *config = _PyInterpreterState_GetConfig(interp); |
| |
| if (!config->_install_importlib) { |
| /* Special mode for freeze_importlib: run with no import system |
| * |
| * This means anything which needs support from extension modules |
| * or pure Python code in the standard library won't work. |
| */ |
| if (is_main_interp) { |
| interp->runtime->initialized = 1; |
| } |
| return _PyStatus_OK(); |
| } |
| |
| // Initialize the import-related configuration. |
| status = _PyConfig_InitImportConfig(&interp->config); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| if (interpreter_update_config(tstate, 1) < 0) { |
| return _PyStatus_ERR("failed to update the Python config"); |
| } |
| |
| status = _PyImport_InitExternal(tstate); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| if (is_main_interp) { |
| /* initialize the faulthandler module */ |
| status = _PyFaulthandler_Init(config->faulthandler); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| } |
| |
| status = _PyUnicode_InitEncodings(tstate); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| if (is_main_interp) { |
| if (_PySignal_Init(config->install_signal_handlers) < 0) { |
| return _PyStatus_ERR("can't initialize signals"); |
| } |
| |
| if (config->tracemalloc) { |
| if (_PyTraceMalloc_Start(config->tracemalloc) < 0) { |
| return _PyStatus_ERR("can't start tracemalloc"); |
| } |
| } |
| |
| #ifdef PY_HAVE_PERF_TRAMPOLINE |
| if (config->perf_profiling) { |
| _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"); |
| } |
| } |
| #endif |
| } |
| |
| status = init_sys_streams(tstate); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| |
| status = init_set_builtins_open(); |
| if (_PyStatus_EXCEPTION(status)) { |
| 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; |
| } |
| |
| if (is_main_interp) { |
| /* Initialize warnings. */ |
| 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) { |
| fprintf(stderr, "'import warnings' failed; traceback:\n"); |
| _PyErr_Print(tstate); |
| } |
| Py_XDECREF(warnings_module); |
| } |
| Py_XDECREF(warnoptions); |
| |
| interp->runtime->initialized = 1; |
| } |
| |
| if (config->site_import) { |
| status = init_import_site(); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| } |
| |
| if (is_main_interp) { |
| #ifndef MS_WINDOWS |
| emit_stderr_warning_for_legacy_locale(interp->runtime); |
| #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. |
| 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]"); |
| } |
| PyObject *sysdict = interp->sysdict; |
| if (sysdict == NULL) { |
| Py_DECREF(path0); |
| return _PyStatus_ERR("can't initialize sys.path[0]"); |
| } |
| PyObject *sys_path = PyDict_GetItemWithError(sysdict, &_Py_ID(path)); |
| if (sys_path == NULL) { |
| Py_DECREF(path0); |
| return _PyStatus_ERR("can't initialize sys.path[0]"); |
| } |
| int res = PyList_Insert(sys_path, 0, path0); |
| Py_DECREF(path0); |
| if (res) { |
| return _PyStatus_ERR("can't initialize sys.path[0]"); |
| } |
| } |
| } |
| |
| |
| 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(); |
| } |
| |
| |
| /* Update interpreter state based on supplied configuration settings |
| * |
| * After calling this function, most of the restrictions on the interpreter |
| * are lifted. The only remaining incomplete settings are those related |
| * to the main module (sys.argv[0], __main__ metadata) |
| * |
| * Calling this when the interpreter is not initializing, is already |
| * initialized or without a valid current thread state is a fatal error. |
| * Other errors should be reported as normal Python exceptions with a |
| * non-zero return code. |
| */ |
| static PyStatus |
| pyinit_main(PyThreadState *tstate) |
| { |
| PyInterpreterState *interp = tstate->interp; |
| if (!interp->runtime->core_initialized) { |
| return _PyStatus_ERR("runtime core not initialized"); |
| } |
| |
| if (interp->runtime->initialized) { |
| return pyinit_main_reconfigure(tstate); |
| } |
| |
| PyStatus status = init_interp_main(tstate); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| return _PyStatus_OK(); |
| } |
| |
| |
| PyStatus |
| Py_InitializeFromConfig(const PyConfig *config) |
| { |
| if (config == NULL) { |
| return _PyStatus_ERR("initialization config is NULL"); |
| } |
| |
| PyStatus status; |
| |
| status = _PyRuntime_Initialize(); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| _PyRuntimeState *runtime = &_PyRuntime; |
| |
| PyThreadState *tstate = NULL; |
| status = pyinit_core(runtime, config, &tstate); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| config = _PyInterpreterState_GetConfig(tstate->interp); |
| |
| if (config->_init_main) { |
| status = pyinit_main(tstate); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| } |
| |
| return _PyStatus_OK(); |
| } |
| |
| |
| void |
| Py_InitializeEx(int install_sigs) |
| { |
| PyStatus status; |
| |
| status = _PyRuntime_Initialize(); |
| if (_PyStatus_EXCEPTION(status)) { |
| Py_ExitStatusException(status); |
| } |
| _PyRuntimeState *runtime = &_PyRuntime; |
| |
| if (runtime->initialized) { |
| /* bpo-33932: Calling Py_Initialize() twice does nothing. */ |
| return; |
| } |
| |
| PyConfig config; |
| _PyConfig_InitCompatConfig(&config); |
| |
| config.install_signal_handlers = install_sigs; |
| |
| status = Py_InitializeFromConfig(&config); |
| PyConfig_Clear(&config); |
| if (_PyStatus_EXCEPTION(status)) { |
| Py_ExitStatusException(status); |
| } |
| } |
| |
| void |
| Py_Initialize(void) |
| { |
| Py_InitializeEx(1); |
| } |
| |
| |
| PyStatus |
| _Py_InitializeMain(void) |
| { |
| PyStatus status = _PyRuntime_Initialize(); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| PyThreadState *tstate = _PyThreadState_GET(); |
| return pyinit_main(tstate); |
| } |
| |
| |
| static void |
| finalize_modules_delete_special(PyThreadState *tstate, int verbose) |
| { |
| // List of names to clear in sys |
| static const char * const sys_deletes[] = { |
| "path", "argv", "ps1", "ps2", "last_exc", |
| "last_type", "last_value", "last_traceback", |
| "__interactivehook__", |
| // path_hooks and path_importer_cache are cleared |
| // by _PyImport_FiniExternal(). |
| // XXX Clear meta_path in _PyImport_FiniCore(). |
| "meta_path", |
| NULL |
| }; |
| |
| static const char * const sys_files[] = { |
| "stdin", "__stdin__", |
| "stdout", "__stdout__", |
| "stderr", "__stderr__", |
| NULL |
| }; |
| |
| PyInterpreterState *interp = tstate->interp; |
| if (verbose) { |
| PySys_WriteStderr("# clear builtins._\n"); |
| } |
| if (PyDict_SetItemString(interp->builtins, "_", Py_None) < 0) { |
| 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_FormatUnraisable("Exception ignored on clearing sys.%s", *p); |
| } |
| } |
| for (p = sys_files; *p != NULL; p+=2) { |
| const char *name = p[0]; |
| const char *orig_name = p[1]; |
| if (verbose) { |
| PySys_WriteStderr("# restore sys.%s\n", name); |
| } |
| PyObject *value; |
| if (PyDict_GetItemStringRef(interp->sysdict, orig_name, &value) < 0) { |
| PyErr_FormatUnraisable("Exception ignored on restoring sys.%s", name); |
| } |
| if (value == NULL) { |
| value = Py_NewRef(Py_None); |
| } |
| if (PyDict_SetItemString(interp->sysdict, name, value) < 0) { |
| PyErr_FormatUnraisable("Exception ignored on restoring sys.%s", name); |
| } |
| Py_DECREF(value); |
| } |
| } |
| |
| |
| static PyObject* |
| finalize_remove_modules(PyObject *modules, int verbose) |
| { |
| PyObject *weaklist = PyList_New(0); |
| if (weaklist == NULL) { |
| PyErr_FormatUnraisable("Exception ignored on removing modules"); |
| } |
| |
| #define STORE_MODULE_WEAKREF(name, mod) \ |
| if (weaklist != NULL) { \ |
| PyObject *wr = PyWeakref_NewRef(mod, NULL); \ |
| if (wr) { \ |
| PyObject *tup = PyTuple_Pack(2, name, wr); \ |
| if (!tup || PyList_Append(weaklist, tup) < 0) { \ |
| PyErr_FormatUnraisable("Exception ignored on removing modules"); \ |
| } \ |
| Py_XDECREF(tup); \ |
| Py_DECREF(wr); \ |
| } \ |
| else { \ |
| PyErr_FormatUnraisable("Exception ignored on removing modules"); \ |
| } \ |
| } |
| |
| #define CLEAR_MODULE(name, mod) \ |
| if (PyModule_Check(mod)) { \ |
| if (verbose && PyUnicode_Check(name)) { \ |
| PySys_FormatStderr("# cleanup[2] removing %U\n", name); \ |
| } \ |
| STORE_MODULE_WEAKREF(name, mod); \ |
| if (PyObject_SetItem(modules, name, Py_None) < 0) { \ |
| PyErr_FormatUnraisable("Exception ignored on removing modules"); \ |
| } \ |
| } |
| |
| if (PyDict_CheckExact(modules)) { |
| Py_ssize_t pos = 0; |
| PyObject *key, *value; |
| while (PyDict_Next(modules, &pos, &key, &value)) { |
| CLEAR_MODULE(key, value); |
| } |
| } |
| else { |
| PyObject *iterator = PyObject_GetIter(modules); |
| if (iterator == 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_FormatUnraisable("Exception ignored on removing modules"); |
| continue; |
| } |
| CLEAR_MODULE(key, value); |
| Py_DECREF(value); |
| Py_DECREF(key); |
| } |
| if (PyErr_Occurred()) { |
| PyErr_FormatUnraisable("Exception ignored on removing modules"); |
| } |
| Py_DECREF(iterator); |
| } |
| } |
| #undef CLEAR_MODULE |
| #undef STORE_MODULE_WEAKREF |
| |
| return weaklist; |
| } |
| |
| |
| static void |
| finalize_clear_modules_dict(PyObject *modules) |
| { |
| if (PyDict_CheckExact(modules)) { |
| PyDict_Clear(modules); |
| } |
| else { |
| if (PyObject_CallMethodNoArgs(modules, &_Py_ID(clear)) == NULL) { |
| PyErr_FormatUnraisable("Exception ignored on clearing sys.modules"); |
| } |
| } |
| } |
| |
| |
| static void |
| finalize_restore_builtins(PyThreadState *tstate) |
| { |
| PyInterpreterState *interp = tstate->interp; |
| PyObject *dict = PyDict_Copy(interp->builtins); |
| if (dict == NULL) { |
| PyErr_FormatUnraisable("Exception ignored on restoring builtins"); |
| } |
| PyDict_Clear(interp->builtins); |
| if (PyDict_Update(interp->builtins, interp->builtins_copy)) { |
| PyErr_FormatUnraisable("Exception ignored on restoring builtins"); |
| } |
| Py_XDECREF(dict); |
| } |
| |
| |
| static void |
| finalize_modules_clear_weaklist(PyInterpreterState *interp, |
| PyObject *weaklist, int verbose) |
| { |
| // First clear modules imported later |
| 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_REF(PyTuple_GET_ITEM(tup, 1)); |
| if (mod == NULL) { |
| continue; |
| } |
| assert(PyModule_Check(mod)); |
| PyObject *dict = _PyModule_GetDict(mod); // borrowed reference |
| if (dict == interp->builtins || dict == interp->sysdict) { |
| Py_DECREF(mod); |
| continue; |
| } |
| if (verbose && PyUnicode_Check(name)) { |
| PySys_FormatStderr("# cleanup[3] wiping %U\n", name); |
| } |
| _PyModule_Clear(mod); |
| Py_DECREF(mod); |
| } |
| } |
| |
| |
| static void |
| finalize_clear_sys_builtins_dict(PyInterpreterState *interp, int verbose) |
| { |
| // Clear sys dict |
| if (verbose) { |
| PySys_FormatStderr("# cleanup[3] wiping sys\n"); |
| } |
| _PyModule_ClearDict(interp->sysdict); |
| |
| // Clear builtins dict |
| if (verbose) { |
| PySys_FormatStderr("# cleanup[3] wiping builtins\n"); |
| } |
| _PyModule_ClearDict(interp->builtins); |
| } |
| |
| |
| /* Clear modules, as good as we can */ |
| // XXX Move most of this to import.c. |
| static void |
| finalize_modules(PyThreadState *tstate) |
| { |
| PyInterpreterState *interp = tstate->interp; |
| |
| #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 |
| return; |
| } |
| int verbose = _PyInterpreterState_GetConfig(interp)->verbose; |
| |
| // Delete some special builtins._ and sys attributes first. These are |
| // common places where user values hide and people complain when their |
| // destructors fail. Since the modules containing them are |
| // deleted *last* of all, they would come too late in the normal |
| // destruction order. Sigh. |
| // |
| // XXX Perhaps these precautions are obsolete. Who knows? |
| finalize_modules_delete_special(tstate, verbose); |
| |
| // Remove all modules from sys.modules, hoping that garbage collection |
| // can reclaim most of them: set all sys.modules values to None. |
| // |
| // We prepare a list which will receive (name, weakref) tuples of |
| // modules when they are removed from sys.modules. The name is used |
| // for diagnosis messages (in verbose mode), while the weakref helps |
| // detect those modules which have been held alive. |
| PyObject *weaklist = finalize_remove_modules(modules, verbose); |
| |
| // Clear the modules dict |
| finalize_clear_modules_dict(modules); |
| |
| // Restore the original builtins dict, to ensure that any |
| // user data gets cleared. |
| finalize_restore_builtins(tstate); |
| |
| // Collect garbage |
| _PyGC_CollectNoFail(tstate); |
| |
| // Dump GC stats before it's too late, since it uses the warnings |
| // machinery. |
| _PyGC_DumpShutdownStats(interp); |
| |
| if (weaklist != NULL) { |
| // Now, if there are any modules left alive, clear their globals to |
| // minimize potential leaks. All C extension modules actually end |
| // up here, since they are kept alive in the interpreter state. |
| // |
| // The special treatment of "builtins" here is because even |
| // when it's not referenced as a module, its dictionary is |
| // referenced by almost every module's __builtins__. Since |
| // deleting a module clears its dictionary (even if there are |
| // references left to it), we need to delete the "builtins" |
| // module last. Likewise, we don't delete sys until the very |
| // end because it is implicitly referenced (e.g. by print). |
| // |
| // Since dict is ordered in CPython 3.6+, modules are saved in |
| // importing order. First clear modules imported later. |
| finalize_modules_clear_weaklist(interp, weaklist, verbose); |
| Py_DECREF(weaklist); |
| } |
| |
| // Clear sys and builtins modules dict |
| finalize_clear_sys_builtins_dict(interp, verbose); |
| |
| // Clear module dict copies stored in the interpreter state: |
| // clear PyInterpreterState.modules_by_index and |
| // clear PyModuleDef.m_base.m_copy (of extensions not using the multi-phase |
| // initialization API) |
| _PyImport_ClearModulesByIndex(interp); |
| |
| // Clear and delete the modules directory. Actual modules will |
| // still be there only if imported during the execution of some |
| // destructor. |
| _PyImport_ClearModules(interp); |
| |
| // Collect garbage once more |
| _PyGC_CollectNoFail(tstate); |
| } |
| |
| |
| /* Flush stdout and stderr */ |
| |
| static int |
| file_is_closed(PyObject *fobj) |
| { |
| int r; |
| PyObject *tmp = PyObject_GetAttrString(fobj, "closed"); |
| if (tmp == NULL) { |
| PyErr_Clear(); |
| return 0; |
| } |
| r = PyObject_IsTrue(tmp); |
| Py_DECREF(tmp); |
| if (r < 0) |
| PyErr_Clear(); |
| return r > 0; |
| } |
| |
| |
| static int |
| flush_std_files(void) |
| { |
| PyObject *file; |
| int status = 0; |
| |
| 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; |
| } |
| } |
| if (status < 0) { |
| PyErr_FormatUnraisable("Exception ignored on flushing sys.stdout"); |
| } |
| Py_XDECREF(file); |
| |
| 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; |
| } |
| } |
| Py_XDECREF(file); |
| |
| return status; |
| } |
| |
| /* Undo the effect of Py_Initialize(). |
| |
| Beware: if multiple interpreter and/or thread states exist, these |
| are not wiped out; only the current thread and interpreter state |
| are deleted. But since everything else is deleted, those other |
| interpreter and thread states should no longer be used. |
| |
| (XXX We should do better, e.g. wipe out all interpreters and |
| threads.) |
| |
| Locking: as above. |
| |
| */ |
| |
| |
| static void |
| finalize_interp_types(PyInterpreterState *interp) |
| { |
| _PyTypes_FiniExtTypes(interp); |
| _PyUnicode_FiniTypes(interp); |
| _PySys_FiniTypes(interp); |
| _PyXI_FiniTypes(interp); |
| _PyExc_Fini(interp); |
| _PyFloat_FiniType(interp); |
| _PyLong_FiniTypes(interp); |
| _PyThread_FiniType(interp); |
| // XXX fini collections module static types (_PyStaticType_Dealloc()) |
| // XXX fini IO module static types (_PyStaticType_Dealloc()) |
| _PyErr_FiniTypes(interp); |
| _PyTypes_FiniTypes(interp); |
| |
| _PyTypes_Fini(interp); |
| |
| _PyCode_Fini(interp); |
| |
| // Call _PyUnicode_ClearInterned() before _PyDict_Fini() since it uses |
| // a dict internally. |
| _PyUnicode_ClearInterned(interp); |
| |
| _PyUnicode_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 |
| |
| #ifdef Py_DEBUG |
| _PyStaticObjects_CheckRefcnt(interp); |
| #endif |
| } |
| |
| |
| static void |
| 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); |
| |
| /* Clear interpreter state and all thread states */ |
| _PyInterpreterState_Clear(tstate); |
| |
| /* Clear all loghooks */ |
| /* Both _PySys_Audit function and users still need PyObject, such as tuple. |
| Call _PySys_ClearAuditHooks when PyObject available. */ |
| if (is_main_interp) { |
| _PySys_ClearAuditHooks(tstate); |
| } |
| |
| if (is_main_interp) { |
| _Py_HashRandomization_Fini(); |
| _PyArg_Fini(); |
| _Py_ClearFileSystemEncoding(); |
| _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); |
| } |
| |
| |
| static void |
| finalize_interp_delete(PyInterpreterState *interp) |
| { |
| /* Cleanup auto-thread-state */ |
| _PyGILState_Fini(interp); |
| |
| /* We can't call _PyEval_FiniGIL() here because destroying the GIL lock can |
| fail when it is being awaited by another running daemon thread (see |
| bpo-9901). Instead pycore_create_interpreter() destroys the previously |
| created GIL, which ensures that Py_Initialize / Py_FinalizeEx can be |
| called multiple times. */ |
| |
| PyInterpreterState_Delete(interp); |
| } |
| |
| |
| /* 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; |
| |
| /* Bail out early if already finalized (or never initialized). */ |
| if (!runtime->initialized) { |
| return status; |
| } |
| |
| /* Get final thread state pointer. */ |
| PyThreadState *tstate = resolve_final_tstate(runtime); |
| |
| // Block some operations. |
| tstate->interp->finalizing = 1; |
| |
| // Wrap up existing "threading"-module-created, non-daemon threads. |
| wait_for_thread_shutdown(tstate); |
| |
| // Make any remaining pending calls. |
| _Py_FinishPendingCalls(tstate); |
| |
| /* The interpreter is still entirely intact at this point, and the |
| * exit funcs may be relying on that. In particular, if some thread |
| * or exit func is still waiting to do an import, the import machinery |
| * expects Py_IsInitialized() to return true. So don't say the |
| * runtime is uninitialized until after the exit funcs have run. |
| * Note that Threading.py uses an exit func to do a join on all the |
| * threads created thru it, so this also protects pending imports in |
| * the threads created via Threading. |
| */ |
| |
| _PyAtExit_Call(tstate->interp); |
| |
| assert(_PyThreadState_GET() == tstate); |
| |
| /* Copy the core config, PyInterpreterState_Delete() free |
| the core config memory */ |
| #ifdef Py_REF_DEBUG |
| int show_ref_count = tstate->interp->config.show_ref_count; |
| #endif |
| #ifdef Py_TRACE_REFS |
| int dump_refs = tstate->interp->config.dump_refs; |
| wchar_t *dump_refs_file = tstate->interp->config.dump_refs_file; |
| #endif |
| #ifdef WITH_PYMALLOC |
| int malloc_stats = tstate->interp->config.malloc_stats; |
| #endif |
| |
| /* Ensure that remaining threads are detached */ |
| _PyEval_StopTheWorldAll(runtime); |
| |
| /* Remaining daemon threads will automatically exit |
| when they attempt to take the GIL (ex: PyEval_RestoreThread()). */ |
| _PyInterpreterState_SetFinalizing(tstate->interp, tstate); |
| _PyRuntimeState_SetFinalizing(runtime, tstate); |
| runtime->initialized = 0; |
| runtime->core_initialized = 0; |
| |
| // XXX Call something like _PyImport_Disable() here? |
| |
| /* Destroy the state of all threads of the interpreter, except of the |
| current thread. In practice, only daemon threads should still be alive, |
| except if wait_for_thread_shutdown() has been cancelled by CTRL+C. |
| Clear frames of other threads to call objects destructors. Destructors |
| 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. 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 |
| interpreter (AKA tstate), in which this code is running right now. |
| There may be other OS threads running but none of them will have |
| thread states associated with them, nor will be able to create |
| new thread states. |
| |
| Thus tstate is the only possible thread state from here on out. |
| It may still be used during finalization to run Python code as |
| needed or provide runtime state (e.g. sys.modules) but that will |
| happen sparingly. Furthermore, the order of finalization aims |
| to not need a thread (or interpreter) state as soon as possible. |
| */ |
| // XXX Make sure we are preventing the creating of any new thread states |
| // (or interpreters). |
| |
| /* Flush sys.stdout and sys.stderr */ |
| if (flush_std_files() < 0) { |
| status = -1; |
| } |
| |
| /* Disable signal handling */ |
| _PySignal_Fini(); |
| |
| /* Collect garbage. This may call finalizers; it's nice to call these |
| * before all modules are destroyed. |
| * XXX If a __del__ or weakref callback is triggered here, and tries to |
| * XXX import a module, bad things can happen, because Python no |
| * XXX longer believes it's initialized. |
| * XXX Fatal Python error: Interpreter not initialized (version mismatch?) |
| * XXX is easy to provoke that way. I've also seen, e.g., |
| * XXX Exception exceptions.ImportError: 'No module named sha' |
| * XXX in <function callback at 0x008F5718> ignored |
| * XXX but I'm unclear on exactly how that one happens. In any case, |
| * XXX I haven't seen a real-life report of either of these. |
| */ |
| PyGC_Collect(); |
| |
| /* Destroy all modules */ |
| _PyImport_FiniExternal(tstate->interp); |
| finalize_modules(tstate); |
| |
| /* Clean up any lingering subinterpreters. */ |
| finalize_subinterpreters(); |
| |
| /* Print debug stats if any */ |
| _PyEval_Fini(); |
| |
| /* Flush sys.stdout and sys.stderr (again, in case more was printed) */ |
| if (flush_std_files() < 0) { |
| status = -1; |
| } |
| |
| /* Collect final garbage. This disposes of cycles created by |
| * class definitions, for example. |
| * XXX This is disabled because it caused too many problems. If |
| * XXX a __del__ or weakref callback triggers here, Python code has |
| * XXX a hard time running, because even the sys module has been |
| * XXX cleared out (sys.stdout is gone, sys.excepthook is gone, etc). |
| * XXX One symptom is a sequence of information-free messages |
| * XXX coming from threads (if a __del__ or callback is invoked, |
| * XXX other threads can execute too, and any exception they encounter |
| * XXX triggers a comedy of errors as subsystem after subsystem |
| * XXX fails to find what it *expects* to find in sys to help report |
| * XXX the exception and consequent unexpected failures). I've also |
| * XXX seen segfaults then, after adding print statements to the |
| * XXX Python code getting called. |
| */ |
| #if 0 |
| _PyGC_CollectIfEnabled(); |
| #endif |
| |
| /* Disable tracemalloc after all Python objects have been destroyed, |
| so it is possible to use tracemalloc in objects destructor. */ |
| _PyTraceMalloc_Stop(); |
| |
| /* Finalize any remaining import state */ |
| // XXX Move these up to where finalize_modules() is currently. |
| _PyImport_FiniCore(tstate->interp); |
| _PyImport_Fini(); |
| |
| /* unload faulthandler module */ |
| _PyFaulthandler_Fini(); |
| |
| /* dump hash stats */ |
| _PyHash_Fini(); |
| |
| #ifdef Py_TRACE_REFS |
| /* Display all objects still alive -- this can invoke arbitrary |
| * __repr__ overrides, so requires a mostly-intact interpreter. |
| * Alas, a lot of stuff may still be alive now that will be cleaned |
| * up later. |
| */ |
| |
| FILE *dump_refs_fp = NULL; |
| if (dump_refs_file != NULL) { |
| dump_refs_fp = _Py_wfopen(dump_refs_file, L"w"); |
| if (dump_refs_fp == NULL) { |
| fprintf(stderr, "PYTHONDUMPREFSFILE: cannot create file: %ls\n", dump_refs_file); |
| } |
| } |
| |
| if (dump_refs) { |
| _Py_PrintReferences(tstate->interp, stderr); |
| } |
| |
| if (dump_refs_fp != NULL) { |
| _Py_PrintReferences(tstate->interp, dump_refs_fp); |
| } |
| #endif /* Py_TRACE_REFS */ |
| |
| /* At this point there's almost no other Python code that will run, |
| nor interpreter state needed. The only possibility is the |
| finalizers of the objects stored on tstate (and tstate->interp), |
| which are triggered via finalize_interp_clear(). |
| |
| For now we operate as though none of those finalizers actually |
| need an operational thread state or interpreter. In reality, |
| those finalizers may rely on some part of tstate or |
| tstate->interp, and/or may raise exceptions |
| or otherwise fail. |
| */ |
| // XXX Do this sooner during finalization. |
| // XXX Ensure finalizer errors are handled properly. |
| |
| finalize_interp_clear(tstate); |
| |
| _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); |
| } |
| #endif |
| |
| finalize_interp_delete(tstate->interp); |
| |
| #ifdef Py_REF_DEBUG |
| if (show_ref_count) { |
| _PyDebug_PrintTotalRefs(); |
| } |
| _Py_FinalizeRefTotal(runtime); |
| #endif |
| _Py_FinalizeAllocatedBlocks(runtime); |
| |
| call_ll_exitfuncs(runtime); |
| |
| _PyRuntime_Finalize(); |
| return status; |
| } |
| |
| int |
| Py_FinalizeEx(void) |
| { |
| return _Py_Finalize(&_PyRuntime); |
| } |
| |
| void |
| Py_Finalize(void) |
| { |
| (void)_Py_Finalize(&_PyRuntime); |
| } |
| |
| |
| /* Create and initialize a new interpreter and thread, and return the |
| new thread. This requires that Py_Initialize() has been called |
| first. |
| |
| Unsuccessful initialization yields a NULL pointer. Note that *no* |
| exception information is available even in this case -- the |
| exception information is held in the thread, and there is no |
| thread. |
| |
| Locking: as above. |
| |
| */ |
| |
| static PyStatus |
| new_interpreter(PyThreadState **tstate_p, |
| const PyInterpreterConfig *config, long whence) |
| { |
| PyStatus status; |
| |
| status = _PyRuntime_Initialize(); |
| if (_PyStatus_EXCEPTION(status)) { |
| return status; |
| } |
| _PyRuntimeState *runtime = &_PyRuntime; |
| |
| if (!runtime->initialized) { |
| return _PyStatus_ERR("Py_Initialize must be called first"); |
| } |
| |
| /* Issue #10915, #15751: The GIL API doesn't work with multiple |
| interpreters: disable PyGILState_Check(). */ |
| runtime->gilstate.check_enabled = 0; |
| |
| PyInterpreterState *interp = PyInterpreterState_New(); |
| if (interp == NULL) { |
| *tstate_p = NULL; |
| return _PyStatus_OK(); |
| } |
| _PyInterpreterState_SetWhence(interp, whence); |
| interp->_ready = 1; |
| |
| // XXX Might new_interpreter() have been called without the GIL held? |
| PyThreadState *save_tstate = _PyThreadState_GET(); |
| PyThreadState *tstate = NULL; |
| |
| /* 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) { |
| src_config = _PyInterpreterState_GetConfig(save_tstate->interp); |
| } |
| else |
| { |
| /* No current thread state, copy from the main interpreter */ |
| PyInterpreterState *main_interp = _PyInterpreterState_Main(); |
| src_config = _PyInterpreterState_GetConfig(main_interp); |
| } |
| |
| /* This does not require that the GIL be held. */ |
| status = _PyConfig_Copy(&interp->config, src_config); |
| if (_PyStatus_EXCEPTION(status)) { |
| goto error; |
| } |
| |
| /* This does not require that the GIL be held. */ |
| status = init_interp_settings(interp, config); |
| if (_PyStatus_EXCEPTION(status)) { |
| goto error; |
| } |
| |
| // This could be done in init_interpreter() (in pystate.c) if it |
| // didn't depend on interp->feature_flags being set already. |
| 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; |
| } |
| |
| _PyThreadState_Bind(tstate); |
| init_interp_create_gil(tstate, config->gil); |
| |
| /* No objects have been created yet. */ |
| |
| status = pycore_interp_init(tstate); |
| if (_PyStatus_EXCEPTION(status)) { |
| goto error; |
| } |
| |
| status = init_interp_main(tstate); |
| if (_PyStatus_EXCEPTION(status)) { |
| goto error; |
| } |
| |
| *tstate_p = tstate; |
| return _PyStatus_OK(); |
| |
| error: |
| *tstate_p = NULL; |
| if (tstate != NULL) { |
| Py_EndInterpreter(tstate); |
| } else { |
| PyInterpreterState_Delete(interp); |
| } |
| if (save_tstate != NULL) { |
| _PyThreadState_Attach(save_tstate); |
| } |
| return status; |
| } |
| |
| PyStatus |
| Py_NewInterpreterFromConfig(PyThreadState **tstate_p, |
| const PyInterpreterConfig *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, whence); |
| if (_PyStatus_EXCEPTION(status)) { |
| Py_ExitStatusException(status); |
| } |
| return tstate; |
| } |
| |
| /* Delete an interpreter and its last thread. This requires that the |
| given thread state is current, that the thread has no remaining |
| frames, and that it is its interpreter's only remaining thread. |
| It is a fatal error to violate these constraints. |
| |
| (Py_FinalizeEx() doesn't have these constraints -- it zaps |
| everything, regardless.) |
| |
| Locking: as above. |
| |
| */ |
| |
| void |
| Py_EndInterpreter(PyThreadState *tstate) |
| { |
| PyInterpreterState *interp = tstate->interp; |
| |
| if (tstate != _PyThreadState_GET()) { |
| Py_FatalError("thread is not current"); |
| } |
| if (tstate->current_frame != NULL) { |
| Py_FatalError("thread still has a frame"); |
| } |
| interp->finalizing = 1; |
| |
| // Wrap up existing "threading"-module-created, non-daemon threads. |
| wait_for_thread_shutdown(tstate); |
| |
| // Make any remaining pending calls. |
| _Py_FinishPendingCalls(tstate); |
| |
| _PyAtExit_Call(tstate->interp); |
| |
| if (tstate != interp->threads.head || tstate->next != NULL) { |
| Py_FatalError("not the last thread"); |
| } |
| |
| /* Remaining daemon threads will automatically exit |
| when they attempt to take the GIL (ex: PyEval_RestoreThread()). */ |
| _PyInterpreterState_SetFinalizing(interp, tstate); |
| |
| // XXX Call something like _PyImport_Disable() here? |
| |
| _PyImport_FiniExternal(tstate->interp); |
| finalize_modules(tstate); |
| _PyImport_FiniCore(tstate->interp); |
| |
| finalize_interp_clear(tstate); |
| finalize_interp_delete(tstate->interp); |
| } |
| |
| int |
| _Py_IsInterpreterFinalizing(PyInterpreterState *interp) |
| { |
| /* We check the runtime first since, in a daemon thread, |
| interp might be dangling pointer. */ |
| PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(&_PyRuntime); |
| if (finalizing == NULL) { |
| finalizing = _PyInterpreterState_GetFinalizing(interp); |
| } |
| return finalizing != NULL; |
| } |
| |
| 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, *ann_dict; |
| m = PyImport_AddModuleObject(&_Py_ID(__main__)); |
| if (m == NULL) |
| return _PyStatus_ERR("can't create __main__ module"); |
| |
| d = PyModule_GetDict(m); |
| ann_dict = PyDict_New(); |
| if ((ann_dict == NULL) || |
| (PyDict_SetItemString(d, "__annotations__", ann_dict) < 0)) { |
| return _PyStatus_ERR("Failed to initialize __main__.__annotations__"); |
| } |
| Py_DECREF(ann_dict); |
| |
| 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"); |
| } |
| if (PyDict_SetItemString(d, "__builtins__", bimod) < 0) { |
| return _PyStatus_ERR("Failed to initialize __main__.__builtins__"); |
| } |
| Py_DECREF(bimod); |
| } |
| |
| /* Main is a little special - BuiltinImporter is the most appropriate |
| * initial setting for its __loader__ attribute. A more suitable value |
| * will be set if __main__ gets further initialized later in the startup |
| * process. |
| */ |
| 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) { |
| return _PyStatus_ERR("Failed to retrieve BuiltinImporter"); |
| } |
| if (PyDict_SetItemString(d, "__loader__", loader) < 0) { |
| return _PyStatus_ERR("Failed to initialize __main__.__loader__"); |
| } |
| Py_DECREF(loader); |
| } |
| return _PyStatus_OK(); |
| } |
| |
| /* Import the site module (not into __main__ though) */ |
| |
| static PyStatus |
| init_import_site(void) |
| { |
| PyObject *m; |
| m = PyImport_ImportModule("site"); |
| if (m == NULL) { |
| return _PyStatus_ERR("Failed to import the site module"); |
| } |
| Py_DECREF(m); |
| return _PyStatus_OK(); |
| } |
| |
| /* returns Py_None if the fd is not valid */ |
| static PyObject* |
| create_stdio(const PyConfig *config, PyObject* io, |
| int fd, int write_mode, const char* name, |
| const wchar_t* encoding, const wchar_t* errors) |
| { |
| PyObject *buf = NULL, *stream = NULL, *text = NULL, *raw = NULL, *res; |
| const char* mode; |
| const char* newline; |
| PyObject *line_buffering, *write_through; |
| int buffering, isatty; |
| const int buffered_stdio = config->buffered_stdio; |
| |
| 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 |
| depends on the presence of a read1() method which only exists on |
| buffered streams. |
| */ |
| if (!buffered_stdio && write_mode) |
| buffering = 0; |
| else |
| buffering = -1; |
| if (write_mode) |
| mode = "wb"; |
| else |
| mode = "rb"; |
| buf = _PyObject_CallMethod(io, &_Py_ID(open), "isiOOOO", |
| fd, mode, buffering, |
| Py_None, Py_None, /* encoding, errors */ |
| Py_None, Py_False); /* newline, closefd */ |
| if (buf == NULL) |
| goto error; |
| |
| if (buffering) { |
| raw = PyObject_GetAttr(buf, &_Py_ID(raw)); |
| if (raw == NULL) |
| goto error; |
| } |
| else { |
| raw = Py_NewRef(buf); |
| } |
| |
| #ifdef HAVE_WINDOWS_CONSOLE_IO |
| /* Windows console IO is always UTF-8 encoded */ |
| PyTypeObject *winconsoleio_type = (PyTypeObject *)_PyImport_GetModuleAttr( |
| &_Py_ID(_io), &_Py_ID(_WindowsConsoleIO)); |
| if (winconsoleio_type == NULL) { |
| goto error; |
| } |
| int is_subclass = PyObject_TypeCheck(raw, winconsoleio_type); |
| Py_DECREF(winconsoleio_type); |
| if (is_subclass) { |
| encoding = L"utf-8"; |
| } |
| #endif |
| |
| text = PyUnicode_FromString(name); |
| if (text == NULL || PyObject_SetAttr(raw, &_Py_ID(name), text) < 0) |
| goto error; |
| res = PyObject_CallMethodNoArgs(raw, &_Py_ID(isatty)); |
| if (res == NULL) |
| goto error; |
| isatty = PyObject_IsTrue(res); |
| Py_DECREF(res); |
| if (isatty == -1) |
| goto error; |
| if (!buffered_stdio) |
| write_through = Py_True; |
| else |
| write_through = Py_False; |
| if (buffered_stdio && (isatty || fd == fileno(stderr))) |
| line_buffering = Py_True; |
| else |
| line_buffering = Py_False; |
| |
| Py_CLEAR(raw); |
| Py_CLEAR(text); |
| |
| #ifdef MS_WINDOWS |
| /* sys.stdin: enable universal newline mode, translate "\r\n" and "\r" |
| newlines to "\n". |
| sys.stdout and sys.stderr: translate "\n" to "\r\n". */ |
| newline = NULL; |
| #else |
| /* sys.stdin: split lines at "\n". |
| sys.stdout and sys.stderr: don't translate newlines (use "\n"). */ |
| newline = "\n"; |
| #endif |
| |
| PyObject *encoding_str = PyUnicode_FromWideChar(encoding, -1); |
| if (encoding_str == NULL) { |
| Py_CLEAR(buf); |
| goto error; |
| } |
| |
| PyObject *errors_str = PyUnicode_FromWideChar(errors, -1); |
| if (errors_str == NULL) { |
| Py_CLEAR(buf); |
| Py_CLEAR(encoding_str); |
| goto error; |
| } |
| |
| stream = _PyObject_CallMethod(io, &_Py_ID(TextIOWrapper), "OOOsOO", |
| buf, encoding_str, errors_str, |
| newline, line_buffering, write_through); |
| Py_CLEAR(buf); |
| Py_CLEAR(encoding_str); |
| Py_CLEAR(errors_str); |
| if (stream == NULL) |
| goto error; |
| |
| if (write_mode) |
| mode = "w"; |
| else |
| mode = "r"; |
| text = PyUnicode_FromString(mode); |
| if (!text || PyObject_SetAttr(stream, &_Py_ID(mode), text) < 0) |
| goto error; |
| Py_CLEAR(text); |
| return stream; |
| |
| error: |
| Py_XDECREF(buf); |
| Py_XDECREF(stream); |
| Py_XDECREF(text); |
| Py_XDECREF(raw); |
| |
| if (PyErr_ExceptionMatches(PyExc_OSError) && !_Py_IsValidFD(fd)) { |
| /* Issue #24891: the file descriptor was closed after the first |
| _Py_IsValidFD() check was called. Ignore the OSError and set the |
| stream to None. */ |
| PyErr_Clear(); |
| Py_RETURN_NONE; |
| } |
| return NULL; |
| } |
| |
| /* Set builtins.open to io.open */ |
| static PyStatus |
| init_set_builtins_open(void) |
| { |
| PyObject *wrapper; |
| PyObject *bimod = NULL; |
| PyStatus res = _PyStatus_OK(); |
| |
| if (!(bimod = PyImport_ImportModule("builtins"))) { |
| goto error; |
| } |
| |
| if (!(wrapper = _PyImport_GetModuleAttrString("io", "open"))) { |
| goto error; |
| } |
| |
| /* Set builtins.open */ |
| if (PyObject_SetAttrString(bimod, "open", wrapper) == -1) { |
| Py_DECREF(wrapper); |
| goto error; |
| } |
| Py_DECREF(wrapper); |
| goto done; |
| |
| error: |
| res = _PyStatus_ERR("can't initialize io.open"); |
| |
| done: |
| Py_XDECREF(bimod); |
| return res; |
| } |
| |
| |
| /* Create sys.stdin, sys.stdout and sys.stderr */ |
| static PyStatus |
| init_sys_streams(PyThreadState *tstate) |
| { |
| PyObject *iomod = NULL; |
| PyObject *std = NULL; |
| int fd; |
| PyObject * encoding_attr; |
| PyStatus res = _PyStatus_OK(); |
| const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp); |
| |
| /* Check that stdin is not a directory |
| Using shell redirection, you can redirect stdin to a directory, |
| crashing the Python interpreter. Catch this common mistake here |
| and output a useful error message. Note that under MS Windows, |
| the shell already prevents that. */ |
| #ifndef MS_WINDOWS |
| struct _Py_stat_struct sb; |
| if (_Py_fstat_noraise(fileno(stdin), &sb) == 0 && |
| S_ISDIR(sb.st_mode)) { |
| return _PyStatus_ERR("<stdin> is a directory, cannot continue"); |
| } |
| #endif |
| |
| if (!(iomod = PyImport_ImportModule("io"))) { |
| goto error; |
| } |
| |
| /* Set sys.stdin */ |
| fd = fileno(stdin); |
| /* Under some conditions stdin, stdout and stderr may not be connected |
| * and fileno() may point to an invalid file descriptor. For example |
| * GUI apps don't have valid standard streams by default. |
| */ |
| std = create_stdio(config, iomod, fd, 0, "<stdin>", |
| config->stdio_encoding, |
| config->stdio_errors); |
| if (std == NULL) |
| goto error; |
| PySys_SetObject("__stdin__", std); |
| _PySys_SetAttr(&_Py_ID(stdin), std); |
| Py_DECREF(std); |
| |
| /* Set sys.stdout */ |
| fd = fileno(stdout); |
| std = create_stdio(config, iomod, fd, 1, "<stdout>", |
| config->stdio_encoding, |
| config->stdio_errors); |
| if (std == NULL) |
| goto error; |
| PySys_SetObject("__stdout__", std); |
| _PySys_SetAttr(&_Py_ID(stdout), std); |
| Py_DECREF(std); |
| |
| #if 1 /* Disable this if you have trouble debugging bootstrap stuff */ |
| /* Set sys.stderr, replaces the preliminary stderr */ |
| fd = fileno(stderr); |
| std = create_stdio(config, iomod, fd, 1, "<stderr>", |
| config->stdio_encoding, |
| L"backslashreplace"); |
| if (std == NULL) |
| goto error; |
| |
| /* Same as hack above, pre-import stderr's codec to avoid recursion |
| when import.c tries to write to stderr in verbose mode. */ |
| encoding_attr = PyObject_GetAttrString(std, "encoding"); |
| if (encoding_attr != NULL) { |
| const char *std_encoding = PyUnicode_AsUTF8(encoding_attr); |
| if (std_encoding != NULL) { |
| PyObject *codec_info = _PyCodec_Lookup(std_encoding); |
| Py_XDECREF(codec_info); |
| } |
| Py_DECREF(encoding_attr); |
| } |
| _PyErr_Clear(tstate); /* Not a fatal error if codec isn't available */ |
| |
| if (PySys_SetObject("__stderr__", std) < 0) { |
| Py_DECREF(std); |
| goto error; |
| } |
| if (_PySys_SetAttr(&_Py_ID(stderr), std) < 0) { |
| Py_DECREF(std); |
| goto error; |
| } |
| Py_DECREF(std); |
| #endif |
| |
| goto done; |
| |
| error: |
| res = _PyStatus_ERR("can't initialize sys standard streams"); |
| |
| done: |
| 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) |
| { |
| PUTS(fd, "\n"); |
| |
| /* display the current Python stack */ |
| _Py_DumpTracebackThreads(fd, interp, tstate); |
| } |
| |
| /* Print the current exception (if an exception is set) with its traceback, |
| or display the current Python stack. |
| |
| Don't call PyErr_PrintEx() and the except hook, because Py_FatalError() is |
| called on catastrophic cases. |
| |
| Return 1 if the traceback was displayed, 0 otherwise. */ |
| |
| static int |
| _Py_FatalError_PrintExc(PyThreadState *tstate) |
| { |
| PyObject *exc = _PyErr_GetRaisedException(tstate); |
| if (exc == NULL) { |
| /* No current exception */ |
| return 0; |
| } |
| |
| 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; |
| } |
| |
| PyErr_DisplayException(exc); |
| |
| PyObject *tb = PyException_GetTraceback(exc); |
| int has_tb = (tb != NULL) && (tb != Py_None); |
| Py_XDECREF(tb); |
| Py_DECREF(exc); |
| |
| /* sys.stderr may be buffered: call sys.stderr.flush() */ |
| if (_PyFile_Flush(ferr) < 0) { |
| _PyErr_Clear(tstate); |
| } |
| Py_DECREF(ferr); |
| |
| return has_tb; |
| } |
| |
| /* Print fatal error message and abort */ |
| |
| #ifdef MS_WINDOWS |
| static void |
| fatal_output_debug(const char *msg) |
| { |
| /* buffer of 256 bytes allocated on the stack */ |
| WCHAR buffer[256 / sizeof(WCHAR)]; |
| size_t buflen = Py_ARRAY_LENGTH(buffer) - 1; |
| size_t msglen; |
| |
| OutputDebugStringW(L"Fatal Python error: "); |
| |
| msglen = strlen(msg); |
| while (msglen) { |
| size_t i; |
| |
| if (buflen > msglen) { |
| buflen = msglen; |
| } |
| |
| /* Convert the message to wchar_t. This uses a simple one-to-one |
| conversion, assuming that the this error message actually uses |
| ASCII only. If this ceases to be true, we will have to convert. */ |
| for (i=0; i < buflen; ++i) { |
| buffer[i] = msg[i]; |
| } |
| buffer[i] = L'\0'; |
| OutputDebugStringW(buffer); |
| |
| msg += buflen; |
| msglen -= buflen; |
| } |
| OutputDebugStringW(L"\n"); |
| } |
| #endif |
| |
| |
| static void |
| fatal_error_dump_runtime(int fd, _PyRuntimeState *runtime) |
| { |
| PUTS(fd, "Python runtime state: "); |
| PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(runtime); |
| if (finalizing) { |
| PUTS(fd, "finalizing (tstate=0x"); |
| _Py_DumpHexadecimal(fd, (uintptr_t)finalizing, sizeof(finalizing) * 2); |
| PUTS(fd, ")"); |
| } |
| else if (runtime->initialized) { |
| PUTS(fd, "initialized"); |
| } |
| else if (runtime->core_initialized) { |
| PUTS(fd, "core initialized"); |
| } |
| else if (runtime->preinitialized) { |
| PUTS(fd, "preinitialized"); |
| } |
| else if (runtime->preinitializing) { |
| PUTS(fd, "preinitializing"); |
| } |
| else { |
| PUTS(fd, "unknown"); |
| } |
| PUTS(fd, "\n"); |
| } |
| |
| |
| static inline void _Py_NO_RETURN |
| fatal_error_exit(int status) |
| { |
| if (status < 0) { |
| #if defined(MS_WINDOWS) && defined(_DEBUG) |
| DebugBreak(); |
| #endif |
| abort(); |
| } |
| else { |
| exit(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. |
| // |
| // This function is called by a signal handler in faulthandler: avoid memory |
| // allocations and keep the implementation simple. For example, the list is not |
| // sorted on purpose. |
| void |
| _Py_DumpExtensionModules(int fd, PyInterpreterState *interp) |
| { |
| if (interp == NULL) { |
| return; |
| } |
| PyObject *modules = _PyImport_GetModules(interp); |
| if (modules == NULL || !PyDict_Check(modules)) { |
| return; |
| } |
| |
| Py_ssize_t pos; |
| PyObject *key, *value; |
| |
| // Avoid PyDict_GetItemString() which calls PyUnicode_FromString(), |
| // memory cannot be allocated on the heap in a signal handler. |
| // Iterate on the dict instead. |
| PyObject *stdlib_module_names = NULL; |
| if (interp->sysdict != NULL) { |
| pos = 0; |
| 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. |
| if (stdlib_module_names != NULL && !PyFrozenSet_Check(stdlib_module_names)) { |
| stdlib_module_names = NULL; |
| } |
| |
| // List extensions |
| int header = 1; |
| Py_ssize_t count = 0; |
| pos = 0; |
| 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; |
| } |
| if (!_PyModule_IsExtension(value)) { |
| continue; |
| } |
| // Use the module name from the sys.modules key, |
| // don't attempt to get the module object name. |
| if (stdlib_module_names != NULL) { |
| int is_stdlib_ext = 0; |
| |
| 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) |
| { |
| is_stdlib_ext = 1; |
| break; |
| } |
| } |
| if (is_stdlib_ext) { |
| // Ignore stdlib extension |
| continue; |
| } |
| } |
| |
| if (header) { |
| PUTS(fd, "\nExtension modules: "); |
| header = 0; |
| } |
| else { |
| PUTS(fd, ", "); |
| } |
| |
| _Py_DumpASCII(fd, key); |
| count++; |
| } |
| release_dict_lock_for_dump(modules); |
| |
| if (count) { |
| PUTS(fd, " (total: "); |
| _Py_DumpDecimal(fd, count); |
| PUTS(fd, ")"); |
| PUTS(fd, "\n"); |
| } |
| } |
| |
| |
| static void _Py_NO_RETURN |
| fatal_error(int fd, int header, const char *prefix, const char *msg, |
| int status) |
| { |
| static int reentrant = 0; |
| |
| if (reentrant) { |
| /* Py_FatalError() caused a second fatal error. |
| Example: flush_std_files() raises a recursion error. */ |
| fatal_error_exit(status); |
| } |
| reentrant = 1; |
| |
| if (header) { |
| PUTS(fd, "Fatal Python error: "); |
| if (prefix) { |
| PUTS(fd, prefix); |
| PUTS(fd, ": "); |
| } |
| if (msg) { |
| PUTS(fd, msg); |
| } |
| else { |
| PUTS(fd, "<message not set>"); |
| } |
| PUTS(fd, "\n"); |
| } |
| |
| _PyRuntimeState *runtime = &_PyRuntime; |
| fatal_error_dump_runtime(fd, runtime); |
| |
| /* Check if the current thread has a Python thread state |
| and holds the GIL. |
| |
| tss_tstate is NULL if Py_FatalError() is called from a C thread which |
| has no Python thread state. |
| |
| tss_tstate != tstate if the current Python thread does not hold the GIL. |
| */ |
| PyThreadState *tstate = _PyThreadState_GET(); |
| PyInterpreterState *interp = NULL; |
| PyThreadState *tss_tstate = PyGILState_GetThisThreadState(); |
| if (tstate != NULL) { |
| interp = tstate->interp; |
| } |
| else if (tss_tstate != NULL) { |
| interp = tss_tstate->interp; |
| } |
| int has_tstate_and_gil = (tss_tstate != NULL && tss_tstate == tstate); |
| |
| if (has_tstate_and_gil) { |
| /* If an exception is set, print the exception with its traceback */ |
| if (!_Py_FatalError_PrintExc(tss_tstate)) { |
| /* No exception is set, or an exception is set without traceback */ |
| _Py_FatalError_DumpTracebacks(fd, interp, tss_tstate); |
| } |
| } |
| else { |
| _Py_FatalError_DumpTracebacks(fd, interp, tss_tstate); |
| } |
| |
| _Py_DumpExtensionModules(fd, interp); |
| |
| /* The main purpose of faulthandler is to display the traceback. |
| This function already did its best to display a traceback. |
| Disable faulthandler to prevent writing a second traceback |
| on abort(). */ |
| _PyFaulthandler_Fini(); |
| |
| /* Check if the current Python thread hold the GIL */ |
| if (has_tstate_and_gil) { |
| /* Flush sys.stdout and sys.stderr */ |
| flush_std_files(); |
| } |
| |
| #ifdef MS_WINDOWS |
| fatal_output_debug(msg); |
| #endif /* MS_WINDOWS */ |
| |
| fatal_error_exit(status); |
| } |
| |
| |
| #undef Py_FatalError |
| |
| void _Py_NO_RETURN |
| Py_FatalError(const char *msg) |
| { |
| fatal_error(fileno(stderr), 1, NULL, msg, -1); |
| } |
| |
| |
| void _Py_NO_RETURN |
| _Py_FatalErrorFunc(const char *func, const char *msg) |
| { |
| fatal_error(fileno(stderr), 1, func, msg, -1); |
| } |
| |
| |
| void _Py_NO_RETURN |
| _Py_FatalErrorFormat(const char *func, const char *format, ...) |
| { |
| static int reentrant = 0; |
| if (reentrant) { |
| /* _Py_FatalErrorFormat() caused a second fatal error */ |
| fatal_error_exit(-1); |
| } |
| reentrant = 1; |
| |
| FILE *stream = stderr; |
| const int fd = fileno(stream); |
| PUTS(fd, "Fatal Python error: "); |
| if (func) { |
| PUTS(fd, func); |
| PUTS(fd, ": "); |
| } |
| |
| va_list vargs; |
| va_start(vargs, format); |
| vfprintf(stream, format, vargs); |
| va_end(vargs); |
| |
| fputs("\n", stream); |
| fflush(stream); |
| |
| fatal_error(fd, 0, NULL, NULL, -1); |
| } |
| |
| |
| void _Py_NO_RETURN |
| _Py_FatalRefcountErrorFunc(const char *func, const char *msg) |
| { |
| _Py_FatalErrorFormat(func, |
| "%s: bug likely caused by a refcount error " |
| "in a C extension", |
| msg); |
| } |
| |
| |
| void _Py_NO_RETURN |
| Py_ExitStatusException(PyStatus status) |
| { |
| if (_PyStatus_IS_EXIT(status)) { |
| exit(status.exitcode); |
| } |
| else if (_PyStatus_IS_ERROR(status)) { |
| fatal_error(fileno(stderr), 1, status.func, status.err_msg, 1); |
| } |
| else { |
| Py_FatalError("Py_ExitStatusException() must not be called on success"); |
| } |
| } |
| |
| |
| /* Wait until threading._shutdown completes, provided |
| the threading module was imported in the first place. |
| The shutdown routine will wait until all non-daemon |
| "threading" threads have completed. */ |
| static void |
| wait_for_thread_shutdown(PyThreadState *tstate) |
| { |
| PyObject *result; |
| PyObject *threading = PyImport_GetModule(&_Py_ID(threading)); |
| if (threading == NULL) { |
| if (_PyErr_Occurred(tstate)) { |
| PyErr_FormatUnraisable("Exception ignored on threading shutdown"); |
| } |
| /* else: threading not imported */ |
| return; |
| } |
| result = PyObject_CallMethodNoArgs(threading, &_Py_ID(_shutdown)); |
| if (result == NULL) { |
| PyErr_FormatUnraisable("Exception ignored on threading shutdown"); |
| } |
| else { |
| Py_DECREF(result); |
| } |
| Py_DECREF(threading); |
| } |
| |
| int Py_AtExit(void (*func)(void)) |
| { |
| struct _atexit_runtime_state *state = &_PyRuntime.atexit; |
| PyMutex_Lock(&state->mutex); |
| if (state->ncallbacks >= NEXITFUNCS) { |
| PyMutex_Unlock(&state->mutex); |
| return -1; |
| } |
| state->callbacks[state->ncallbacks++] = func; |
| PyMutex_Unlock(&state->mutex); |
| return 0; |
| } |
| |
| static void |
| call_ll_exitfuncs(_PyRuntimeState *runtime) |
| { |
| atexit_callbackfunc exitfunc; |
| struct _atexit_runtime_state *state = &runtime->atexit; |
| |
| 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; |
| |
| PyMutex_Unlock(&state->mutex); |
| exitfunc(); |
| PyMutex_Lock(&state->mutex); |
| } |
| PyMutex_Unlock(&state->mutex); |
| |
| fflush(stdout); |
| fflush(stderr); |
| } |
| |
| void _Py_NO_RETURN |
| Py_Exit(int sts) |
| { |
| PyThreadState *tstate = _PyThreadState_GET(); |
| if (tstate != NULL && _PyThreadState_IsRunningMain(tstate)) { |
| _PyInterpreterState_SetNotRunningMain(tstate->interp); |
| } |
| if (_Py_Finalize(&_PyRuntime) < 0) { |
| sts = 120; |
| } |
| |
| exit(sts); |
| } |
| |
| |
| /* |
| * The file descriptor fd is considered ``interactive'' if either |
| * a) isatty(fd) is TRUE, or |
| * b) the -i flag was given, and the filename associated with |
| * the descriptor is NULL or "<stdin>" or "???". |
| */ |
| int |
| Py_FdIsInteractive(FILE *fp, const char *filename) |
| { |
| if (isatty(fileno(fp))) { |
| return 1; |
| } |
| if (!_Py_GetConfig()->interactive) { |
| return 0; |
| } |
| return ((filename == NULL) |
| || (strcmp(filename, "<stdin>") == 0) |
| || (strcmp(filename, "???") == 0)); |
| } |
| |
| |
| int |
| _Py_FdIsInteractive(FILE *fp, PyObject *filename) |
| { |
| if (isatty(fileno(fp))) { |
| return 1; |
| } |
| if (!_Py_GetConfig()->interactive) { |
| return 0; |
| } |
| return ((filename == NULL) |
| || (PyUnicode_CompareWithASCIIString(filename, "<stdin>") == 0) |
| || (PyUnicode_CompareWithASCIIString(filename, "???") == 0)); |
| } |
| |
| |
| /* Wrappers around sigaction() or signal(). */ |
| |
| PyOS_sighandler_t |
| PyOS_getsig(int sig) |
| { |
| #ifdef HAVE_SIGACTION |
| struct sigaction context; |
| if (sigaction(sig, NULL, &context) == -1) |
| return SIG_ERR; |
| return context.sa_handler; |
| #else |
| PyOS_sighandler_t handler; |
| /* Special signal handling for the secure CRT in Visual Studio 2005 */ |
| #if defined(_MSC_VER) && _MSC_VER >= 1400 |
| switch (sig) { |
| /* Only these signals are valid */ |
| case SIGINT: |
| case SIGILL: |
| case SIGFPE: |
| case SIGSEGV: |
| case SIGTERM: |
| case SIGBREAK: |
| case SIGABRT: |
| break; |
| /* Don't call signal() with other values or it will assert */ |
| default: |
| return SIG_ERR; |
| } |
| #endif /* _MSC_VER && _MSC_VER >= 1400 */ |
| handler = signal(sig, SIG_IGN); |
| if (handler != SIG_ERR) |
| signal(sig, handler); |
| return handler; |
| #endif |
| } |
| |
| /* |
| * All of the code in this function must only use async-signal-safe functions, |
| * listed at `man 7 signal` or |
| * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html. |
| */ |
| PyOS_sighandler_t |
| PyOS_setsig(int sig, PyOS_sighandler_t handler) |
| { |
| #ifdef HAVE_SIGACTION |
| /* Some code in Modules/signalmodule.c depends on sigaction() being |
| * used here if HAVE_SIGACTION is defined. Fix that if this code |
| * changes to invalidate that assumption. |
| */ |
| struct sigaction context, ocontext; |
| context.sa_handler = handler; |
| sigemptyset(&context.sa_mask); |
| /* Using SA_ONSTACK is friendlier to other C/C++/Golang-VM code that |
| * extension module or embedding code may use where tiny thread stacks |
| * are used. https://bugs.python.org/issue43390 */ |
| context.sa_flags = SA_ONSTACK; |
| if (sigaction(sig, &context, &ocontext) == -1) |
| return SIG_ERR; |
| return ocontext.sa_handler; |
| #else |
| PyOS_sighandler_t oldhandler; |
| oldhandler = signal(sig, handler); |
| #ifdef HAVE_SIGINTERRUPT |
| siginterrupt(sig, 1); |
| #endif |
| return oldhandler; |
| #endif |
| } |