diff options
author | Victor Stinner <vstinner@redhat.com> | 2018-07-25 02:49:17 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-25 02:49:17 +0200 |
commit | 1dc6e3906acb81163725e98378bf4d1bd1ce771a (patch) | |
tree | 8aa562d0a219b6880ed4757ac6ae2367024b3b76 /Python | |
parent | 6cf8255912c36fec6f87f62513034d0818f61390 (diff) | |
download | cpython-git-1dc6e3906acb81163725e98378bf4d1bd1ce771a.tar.gz |
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.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/pathconfig.c | 49 | ||||
-rw-r--r-- | Python/pylifecycle.c | 178 |
2 files changed, 159 insertions, 68 deletions
diff --git a/Python/pathconfig.c b/Python/pathconfig.c index 509ea8eb18..4e0830f4cf 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 c88e945f8e..0729a5f83b 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); } |