Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-46964: Move PyInterpreterState.config to _PyRuntimeState.config #31771

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions Include/cpython/initconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

structs must be at least byte aligned, so this isn't strictly necessary.

} _PyInterpreterConfig;

/* --- Helper functions --------------------------------------- */

Expand Down
2 changes: 1 addition & 1 deletion Include/cpython/pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
21 changes: 11 additions & 10 deletions Include/cpython/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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.

Expand All @@ -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 */
Expand Down
5 changes: 5 additions & 0 deletions Include/internal/pycore_initconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ struct _is {
PyObject *codec_error_registry;
int codecs_initialized;

PyConfig config;
_PyInterpreterConfig config;

#ifdef HAVE_DLOPEN
int dlopenflags;
#endif
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ _Py_GetMainConfig(void)
if (interp == NULL) {
return NULL;
}
return _PyInterpreterState_GetConfig(interp);
return _PyInterpreterState_GetGlobalConfig(interp);
}


Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions Include/internal/pycore_runtime_init.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ extern "C" {
}, \
}, \
._initial_thread = _PyThreadState_INIT, \
.config = { \
.allow_fork = 1, \
.allow_subprocess = 1, \
.allow_threading = 1, \
}, \
}

#define _PyThreadState_INIT \
Expand Down
1 change: 0 additions & 1 deletion Lib/test/_test_embed_set_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
3 changes: 0 additions & 3 deletions Lib/test/test_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion Modules/_io/_iomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions Modules/_io/textio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions Modules/_posixsubprocess.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions Modules/_testinternalcapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion Modules/_threadmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions Modules/_winapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion Modules/_xxsubinterpretersmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Modules/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the cast?


/* ensure path config is written into global variables */
if (_PyStatus_EXCEPTION(_PyPathConfig_UpdateGlobal(config))) {
Expand Down
2 changes: 1 addition & 1 deletion Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
14 changes: 7 additions & 7 deletions Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the cast?

if (config_get_codec_name(&config->stdio_encoding) < 0) {
return _PyStatus_ERR("failed to get the Python codec name "
"of the stdio encoding");
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

if (config_get_codec_name(&config->filesystem_encoding) < 0) {
_Py_DumpPathConfig(tstate);
return _PyStatus_ERR("failed to get the Python codec "
Expand Down Expand Up @@ -15140,7 +15140,7 @@ int
_PyUnicode_EnableLegacyWindowsFSEncoding(void)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
PyConfig *config = (PyConfig *)_PyInterpreterState_GetConfig(interp);
PyConfig *config = (PyConfig *)_PyInterpreterState_GetGlobalConfig(interp);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto


/* Set the filesystem encoding to mbcs/replace (PEP 529) */
wchar_t *encoding = _PyMem_RawWcsdup(L"mbcs");
Expand Down
8 changes: 3 additions & 5 deletions Programs/_testembed.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -1651,15 +1649,15 @@ 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;
}

config.bytes_warning = 2;

if (_PyInterpreterState_SetConfig(&config) < 0) {
if (_Py_SetConfig(&config) < 0) {
PyConfig_Clear(&config);
return -1;
}
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion Python/bltinmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion Python/dynload_win.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading