Skip to content

gh-76785: Minor Cleanup of Exception-related Cross-interpreter State #126602

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

Merged
Merged
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
10 changes: 8 additions & 2 deletions Include/internal/pycore_crossinterp.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ extern "C" {
#include "pycore_lock.h" // PyMutex
#include "pycore_pyerrors.h"


/**************/
/* exceptions */
/**************/
Expand Down Expand Up @@ -163,8 +164,13 @@ struct _xi_state {
// heap types
_PyXIData_lookup_t data_lookup;

// heap types
PyObject *PyExc_NotShareableError;
struct xi_exceptions {
// static types
PyObject *PyExc_InterpreterError;
PyObject *PyExc_InterpreterNotFoundError;
// heap types
PyObject *PyExc_NotShareableError;
} exceptions;
};

extern PyStatus _PyXI_Init(PyInterpreterState *interp);
Expand Down
2 changes: 1 addition & 1 deletion Modules/_interpretersmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1502,7 +1502,7 @@ module_exec(PyObject *mod)
goto error;
}
PyObject *PyExc_NotShareableError = \
_PyInterpreterState_GetXIState(interp)->PyExc_NotShareableError;
_PyInterpreterState_GetXIState(interp)->exceptions.PyExc_NotShareableError;
if (PyModule_AddType(mod, (PyTypeObject *)PyExc_NotShareableError) < 0) {
goto error;
}
Expand Down
36 changes: 23 additions & 13 deletions Python/crossinterp.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
/* exceptions */
/**************/

static int init_exceptions(PyInterpreterState *);
static void fini_exceptions(PyInterpreterState *);
static int _init_not_shareable_error_type(PyInterpreterState *);
static void _fini_not_shareable_error_type(PyInterpreterState *);
static PyObject * _get_not_shareable_error_type(PyInterpreterState *);
typedef struct xi_exceptions exceptions_t;
static int init_static_exctypes(exceptions_t *, PyInterpreterState *);
static void fini_static_exctypes(exceptions_t *, PyInterpreterState *);
static int init_heap_exctypes(exceptions_t *);
static void fini_heap_exctypes(exceptions_t *);
#include "crossinterp_exceptions.h"


Expand Down Expand Up @@ -205,7 +205,8 @@ static inline void
_set_xid_lookup_failure(PyInterpreterState *interp,
PyObject *obj, const char *msg)
{
PyObject *exctype = _get_not_shareable_error_type(interp);
exceptions_t *state = &_PyInterpreterState_GetXIState(interp)->exceptions;
PyObject *exctype = state->PyExc_NotShareableError;
assert(exctype != NULL);
if (msg != NULL) {
assert(obj == NULL);
Expand Down Expand Up @@ -1605,7 +1606,9 @@ _propagate_not_shareable_error(_PyXI_session *session)
return;
}
PyInterpreterState *interp = PyInterpreterState_Get();
if (PyErr_ExceptionMatches(_get_not_shareable_error_type(interp))) {
exceptions_t *state = &_PyInterpreterState_GetXIState(interp)->exceptions;
assert(state->PyExc_NotShareableError != NULL);
if (PyErr_ExceptionMatches(state->PyExc_NotShareableError)) {
// We want to propagate the exception directly.
session->_error_override = _PyXI_ERR_NOT_SHAREABLE;
session->error_override = &session->_error_override;
Expand Down Expand Up @@ -1782,9 +1785,11 @@ _PyXI_Init(PyInterpreterState *interp)
}
xid_lookup_init(&_PyXI_GET_STATE(interp)->data_lookup);

// Initialize exceptions (heap types).
if (_init_not_shareable_error_type(interp) < 0) {
return _PyStatus_ERR("failed to initialize NotShareableError");
// Initialize exceptions.(heap types).
// See _PyXI_InitTypes() for the static types.
if (init_heap_exctypes(&_PyXI_GET_STATE(interp)->exceptions) < 0) {
PyErr_PrintEx(0);
return _PyStatus_ERR("failed to initialize exceptions");
}

return _PyStatus_OK();
Expand All @@ -1797,7 +1802,8 @@ void
_PyXI_Fini(PyInterpreterState *interp)
{
// Finalize exceptions (heap types).
_fini_not_shareable_error_type(interp);
// See _PyXI_FiniTypes() for the static types.
fini_heap_exctypes(&_PyXI_GET_STATE(interp)->exceptions);

// Finalize the XID lookup state (e.g. registry).
xid_lookup_fini(&_PyXI_GET_STATE(interp)->data_lookup);
Expand All @@ -1809,17 +1815,21 @@ _PyXI_Fini(PyInterpreterState *interp)
PyStatus
_PyXI_InitTypes(PyInterpreterState *interp)
{
if (init_exceptions(interp) < 0) {
if (init_static_exctypes(&_PyXI_GET_STATE(interp)->exceptions, interp) < 0) {
PyErr_PrintEx(0);
return _PyStatus_ERR("failed to initialize an exception type");
}
// We would initialize heap types here too but that leads to ref leaks.
// Instead, we intialize them in _PyXI_Init().
return _PyStatus_OK();
}

void
_PyXI_FiniTypes(PyInterpreterState *interp)
{
fini_exceptions(interp);
// We would finalize heap types here too but that leads to ref leaks.
// Instead, we finalize them in _PyXI_Fini().
fini_static_exctypes(&_PyXI_GET_STATE(interp)->exceptions, interp);
}


Expand Down
91 changes: 49 additions & 42 deletions Python/crossinterp_exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,71 +25,78 @@ static PyTypeObject _PyExc_InterpreterNotFoundError = {
};
PyObject *PyExc_InterpreterNotFoundError = (PyObject *)&_PyExc_InterpreterNotFoundError;

/* NotShareableError extends ValueError */

static int
_init_not_shareable_error_type(PyInterpreterState *interp)
{
const char *name = "interpreters.NotShareableError";
PyObject *base = PyExc_ValueError;
PyObject *ns = NULL;
PyObject *exctype = PyErr_NewException(name, base, ns);
if (exctype == NULL) {
return -1;
}

_PyInterpreterState_GetXIState(interp)->PyExc_NotShareableError = exctype;
return 0;
}

static void
_fini_not_shareable_error_type(PyInterpreterState *interp)
{
Py_CLEAR(_PyInterpreterState_GetXIState(interp)->PyExc_NotShareableError);
}

static PyObject *
_get_not_shareable_error_type(PyInterpreterState *interp)
{
assert(_PyInterpreterState_GetXIState(interp)->PyExc_NotShareableError != NULL);
return _PyInterpreterState_GetXIState(interp)->PyExc_NotShareableError;
}


/* lifecycle */

static int
init_exceptions(PyInterpreterState *interp)
init_static_exctypes(exceptions_t *state, PyInterpreterState *interp)
{
assert(state == &_PyXI_GET_STATE(interp)->exceptions);
PyTypeObject *base = (PyTypeObject *)PyExc_Exception;

// builtin static types

// PyExc_InterpreterError
_PyExc_InterpreterError.tp_base = base;
_PyExc_InterpreterError.tp_traverse = base->tp_traverse;
_PyExc_InterpreterError.tp_clear = base->tp_clear;
if (_PyStaticType_InitBuiltin(interp, &_PyExc_InterpreterError) < 0) {
return -1;
goto error;
}
state->PyExc_InterpreterError = (PyObject *)&_PyExc_InterpreterError;

// PyExc_InterpreterNotFoundError
_PyExc_InterpreterNotFoundError.tp_traverse = base->tp_traverse;
_PyExc_InterpreterNotFoundError.tp_clear = base->tp_clear;
if (_PyStaticType_InitBuiltin(interp, &_PyExc_InterpreterNotFoundError) < 0) {
return -1;
goto error;
}
state->PyExc_InterpreterNotFoundError =
(PyObject *)&_PyExc_InterpreterNotFoundError;

// heap types
return 0;

// We would call _init_not_shareable_error_type() here too,
// but that leads to ref leaks
error:
fini_static_exctypes(state, interp);
return -1;
}

static void
fini_static_exctypes(exceptions_t *state, PyInterpreterState *interp)
{
assert(state == &_PyXI_GET_STATE(interp)->exceptions);
if (state->PyExc_InterpreterNotFoundError != NULL) {
state->PyExc_InterpreterNotFoundError = NULL;
_PyStaticType_FiniBuiltin(interp, &_PyExc_InterpreterNotFoundError);
}
if (state->PyExc_InterpreterError != NULL) {
state->PyExc_InterpreterError = NULL;
_PyStaticType_FiniBuiltin(interp, &_PyExc_InterpreterError);
}
}

static int
init_heap_exctypes(exceptions_t *state)
{
PyObject *exctype;

/* NotShareableError extends ValueError */
const char *name = "interpreters.NotShareableError";
PyObject *base = PyExc_ValueError;
PyObject *ns = NULL;
exctype = PyErr_NewException(name, base, ns);
if (exctype == NULL) {
goto error;
}
state->PyExc_NotShareableError = exctype;

return 0;

error:
fini_heap_exctypes(state);
return -1;
}

static void
fini_exceptions(PyInterpreterState *interp)
fini_heap_exctypes(exceptions_t *state)
{
// Likewise with _fini_not_shareable_error_type().
_PyStaticType_FiniBuiltin(interp, &_PyExc_InterpreterNotFoundError);
_PyStaticType_FiniBuiltin(interp, &_PyExc_InterpreterError);
Py_CLEAR(state->PyExc_NotShareableError);
}
Loading