cpython/Python/crossinterp_exceptions.h
Eric Snow 62143736b6
gh-134939: Add the concurrent.interpreters Module (gh-133958)
PEP-734 has been accepted (for 3.14).

(FTR, I'm opposed to putting this under the concurrent package, but
doing so is the SC condition under which the module can land in 3.14.)
2025-06-11 17:35:48 -06:00

207 lines
6.0 KiB
C

static void
_ensure_current_cause(PyThreadState *tstate, PyObject *cause)
{
if (cause == NULL) {
return;
}
PyObject *exc = _PyErr_GetRaisedException(tstate);
assert(exc != NULL);
PyObject *ctx = PyException_GetContext(exc);
if (ctx == NULL) {
PyException_SetContext(exc, Py_NewRef(cause));
}
else {
Py_DECREF(ctx);
}
assert(PyException_GetCause(exc) == NULL);
PyException_SetCause(exc, Py_NewRef(cause));
_PyErr_SetRaisedException(tstate, exc);
}
/* InterpreterError extends Exception */
static PyTypeObject _PyExc_InterpreterError = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "concurrent.interpreters.InterpreterError",
.tp_doc = PyDoc_STR("A cross-interpreter operation failed"),
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
//.tp_traverse = ((PyTypeObject *)PyExc_Exception)->tp_traverse,
//.tp_clear = ((PyTypeObject *)PyExc_Exception)->tp_clear,
//.tp_base = (PyTypeObject *)PyExc_Exception,
};
PyObject *PyExc_InterpreterError = (PyObject *)&_PyExc_InterpreterError;
/* InterpreterNotFoundError extends InterpreterError */
static PyTypeObject _PyExc_InterpreterNotFoundError = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "concurrent.interpreters.InterpreterNotFoundError",
.tp_doc = PyDoc_STR("An interpreter was not found"),
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
//.tp_traverse = ((PyTypeObject *)PyExc_Exception)->tp_traverse,
//.tp_clear = ((PyTypeObject *)PyExc_Exception)->tp_clear,
.tp_base = &_PyExc_InterpreterError,
};
PyObject *PyExc_InterpreterNotFoundError = (PyObject *)&_PyExc_InterpreterNotFoundError;
/* NotShareableError extends TypeError */
static int
_init_notshareableerror(exceptions_t *state)
{
const char *name = "concurrent.interpreters.NotShareableError";
PyObject *base = PyExc_TypeError;
PyObject *ns = NULL;
PyObject *exctype = PyErr_NewException(name, base, ns);
if (exctype == NULL) {
return -1;
}
state->PyExc_NotShareableError = exctype;
return 0;
}
static void
_fini_notshareableerror(exceptions_t *state)
{
Py_CLEAR(state->PyExc_NotShareableError);
}
static PyObject *
get_notshareableerror_type(PyThreadState *tstate)
{
_PyXI_state_t *local = _PyXI_GET_STATE(tstate->interp);
if (local == NULL) {
PyErr_Clear();
return NULL;
}
return local->exceptions.PyExc_NotShareableError;
}
static void
_ensure_notshareableerror(PyThreadState *tstate,
PyObject *cause, int force, PyObject *msgobj)
{
PyObject *ctx = _PyErr_GetRaisedException(tstate);
PyObject *exctype = get_notshareableerror_type(tstate);
if (exctype != NULL) {
if (!force && ctx != NULL && Py_TYPE(ctx) == (PyTypeObject *)exctype) {
// A NotShareableError instance is already set.
assert(cause == NULL);
_PyErr_SetRaisedException(tstate, ctx);
}
}
else {
exctype = PyExc_TypeError;
}
_PyErr_SetObject(tstate, exctype, msgobj);
// We have to set the context manually since _PyErr_SetObject() doesn't.
_PyErr_ChainExceptions1Tstate(tstate, ctx);
_ensure_current_cause(tstate, cause);
}
static void
set_notshareableerror(PyThreadState *tstate, PyObject *cause, int force, const char *msg)
{
PyObject *msgobj = PyUnicode_FromString(msg);
if (msgobj == NULL) {
assert(_PyErr_Occurred(tstate));
}
else {
_ensure_notshareableerror(tstate, cause, force, msgobj);
Py_DECREF(msgobj);
}
}
static void
format_notshareableerror_v(PyThreadState *tstate, PyObject *cause, int force,
const char *format, va_list vargs)
{
PyObject *msgobj = PyUnicode_FromFormatV(format, vargs);
if (msgobj == NULL) {
assert(_PyErr_Occurred(tstate));
}
else {
_ensure_notshareableerror(tstate, cause, force, msgobj);
Py_DECREF(msgobj);
}
}
static void
format_notshareableerror(PyThreadState *tstate, PyObject *cause, int force,
const char *format, ...)
{
va_list vargs;
va_start(vargs, format);
format_notshareableerror_v(tstate, cause, force, format, vargs);
va_end(vargs);
}
/* lifecycle */
static int
init_static_exctypes(exceptions_t *state, PyInterpreterState *interp)
{
assert(state == &_PyXI_GET_STATE(interp)->exceptions);
PyTypeObject *base = (PyTypeObject *)PyExc_Exception;
// 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) {
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) {
goto error;
}
state->PyExc_InterpreterNotFoundError =
(PyObject *)&_PyExc_InterpreterNotFoundError;
return 0;
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)
{
if (_init_notshareableerror(state) < 0) {
goto error;
}
return 0;
error:
fini_heap_exctypes(state);
return -1;
}
static void
fini_heap_exctypes(exceptions_t *state)
{
_fini_notshareableerror(state);
}