diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index c6057a4c3ed945..781007f787ef8e 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -212,10 +212,6 @@ typedef struct PyConfig { // If equal to 0, stop Python initialization before the "main" phase. int _init_main; - // If non-zero, disallow threads, subprocesses, and fork. - // Default: 0. - int _isolated_interpreter; - // If non-zero, we believe we're running from a source tree. int _is_python_build; } PyConfig; @@ -243,6 +239,16 @@ PyAPI_FUNC(PyStatus) PyConfig_SetWideStringList(PyConfig *config, PyWideStringList *list, Py_ssize_t length, wchar_t **items); +typedef struct { + /* Allow forking the process. */ + unsigned int allow_fork:1; + /* Allow creating subprocesses. */ + unsigned int allow_subprocess:1; + /* Allow the creation of threads. */ + unsigned int allow_threading:1; + /* Padding to ensure byte alignment. */ + unsigned int :5; +} _PyInterpreterConfig; /* --- Helper functions --------------------------------------- */ diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h index bb5b07ef5901c8..ec50d31842f6b2 100644 --- a/Include/cpython/pylifecycle.h +++ b/Include/cpython/pylifecycle.h @@ -62,4 +62,4 @@ PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn); PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn); PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category); -PyAPI_FUNC(PyThreadState *) _Py_NewInterpreter(int isolated_subinterpreter); +PyAPI_FUNC(PyThreadState *) _Py_NewInterpreter(const _PyInterpreterConfig *); diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index cc3c3eae941933..2cec5cbe17261a 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -269,7 +269,14 @@ PyAPI_FUNC(void) _PyInterpreterState_SetEvalFrameFunc( PyInterpreterState *interp, _PyFrameEvalFunction eval_frame); -PyAPI_FUNC(const PyConfig*) _PyInterpreterState_GetConfig(PyInterpreterState *interp); +PyAPI_FUNC(const _PyInterpreterConfig*) _PyInterpreterState_GetConfig( + PyInterpreterState *interp); + +PyAPI_FUNC(const PyConfig*) _PyInterpreterState_GetGlobalConfig(PyInterpreterState *interp); + +// Get the configuration of the current interpreter. +// The caller must hold the GIL. +PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void); /* Get a copy of the current interpreter configuration. @@ -283,8 +290,7 @@ PyAPI_FUNC(const PyConfig*) _PyInterpreterState_GetConfig(PyInterpreterState *in Once done with the configuration, PyConfig_Clear() must be called to clear it. */ -PyAPI_FUNC(int) _PyInterpreterState_GetConfigCopy( - struct PyConfig *config); +PyAPI_FUNC(int) _Py_CopyConfig(PyConfig *config); /* Set the configuration of the current interpreter. @@ -300,13 +306,8 @@ PyAPI_FUNC(int) _PyInterpreterState_GetConfigCopy( Return 0 on success. Raise an exception and return -1 on error. - The configuration should come from _PyInterpreterState_GetConfigCopy(). */ -PyAPI_FUNC(int) _PyInterpreterState_SetConfig( - const struct PyConfig *config); - -// Get the configuration of the current interpreter. -// The caller must hold the GIL. -PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void); + The configuration should come from _Py_CopyConfig(). */ +PyAPI_FUNC(int) _Py_SetConfig(const PyConfig *config); /* cross-interpreter data */ diff --git a/Include/internal/pycore_initconfig.h b/Include/internal/pycore_initconfig.h index 6e491261d55ca6..2114bc4db5fa55 100644 --- a/Include/internal/pycore_initconfig.h +++ b/Include/internal/pycore_initconfig.h @@ -166,6 +166,11 @@ extern PyStatus _PyConfig_SetPyArgv( PyAPI_FUNC(PyObject*) _PyConfig_AsDict(const PyConfig *config); PyAPI_FUNC(int) _PyConfig_FromDict(PyConfig *config, PyObject *dict); +extern void _PyInterpreterConfig_Clear(_PyInterpreterConfig *); +extern PyStatus _PyInterpreterConfig_Copy( + _PyInterpreterConfig *config, + const _PyInterpreterConfig *config2); + extern void _Py_DumpPathConfig(PyThreadState *tstate); PyAPI_FUNC(PyObject*) _Py_Get_Getpath_CodeObject(void); diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index e7f914ec2fe521..e85594e86ac116 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -132,7 +132,8 @@ struct _is { PyObject *codec_error_registry; int codecs_initialized; - PyConfig config; + _PyInterpreterConfig config; + #ifdef HAVE_DLOPEN int dlopenflags; #endif diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 3d6d400f74dd1d..6c9d3e4d456f4d 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -41,7 +41,7 @@ _Py_GetMainConfig(void) if (interp == NULL) { return NULL; } - return _PyInterpreterState_GetConfig(interp); + return _PyInterpreterState_GetGlobalConfig(interp); } diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 2c04ead45869fc..3f9f6e092ecc97 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -120,6 +120,7 @@ typedef struct pyruntimestate { struct _getargs_runtime_state getargs; PyPreConfig preconfig; + PyConfig config; // Audit values must be preserved when Py_Initialize()/Py_Finalize() // is called multiple times. diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index 621d5cc864255d..d8b2ddfaafa2f1 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -63,6 +63,11 @@ extern "C" { }, \ }, \ ._initial_thread = _PyThreadState_INIT, \ + .config = { \ + .allow_fork = 1, \ + .allow_subprocess = 1, \ + .allow_threading = 1, \ + }, \ } #define _PyThreadState_INIT \ diff --git a/Lib/test/_test_embed_set_config.py b/Lib/test/_test_embed_set_config.py index 7ff641b37bf188..0c016b5d75d734 100644 --- a/Lib/test/_test_embed_set_config.py +++ b/Lib/test/_test_embed_set_config.py @@ -84,7 +84,6 @@ def test_set_invalid(self): 'skip_source_first_line', '_install_importlib', '_init_main', - '_isolated_interpreter', ] if MS_WINDOWS: options.append('legacy_windows_stdio') diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 70d7367ea9e64f..afcbcc0f496109 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -495,7 +495,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'check_hash_pycs_mode': 'default', 'pathconfig_warnings': 1, '_init_main': 1, - '_isolated_interpreter': 0, 'use_frozen_modules': not support.Py_DEBUG, 'safe_path': 0, '_is_python_build': IGNORE_CONFIG, @@ -879,8 +878,6 @@ def test_init_from_config(self): 'check_hash_pycs_mode': 'always', 'pathconfig_warnings': 0, - - '_isolated_interpreter': 1, } self.check_all_configs("test_init_from_config", config, preconfig, api=API_COMPAT) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 38ef24637b7318..08bf345ead73c6 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -474,7 +474,7 @@ _io_text_encoding_impl(PyObject *module, PyObject *encoding, int stacklevel) { if (encoding == NULL || encoding == Py_None) { PyInterpreterState *interp = _PyInterpreterState_GET(); - if (_PyInterpreterState_GetConfig(interp)->warn_default_encoding) { + if (_PyInterpreterState_GetGlobalConfig(interp)->warn_default_encoding) { if (PyErr_WarnEx(PyExc_EncodingWarning, "'encoding' argument not specified", stacklevel)) { return NULL; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 3369694653fd96..d90f891736b5b5 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -979,7 +979,7 @@ io_check_errors(PyObject *errors) PyInterpreterState *interp = _PyInterpreterState_GET(); #ifndef Py_DEBUG /* In release mode, only check in development mode (-X dev) */ - if (!_PyInterpreterState_GetConfig(interp)->dev_mode) { + if (!_PyInterpreterState_GetGlobalConfig(interp)->dev_mode) { return 0; } #else @@ -1066,7 +1066,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, if (encoding == NULL) { PyInterpreterState *interp = _PyInterpreterState_GET(); - if (_PyInterpreterState_GetConfig(interp)->warn_default_encoding) { + if (_PyInterpreterState_GetGlobalConfig(interp)->warn_default_encoding) { if (PyErr_WarnEx(PyExc_EncodingWarning, "'encoding' argument not specified", 1)) { return -1; diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 44e60d7c14954d..769ad9edb001e2 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -842,8 +842,8 @@ subprocess_fork_exec(PyObject *module, PyObject *args) } PyInterpreterState *interp = PyInterpreterState_Get(); - const PyConfig *config = _PyInterpreterState_GetConfig(interp); - if (config->_isolated_interpreter) { + const _PyInterpreterConfig *config = _PyInterpreterState_GetConfig(interp); + if (!config->allow_subprocess) { PyErr_SetString(PyExc_RuntimeError, "subprocess not supported for isolated subinterpreters"); return NULL; diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 02a061b84f85a3..a2cc0c7131b157 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -21,7 +21,7 @@ #include "pycore_hashtable.h" // _Py_hashtable_new() #include "pycore_initconfig.h" // _Py_GetConfigsAsDict() #include "pycore_pathconfig.h" // _PyPathConfig_ClearGlobal() -#include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy() +#include "pycore_interp.h" // _Py_CopyConfig() #include "pycore_pyerrors.h" // _Py_UTF8_Edit_Cost() #include "pycore_pystate.h" // _PyThreadState_GET() #include "osdefs.h" // MAXPATHLEN @@ -252,7 +252,7 @@ test_get_config(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) { PyConfig config; PyConfig_InitIsolatedConfig(&config); - if (_PyInterpreterState_GetConfigCopy(&config) < 0) { + if (_Py_CopyConfig(&config) < 0) { PyConfig_Clear(&config); return NULL; } @@ -270,7 +270,7 @@ test_set_config(PyObject *Py_UNUSED(self), PyObject *dict) if (_PyConfig_FromDict(&config, dict) < 0) { goto error; } - if (_PyInterpreterState_SetConfig(&config) < 0) { + if (_Py_SetConfig(&config) < 0) { goto error; } PyConfig_Clear(&config); diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 4ac90dc8068934..eafdf0d0c49788 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1128,7 +1128,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) } PyInterpreterState *interp = _PyInterpreterState_GET(); - if (interp->config._isolated_interpreter) { + if (!_PyInterpreterState_GetConfig(interp)->allow_threading) { PyErr_SetString(PyExc_RuntimeError, "thread is not supported for isolated subinterpreters"); return NULL; diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 4845b4e6d4ad7c..443d2074a26572 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -1090,8 +1090,8 @@ _winapi_CreateProcess_impl(PyObject *module, } PyInterpreterState *interp = PyInterpreterState_Get(); - const PyConfig *config = _PyInterpreterState_GetConfig(interp); - if (config->_isolated_interpreter) { + const _PyInterpreterConfig *config = _PyInterpreterState_GetConfig(interp); + if (!config->allow_subprocess) { PyErr_SetString(PyExc_RuntimeError, "subprocess not supported for isolated subinterpreters"); return NULL; diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index f40601ad3a1a72..82a5704fb1372f 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -2001,10 +2001,13 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds) return NULL; } + // The struct is isolated by default. + const _PyInterpreterConfig config = (const _PyInterpreterConfig){}; + // Create and initialize the new interpreter. PyThreadState *save_tstate = _PyThreadState_GET(); // XXX Possible GILState issues? - PyThreadState *tstate = _Py_NewInterpreter(isolated); + PyThreadState *tstate = _Py_NewInterpreter(isolated ? &config : NULL); PyThreadState_Swap(save_tstate); if (tstate == NULL) { /* Since no new thread state was created, there is no exception to diff --git a/Modules/main.c b/Modules/main.c index aa523fc58d93fb..3b8ae68c704a01 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -552,7 +552,7 @@ pymain_run_python(int *exitcode) PyObject *main_importer_path = NULL; PyInterpreterState *interp = _PyInterpreterState_GET(); /* pymain_run_stdin() modify the config */ - PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp); + PyConfig *config = (PyConfig*)_PyInterpreterState_GetGlobalConfig(interp); /* ensure path config is written into global variables */ if (_PyStatus_EXCEPTION(_PyPathConfig_UpdateGlobal(config))) { diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 3810bc87c1fbab..1ada15ee80474f 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -6777,7 +6777,7 @@ os_fork_impl(PyObject *module) { pid_t pid; PyInterpreterState *interp = _PyInterpreterState_GET(); - if (interp->config._isolated_interpreter) { + if (!_PyInterpreterState_GetConfig(interp)->allow_fork) { PyErr_SetString(PyExc_RuntimeError, "fork not supported for isolated subinterpreters"); return NULL; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index bd169ed714212d..bc0570326a8f8b 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -436,7 +436,7 @@ unicode_check_encoding_errors(const char *encoding, const char *errors) PyInterpreterState *interp = _PyInterpreterState_GET(); #ifndef Py_DEBUG /* In release mode, only check in development mode (-X dev) */ - if (!_PyInterpreterState_GetConfig(interp)->dev_mode) { + if (!_PyInterpreterState_GetGlobalConfig(interp)->dev_mode) { return 0; } #else @@ -3324,7 +3324,7 @@ PyUnicode_EncodeFSDefault(PyObject *unicode) /* Before _PyUnicode_InitEncodings() is called, the Python codec machinery is not ready and so cannot be used: use wcstombs() in this case. */ - const PyConfig *config = _PyInterpreterState_GetConfig(interp); + const PyConfig *config = _PyInterpreterState_GetGlobalConfig(interp); const wchar_t *filesystem_errors = config->filesystem_errors; assert(filesystem_errors != NULL); _Py_error_handler errors = get_error_handler_wide(filesystem_errors); @@ -3562,7 +3562,7 @@ PyUnicode_DecodeFSDefaultAndSize(const char *s, Py_ssize_t size) /* Before _PyUnicode_InitEncodings() is called, the Python codec machinery is not ready and so cannot be used: use mbstowcs() in this case. */ - const PyConfig *config = _PyInterpreterState_GetConfig(interp); + const PyConfig *config = _PyInterpreterState_GetGlobalConfig(interp); const wchar_t *filesystem_errors = config->filesystem_errors; assert(filesystem_errors != NULL); _Py_error_handler errors = get_error_handler_wide(filesystem_errors); @@ -15026,7 +15026,7 @@ static PyStatus init_stdio_encoding(PyInterpreterState *interp) { /* Update the stdio encoding to the normalized Python codec name. */ - PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp); + PyConfig *config = (PyConfig*)_PyInterpreterState_GetGlobalConfig(interp); if (config_get_codec_name(&config->stdio_encoding) < 0) { return _PyStatus_ERR("failed to get the Python codec name " "of the stdio encoding"); @@ -15038,7 +15038,7 @@ init_stdio_encoding(PyInterpreterState *interp) static int init_fs_codec(PyInterpreterState *interp) { - const PyConfig *config = _PyInterpreterState_GetConfig(interp); + const PyConfig *config = _PyInterpreterState_GetGlobalConfig(interp); _Py_error_handler error_handler; error_handler = get_error_handler_wide(config->filesystem_errors); @@ -15097,7 +15097,7 @@ init_fs_encoding(PyThreadState *tstate) /* Update the filesystem encoding to the normalized Python codec name. For example, replace "ANSI_X3.4-1968" (locale encoding) with "ascii" (Python codec name). */ - PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp); + PyConfig *config = (PyConfig*)_PyInterpreterState_GetGlobalConfig(interp); if (config_get_codec_name(&config->filesystem_encoding) < 0) { _Py_DumpPathConfig(tstate); return _PyStatus_ERR("failed to get the Python codec " @@ -15140,7 +15140,7 @@ int _PyUnicode_EnableLegacyWindowsFSEncoding(void) { PyInterpreterState *interp = _PyInterpreterState_GET(); - PyConfig *config = (PyConfig *)_PyInterpreterState_GetConfig(interp); + PyConfig *config = (PyConfig *)_PyInterpreterState_GetGlobalConfig(interp); /* Set the filesystem encoding to mbcs/replace (PEP 529) */ wchar_t *encoding = _PyMem_RawWcsdup(L"mbcs"); diff --git a/Programs/_testembed.c b/Programs/_testembed.c index f84445690eb8f6..33c936ac51f93b 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -681,8 +681,6 @@ static int test_init_from_config(void) config.safe_path = 1; - config._isolated_interpreter = 1; - init_from_config_clear(&config); dump_config(); @@ -1651,7 +1649,7 @@ static int tune_config(void) { PyConfig config; PyConfig_InitPythonConfig(&config); - if (_PyInterpreterState_GetConfigCopy(&config) < 0) { + if (_Py_CopyConfig(&config) < 0) { PyConfig_Clear(&config); PyErr_Print(); return -1; @@ -1659,7 +1657,7 @@ static int tune_config(void) config.bytes_warning = 2; - if (_PyInterpreterState_SetConfig(&config) < 0) { + if (_Py_SetConfig(&config) < 0) { PyConfig_Clear(&config); return -1; } @@ -1678,7 +1676,7 @@ static int test_init_set_config(void) config.bytes_warning = 0; init_from_config_clear(&config); - // Tune the configuration using _PyInterpreterState_SetConfig() + // Tune the configuration using _Py_SetConfig() if (tune_config() < 0) { PyErr_Print(); return 1; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 6284bbdf97468e..8ae9e3de48e17e 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -3020,7 +3020,7 @@ _PyBuiltin_Init(PyInterpreterState *interp) { PyObject *mod, *dict, *debug; - const PyConfig *config = _PyInterpreterState_GetConfig(interp); + const PyConfig *config = _PyInterpreterState_GetGlobalConfig(interp); mod = _PyModule_CreateInitialized(&builtinsmodule, PYTHON_API_VERSION); if (mod == NULL) diff --git a/Python/dynload_win.c b/Python/dynload_win.c index c03bc5602bffee..c11045395bd2e0 100644 --- a/Python/dynload_win.c +++ b/Python/dynload_win.c @@ -204,7 +204,7 @@ _Py_CheckPython3(void) /* For back-compat, also search {sys.prefix}\DLLs, though that has not been a normal install layout for a while */ PyInterpreterState *interp = _PyInterpreterState_GET(); - PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp); + PyConfig *config = (PyConfig*)_PyInterpreterState_GetGlobalConfig(interp); assert(config->prefix); if (config->prefix) { wcscpy_s(py3path, MAXPATHLEN, config->prefix); diff --git a/Python/import.c b/Python/import.c index 54c21fa4a56aa9..356127e52a289c 100644 --- a/Python/import.c +++ b/Python/import.c @@ -58,7 +58,7 @@ _PyImportZip_Init(PyThreadState *tstate) goto error; } - int verbose = _PyInterpreterState_GetConfig(tstate->interp)->verbose; + int verbose = _PyInterpreterState_GetGlobalConfig(tstate->interp)->verbose; if (verbose) { PySys_WriteStderr("# installing zipimport hook\n"); } @@ -531,7 +531,7 @@ import_find_extension(PyThreadState *tstate, PyObject *name, return NULL; } - int verbose = _PyInterpreterState_GetConfig(tstate->interp)->verbose; + int verbose = _PyInterpreterState_GetGlobalConfig(tstate->interp)->verbose; if (verbose) { PySys_FormatStderr("import %U # previously loaded (%R)\n", name, filename); @@ -1064,7 +1064,7 @@ use_frozen(void) return false; } else { - return interp->config.use_frozen_modules; + return _PyInterpreterState_GetGlobalConfig(interp)->use_frozen_modules; } } @@ -1479,7 +1479,7 @@ remove_importlib_frames(PyThreadState *tstate) which end with a call to "_call_with_frames_removed". */ _PyErr_Fetch(tstate, &exception, &value, &base_tb); - if (!exception || _PyInterpreterState_GetConfig(tstate->interp)->verbose) { + if (!exception || _PyInterpreterState_GetGlobalConfig(tstate->interp)->verbose) { goto done; } @@ -1684,7 +1684,7 @@ import_find_and_load(PyThreadState *tstate, PyObject *abs_name) { PyObject *mod = NULL; PyInterpreterState *interp = tstate->interp; - int import_time = _PyInterpreterState_GetConfig(interp)->import_time; + int import_time = _PyInterpreterState_GetGlobalConfig(interp)->import_time; static int import_level; static _PyTime_t accumulated; diff --git a/Python/initconfig.c b/Python/initconfig.c index f18ec4068bc443..b69e9b12be33bc 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -779,7 +779,6 @@ _PyConfig_InitCompatConfig(PyConfig *config) config->check_hash_pycs_mode = NULL; config->pathconfig_warnings = -1; config->_init_main = 1; - config->_isolated_interpreter = 0; #ifdef MS_WINDOWS config->legacy_windows_stdio = -1; #endif @@ -1016,7 +1015,6 @@ _PyConfig_Copy(PyConfig *config, const PyConfig *config2) COPY_WSTR_ATTR(check_hash_pycs_mode); COPY_ATTR(pathconfig_warnings); COPY_ATTR(_init_main); - COPY_ATTR(_isolated_interpreter); COPY_ATTR(use_frozen_modules); COPY_ATTR(safe_path); COPY_WSTRLIST(orig_argv); @@ -1123,7 +1121,6 @@ _PyConfig_AsDict(const PyConfig *config) SET_ITEM_WSTR(check_hash_pycs_mode); SET_ITEM_INT(pathconfig_warnings); SET_ITEM_INT(_init_main); - SET_ITEM_INT(_isolated_interpreter); SET_ITEM_WSTRLIST(orig_argv); SET_ITEM_INT(use_frozen_modules); SET_ITEM_INT(safe_path); @@ -1411,7 +1408,6 @@ _PyConfig_FromDict(PyConfig *config, PyObject *dict) GET_UINT(_install_importlib); GET_UINT(_init_main); - GET_UINT(_isolated_interpreter); GET_UINT(use_frozen_modules); GET_UINT(safe_path); GET_UINT(_is_python_build); @@ -3066,7 +3062,7 @@ _Py_GetConfigsAsDict(void) Py_CLEAR(dict); /* core config */ - const PyConfig *config = _PyInterpreterState_GetConfig(interp); + const PyConfig *config = _PyInterpreterState_GetGlobalConfig(interp); dict = _PyConfig_AsDict(config); if (dict == NULL) { goto error; @@ -3133,7 +3129,7 @@ _Py_DumpPathConfig(PyThreadState *tstate) PySys_WriteStderr("\n"); \ } while (0) - const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp); + const PyConfig *config = _PyInterpreterState_GetGlobalConfig(tstate->interp); DUMP_CONFIG("PYTHONHOME", home); DUMP_CONFIG("PYTHONPATH", pythonpath_env); DUMP_CONFIG("program name", program_name); @@ -3182,3 +3178,22 @@ _Py_DumpPathConfig(PyThreadState *tstate) _PyErr_Restore(tstate, exc_type, exc_value, exc_tb); } + + +/* --- _PyInterpreterConfig ---------------------------------- */ + +void +_PyInterpreterConfig_Clear(_PyInterpreterConfig *config) +{ + *config = (_PyInterpreterConfig){}; +} + + +PyStatus +_PyInterpreterConfig_Copy(_PyInterpreterConfig *config, + const _PyInterpreterConfig *config2) +{ + *config = *config2; + + return _PyStatus_OK(); +} diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index c550f13bc14820..404b1a78e4d556 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -177,7 +177,7 @@ init_importlib(PyThreadState *tstate, PyObject *sysmod) assert(!_PyErr_Occurred(tstate)); PyInterpreterState *interp = tstate->interp; - int verbose = _PyInterpreterState_GetConfig(interp)->verbose; + int verbose = _PyInterpreterState_GetGlobalConfig(interp)->verbose; // Import _importlib through its frozen version, _frozen_importlib. if (verbose) { @@ -460,26 +460,28 @@ _Py_SetLocaleFromEnv(int category) static int -interpreter_update_config(PyThreadState *tstate, int only_update_path_config) +runtime_update_config(_PyRuntimeState *runtime, int only_update_path_config) { - const PyConfig *config = &tstate->interp->config; - if (!only_update_path_config) { - PyStatus status = _PyConfig_Write(config, tstate->interp->runtime); + PyStatus status = _PyConfig_Write(&runtime->config, 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; - } + PyStatus status = _PyPathConfig_UpdateGlobal(&runtime->config); + if (_PyStatus_EXCEPTION(status)) { + _PyErr_SetFromPyStatus(status); + return -1; } + return 0; +} + +static int +interpreter_update_config(PyThreadState *tstate) +{ // Update the sys module for the new configuration if (_PySys_UpdateConfig(tstate) < 0) { return -1; @@ -489,7 +491,7 @@ interpreter_update_config(PyThreadState *tstate, int only_update_path_config) int -_PyInterpreterState_SetConfig(const PyConfig *src_config) +_Py_SetConfig(const PyConfig *src_config) { PyThreadState *tstate = _PyThreadState_GET(); int res = -1; @@ -508,13 +510,20 @@ _PyInterpreterState_SetConfig(const PyConfig *src_config) goto done; } - status = _PyConfig_Copy(&tstate->interp->config, &config); + status = _PyConfig_Copy(&tstate->interp->runtime->config, &config); if (_PyStatus_EXCEPTION(status)) { _PyErr_SetFromPyStatus(status); goto done; } - res = interpreter_update_config(tstate, 0); + if (_Py_IsMainInterpreter(tstate->interp)) { + res = runtime_update_config(tstate->interp->runtime, 0); + if (res < 0) { + goto done; + } + } + + res = interpreter_update_config(tstate); done: PyConfig_Clear(&config); @@ -550,17 +559,19 @@ pyinit_core_reconfigure(_PyRuntimeState *runtime, if (interp == NULL) { return _PyStatus_ERR("can't make main interpreter"); } + assert(interp->runtime == runtime); + assert(_Py_IsMainInterpreter(interp)); status = _PyConfig_Write(config, runtime); if (_PyStatus_EXCEPTION(status)) { return status; } - status = _PyConfig_Copy(&interp->config, config); + status = _PyConfig_Copy(&runtime->config, config); if (_PyStatus_EXCEPTION(status)) { return status; } - config = _PyInterpreterState_GetConfig(interp); + config = _PyInterpreterState_GetGlobalConfig(interp); if (config->_install_importlib) { status = _PyPathConfig_UpdateGlobal(config); @@ -649,9 +660,10 @@ pycore_create_interpreter(_PyRuntimeState *runtime, if (interp == NULL) { return _PyStatus_ERR("can't make main interpreter"); } + assert(interp->runtime == runtime); assert(_Py_IsMainInterpreter(interp)); - status = _PyConfig_Copy(&interp->config, config); + status = _PyConfig_Copy(&runtime->config, config); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -863,7 +875,7 @@ pycore_interp_init(PyThreadState *tstate) goto done; } - const PyConfig *config = _PyInterpreterState_GetConfig(interp); + const PyConfig *config = _PyInterpreterState_GetGlobalConfig(interp); if (config->_install_importlib) { /* This call sets up builtin and frozen import support */ if (init_importlib(tstate, sysmod) < 0) { @@ -1079,7 +1091,12 @@ pyinit_core(_PyRuntimeState *runtime, static PyStatus pyinit_main_reconfigure(PyThreadState *tstate) { - if (interpreter_update_config(tstate, 0) < 0) { + if (_Py_IsMainInterpreter(tstate->interp)) { + if (runtime_update_config(tstate->interp->runtime, 0) < 0) { + return _PyStatus_ERR("fail to reconfigure Python"); + } + } + if (interpreter_update_config(tstate) < 0) { return _PyStatus_ERR("fail to reconfigure Python"); } return _PyStatus_OK(); @@ -1094,7 +1111,7 @@ init_interp_main(PyThreadState *tstate) PyStatus status; int is_main_interp = _Py_IsMainInterpreter(tstate->interp); PyInterpreterState *interp = tstate->interp; - const PyConfig *config = _PyInterpreterState_GetConfig(interp); + const PyConfig *config = _PyInterpreterState_GetGlobalConfig(interp); if (!config->_install_importlib) { /* Special mode for freeze_importlib: run with no import system @@ -1108,13 +1125,18 @@ init_interp_main(PyThreadState *tstate) return _PyStatus_OK(); } - // Initialize the import-related configuration. - status = _PyConfig_InitImportConfig(&interp->config); - if (_PyStatus_EXCEPTION(status)) { - return status; - } + if (is_main_interp) { + // Initialize the import-related configuration. + status = _PyConfig_InitImportConfig(&interp->runtime->config); + if (_PyStatus_EXCEPTION(status)) { + return status; + } - if (interpreter_update_config(tstate, 1) < 0) { + if (runtime_update_config(tstate->interp->runtime, 1) < 0) { + return _PyStatus_ERR("failed to update the Python config"); + } + } + if (interpreter_update_config(tstate) < 0) { return _PyStatus_ERR("failed to update the Python config"); } @@ -1257,7 +1279,7 @@ Py_InitializeFromConfig(const PyConfig *config) if (_PyStatus_EXCEPTION(status)) { return status; } - config = _PyInterpreterState_GetConfig(tstate->interp); + config = _PyInterpreterState_GetGlobalConfig(tstate->interp); if (config->_init_main) { status = pyinit_main(tstate); @@ -1530,7 +1552,7 @@ finalize_modules(PyThreadState *tstate) // Already done return; } - int verbose = _PyInterpreterState_GetConfig(interp)->verbose; + int verbose = _PyInterpreterState_GetGlobalConfig(interp)->verbose; // Delete some special builtins._ and sys attributes first. These are // common places where user values hide and people complain when their @@ -1787,14 +1809,14 @@ Py_FinalizeEx(void) /* 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; + int show_ref_count = runtime->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; + int dump_refs = runtime->config.dump_refs; + wchar_t *dump_refs_file = runtime->config.dump_refs_file; #endif #ifdef WITH_PYMALLOC - int malloc_stats = tstate->interp->config.malloc_stats; + int malloc_stats = runtime->config.malloc_stats; #endif /* Remaining daemon threads will automatically exit @@ -1959,7 +1981,7 @@ Py_Finalize(void) */ static PyStatus -new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter) +new_interpreter(PyThreadState **tstate_p, const _PyInterpreterConfig *config) { PyStatus status; @@ -1993,23 +2015,15 @@ new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter) PyThreadState *save_tstate = PyThreadState_Swap(tstate); /* Copy the current interpreter config into the new interpreter */ - const PyConfig *config; - if (save_tstate != NULL) { - config = _PyInterpreterState_GetConfig(save_tstate->interp); - } - else - { + if (config == NULL) { /* No current thread state, copy from the main interpreter */ PyInterpreterState *main_interp = _PyInterpreterState_Main(); config = _PyInterpreterState_GetConfig(main_interp); } - - - status = _PyConfig_Copy(&interp->config, config); + status = _PyInterpreterConfig_Copy(&interp->config, config); if (_PyStatus_EXCEPTION(status)) { goto error; } - interp->config._isolated_interpreter = isolated_subinterpreter; status = init_interp_create_gil(tstate); if (_PyStatus_EXCEPTION(status)) { @@ -2043,10 +2057,10 @@ new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter) } PyThreadState * -_Py_NewInterpreter(int isolated_subinterpreter) +_Py_NewInterpreter(const _PyInterpreterConfig *config) { PyThreadState *tstate = NULL; - PyStatus status = new_interpreter(&tstate, isolated_subinterpreter); + PyStatus status = new_interpreter(&tstate, config); if (_PyStatus_EXCEPTION(status)) { Py_ExitStatusException(status); } @@ -2057,7 +2071,7 @@ _Py_NewInterpreter(int isolated_subinterpreter) PyThreadState * Py_NewInterpreter(void) { - return _Py_NewInterpreter(0); + return _Py_NewInterpreter(NULL); } /* Delete an interpreter and its last thread. This requires that the @@ -2393,7 +2407,7 @@ init_sys_streams(PyThreadState *tstate) int fd; PyObject * encoding_attr; PyStatus res = _PyStatus_OK(); - const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp); + const PyConfig *config = _PyInterpreterState_GetGlobalConfig(tstate->interp); /* Check that stdin is not a directory Using shell redirection, you can redirect stdin to a directory, diff --git a/Python/pystate.c b/Python/pystate.c index a0d61d7ebb3be9..1ef3819b7d06d1 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -134,6 +134,8 @@ init_runtime(_PyRuntimeState *runtime, // Set it to the ID of the main thread of the main interpreter. runtime->main_thread = PyThread_get_thread_ident(); + PyConfig_InitPythonConfig(&runtime->config); + runtime->unicode_ids.next_index = unicode_next_index; runtime->unicode_ids.lock = unicode_ids_mutex; @@ -188,6 +190,8 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime) #undef FREE_LOCK PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + + PyConfig_Clear(&runtime->config); } #ifdef HAVE_FORK @@ -307,7 +311,6 @@ init_interpreter(PyInterpreterState *interp, _PyEval_InitState(&interp->ceval, pending_lock); _PyGC_InitState(&interp->gc); - PyConfig_InitPythonConfig(&interp->config); _PyType_InitCache(interp); interp->_initialized = 1; @@ -415,7 +418,6 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) Py_CLEAR(interp->audit_hooks); - PyConfig_Clear(&interp->config); Py_CLEAR(interp->codec_search_path); Py_CLEAR(interp->codec_search_cache); Py_CLEAR(interp->codec_error_registry); @@ -1017,7 +1019,7 @@ _PyInterpreterState_ClearModules(PyInterpreterState *interp) void PyThreadState_Clear(PyThreadState *tstate) { - int verbose = _PyInterpreterState_GetConfig(tstate->interp)->verbose; + int verbose = _PyInterpreterState_GetGlobalConfig(tstate->interp)->verbose; if (verbose && tstate->cframe->current_frame != NULL) { /* bpo-20526: After the main thread calls @@ -2139,19 +2141,26 @@ _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, } -const PyConfig* +const _PyInterpreterConfig* _PyInterpreterState_GetConfig(PyInterpreterState *interp) { return &interp->config; } +const PyConfig* +_PyInterpreterState_GetGlobalConfig(PyInterpreterState *interp) +{ + return &interp->runtime->config; +} + + int -_PyInterpreterState_GetConfigCopy(PyConfig *config) +_Py_CopyConfig(PyConfig *config) { PyInterpreterState *interp = PyInterpreterState_Get(); - PyStatus status = _PyConfig_Copy(config, &interp->config); + PyStatus status = _PyConfig_Copy(config, &interp->runtime->config); if (PyStatus_Exception(status)) { _PyErr_SetFromPyStatus(status); return -1; @@ -2166,7 +2175,7 @@ _Py_GetConfig(void) assert(PyGILState_Check()); PyThreadState *tstate = _PyThreadState_GET(); _Py_EnsureTstateNotNULL(tstate); - return _PyInterpreterState_GetConfig(tstate->interp); + return _PyInterpreterState_GetGlobalConfig(tstate->interp); } #define MINIMUM_OVERHEAD 1000 diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 653b5a55e885e5..209eddb2fbbfe1 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -330,7 +330,7 @@ _PySys_ClearAuditHooks(PyThreadState *ts) return; } - const PyConfig *config = _PyInterpreterState_GetConfig(ts->interp); + const PyConfig *config = _PyInterpreterState_GetGlobalConfig(ts->interp); if (config->verbose) { PySys_WriteStderr("# clear sys.audit hooks\n"); } @@ -854,7 +854,7 @@ sys_getfilesystemencoding_impl(PyObject *module) /*[clinic end generated code: output=1dc4bdbe9be44aa7 input=8475f8649b8c7d8c]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); - const PyConfig *config = _PyInterpreterState_GetConfig(interp); + const PyConfig *config = _PyInterpreterState_GetGlobalConfig(interp); return PyUnicode_FromWideChar(config->filesystem_encoding, -1); } @@ -869,7 +869,7 @@ sys_getfilesystemencodeerrors_impl(PyObject *module) /*[clinic end generated code: output=ba77b36bbf7c96f5 input=22a1e8365566f1e5]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); - const PyConfig *config = _PyInterpreterState_GetConfig(interp); + const PyConfig *config = _PyInterpreterState_GetGlobalConfig(interp); return PyUnicode_FromWideChar(config->filesystem_errors, -1); } @@ -2776,7 +2776,7 @@ static int set_flags_from_config(PyInterpreterState *interp, PyObject *flags) { const PyPreConfig *preconfig = &interp->runtime->preconfig; - const PyConfig *config = _PyInterpreterState_GetConfig(interp); + const PyConfig *config = _PyInterpreterState_GetGlobalConfig(interp); // _PySys_UpdateConfig() modifies sys.flags in-place: // Py_XDECREF() is needed in this case. @@ -3298,7 +3298,7 @@ _PySys_UpdateConfig(PyThreadState *tstate) { PyInterpreterState *interp = tstate->interp; PyObject *sysdict = interp->sysdict; - const PyConfig *config = _PyInterpreterState_GetConfig(interp); + const PyConfig *config = _PyInterpreterState_GetGlobalConfig(interp); int res; #define COPY_LIST(KEY, VALUE) \