gh-98608: Change _Py_NewInterpreter() to _Py_NewInterpreterFromConfig() (gh-98609)

(see https://github.com/python/cpython/issues/98608)

This change does the following:

1. change the argument to a new `_PyInterpreterConfig` struct
2. rename the function to `_Py_NewInterpreterFromConfig()`, inspired by `Py_InitializeFromConfig()` (takes a `_PyInterpreterConfig`  instead of `isolated_subinterpreter`)
3. split up the boolean `isolated_subinterpreter` into the corresponding multiple granular settings
   * allow_fork
   * allow_subprocess
   * allow_threads
4. add `PyInterpreterState.feature_flags` to store those settings
5. add a function for checking if a feature is enabled on an opaque `PyInterpreterState *`
6. drop `PyConfig._isolated_interpreter`

The existing default (see `Py_NewInterpeter()` and `Py_Initialize*()`) allows fork, subprocess, and threads and the optional "isolated" interpreter (see the `_xxsubinterpreters` module) disables all three.  None of that changes here; the defaults are preserved.

Note that the given `_PyInterpreterConfig` will not be used outside `_Py_NewInterpreterFromConfig()`, nor preserved.  This contrasts with how `PyConfig` is currently preserved, used, and even modified outside `Py_InitializeFromConfig()`.  I'd rather just avoid that mess from the start for `_PyInterpreterConfig`.  We can preserve it later if we find an actual need.

This change allows us to follow up with a number of improvements (e.g. stop disallowing subprocess and support disallowing exec instead).

(Note that this PR adds "private" symbols.  We'll probably make them public, and add docs, in a separate change.)
This commit is contained in:
Eric Snow 2022-10-26 11:16:30 -06:00 committed by GitHub
parent 24c56b4642
commit f32369480d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 295 additions and 39 deletions

View file

@ -550,6 +550,51 @@ _testinternalcapi_optimize_cfg_impl(PyObject *module, PyObject *instructions,
}
static PyObject *
get_interp_settings(PyObject *self, PyObject *args)
{
int interpid = -1;
if (!PyArg_ParseTuple(args, "|i:get_interp_settings", &interpid)) {
return NULL;
}
PyInterpreterState *interp = NULL;
if (interpid < 0) {
PyThreadState *tstate = _PyThreadState_GET();
interp = tstate ? tstate->interp : _PyInterpreterState_Main();
}
else if (interpid == 0) {
interp = _PyInterpreterState_Main();
}
else {
PyErr_Format(PyExc_NotImplementedError,
"%zd", interpid);
return NULL;
}
assert(interp != NULL);
PyObject *settings = PyDict_New();
if (settings == NULL) {
return NULL;
}
/* Add the feature flags. */
PyObject *flags = PyLong_FromUnsignedLong(interp->feature_flags);
if (flags == NULL) {
Py_DECREF(settings);
return NULL;
}
int res = PyDict_SetItemString(settings, "feature_flags", flags);
Py_DECREF(flags);
if (res != 0) {
Py_DECREF(settings);
return NULL;
}
return settings;
}
static PyMethodDef TestMethods[] = {
{"get_configs", get_configs, METH_NOARGS},
{"get_recursion_depth", get_recursion_depth, METH_NOARGS},
@ -569,6 +614,7 @@ static PyMethodDef TestMethods[] = {
{"set_eval_frame_default", set_eval_frame_default, METH_NOARGS, NULL},
{"set_eval_frame_record", set_eval_frame_record, METH_O, NULL},
_TESTINTERNALCAPI_OPTIMIZE_CFG_METHODDEF
{"get_interp_settings", get_interp_settings, METH_VARARGS, NULL},
{NULL, NULL} /* sentinel */
};