Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Revert "Pass the interpreter config to init_interpreter()."
This reverts commit 3421a19.
  • Loading branch information
ericsnowcurrently committed Oct 22, 2024
commit b276454b1e92ca3f2917d06f17a461c59df243f7
1 change: 0 additions & 1 deletion Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,6 @@ extern int _PyInterpreterState_HasFeature(PyInterpreterState *interp,

PyAPI_FUNC(PyStatus) _PyInterpreterState_New(
PyThreadState *tstate,
const PyInterpreterConfig *config,
PyInterpreterState **pinterp);


Expand Down
96 changes: 80 additions & 16 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,62 @@ pycore_init_runtime(_PyRuntimeState *runtime,
}


static PyStatus
init_interp_settings(PyInterpreterState *interp,
const PyInterpreterConfig *config)
{
assert(interp->feature_flags == 0);

if (config->use_main_obmalloc) {
interp->feature_flags |= Py_RTFLAGS_USE_MAIN_OBMALLOC;
}
else if (!config->check_multi_interp_extensions) {
/* The reason: PyModuleDef.m_base.m_copy leaks objects between
interpreters. */
return _PyStatus_ERR("per-interpreter obmalloc does not support "
"single-phase init extension modules");
}
#ifdef Py_GIL_DISABLED
if (!_Py_IsMainInterpreter(interp) &&
!config->check_multi_interp_extensions)
{
return _PyStatus_ERR("The free-threaded build does not support "
"single-phase init extension modules in "
"subinterpreters");
}
#endif

if (config->allow_fork) {
interp->feature_flags |= Py_RTFLAGS_FORK;
}
if (config->allow_exec) {
interp->feature_flags |= Py_RTFLAGS_EXEC;
}
// Note that fork+exec is always allowed.

if (config->allow_threads) {
interp->feature_flags |= Py_RTFLAGS_THREADS;
}
if (config->allow_daemon_threads) {
interp->feature_flags |= Py_RTFLAGS_DAEMON_THREADS;
}

if (config->check_multi_interp_extensions) {
interp->feature_flags |= Py_RTFLAGS_MULTI_INTERP_EXTENSIONS;
}

switch (config->gil) {
case PyInterpreterConfig_DEFAULT_GIL: break;
case PyInterpreterConfig_SHARED_GIL: break;
case PyInterpreterConfig_OWN_GIL: break;
default:
return _PyStatus_ERR("invalid interpreter config 'gil' value");
}

return _PyStatus_OK();
}


static void
init_interp_create_gil(PyThreadState *tstate, int gil)
{
Expand Down Expand Up @@ -587,15 +643,8 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
PyThreadState **tstate_p)
{
PyStatus status;

PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
// The main interpreter always has its own GIL and supports single-phase
// init extensions.
config.gil = PyInterpreterConfig_OWN_GIL;
config.check_multi_interp_extensions = 0;

PyInterpreterState *interp;
status = _PyInterpreterState_New(NULL, &config, &interp);
status = _PyInterpreterState_New(NULL, &interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
Expand All @@ -615,6 +664,16 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
return status;
}

PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
// The main interpreter always has its own GIL and supports single-phase
// init extensions.
config.gil = PyInterpreterConfig_OWN_GIL;
config.check_multi_interp_extensions = 0;
status = init_interp_settings(interp, &config);
if (_PyStatus_EXCEPTION(status)) {
return status;
}

// initialize the interp->obmalloc state. This must be done after
// the settings are loaded (so that feature_flags are set) but before
// any calls are made to obmalloc functions.
Expand Down Expand Up @@ -2194,19 +2253,18 @@ new_interpreter(PyThreadState **tstate_p,
interpreters: disable PyGILState_Check(). */
runtime->gilstate.check_enabled = 0;

PyInterpreterState *interp = PyInterpreterState_New();
if (interp == NULL) {
*tstate_p = NULL;
return _PyStatus_OK();
}
_PyInterpreterState_SetWhence(interp, whence);
interp->_ready = 1;

// XXX Might new_interpreter() have been called without the GIL held?
PyThreadState *save_tstate = _PyThreadState_GET();
PyThreadState *tstate = NULL;

PyInterpreterState *interp;
status = _PyInterpreterState_New(save_tstate, config, &interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
_PyInterpreterState_SetWhence(interp, whence);
interp->_ready = 1;

/* From this point until the init_interp_create_gil() call,
we must not do anything that requires that the GIL be held
(or otherwise exist). That applies whether or not the new
Expand All @@ -2233,6 +2291,12 @@ new_interpreter(PyThreadState **tstate_p,
goto error;
}

/* This does not require that the GIL be held. */
status = init_interp_settings(interp, config);
if (_PyStatus_EXCEPTION(status)) {
goto error;
}

// initialize the interp->obmalloc state. This must be done after
// the settings are loaded (so that feature_flags are set) but before
// any calls are made to obmalloc functions.
Expand Down
77 changes: 5 additions & 72 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -581,66 +581,9 @@ free_interpreter(PyInterpreterState *interp)
PyMem_RawFree(interp);
}
}

static PyStatus
init_interp_settings(PyInterpreterState *interp,
const PyInterpreterConfig *config)
{
assert(interp->feature_flags == 0);

if (config->use_main_obmalloc) {
interp->feature_flags |= Py_RTFLAGS_USE_MAIN_OBMALLOC;
}
else if (!config->check_multi_interp_extensions) {
/* The reason: PyModuleDef.m_base.m_copy leaks objects between
interpreters. */
return _PyStatus_ERR("per-interpreter obmalloc does not support "
"single-phase init extension modules");
}
#ifdef Py_GIL_DISABLED
if (!_Py_IsMainInterpreter(interp) &&
!config->check_multi_interp_extensions)
{
return _PyStatus_ERR("The free-threaded build does not support "
"single-phase init extension modules in "
"subinterpreters");
}
#endif

if (config->allow_fork) {
interp->feature_flags |= Py_RTFLAGS_FORK;
}
if (config->allow_exec) {
interp->feature_flags |= Py_RTFLAGS_EXEC;
}
// Note that fork+exec is always allowed.

if (config->allow_threads) {
interp->feature_flags |= Py_RTFLAGS_THREADS;
}
if (config->allow_daemon_threads) {
interp->feature_flags |= Py_RTFLAGS_DAEMON_THREADS;
}

if (config->check_multi_interp_extensions) {
interp->feature_flags |= Py_RTFLAGS_MULTI_INTERP_EXTENSIONS;
}

switch (config->gil) {
case PyInterpreterConfig_DEFAULT_GIL: break;
case PyInterpreterConfig_SHARED_GIL: break;
case PyInterpreterConfig_OWN_GIL: break;
default:
return _PyStatus_ERR("invalid interpreter config 'gil' value");
}

return _PyStatus_OK();
}

#ifndef NDEBUG
static inline int check_interpreter_whence(long);
#endif

/* Get the interpreter state to a minimal consistent state.
Further init happens in pylifecycle.c before it can be used.
All fields not initialized here are expected to be zeroed out,
Expand All @@ -664,8 +607,7 @@ static PyStatus
init_interpreter(PyInterpreterState *interp,
_PyRuntimeState *runtime, int64_t id,
PyInterpreterState *next,
long whence,
const PyInterpreterConfig *config)
long whence)
{
if (interp->_initialized) {
return _PyStatus_ERR("interpreter already initialized");
Expand All @@ -687,15 +629,10 @@ init_interpreter(PyInterpreterState *interp,
assert(next != NULL || (interp == runtime->interpreters.main));
interp->next = next;

PyStatus status = init_interp_settings(interp, config);
if (_PyStatus_EXCEPTION(status)) {
return status;
}

// This relies on interp->feature_flags being set already,
// but currently we don't set that by this point.
// That's something to fix.
status = _PyObject_InitState(interp);
PyStatus status = _PyObject_InitState(interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
Expand Down Expand Up @@ -736,9 +673,7 @@ init_interpreter(PyInterpreterState *interp,


PyStatus
_PyInterpreterState_New(PyThreadState *tstate,
const PyInterpreterConfig *config,
PyInterpreterState **pinterp)
_PyInterpreterState_New(PyThreadState *tstate, PyInterpreterState **pinterp)
{
*pinterp = NULL;

Expand Down Expand Up @@ -800,7 +735,7 @@ _PyInterpreterState_New(PyThreadState *tstate,

long whence = _PyInterpreterState_WHENCE_UNKNOWN;
status = init_interpreter(interp, runtime,
id, old_head, whence, config);
id, old_head, whence);
if (_PyStatus_EXCEPTION(status)) {
goto error;
}
Expand All @@ -827,10 +762,8 @@ PyInterpreterState_New(void)
// tstate can be NULL
PyThreadState *tstate = current_fast_get();

const PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;

PyInterpreterState *interp;
PyStatus status = _PyInterpreterState_New(tstate, &config, &interp);
PyStatus status = _PyInterpreterState_New(tstate, &interp);
if (_PyStatus_EXCEPTION(status)) {
Py_ExitStatusException(status);
}
Expand Down