diff options
author | Victor Stinner <vstinner@redhat.com> | 2018-07-25 00:49:17 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-25 00:49:17 (GMT) |
commit | 1dc6e3906acb81163725e98378bf4d1bd1ce771a (patch) | |
tree | 8aa562d0a219b6880ed4757ac6ae2367024b3b76 | |
parent | 6cf8255912c36fec6f87f62513034d0818f61390 (diff) | |
download | cpython-1dc6e3906acb81163725e98378bf4d1bd1ce771a.zip cpython-1dc6e3906acb81163725e98378bf4d1bd1ce771a.tar.gz cpython-1dc6e3906acb81163725e98378bf4d1bd1ce771a.tar.bz2 |
bpo-34170: Add _Py_InitializeFromConfig() (GH-8454)
* If _Py_InitializeCore() is called twice, the second call now copies
and apply (partially) the new configuration.
* Rename _Py_CommandLineDetails to _PyCmdline
* Move more code into pymain_init(). The core configuration created
by Py_Main() is new destroyed before running Python to reduce the
memory footprint.
* _Py_InitializeCore() now returns the created interpreter.
_Py_InitializeMainInterpreter() now expects an interpreter.
* Remove _Py_InitializeEx_Private(): _freeze_importlib now uses
_Py_InitializeFromConfig()
* _PyCoreConfig_InitPathConfig() now only computes the path
configuration if needed.
-rw-r--r-- | Include/pylifecycle.h | 11 | ||||
-rw-r--r-- | Include/pystate.h | 3 | ||||
-rw-r--r-- | Modules/main.c | 238 | ||||
-rw-r--r-- | Programs/_freeze_importlib.c | 18 | ||||
-rw-r--r-- | Python/pathconfig.c | 49 | ||||
-rw-r--r-- | Python/pylifecycle.c | 178 |
6 files changed, 297 insertions, 200 deletions
diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h index 3e43a98..6e5d796 100644 --- a/Include/pylifecycle.h +++ b/Include/pylifecycle.h @@ -51,7 +51,9 @@ PyAPI_FUNC(int) Py_SetStandardStreamEncoding(const char *encoding, const char *errors); /* PEP 432 Multi-phase initialization API (Private while provisional!) */ -PyAPI_FUNC(_PyInitError) _Py_InitializeCore(const _PyCoreConfig *); +PyAPI_FUNC(_PyInitError) _Py_InitializeCore( + PyInterpreterState **interp, + const _PyCoreConfig *); PyAPI_FUNC(int) _Py_IsCoreInitialized(void); PyAPI_FUNC(_PyInitError) _PyCoreConfig_Read(_PyCoreConfig *config); @@ -73,14 +75,17 @@ PyAPI_FUNC(int) _PyMainInterpreterConfig_Copy( _PyMainInterpreterConfig *config, const _PyMainInterpreterConfig *config2); -PyAPI_FUNC(_PyInitError) _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *); +PyAPI_FUNC(_PyInitError) _Py_InitializeMainInterpreter( + PyInterpreterState *interp, + const _PyMainInterpreterConfig *); #endif /* Initialization and finalization */ PyAPI_FUNC(void) Py_Initialize(void); PyAPI_FUNC(void) Py_InitializeEx(int); #ifndef Py_LIMITED_API -PyAPI_FUNC(_PyInitError) _Py_InitializeEx_Private(int, int); +PyAPI_FUNC(_PyInitError) _Py_InitializeFromConfig( + const _PyCoreConfig *config); PyAPI_FUNC(void) _Py_FatalInitError(_PyInitError err) _Py_NO_RETURN; #endif PyAPI_FUNC(void) Py_Finalize(void); diff --git a/Include/pystate.h b/Include/pystate.h index 84428bc..fe14832 100644 --- a/Include/pystate.h +++ b/Include/pystate.h @@ -200,8 +200,7 @@ typedef struct { /* --- Private fields -------- */ /* Install importlib? If set to 0, importlib is not initialized at all. - Needed by freeze_importlib: see install_importlib argument of - _Py_InitializeEx_Private(). */ + Needed by freeze_importlib. */ int _install_importlib; /* Value of the --check-hash-based-pycs configure option. Valid values: diff --git a/Modules/main.c b/Modules/main.c index 73ffecd..8c29ef8 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -421,7 +421,7 @@ typedef struct { wchar_t **env_warnoptions; /* PYTHONWARNINGS environment variables */ int print_help; /* -h, -? options */ int print_version; /* -V option */ -} _Py_CommandLineDetails; +} _PyCmdline; /* Structure used by Py_Main() to pass data to subfunctions */ typedef struct { @@ -443,14 +443,10 @@ typedef struct { wchar_t *command; /* -c argument */ wchar_t *module; /* -m argument */ - _PyCoreConfig config; - PyObject *main_importer_path; } _PyMain; -#define _PyMain_INIT \ - {.config = _PyCoreConfig_INIT, \ - .err = _Py_INIT_OK()} +#define _PyMain_INIT {.err = _Py_INIT_OK()} /* Note: _PyMain_INIT sets other fields to 0/NULL */ @@ -502,7 +498,8 @@ pymain_wstrdup(_PyMain *pymain, const wchar_t *str) static int -pymain_init_cmdline_argv(_PyMain *pymain, _Py_CommandLineDetails *cmdline) +pymain_init_cmdline_argv(_PyMain *pymain, _PyCoreConfig *config, + _PyCmdline *cmdline) { assert(cmdline->argv == NULL); @@ -541,8 +538,8 @@ pymain_init_cmdline_argv(_PyMain *pymain, _Py_CommandLineDetails *cmdline) else { program = L""; } - pymain->config.program = pymain_wstrdup(pymain, program); - if (pymain->config.program == NULL) { + config->program = pymain_wstrdup(pymain, program); + if (config->program == NULL) { return -1; } @@ -767,7 +764,7 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2) static void -pymain_clear_cmdline(_PyMain *pymain, _Py_CommandLineDetails *cmdline) +pymain_clear_cmdline(_PyMain *pymain, _PyCmdline *cmdline) { PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); @@ -805,14 +802,14 @@ pymain_clear_pymain(_PyMain *pymain) } static void -pymain_clear_config(_PyMain *pymain) +pymain_clear_config(_PyCoreConfig *config) { /* Clear core config with the memory allocator used by pymain_read_conf() */ PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - _PyCoreConfig_Clear(&pymain->config); + _PyCoreConfig_Clear(config); PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); } @@ -849,8 +846,6 @@ pymain_free_raw(_PyMain *pymain) Py_Initialize()-Py_Finalize() can be called multiple times. */ _PyPathConfig_ClearGlobal(); - pymain_clear_config(pymain); - /* Force the allocator used by pymain_read_conf() */ PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); @@ -940,10 +935,9 @@ pymain_wstrlist_append(_PyMain *pymain, int *len, wchar_t ***list, const wchar_t Return 1 if parsing failed. Set pymain->err and return -1 on other errors. */ static int -pymain_parse_cmdline_impl(_PyMain *pymain, _Py_CommandLineDetails *cmdline) +pymain_parse_cmdline_impl(_PyMain *pymain, _PyCoreConfig *config, + _PyCmdline *cmdline) { - _PyCoreConfig *config = &pymain->config; - _PyOS_ResetGetOpt(); do { int longindex = -1; @@ -1185,7 +1179,7 @@ config_add_warnings_optlist(_PyCoreConfig *config, int len, wchar_t **options) static _PyInitError -config_init_warnoptions(_PyCoreConfig *config, _Py_CommandLineDetails *cmdline) +config_init_warnoptions(_PyCoreConfig *config, _PyCmdline *cmdline) { _PyInitError err; @@ -1256,14 +1250,14 @@ config_init_warnoptions(_PyCoreConfig *config, _Py_CommandLineDetails *cmdline) Return 0 on success. Set pymain->err and return -1 on error. */ static _PyInitError -cmdline_init_env_warnoptions(_PyMain *pymain, _Py_CommandLineDetails *cmdline) +cmdline_init_env_warnoptions(_PyMain *pymain, _PyCoreConfig *config, _PyCmdline *cmdline) { - if (pymain->config.ignore_environment) { + if (config->ignore_environment) { return _Py_INIT_OK(); } wchar_t *env; - int res = config_get_env_var_dup(&pymain->config, &env, + int res = config_get_env_var_dup(config, &env, L"PYTHONWARNINGS", "PYTHONWARNINGS"); if (res < 0) { return DECODE_LOCALE_ERR("PYTHONWARNINGS", res); @@ -1293,10 +1287,8 @@ cmdline_init_env_warnoptions(_PyMain *pymain, _Py_CommandLineDetails *cmdline) static void -pymain_init_stdio(_PyMain *pymain) +pymain_init_stdio(_PyMain *pymain, _PyCoreConfig *config) { - _PyCoreConfig *config = &pymain->config; - pymain->stdin_is_interactive = (isatty(fileno(stdin)) || config->interactive); @@ -1339,8 +1331,6 @@ pymain_init_stdio(_PyMain *pymain) static _PyInitError config_init_program_name(_PyCoreConfig *config) { - assert(config->program_name == NULL); - /* If Py_SetProgramName() was called, use its value */ const wchar_t *program_name = _Py_path_config.program_name; if (program_name != NULL) { @@ -1434,7 +1424,7 @@ pymain_header(_PyMain *pymain) static int -pymain_init_core_argv(_PyMain *pymain, _Py_CommandLineDetails *cmdline) +pymain_init_core_argv(_PyMain *pymain, _PyCoreConfig *config, _PyCmdline *cmdline) { /* Copy argv to be able to modify it (to force -c/-m) */ int argc = pymain->argc - _PyOS_optind; @@ -1477,8 +1467,8 @@ pymain_init_core_argv(_PyMain *pymain, _Py_CommandLineDetails *cmdline) argv[0] = arg0; } - pymain->config.argc = argc; - pymain->config.argv = argv; + config->argc = argc; + config->argv = argv; return 0; } @@ -1506,7 +1496,7 @@ wstrlist_as_pylist(int len, wchar_t **list) static int -pymain_compute_path0(_PyMain *pymain, PyObject **path0) +pymain_compute_path0(_PyMain *pymain, _PyCoreConfig *config, PyObject **path0) { if (pymain->main_importer_path != NULL) { /* Let pymain_run_main_from_importer() adjust sys.path[0] later */ @@ -1519,8 +1509,8 @@ pymain_compute_path0(_PyMain *pymain, PyObject **path0) return 0; } - *path0 = _PyPathConfig_ComputeArgv0(pymain->config.argc, - pymain->config.argv); + *path0 = _PyPathConfig_ComputeArgv0(config->argc, + config->argv); if (*path0 == NULL) { pymain->err = _Py_INIT_NO_MEMORY(); return -1; @@ -1573,7 +1563,7 @@ pymain_import_readline(_PyMain *pymain) static FILE* -pymain_open_filename(_PyMain *pymain) +pymain_open_filename(_PyMain *pymain, _PyCoreConfig *config) { FILE* fp; @@ -1588,7 +1578,7 @@ pymain_open_filename(_PyMain *pymain) else cfilename = "<unprintable file name>"; fprintf(stderr, "%ls: can't open file '%s': [Errno %d] %s\n", - pymain->config.program, cfilename, err, strerror(err)); + config->program, cfilename, err, strerror(err)); PyMem_RawFree(cfilename_buffer); pymain->status = 2; return NULL; @@ -1611,7 +1601,7 @@ pymain_open_filename(_PyMain *pymain) S_ISDIR(sb.st_mode)) { fprintf(stderr, "%ls: '%ls' is a directory, cannot continue\n", - pymain->config.program, pymain->filename); + config->program, pymain->filename); fclose(fp); pymain->status = 1; return NULL; @@ -1622,9 +1612,9 @@ pymain_open_filename(_PyMain *pymain) static void -pymain_run_startup(_PyMain *pymain, PyCompilerFlags *cf) +pymain_run_startup(_PyMain *pymain, _PyCoreConfig *config, PyCompilerFlags *cf) { - const char *startup = config_get_env_var(&pymain->config, "PYTHONSTARTUP"); + const char *startup = config_get_env_var(config, "PYTHONSTARTUP"); if (startup == NULL) { return; } @@ -1649,11 +1639,11 @@ pymain_run_startup(_PyMain *pymain, PyCompilerFlags *cf) static void -pymain_run_filename(_PyMain *pymain, PyCompilerFlags *cf) +pymain_run_filename(_PyMain *pymain, _PyCoreConfig *config, PyCompilerFlags *cf) { if (pymain->filename == NULL && pymain->stdin_is_interactive) { Py_InspectFlag = 0; /* do exit on SystemExit */ - pymain_run_startup(pymain, cf); + pymain_run_startup(pymain, config, cf); pymain_run_interactive_hook(); } @@ -1664,7 +1654,7 @@ pymain_run_filename(_PyMain *pymain, PyCompilerFlags *cf) FILE *fp; if (pymain->filename != NULL) { - fp = pymain_open_filename(pymain); + fp = pymain_open_filename(pymain, config); if (fp == NULL) { return; } @@ -1678,11 +1668,11 @@ pymain_run_filename(_PyMain *pymain, PyCompilerFlags *cf) static void -pymain_repl(_PyMain *pymain, PyCompilerFlags *cf) +pymain_repl(_PyMain *pymain, _PyCoreConfig *config, PyCompilerFlags *cf) { /* Check this environment variable at the end, to give programs the opportunity to set it from Python. */ - if (!Py_InspectFlag && config_get_env_var(&pymain->config, "PYTHONINSPECT")) { + if (!Py_InspectFlag && config_get_env_var(config, "PYTHONINSPECT")) { Py_InspectFlag = 1; } @@ -1705,14 +1695,15 @@ pymain_repl(_PyMain *pymain, PyCompilerFlags *cf) Return 0 on success. Set pymain->err and return -1 on failure. */ static int -pymain_parse_cmdline(_PyMain *pymain, _Py_CommandLineDetails *cmdline) +pymain_parse_cmdline(_PyMain *pymain, _PyCoreConfig *config, + _PyCmdline *cmdline) { - int res = pymain_parse_cmdline_impl(pymain, cmdline); + int res = pymain_parse_cmdline_impl(pymain, config, cmdline); if (res < 0) { return -1; } if (res) { - pymain_usage(1, pymain->config.program); + pymain_usage(1, config->program); pymain->status = 2; return 1; } @@ -1881,10 +1872,9 @@ get_env_flag(_PyCoreConfig *config, int *flag, const char *name) static void -cmdline_get_env_flags(_PyMain *pymain, _Py_CommandLineDetails *cmdline) +cmdline_get_env_flags(_PyMain *pymain, _PyCoreConfig *config, + _PyCmdline *cmdline) { - _PyCoreConfig *config = &pymain->config; - get_env_flag(config, &config->debug, "PYTHONDEBUG"); get_env_flag(config, &config->verbose, "PYTHONVERBOSE"); get_env_flag(config, &config->optimization_level, "PYTHONOPTIMIZE"); @@ -2085,20 +2075,20 @@ config_read_complex_options(_PyCoreConfig *config) Return 1 if Python is done and must exit. Set pymain->err and return -1 on error. */ static int -pymain_read_conf_impl(_PyMain *pymain, _Py_CommandLineDetails *cmdline) +pymain_read_conf_impl(_PyMain *pymain, _PyCoreConfig *config, + _PyCmdline *cmdline) { - _PyCoreConfig *config = &pymain->config; _PyInitError err; - int res = pymain_parse_cmdline(pymain, cmdline); + int res = pymain_parse_cmdline(pymain, config, cmdline); if (res != 0) { return res; } /* Get environment variables */ - cmdline_get_env_flags(pymain, cmdline); + cmdline_get_env_flags(pymain, config, cmdline); - err = cmdline_init_env_warnoptions(pymain, cmdline); + err = cmdline_init_env_warnoptions(pymain, config, cmdline); if (_Py_INIT_FAILED(err)) { pymain->err = err; return -1; @@ -2110,12 +2100,11 @@ pymain_read_conf_impl(_PyMain *pymain, _Py_CommandLineDetails *cmdline) } #endif - if (pymain_init_core_argv(pymain, cmdline) < 0) { + if (pymain_init_core_argv(pymain, config, cmdline) < 0) { return -1; } err = _PyCoreConfig_Read(config); - if (_Py_INIT_FAILED(err)) { pymain->err = err; return -1; @@ -2127,9 +2116,9 @@ pymain_read_conf_impl(_PyMain *pymain, _Py_CommandLineDetails *cmdline) /* Read the configuration, but initialize also the LC_CTYPE locale: enable UTF-8 mode (PEP 540) and/or coerce the C locale (PEP 538) */ static int -pymain_read_conf(_PyMain *pymain, _Py_CommandLineDetails *cmdline) +pymain_read_conf(_PyMain *pymain, _PyCoreConfig *config, + _PyCmdline *cmdline) { - _PyCoreConfig *config = &pymain->config; _PyCoreConfig save_config = _PyCoreConfig_INIT; char *oldloc = NULL; int res = -1; @@ -2163,11 +2152,11 @@ pymain_read_conf(_PyMain *pymain, _Py_CommandLineDetails *cmdline) goto done; } - if (pymain_init_cmdline_argv(pymain, cmdline) < 0) { + if (pymain_init_cmdline_argv(pymain, config, cmdline) < 0) { goto done; } - int conf_res = pymain_read_conf_impl(pymain, cmdline); + int conf_res = pymain_read_conf_impl(pymain, config, cmdline); if (conf_res != 0) { res = conf_res; goto done; @@ -2214,7 +2203,7 @@ pymain_read_conf(_PyMain *pymain, _Py_CommandLineDetails *cmdline) } pymain_clear_cmdline(pymain, cmdline); memset(cmdline, 0, sizeof(*cmdline)); - pymain->config.utf8_mode = new_utf8_mode; + config->utf8_mode = new_utf8_mode; /* The encoding changed: read again the configuration with the new encoding */ @@ -2307,9 +2296,11 @@ _PyCoreConfig_Read(_PyCoreConfig *config) return err; } - err = config_init_program_name(config); - if (_Py_INIT_FAILED(err)) { - return err; + if (config->program_name == NULL) { + err = config_init_program_name(config); + if (_Py_INIT_FAILED(err)) { + return err; + } } config_init_locale(config); @@ -2419,7 +2410,7 @@ _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *main_config, #define COPY_WSTR(ATTR) \ do { \ - if (main_config->ATTR == NULL) { \ + if (main_config->ATTR == NULL && config->ATTR != NULL) { \ main_config->ATTR = PyUnicode_FromWideChar(config->ATTR, -1); \ if (main_config->ATTR == NULL) { \ return _Py_INIT_NO_MEMORY(); \ @@ -2468,14 +2459,15 @@ _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *main_config, static int -pymain_init_python_main(_PyMain *pymain) +pymain_init_python_main(_PyMain *pymain, _PyCoreConfig *config, + PyInterpreterState *interp) { _PyInitError err; _PyMainInterpreterConfig main_config = _PyMainInterpreterConfig_INIT; - err = _PyMainInterpreterConfig_Read(&main_config, &pymain->config); + err = _PyMainInterpreterConfig_Read(&main_config, config); if (!_Py_INIT_FAILED(err)) { - err = _Py_InitializeMainInterpreter(&main_config); + err = _Py_InitializeMainInterpreter(interp, &main_config); } _PyMainInterpreterConfig_Clear(&main_config); @@ -2488,7 +2480,7 @@ pymain_init_python_main(_PyMain *pymain) static int -pymain_init_sys_path(_PyMain *pymain) +pymain_init_sys_path(_PyMain *pymain, _PyCoreConfig *config) { if (pymain->filename != NULL) { /* If filename is a package (ex: directory or ZIP file) which contains @@ -2499,12 +2491,10 @@ pymain_init_sys_path(_PyMain *pymain) } PyObject *path0; - if (pymain_compute_path0(pymain, &path0) < 0) { + if (pymain_compute_path0(pymain, config, &path0) < 0) { return -1; } - pymain_clear_config(pymain); - if (path0 != NULL) { if (pymain_update_sys_path(pymain, path0) < 0) { Py_DECREF(path0); @@ -2520,6 +2510,7 @@ static void pymain_run_python(_PyMain *pymain) { PyCompilerFlags cf = {.cf_flags = 0}; + _PyCoreConfig *config = &PyThreadState_GET()->interp->core_config; pymain_header(pymain); pymain_import_readline(pymain); @@ -2531,38 +2522,23 @@ pymain_run_python(_PyMain *pymain) pymain->status = (pymain_run_module(pymain->module, 1) != 0); } else { - pymain_run_filename(pymain, &cf); + pymain_run_filename(pymain, config, &cf); } - pymain_repl(pymain, &cf); -} - - -static void -pymain_init(_PyMain *pymain) -{ - /* 754 requires that FP exceptions run in "no stop" mode by default, - * and until C vendors implement C99's ways to control FP exceptions, - * Python requires non-stop mode. Alas, some platforms enable FP - * exceptions by default. Here we disable them. - */ -#ifdef __FreeBSD__ - fedisableexcept(FE_OVERFLOW); -#endif - - pymain->config.install_signal_handlers = 1; + pymain_repl(pymain, config, &cf); } static int -pymain_cmdline_impl(_PyMain *pymain, _Py_CommandLineDetails *cmdline) +pymain_cmdline_impl(_PyMain *pymain, _PyCoreConfig *config, + _PyCmdline *cmdline) { pymain->err = _PyRuntime_Initialize(); if (_Py_INIT_FAILED(pymain->err)) { return -1; } - int res = pymain_read_conf(pymain, cmdline); + int res = pymain_read_conf(pymain, config, cmdline); if (res < 0) { return -1; } @@ -2572,7 +2548,7 @@ pymain_cmdline_impl(_PyMain *pymain, _Py_CommandLineDetails *cmdline) } if (cmdline->print_help) { - pymain_usage(0, pymain->config.program); + pymain_usage(0, config->program); return 1; } @@ -2590,7 +2566,7 @@ pymain_cmdline_impl(_PyMain *pymain, _Py_CommandLineDetails *cmdline) } orig_argc = pymain->argc; - _PyInitError err = config_init_warnoptions(&pymain->config, cmdline); + _PyInitError err = config_init_warnoptions(config, cmdline); if (_Py_INIT_FAILED(err)) { pymain->err = err; return -1; @@ -2608,10 +2584,10 @@ pymain_cmdline_impl(_PyMain *pymain, _Py_CommandLineDetails *cmdline) * Environment variables * Py_xxx global configuration variables - _Py_CommandLineDetails is a temporary structure used to prioritize these + _PyCmdline is a temporary structure used to prioritize these variables. */ static int -pymain_cmdline(_PyMain *pymain) +pymain_cmdline(_PyMain *pymain, _PyCoreConfig *config) { /* Force default allocator, since pymain_free() and pymain_clear_config() must use the same allocator than this function. */ @@ -2622,10 +2598,10 @@ pymain_cmdline(_PyMain *pymain) PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &default_alloc); #endif - _Py_CommandLineDetails cmdline; + _PyCmdline cmdline; memset(&cmdline, 0, sizeof(cmdline)); - int res = pymain_cmdline_impl(pymain, &cmdline); + int res = pymain_cmdline_impl(pymain, config, &cmdline); pymain_clear_cmdline(pymain, &cmdline); @@ -2641,50 +2617,70 @@ pymain_cmdline(_PyMain *pymain) static int -pymain_main(_PyMain *pymain) +pymain_init(_PyMain *pymain) { - pymain_init(pymain); + /* 754 requires that FP exceptions run in "no stop" mode by default, + * and until C vendors implement C99's ways to control FP exceptions, + * Python requires non-stop mode. Alas, some platforms enable FP + * exceptions by default. Here we disable them. + */ +#ifdef __FreeBSD__ + fedisableexcept(FE_OVERFLOW); +#endif - _PyCoreConfig_GetGlobalConfig(&pymain->config); + _PyCoreConfig local_config = _PyCoreConfig_INIT; + _PyCoreConfig *config = &local_config; + config->install_signal_handlers = 1; - int res = pymain_cmdline(pymain); - if (res < 0) { + _PyCoreConfig_GetGlobalConfig(config); + + int cmd_res = pymain_cmdline(pymain, config); + if (cmd_res < 0) { _Py_FatalInitError(pymain->err); } - if (res == 1) { - goto done; + if (cmd_res == 1) { + pymain_clear_config(config); + return 1; } - _PyCoreConfig_SetGlobalConfig(&pymain->config); + _PyCoreConfig_SetGlobalConfig(config); - pymain_init_stdio(pymain); + pymain_init_stdio(pymain, config); - /* bpo-34008: For backward compatibility reasons, calling Py_Main() after - Py_Initialize() ignores the new configuration. */ - if (!_PyRuntime.initialized) { - pymain->err = _Py_InitializeCore(&pymain->config); - if (_Py_INIT_FAILED(pymain->err)) { - _Py_FatalInitError(pymain->err); - } + PyInterpreterState *interp; + pymain->err = _Py_InitializeCore(&interp, config); + if (_Py_INIT_FAILED(pymain->err)) { + _Py_FatalInitError(pymain->err); } - if (pymain_init_python_main(pymain) < 0) { + pymain_clear_config(config); + config = &interp->core_config; + + if (pymain_init_python_main(pymain, config, interp) < 0) { _Py_FatalInitError(pymain->err); } - if (pymain_init_sys_path(pymain) < 0) { + if (pymain_init_sys_path(pymain, config) < 0) { _Py_FatalInitError(pymain->err); } + return 0; +} - pymain_run_python(pymain); - if (Py_FinalizeEx() < 0) { - /* Value unlikely to be confused with a non-error exit status or - other special meaning */ - pymain->status = 120; +static int +pymain_main(_PyMain *pymain) +{ + int res = pymain_init(pymain); + if (res != 1) { + pymain_run_python(pymain); + + if (Py_FinalizeEx() < 0) { + /* Value unlikely to be confused with a non-error exit status or + other special meaning */ + pymain->status = 120; + } } -done: pymain_free(pymain); return pymain->status; diff --git a/Programs/_freeze_importlib.c b/Programs/_freeze_importlib.c index b8b630c..03e0826 100644 --- a/Programs/_freeze_importlib.c +++ b/Programs/_freeze_importlib.c @@ -74,14 +74,20 @@ main(int argc, char *argv[]) } text[text_size] = '\0'; - Py_NoUserSiteDirectory++; - Py_NoSiteFlag++; - Py_IgnoreEnvironmentFlag++; + _PyCoreConfig config = _PyCoreConfig_INIT; + config.user_site_directory = 0; + config.site_import = 0; + config.ignore_environment = 1; + config.program_name = L"./_freeze_importlib"; + /* Don't install importlib, since it could execute outdated bytecode. */ + config._install_importlib = 0; + config.install_signal_handlers = 1; + Py_FrozenFlag++; - Py_SetProgramName(L"./_freeze_importlib"); - /* Don't install importlib, since it could execute outdated bytecode. */ - _PyInitError err = _Py_InitializeEx_Private(1, 0); + _PyInitError err = _Py_InitializeFromConfig(&config); + /* No need to call _PyCoreConfig_Clear() since we didn't allocate any + memory: program_name is a constant string. */ if (_Py_INIT_FAILED(err)) { _Py_FatalInitError(err); } diff --git a/Python/pathconfig.c b/Python/pathconfig.c index 509ea8e..4e0830f 100644 --- a/Python/pathconfig.c +++ b/Python/pathconfig.c @@ -282,8 +282,8 @@ core_config_init_module_search_paths(_PyCoreConfig *config, } -_PyInitError -_PyCoreConfig_InitPathConfig(_PyCoreConfig *config) +static _PyInitError +_PyCoreConfig_CalculatePathConfig(_PyCoreConfig *config) { _PyPathConfig path_config = _PyPathConfig_INIT; _PyInitError err; @@ -332,18 +332,6 @@ _PyCoreConfig_InitPathConfig(_PyCoreConfig *config) } #endif - if (config->base_prefix == NULL) { - if (copy_wstr(&config->base_prefix, config->prefix) < 0) { - goto no_memory; - } - } - - if (config->base_exec_prefix == NULL) { - if (copy_wstr(&config->base_exec_prefix, config->exec_prefix) < 0) { - goto no_memory; - } - } - if (path_config.isolated != -1) { config->isolated = path_config.isolated; } @@ -363,6 +351,39 @@ error: } +_PyInitError +_PyCoreConfig_InitPathConfig(_PyCoreConfig *config) +{ + /* Do we need to calculate the path? */ + if ((config->nmodule_search_path < 0) + || (config->executable == NULL) + || (config->prefix == NULL) +#ifdef MS_WINDOWS + || (config->dll_path == NULL) +#endif + || (config->exec_prefix == NULL)) + { + _PyInitError err = _PyCoreConfig_CalculatePathConfig(config); + if (_Py_INIT_FAILED(err)) { + return err; + } + } + + if (config->base_prefix == NULL) { + if (copy_wstr(&config->base_prefix, config->prefix) < 0) { + return _Py_INIT_NO_MEMORY(); + } + } + + if (config->base_exec_prefix == NULL) { + if (copy_wstr(&config->base_exec_prefix, config->exec_prefix) < 0) { + return _Py_INIT_NO_MEMORY(); + } + } + return _Py_INIT_OK(); +} + + static void pathconfig_global_init(void) { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index c88e945..0729a5f 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -567,7 +567,7 @@ _Py_SetLocaleFromEnv(int category) /* Global initializations. Can be undone by Py_Finalize(). Don't call this twice without an intervening Py_Finalize() call. - Every call to Py_InitializeCore, Py_Initialize or Py_InitializeEx + Every call to _Py_InitializeCore, Py_Initialize or Py_InitializeEx must have a corresponding call to Py_Finalize. Locking: you must hold the interpreter lock while calling these APIs. @@ -576,6 +576,35 @@ _Py_SetLocaleFromEnv(int category) */ +static _PyInitError +_Py_Initialize_ReconfigureCore(PyInterpreterState *interp, + const _PyCoreConfig *core_config) +{ + if (core_config->allocator != NULL) { + const char *allocator = _PyMem_GetAllocatorsName(); + if (allocator == NULL || strcmp(core_config->allocator, allocator) != 0) { + return _Py_INIT_USER_ERR("cannot modify memory allocator " + "after first Py_Initialize()"); + } + } + + _PyCoreConfig_SetGlobalConfig(core_config); + + if (_PyCoreConfig_Copy(&interp->core_config, core_config) < 0) { + return _Py_INIT_ERR("failed to copy core config"); + } + core_config = &interp->core_config; + + if (core_config->_install_importlib) { + _PyInitError err = _PyCoreConfig_SetPathConfig(core_config); + if (_Py_INIT_FAILED(err)) { + return err; + } + } + return _Py_INIT_OK(); +} + + /* Begin interpreter initialization * * On return, the first thread and interpreter state have been created, @@ -592,16 +621,41 @@ _Py_SetLocaleFromEnv(int category) * 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) + * + * The caller is responsible to call _PyCoreConfig_Read(). */ -_PyInitError -_Py_InitializeCore(const _PyCoreConfig *core_config) +static _PyInitError +_Py_InitializeCore_impl(PyInterpreterState **interp_p, + const _PyCoreConfig *core_config) { - assert(core_config != NULL); + PyInterpreterState *interp; + _PyInitError err; + + /* bpo-34008: For backward compatibility reasons, calling Py_Main() after + Py_Initialize() ignores the new configuration. */ + if (_PyRuntime.core_initialized) { + PyThreadState *tstate = PyThreadState_GET(); + if (!tstate) { + return _Py_INIT_ERR("failed to read thread state"); + } + + interp = tstate->interp; + if (interp == NULL) { + return _Py_INIT_ERR("can't make main interpreter"); + } + *interp_p = interp; + + return _Py_Initialize_ReconfigureCore(interp, core_config); + } + + if (_PyRuntime.initialized) { + return _Py_INIT_ERR("main interpreter already initialized"); + } _PyCoreConfig_SetGlobalConfig(core_config); - _PyInitError err = _PyRuntime_Initialize(); + err = _PyRuntime_Initialize(); if (_Py_INIT_FAILED(err)) { return err; } @@ -612,13 +666,6 @@ _Py_InitializeCore(const _PyCoreConfig *core_config) } } - if (_PyRuntime.initialized) { - return _Py_INIT_ERR("main interpreter already initialized"); - } - if (_PyRuntime.core_initialized) { - return _Py_INIT_ERR("runtime core already initialized"); - } - /* 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 @@ -648,10 +695,11 @@ _Py_InitializeCore(const _PyCoreConfig *core_config) return err; } - PyInterpreterState *interp = PyInterpreterState_New(); + interp = PyInterpreterState_New(); if (interp == NULL) { return _Py_INIT_ERR("can't make main interpreter"); } + *interp_p = interp; if (_PyCoreConfig_Copy(&interp->core_config, core_config) < 0) { return _Py_INIT_ERR("failed to copy core config"); @@ -773,6 +821,43 @@ _Py_InitializeCore(const _PyCoreConfig *core_config) return _Py_INIT_OK(); } +_PyInitError +_Py_InitializeCore(PyInterpreterState **interp_p, + const _PyCoreConfig *src_config) +{ + assert(src_config != NULL); + + + PyMemAllocatorEx old_alloc; + _PyInitError err; + + /* Copy the configuration, since _PyCoreConfig_Read() modifies it + (and the input configuration is read only). */ + _PyCoreConfig config = _PyCoreConfig_INIT; + + _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + if (_PyCoreConfig_Copy(&config, src_config) >= 0) { + err = _PyCoreConfig_Read(&config); + } + else { + err = _Py_INIT_ERR("failed to copy core config"); + } + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + + if (_Py_INIT_FAILED(err)) { + goto done; + } + + err = _Py_InitializeCore_impl(interp_p, &config); + +done: + _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + _PyCoreConfig_Clear(&config); + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + + return err; +} + /* Py_Initialize() has already been called: update the main interpreter configuration. Example of bpo-34008: Py_Main() called after Py_Initialize(). */ @@ -801,27 +886,19 @@ _Py_ReconfigureMainInterpreter(PyInterpreterState *interp, * non-zero return code. */ _PyInitError -_Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config) +_Py_InitializeMainInterpreter(PyInterpreterState *interp, + const _PyMainInterpreterConfig *config) { if (!_PyRuntime.core_initialized) { return _Py_INIT_ERR("runtime core not initialized"); } - /* Get current thread state and interpreter pointer */ - PyThreadState *tstate = PyThreadState_GET(); - if (!tstate) { - return _Py_INIT_ERR("failed to read thread state"); - } - PyInterpreterState *interp = tstate->interp; - if (!interp) { - return _Py_INIT_ERR("failed to get interpreter"); - } - _PyCoreConfig *core_config = &interp->core_config; - - /* Now finish configuring the main interpreter */ + /* Configure the main interpreter */ if (_PyMainInterpreterConfig_Copy(&interp->config, config) < 0) { return _Py_INIT_ERR("failed to copy main interpreter config"); } + config = &interp->config; + _PyCoreConfig *core_config = &interp->core_config; if (_PyRuntime.initialized) { return _Py_ReconfigureMainInterpreter(interp, config); @@ -908,51 +985,44 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config) #undef _INIT_DEBUG_PRINT _PyInitError -_Py_InitializeEx_Private(int install_sigs, int install_importlib) +_Py_InitializeFromConfig(const _PyCoreConfig *config) { - if (_PyRuntime.initialized) { - /* bpo-33932: Calling Py_Initialize() twice does nothing. */ - return _Py_INIT_OK(); - } - - _PyCoreConfig config = _PyCoreConfig_INIT; + PyInterpreterState *interp; _PyInitError err; - - config._install_importlib = install_importlib; - config.install_signal_handlers = install_sigs; - - err = _PyCoreConfig_Read(&config); - if (_Py_INIT_FAILED(err)) { - goto done; - } - - err = _Py_InitializeCore(&config); + err = _Py_InitializeCore(&interp, config); if (_Py_INIT_FAILED(err)) { - goto done; + return err; } + config = &interp->core_config; _PyMainInterpreterConfig main_config = _PyMainInterpreterConfig_INIT; - err = _PyMainInterpreterConfig_Read(&main_config, &config); + err = _PyMainInterpreterConfig_Read(&main_config, config); if (!_Py_INIT_FAILED(err)) { - err = _Py_InitializeMainInterpreter(&main_config); + err = _Py_InitializeMainInterpreter(interp, &main_config); } _PyMainInterpreterConfig_Clear(&main_config); if (_Py_INIT_FAILED(err)) { - goto done; + return err; } - - err = _Py_INIT_OK(); - -done: - _PyCoreConfig_Clear(&config); - return err; + return _Py_INIT_OK(); } void Py_InitializeEx(int install_sigs) { - _PyInitError err = _Py_InitializeEx_Private(install_sigs, 1); + if (_PyRuntime.initialized) { + /* bpo-33932: Calling Py_Initialize() twice does nothing. */ + return; + } + + _PyInitError err; + _PyCoreConfig config = _PyCoreConfig_INIT; + config.install_signal_handlers = install_sigs; + + err = _Py_InitializeFromConfig(&config); + _PyCoreConfig_Clear(&config); + if (_Py_INIT_FAILED(err)) { _Py_FatalInitError(err); } |