cpython/Modules/_interpretersmodule.c

1684 lines
46 KiB
C
Raw Normal View History

/* interpreters module */
/* low-level access to interpreter primitives */
#ifndef Py_BUILD_CORE_BUILTIN
# define Py_BUILD_CORE_MODULE 1
#endif
#include "Python.h"
#include "pycore_code.h" // _PyCode_HAS_EXECUTORS()
#include "pycore_crossinterp.h" // _PyXIData_t
#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
#include "pycore_interp.h" // _PyInterpreterState_IDIncref()
#include "pycore_modsupport.h" // _PyArg_BadArgument()
#include "pycore_namespace.h" // _PyNamespace_New()
#include "pycore_pybuffer.h" // _PyBuffer_ReleaseInInterpreterAndRawFree()
#include "pycore_pylifecycle.h" // _PyInterpreterConfig_AsDict()
#include "pycore_pystate.h" // _PyInterpreterState_IsRunningMain()
#include "marshal.h" // PyMarshal_ReadObjectFromString()
#include "_interpreters_common.h"
#include "clinic/_interpretersmodule.c.h"
#define MODULE_NAME _interpreters
#define MODULE_NAME_STR Py_STRINGIFY(MODULE_NAME)
#define MODINIT_FUNC_NAME RESOLVE_MODINIT_FUNC_NAME(MODULE_NAME)
/*[clinic input]
module _interpreters
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=bfd967980a0de892]*/
static PyInterpreterState *
_get_current_interp(void)
{
// PyInterpreterState_Get() aborts if lookup fails, so don't need
// to check the result for NULL.
return PyInterpreterState_Get();
}
#define look_up_interp _PyInterpreterState_LookUpIDObject
static PyObject *
_get_current_module(void)
{
PyObject *name = PyUnicode_FromString(MODULE_NAME_STR);
if (name == NULL) {
return NULL;
}
PyObject *mod = PyImport_GetModule(name);
Py_DECREF(name);
if (mod == NULL) {
return NULL;
}
assert(mod != Py_None);
return mod;
}
static int
is_running_main(PyInterpreterState *interp)
{
if (_PyInterpreterState_IsRunningMain(interp)) {
return 1;
}
// Unlike with the general C-API, we can be confident that someone
// using this module for the main interpreter is doing so through
// the main program. Thus we can make this extra check. This benefits
// applications that embed Python but haven't been updated yet
// to call _PyInterpreterState_SetRunningMain().
if (_Py_IsMainInterpreter(interp)) {
return 1;
}
return 0;
}
static inline int
is_notshareable_raised(PyThreadState *tstate)
{
PyObject *exctype = _PyXIData_GetNotShareableErrorType(tstate);
return _PyErr_ExceptionMatches(tstate, exctype);
}
static void
unwrap_not_shareable(PyThreadState *tstate, _PyXI_failure *failure)
{
if (_PyXI_UnwrapNotShareableError(tstate, failure) < 0) {
_PyErr_Clear(tstate);
}
}
/* Cross-interpreter Buffer Views *******************************************/
/* When a memoryview object is "shared" between interpreters,
* its underlying "buffer" memory is actually shared, rather than just
* copied. This facilitates efficient use of that data where otherwise
* interpreters are strictly isolated. However, this also means that
* the underlying data is subject to the complexities of thread-safety,
* which the user must manage carefully.
*
* When the memoryview is "shared", it is essentially copied in the same
* way as PyMemory_FromObject() does, but in another interpreter.
* The Py_buffer value is copied like normal, including the "buf" pointer,
* with one key exception.
*
* When a Py_buffer is released and it holds a reference to an object,
* that object gets a chance to call its bf_releasebuffer() (if any)
* before the object is decref'ed. The same is true with the memoryview
* tp_dealloc, which essentially calls PyBuffer_Release().
*
* The problem for a Py_buffer shared between two interpreters is that
* the naive approach breaks interpreter isolation. Operations on an
* object must only happen while that object's interpreter is active.
* If the copied mv->view.obj pointed to the original memoryview then
* the PyBuffer_Release() would happen under the wrong interpreter.
*
* To work around this, we set mv->view.obj on the copied memoryview
* to a wrapper object with the only job of releasing the original
* buffer in a cross-interpreter-safe way.
*/
// XXX Note that there is still an issue to sort out, where the original
// interpreter is destroyed but code in another interpreter is still
// using dependent buffers. Using such buffers segfaults. This will
// require a careful fix. In the meantime, users will have to be
// diligent about avoiding the problematic situation.
typedef struct {
PyObject base;
Py_buffer *view;
int64_t interpid;
} xibufferview;
static PyObject *
xibufferview_from_buffer(PyTypeObject *cls, Py_buffer *view, int64_t interpid)
{
assert(interpid >= 0);
Py_buffer *copied = PyMem_RawMalloc(sizeof(Py_buffer));
if (copied == NULL) {
return NULL;
}
/* This steals the view->obj reference */
*copied = *view;
xibufferview *self = PyObject_Malloc(sizeof(xibufferview));
if (self == NULL) {
PyMem_RawFree(copied);
return NULL;
}
PyObject_Init(&self->base, cls);
*self = (xibufferview){
.base = self->base,
.view = copied,
.interpid = interpid,
};
return (PyObject *)self;
}
static void
xibufferview_dealloc(PyObject *op)
{
xibufferview *self = (xibufferview *)op;
if (self->view != NULL) {
PyInterpreterState *interp =
_PyInterpreterState_LookUpID(self->interpid);
if (interp == NULL) {
/* The interpreter is no longer alive. */
PyErr_Clear();
PyMem_RawFree(self->view);
}
else {
if (_PyBuffer_ReleaseInInterpreterAndRawFree(interp,
self->view) < 0)
{
// XXX Emit a warning?
PyErr_Clear();
}
}
}
PyTypeObject *tp = Py_TYPE(self);
tp->tp_free(self);
/* "Instances of heap-allocated types hold a reference to their type."
* See: https://docs.python.org/3.11/howto/isolating-extensions.html#garbage-collection-protocol
* See: https://docs.python.org/3.11/c-api/typeobj.html#c.PyTypeObject.tp_traverse
*/
// XXX Why don't we implement Py_TPFLAGS_HAVE_GC, e.g. Py_tp_traverse,
// like we do for _abc._abc_data?
Py_DECREF(tp);
}
static int
xibufferview_getbuf(PyObject *op, Py_buffer *view, int flags)
{
/* Only PyMemoryView_FromObject() should ever call this,
via _memoryview_from_xid() below. */
xibufferview *self = (xibufferview *)op;
*view = *self->view;
/* This is the workaround mentioned earlier. */
view->obj = op;
// XXX Should we leave it alone?
view->internal = NULL;
return 0;
}
static PyType_Slot XIBufferViewType_slots[] = {
{Py_tp_dealloc, xibufferview_dealloc},
{Py_bf_getbuffer, xibufferview_getbuf},
// We don't bother with Py_bf_releasebuffer since we don't need it.
{0, NULL},
};
static PyType_Spec XIBufferViewType_spec = {
.name = MODULE_NAME_STR ".CrossInterpreterBufferView",
.basicsize = sizeof(xibufferview),
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE),
.slots = XIBufferViewType_slots,
};
static PyTypeObject * _get_current_xibufferview_type(void);
struct xibuffer {
Py_buffer view;
int used;
};
static PyObject *
_memoryview_from_xid(_PyXIData_t *data)
{
assert(_PyXIData_DATA(data) != NULL);
assert(_PyXIData_OBJ(data) == NULL);
assert(_PyXIData_INTERPID(data) >= 0);
struct xibuffer *view = (struct xibuffer *)_PyXIData_DATA(data);
assert(!view->used);
PyTypeObject *cls = _get_current_xibufferview_type();
if (cls == NULL) {
return NULL;
}
PyObject *obj = xibufferview_from_buffer(
cls, &view->view, _PyXIData_INTERPID(data));
if (obj == NULL) {
return NULL;
}
PyObject *res = PyMemoryView_FromObject(obj);
if (res == NULL) {
Py_DECREF(obj);
return NULL;
}
view->used = 1;
return res;
}
static void
_pybuffer_shared_free(void* data)
{
struct xibuffer *view = (struct xibuffer *)data;
if (!view->used) {
PyBuffer_Release(&view->view);
}
PyMem_RawFree(data);
}
static int
_pybuffer_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
{
struct xibuffer *view = PyMem_RawMalloc(sizeof(struct xibuffer));
if (view == NULL) {
return -1;
}
view->used = 0;
/* This will increment the memoryview's export count, which won't get
* decremented until the view sent to other interpreters is released. */
if (PyObject_GetBuffer(obj, &view->view, PyBUF_FULL_RO) < 0) {
PyMem_RawFree(view);
return -1;
}
/* The view holds a reference to the object, so we don't worry
* about also tracking it on the cross-interpreter data. */
_PyXIData_Init(data, tstate->interp, view, NULL, _memoryview_from_xid);
data->free = _pybuffer_shared_free;
return 0;
}
static int
register_memoryview_xid(PyObject *mod, PyTypeObject **p_state)
{
// XIBufferView
assert(*p_state == NULL);
PyTypeObject *cls = (PyTypeObject *)PyType_FromModuleAndSpec(
mod, &XIBufferViewType_spec, NULL);
if (cls == NULL) {
return -1;
}
if (PyModule_AddType(mod, cls) < 0) {
Py_DECREF(cls);
return -1;
}
*p_state = cls;
// Register XID for the builtin memoryview type.
if (ensure_xid_class(&PyMemoryView_Type, GETDATA(_pybuffer_shared)) < 0) {
return -1;
}
// We don't ever bother un-registering memoryview.
return 0;
}
/* module state *************************************************************/
typedef struct {
int _notused;
/* heap types */
PyTypeObject *XIBufferViewType;
} module_state;
static inline module_state *
get_module_state(PyObject *mod)
{
assert(mod != NULL);
module_state *state = PyModule_GetState(mod);
assert(state != NULL);
return state;
}
static module_state *
_get_current_module_state(void)
{
PyObject *mod = _get_current_module();
if (mod == NULL) {
mod = PyImport_ImportModule(MODULE_NAME_STR);
if (mod == NULL) {
return NULL;
}
}
module_state *state = get_module_state(mod);
Py_DECREF(mod);
return state;
}
static int
traverse_module_state(module_state *state, visitproc visit, void *arg)
{
/* heap types */
Py_VISIT(state->XIBufferViewType);
return 0;
}
static int
clear_module_state(module_state *state)
{
/* heap types */
Py_CLEAR(state->XIBufferViewType);
return 0;
}
static PyTypeObject *
_get_current_xibufferview_type(void)
{
module_state *state = _get_current_module_state();
if (state == NULL) {
return NULL;
}
return state->XIBufferViewType;
}
/* interpreter-specific code ************************************************/
static int
init_named_config(PyInterpreterConfig *config, const char *name)
{
if (name == NULL
|| strcmp(name, "") == 0
|| strcmp(name, "default") == 0)
{
name = "isolated";
}
if (strcmp(name, "isolated") == 0) {
*config = (PyInterpreterConfig)_PyInterpreterConfig_INIT;
}
else if (strcmp(name, "legacy") == 0) {
*config = (PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT;
}
else if (strcmp(name, "empty") == 0) {
*config = (PyInterpreterConfig){0};
}
else {
PyErr_Format(PyExc_ValueError,
"unsupported config name '%s'", name);
return -1;
}
return 0;
}
static int
config_from_object(PyObject *configobj, PyInterpreterConfig *config)
{
if (configobj == NULL || configobj == Py_None) {
if (init_named_config(config, NULL) < 0) {
return -1;
}
}
else if (PyUnicode_Check(configobj)) {
const char *utf8name = PyUnicode_AsUTF8(configobj);
if (utf8name == NULL) {
return -1;
}
if (init_named_config(config, utf8name) < 0) {
return -1;
}
}
else {
PyObject *dict = PyObject_GetAttrString(configobj, "__dict__");
if (dict == NULL) {
PyErr_Format(PyExc_TypeError, "bad config %R", configobj);
return -1;
}
int res = _PyInterpreterConfig_InitFromDict(config, dict);
Py_DECREF(dict);
if (res < 0) {
return -1;
}
}
return 0;
}
struct interp_call {
_PyXIData_t *func;
_PyXIData_t *args;
_PyXIData_t *kwargs;
struct {
_PyXIData_t func;
_PyXIData_t args;
_PyXIData_t kwargs;
} _preallocated;
};
static void
_interp_call_clear(struct interp_call *call)
{
if (call->func != NULL) {
_PyXIData_Clear(NULL, call->func);
}
if (call->args != NULL) {
_PyXIData_Clear(NULL, call->args);
}
if (call->kwargs != NULL) {
_PyXIData_Clear(NULL, call->kwargs);
}
*call = (struct interp_call){0};
}
static int
_interp_call_pack(PyThreadState *tstate, struct interp_call *call,
PyObject *func, PyObject *args, PyObject *kwargs)
{
xidata_fallback_t fallback = _PyXIDATA_FULL_FALLBACK;
assert(call->func == NULL);
assert(call->args == NULL);
assert(call->kwargs == NULL);
// Handle the func.
if (!PyCallable_Check(func)) {
_PyErr_Format(tstate, PyExc_TypeError,
"expected a callable, got %R", func);
return -1;
}
if (_PyFunction_GetXIData(tstate, func, &call->_preallocated.func) < 0) {
PyObject *exc = _PyErr_GetRaisedException(tstate);
if (_PyPickle_GetXIData(tstate, func, &call->_preallocated.func) < 0) {
_PyErr_SetRaisedException(tstate, exc);
return -1;
}
Py_DECREF(exc);
}
call->func = &call->_preallocated.func;
// Handle the args.
if (args == NULL || args == Py_None) {
// Leave it empty.
}
else {
assert(PyTuple_Check(args));
if (PyTuple_GET_SIZE(args) > 0) {
if (_PyObject_GetXIData(
tstate, args, fallback, &call->_preallocated.args) < 0)
{
_interp_call_clear(call);
return -1;
}
call->args = &call->_preallocated.args;
}
}
// Handle the kwargs.
if (kwargs == NULL || kwargs == Py_None) {
// Leave it empty.
}
else {
assert(PyDict_Check(kwargs));
if (PyDict_GET_SIZE(kwargs) > 0) {
if (_PyObject_GetXIData(
tstate, kwargs, fallback, &call->_preallocated.kwargs) < 0)
{
_interp_call_clear(call);
return -1;
}
call->kwargs = &call->_preallocated.kwargs;
}
}
return 0;
}
static void
wrap_notshareable(PyThreadState *tstate, const char *label)
{
if (!is_notshareable_raised(tstate)) {
return;
}
assert(label != NULL && strlen(label) > 0);
PyObject *cause = _PyErr_GetRaisedException(tstate);
_PyXIData_FormatNotShareableError(tstate, "%s not shareable", label);
PyObject *exc = _PyErr_GetRaisedException(tstate);
PyException_SetCause(exc, cause);
_PyErr_SetRaisedException(tstate, exc);
}
static int
_interp_call_unpack(struct interp_call *call,
PyObject **p_func, PyObject **p_args, PyObject **p_kwargs)
{
PyThreadState *tstate = PyThreadState_Get();
// Unpack the func.
PyObject *func = _PyXIData_NewObject(call->func);
if (func == NULL) {
wrap_notshareable(tstate, "func");
return -1;
}
// Unpack the args.
PyObject *args;
if (call->args == NULL) {
args = PyTuple_New(0);
if (args == NULL) {
Py_DECREF(func);
return -1;
}
}
else {
args = _PyXIData_NewObject(call->args);
if (args == NULL) {
wrap_notshareable(tstate, "args");
Py_DECREF(func);
return -1;
}
assert(PyTuple_Check(args));
}
// Unpack the kwargs.
PyObject *kwargs = NULL;
if (call->kwargs != NULL) {
kwargs = _PyXIData_NewObject(call->kwargs);
if (kwargs == NULL) {
wrap_notshareable(tstate, "kwargs");
Py_DECREF(func);
Py_DECREF(args);
return -1;
}
assert(PyDict_Check(kwargs));
}
*p_func = func;
*p_args = args;
*p_kwargs = kwargs;
return 0;
}
static int
_make_call(struct interp_call *call,
PyObject **p_result, _PyXI_failure *failure)
{
assert(call != NULL && call->func != NULL);
PyThreadState *tstate = _PyThreadState_GET();
// Get the func and args.
PyObject *func = NULL, *args = NULL, *kwargs = NULL;
if (_interp_call_unpack(call, &func, &args, &kwargs) < 0) {
assert(func == NULL);
assert(args == NULL);
assert(kwargs == NULL);
_PyXI_InitFailure(failure, _PyXI_ERR_OTHER, NULL);
unwrap_not_shareable(tstate, failure);
return -1;
}
assert(!_PyErr_Occurred(tstate));
// Make the call.
PyObject *resobj = PyObject_Call(func, args, kwargs);
Py_DECREF(func);
Py_XDECREF(args);
Py_XDECREF(kwargs);
if (resobj == NULL) {
return -1;
}
*p_result = resobj;
return 0;
}
static int
_run_script(_PyXIData_t *script, PyObject *ns, _PyXI_failure *failure)
{
PyObject *code = _PyXIData_NewObject(script);
if (code == NULL) {
_PyXI_InitFailure(failure, _PyXI_ERR_NOT_SHAREABLE, NULL);
return -1;
}
PyObject *result = PyEval_EvalCode(code, ns, ns);
Py_DECREF(code);
if (result == NULL) {
_PyXI_InitFailure(failure, _PyXI_ERR_UNCAUGHT_EXCEPTION, NULL);
return -1;
}
assert(result == Py_None);
Py_DECREF(result); // We throw away the result.
return 0;
}
struct run_result {
PyObject *result;
PyObject *excinfo;
};
static void
_run_result_clear(struct run_result *runres)
{
Py_CLEAR(runres->result);
Py_CLEAR(runres->excinfo);
}
static int
_run_in_interpreter(PyThreadState *tstate, PyInterpreterState *interp,
_PyXIData_t *script, struct interp_call *call,
PyObject *shareables, struct run_result *runres)
{
assert(!_PyErr_Occurred(tstate));
int res = -1;
_PyXI_failure *failure = _PyXI_NewFailure();
if (failure == NULL) {
return -1;
}
_PyXI_session *session = _PyXI_NewSession();
if (session == NULL) {
_PyXI_FreeFailure(failure);
return -1;
}
_PyXI_session_result result = {0};
// Prep and switch interpreters.
if (_PyXI_Enter(session, interp, shareables, &result) < 0) {
// If an error occurred at this step, it means that interp
// was not prepared and switched.
_PyXI_FreeSession(session);
_PyXI_FreeFailure(failure);
assert(result.excinfo == NULL);
return -1;
}
// Run in the interpreter.
if (script != NULL) {
assert(call == NULL);
PyObject *mainns = _PyXI_GetMainNamespace(session, failure);
if (mainns == NULL) {
goto finally;
}
res = _run_script(script, mainns, failure);
}
else {
assert(call != NULL);
PyObject *resobj;
res = _make_call(call, &resobj, failure);
if (res == 0) {
res = _PyXI_Preserve(session, "resobj", resobj, failure);
Py_DECREF(resobj);
if (res < 0) {
goto finally;
}
}
}
finally:
// Clean up and switch back.
(void)res;
int exitres = _PyXI_Exit(session, failure, &result);
assert(res == 0 || exitres != 0);
_PyXI_FreeSession(session);
_PyXI_FreeFailure(failure);
res = exitres;
if (_PyErr_Occurred(tstate)) {
// It's a directly propagated exception.
assert(res < 0);
}
else if (res < 0) {
assert(result.excinfo != NULL);
runres->excinfo = Py_NewRef(result.excinfo);
res = -1;
}
else {
assert(result.excinfo == NULL);
runres->result = _PyXI_GetPreserved(&result, "resobj");
if (_PyErr_Occurred(tstate)) {
res = -1;
}
}
_PyXI_ClearResult(&result);
return res;
}
/* module level code ********************************************************/
static long
get_whence(PyInterpreterState *interp)
{
return _PyInterpreterState_GetWhence(interp);
}
static PyInterpreterState *
resolve_interp(PyObject *idobj, int restricted, int reqready, const char *op)
{
PyInterpreterState *interp;
if (idobj == NULL) {
interp = PyInterpreterState_Get();
}
else {
interp = look_up_interp(idobj);
if (interp == NULL) {
return NULL;
}
}
if (reqready && !_PyInterpreterState_IsReady(interp)) {
if (idobj == NULL) {
PyErr_Format(PyExc_InterpreterError,
"cannot %s current interpreter (not ready)", op);
}
else {
PyErr_Format(PyExc_InterpreterError,
"cannot %s interpreter %R (not ready)", op, idobj);
}
return NULL;
}
if (restricted && get_whence(interp) != _PyInterpreterState_WHENCE_STDLIB) {
if (idobj == NULL) {
PyErr_Format(PyExc_InterpreterError,
"cannot %s unrecognized current interpreter", op);
}
else {
PyErr_Format(PyExc_InterpreterError,
"cannot %s unrecognized interpreter %R", op, idobj);
}
return NULL;
}
return interp;
}
static PyObject *
get_summary(PyInterpreterState *interp)
{
PyObject *idobj = _PyInterpreterState_GetIDObject(interp);
if (idobj == NULL) {
return NULL;
}
PyObject *whenceobj = PyLong_FromLong(
get_whence(interp));
if (whenceobj == NULL) {
Py_DECREF(idobj);
return NULL;
}
PyObject *res = PyTuple_Pack(2, idobj, whenceobj);
Py_DECREF(idobj);
Py_DECREF(whenceobj);
return res;
}
// Not converted to Argument Clinic because the function uses ``**kwargs``.
static PyObject *
interp_new_config(PyObject *self, PyObject *args, PyObject *kwds)
{
const char *name = NULL;
if (!PyArg_ParseTuple(args, "|s:" MODULE_NAME_STR ".new_config", &name))
{
return NULL;
}
PyObject *overrides = kwds;
PyInterpreterConfig config;
if (init_named_config(&config, name) < 0) {
return NULL;
}
if (overrides != NULL && PyDict_GET_SIZE(overrides) > 0) {
if (_PyInterpreterConfig_UpdateFromDict(&config, overrides) < 0) {
return NULL;
}
}
PyObject *dict = _PyInterpreterConfig_AsDict(&config);
if (dict == NULL) {
return NULL;
}
PyObject *configobj = _PyNamespace_New(dict);
Py_DECREF(dict);
return configobj;
}
PyDoc_STRVAR(new_config_doc,
"new_config($module, name='isolated', /, **overrides)\n\
--\n\
\n\
Return a representation of a new PyInterpreterConfig.\n\
\n\
The name determines the initial values of the config. Supported named\n\
configs are: default, isolated, legacy, and empty.\n\
\n\
Any keyword arguments are set on the corresponding config fields,\n\
overriding the initial values.");
/*[clinic input]
_interpreters.create
config as configobj: object(py_default="'isolated'") = NULL
*
reqrefs: bool = False
Create a new interpreter and return a unique generated ID.
The caller is responsible for destroying the interpreter before exiting,
typically by using _interpreters.destroy(). This can be managed
automatically by passing "reqrefs=True" and then using _incref() and
_decref() appropriately.
"config" must be a valid interpreter config or the name of a
predefined config ('isolated' or 'legacy'). The default
is 'isolated'.
[clinic start generated code]*/
static PyObject *
_interpreters_create_impl(PyObject *module, PyObject *configobj, int reqrefs)
/*[clinic end generated code: output=c1cc6835b1277c16 input=235ce396a23624d5]*/
{
PyInterpreterConfig config;
if (config_from_object(configobj, &config) < 0) {
return NULL;
}
long whence = _PyInterpreterState_WHENCE_STDLIB;
PyInterpreterState *interp = \
_PyXI_NewInterpreter(&config, &whence, NULL, NULL);
if (interp == NULL) {
// XXX Move the chained exception to interpreters.create()?
PyObject *exc = PyErr_GetRaisedException();
assert(exc != NULL);
PyErr_SetString(PyExc_InterpreterError, "interpreter creation failed");
_PyErr_ChainExceptions1(exc);
return NULL;
}
assert(_PyInterpreterState_IsReady(interp));
PyObject *idobj = _PyInterpreterState_GetIDObject(interp);
if (idobj == NULL) {
_PyXI_EndInterpreter(interp, NULL, NULL);
return NULL;
}
if (reqrefs) {
// Decref to 0 will destroy the interpreter.
_PyInterpreterState_RequireIDRef(interp, 1);
}
return idobj;
}
/*[clinic input]
_interpreters.destroy
id: object
*
restrict as restricted: bool = False
Destroy the identified interpreter.
Attempting to destroy the current interpreter raises InterpreterError.
So does an unrecognized ID.
[clinic start generated code]*/
static PyObject *
_interpreters_destroy_impl(PyObject *module, PyObject *id, int restricted)
/*[clinic end generated code: output=0bc20da8700ab4dd input=561bdd6537639d40]*/
{
// Look up the interpreter.
int reqready = 0;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "destroy");
if (interp == NULL) {
return NULL;
}
// Ensure we don't try to destroy the current interpreter.
PyInterpreterState *current = _get_current_interp();
if (current == NULL) {
return NULL;
}
if (interp == current) {
PyErr_SetString(PyExc_InterpreterError,
"cannot destroy the current interpreter");
return NULL;
}
// Ensure the interpreter isn't running.
/* XXX We *could* support destroying a running interpreter but
aren't going to worry about it for now. */
if (is_running_main(interp)) {
PyErr_Format(PyExc_InterpreterError, "interpreter running");
return NULL;
}
// Destroy the interpreter.
_PyXI_EndInterpreter(interp, NULL, NULL);
Py_RETURN_NONE;
}
/*[clinic input]
_interpreters.list_all
*
require_ready as reqready: bool = False
Return a list containing the ID of every existing interpreter.
[clinic start generated code]*/
static PyObject *
_interpreters_list_all_impl(PyObject *module, int reqready)
/*[clinic end generated code: output=3f21c1a7c78043c0 input=35bae91c381a2cf9]*/
{
PyObject *ids = PyList_New(0);
if (ids == NULL) {
return NULL;
}
PyInterpreterState *interp = PyInterpreterState_Head();
while (interp != NULL) {
if (!reqready || _PyInterpreterState_IsReady(interp)) {
PyObject *item = get_summary(interp);
if (item == NULL) {
Py_DECREF(ids);
return NULL;
}
// insert at front of list
int res = PyList_Insert(ids, 0, item);
Py_DECREF(item);
if (res < 0) {
Py_DECREF(ids);
return NULL;
}
}
interp = PyInterpreterState_Next(interp);
}
return ids;
}
/*[clinic input]
_interpreters.get_current
Return (ID, whence) of the current interpreter.
[clinic start generated code]*/
static PyObject *
_interpreters_get_current_impl(PyObject *module)
/*[clinic end generated code: output=03161c8fcc0136eb input=37fb2c067c14d543]*/
{
PyInterpreterState *interp =_get_current_interp();
if (interp == NULL) {
return NULL;
}
assert(_PyInterpreterState_IsReady(interp));
return get_summary(interp);
}
/*[clinic input]
_interpreters.get_main
Return (ID, whence) of the main interpreter.
[clinic start generated code]*/
static PyObject *
_interpreters_get_main_impl(PyObject *module)
/*[clinic end generated code: output=9647288aff735557 input=b4ace23ca562146f]*/
{
PyInterpreterState *interp = _PyInterpreterState_Main();
assert(_PyInterpreterState_IsReady(interp));
return get_summary(interp);
}
/*[clinic input]
_interpreters.set___main___attrs
id: object
updates: object(subclass_of='&PyDict_Type')
*
restrict as restricted: bool = False
Bind the given attributes in the interpreter's __main__ module.
[clinic start generated code]*/
static PyObject *
_interpreters_set___main___attrs_impl(PyObject *module, PyObject *id,
PyObject *updates, int restricted)
/*[clinic end generated code: output=f3803010cb452bf0 input=d16ab8d81371f86a]*/
{
// Look up the interpreter.
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "update __main__ for");
if (interp == NULL) {
return NULL;
}
// Check the updates.
Py_ssize_t size = PyDict_Size(updates);
if (size < 0) {
return NULL;
}
if (size == 0) {
PyErr_SetString(PyExc_ValueError,
"arg 2 must be a non-empty dict");
return NULL;
}
_PyXI_session *session = _PyXI_NewSession();
if (session == NULL) {
return NULL;
}
// Prep and switch interpreters, including apply the updates.
if (_PyXI_Enter(session, interp, updates, NULL) < 0) {
_PyXI_FreeSession(session);
return NULL;
}
// Clean up and switch back.
assert(!PyErr_Occurred());
int res = _PyXI_Exit(session, NULL, NULL);
_PyXI_FreeSession(session);
assert(res == 0);
if (res < 0) {
// unreachable
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_RuntimeError, "unresolved error");
}
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
_handle_script_error(struct run_result *runres)
{
assert(runres->result == NULL);
if (runres->excinfo == NULL) {
assert(PyErr_Occurred());
return NULL;
}
assert(!PyErr_Occurred());
return runres->excinfo;
}
/*[clinic input]
_interpreters.exec
id: object
code: object
shared: object(subclass_of='&PyDict_Type', c_default='NULL') = {}
*
restrict as restricted: bool = False
Execute the provided code in the identified interpreter.
This is equivalent to running the builtin exec() under the target
interpreter, using the __dict__ of its __main__ module as both
globals and locals.
"code" may be a string containing the text of a Python script.
Functions (and code objects) are also supported, with some restrictions.
The code/function must not take any arguments or be a closure
(i.e. have cell vars). Methods and other callables are not supported.
If a function is provided, its code object is used and all its state
is ignored, including its __globals__ dict.
[clinic start generated code]*/
static PyObject *
_interpreters_exec_impl(PyObject *module, PyObject *id, PyObject *code,
PyObject *shared, int restricted)
/*[clinic end generated code: output=492057c4f10dc304 input=5a22c1ed0c5dbcf3]*/
{
PyThreadState *tstate = _PyThreadState_GET();
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "exec code for");
if (interp == NULL) {
return NULL;
}
// We don't need the script to be "pure", which means it can use
// global variables. They will be resolved against __main__.
_PyXIData_t xidata = {0};
if (_PyCode_GetScriptXIData(tstate, code, &xidata) < 0) {
unwrap_not_shareable(tstate, NULL);
return NULL;
}
struct run_result runres = {0};
int res = _run_in_interpreter(
tstate, interp, &xidata, NULL, shared, &runres);
_PyXIData_Release(&xidata);
if (res < 0) {
return _handle_script_error(&runres);
}
assert(runres.result == NULL);
Py_RETURN_NONE;
}
/*[clinic input]
_interpreters.run_string
id: object
script: unicode
shared: object(subclass_of='&PyDict_Type', c_default='NULL') = {}
*
restrict as restricted: bool = False
Execute the provided string in the identified interpreter.
(See _interpreters.exec().)
[clinic start generated code]*/
static PyObject *
_interpreters_run_string_impl(PyObject *module, PyObject *id,
PyObject *script, PyObject *shared,
int restricted)
/*[clinic end generated code: output=a30a64fb9ad396a2 input=51ce549b9a8dbe21]*/
{
#define FUNCNAME MODULE_NAME_STR ".run_string"
PyThreadState *tstate = _PyThreadState_GET();
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "run a string in");
if (interp == NULL) {
return NULL;
}
if (PyFunction_Check(script) || PyCode_Check(script)) {
_PyArg_BadArgument(FUNCNAME, "argument 2", "a string", script);
return NULL;
}
_PyXIData_t xidata = {0};
if (_PyCode_GetScriptXIData(tstate, script, &xidata) < 0) {
unwrap_not_shareable(tstate, NULL);
return NULL;
}
struct run_result runres = {0};
int res = _run_in_interpreter(
tstate, interp, &xidata, NULL, shared, &runres);
_PyXIData_Release(&xidata);
if (res < 0) {
return _handle_script_error(&runres);
}
assert(runres.result == NULL);
Py_RETURN_NONE;
#undef FUNCNAME
}
/*[clinic input]
_interpreters.run_func
id: object
func: object
shared: object(subclass_of='&PyDict_Type', c_default='NULL') = {}
*
restrict as restricted: bool = False
Execute the body of the provided function in the identified interpreter.
Code objects are also supported. In both cases, closures and args
are not supported. Methods and other callables are not supported either.
(See _interpreters.exec().)
[clinic start generated code]*/
static PyObject *
_interpreters_run_func_impl(PyObject *module, PyObject *id, PyObject *func,
PyObject *shared, int restricted)
/*[clinic end generated code: output=131f7202ca4a0c5e input=2d62bb9b9eaf4948]*/
{
#define FUNCNAME MODULE_NAME_STR ".run_func"
PyThreadState *tstate = _PyThreadState_GET();
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "run a function in");
if (interp == NULL) {
return NULL;
}
// We don't worry about checking globals. They will be resolved
// against __main__.
PyObject *code;
if (PyFunction_Check(func)) {
code = PyFunction_GET_CODE(func);
}
else if (PyCode_Check(func)) {
code = func;
}
else {
_PyArg_BadArgument(FUNCNAME, "argument 2", "a function", func);
return NULL;
}
_PyXIData_t xidata = {0};
if (_PyCode_GetScriptXIData(tstate, code, &xidata) < 0) {
unwrap_not_shareable(tstate, NULL);
return NULL;
}
struct run_result runres = {0};
int res = _run_in_interpreter(
tstate, interp, &xidata, NULL, shared, &runres);
_PyXIData_Release(&xidata);
if (res < 0) {
return _handle_script_error(&runres);
}
assert(runres.result == NULL);
Py_RETURN_NONE;
#undef FUNCNAME
}
/*[clinic input]
_interpreters.call
id: object
callable: object
args: object(subclass_of='&PyTuple_Type', c_default='NULL') = ()
kwargs: object(subclass_of='&PyDict_Type', c_default='NULL') = {}
*
preserve_exc: bool = False
restrict as restricted: bool = False
Call the provided object in the identified interpreter.
Pass the given args and kwargs, if possible.
[clinic start generated code]*/
static PyObject *
_interpreters_call_impl(PyObject *module, PyObject *id, PyObject *callable,
PyObject *args, PyObject *kwargs, int preserve_exc,
int restricted)
/*[clinic end generated code: output=b7a4a27d72df3ebc input=b026d0b212a575e6]*/
{
PyThreadState *tstate = _PyThreadState_GET();
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "make a call in");
if (interp == NULL) {
return NULL;
}
struct interp_call call = {0};
if (_interp_call_pack(tstate, &call, callable, args, kwargs) < 0) {
return NULL;
}
PyObject *res_and_exc = NULL;
struct run_result runres = {0};
if (_run_in_interpreter(tstate, interp, NULL, &call, NULL, &runres) < 0) {
if (runres.excinfo == NULL) {
assert(_PyErr_Occurred(tstate));
goto finally;
}
assert(!_PyErr_Occurred(tstate));
}
assert(runres.result == NULL || runres.excinfo == NULL);
res_and_exc = Py_BuildValue("OO",
(runres.result ? runres.result : Py_None),
(runres.excinfo ? runres.excinfo : Py_None));
finally:
_interp_call_clear(&call);
_run_result_clear(&runres);
return res_and_exc;
}
/*[clinic input]
@permit_long_summary
_interpreters.is_shareable
obj: object
Return True if the object's data may be shared between interpreters and False otherwise.
[clinic start generated code]*/
static PyObject *
_interpreters_is_shareable_impl(PyObject *module, PyObject *obj)
/*[clinic end generated code: output=227856926a22940b input=95f888d35a6d4bb3]*/
{
PyThreadState *tstate = _PyThreadState_GET();
if (_PyObject_CheckXIData(tstate, obj) == 0) {
Py_RETURN_TRUE;
}
PyErr_Clear();
Py_RETURN_FALSE;
}
/*[clinic input]
_interpreters.is_running
id: object
*
restrict as restricted: bool = False
Return whether or not the identified interpreter is running.
[clinic start generated code]*/
static PyObject *
_interpreters_is_running_impl(PyObject *module, PyObject *id, int restricted)
/*[clinic end generated code: output=32a6225d5ded9bdb input=3291578d04231125]*/
{
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "check if running for");
if (interp == NULL) {
return NULL;
}
if (is_running_main(interp)) {
Py_RETURN_TRUE;
}
Py_RETURN_FALSE;
}
/*[clinic input]
_interpreters.get_config
id: object
*
restrict as restricted: bool = False
Return a representation of the config used to initialize the interpreter.
[clinic start generated code]*/
static PyObject *
_interpreters_get_config_impl(PyObject *module, PyObject *id, int restricted)
/*[clinic end generated code: output=56773353b9b7224a input=59519a01c22d96d1]*/
{
if (id == Py_None) {
id = NULL;
}
int reqready = 0;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "get the config of");
if (interp == NULL) {
return NULL;
}
PyInterpreterConfig config;
if (_PyInterpreterConfig_InitFromState(&config, interp) < 0) {
return NULL;
}
PyObject *dict = _PyInterpreterConfig_AsDict(&config);
if (dict == NULL) {
return NULL;
}
PyObject *configobj = _PyNamespace_New(dict);
Py_DECREF(dict);
return configobj;
}
/*[clinic input]
_interpreters.whence
id: object
Return an identifier for where the interpreter was created.
[clinic start generated code]*/
static PyObject *
_interpreters_whence_impl(PyObject *module, PyObject *id)
/*[clinic end generated code: output=ef2c21ab106c2c20 input=eeede0a2fbfa2968]*/
{
PyInterpreterState *interp = look_up_interp(id);
if (interp == NULL) {
return NULL;
}
long whence = get_whence(interp);
return PyLong_FromLong(whence);
}
/*[clinic input]
_interpreters.incref
id: object
*
implieslink: bool = False
restrict as restricted: bool = False
[clinic start generated code]*/
static PyObject *
_interpreters_incref_impl(PyObject *module, PyObject *id, int implieslink,
int restricted)
/*[clinic end generated code: output=eccaa4e03fbe8ee2 input=a0a614748f2e348c]*/
{
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "incref");
if (interp == NULL) {
return NULL;
}
if (implieslink) {
// Decref to 0 will destroy the interpreter.
_PyInterpreterState_RequireIDRef(interp, 1);
}
_PyInterpreterState_IDIncref(interp);
Py_RETURN_NONE;
}
/*[clinic input]
_interpreters.decref
id: object
*
restrict as restricted: bool = False
[clinic start generated code]*/
static PyObject *
_interpreters_decref_impl(PyObject *module, PyObject *id, int restricted)
/*[clinic end generated code: output=5c54db4b22086171 input=c4aa34f09c44e62a]*/
{
int reqready = 1;
PyInterpreterState *interp = \
resolve_interp(id, restricted, reqready, "decref");
if (interp == NULL) {
return NULL;
}
_PyInterpreterState_IDDecref(interp);
Py_RETURN_NONE;
}
/*[clinic input]
@permit_long_docstring_body
_interpreters.capture_exception
exc as exc_arg: object = None
Return a snapshot of an exception.
If "exc" is None then the current exception, if any, is used (but not cleared).
The returned snapshot is the same as what _interpreters.exec() returns.
[clinic start generated code]*/
static PyObject *
_interpreters_capture_exception_impl(PyObject *module, PyObject *exc_arg)
/*[clinic end generated code: output=ef3f5393ef9c88a6 input=6c4dcb78fb722217]*/
{
PyObject *exc = exc_arg;
if (exc == NULL || exc == Py_None) {
exc = PyErr_GetRaisedException();
if (exc == NULL) {
Py_RETURN_NONE;
}
}
else if (!PyExceptionInstance_Check(exc)) {
PyErr_Format(PyExc_TypeError, "expected exception, got %R", exc);
return NULL;
}
PyObject *captured = NULL;
_PyXI_excinfo *info = _PyXI_NewExcInfo(exc);
if (info == NULL) {
goto finally;
}
captured = _PyXI_ExcInfoAsObject(info);
if (captured == NULL) {
goto finally;
}
PyObject *formatted = _PyXI_FormatExcInfo(info);
if (formatted == NULL) {
Py_CLEAR(captured);
goto finally;
}
int res = PyObject_SetAttrString(captured, "formatted", formatted);
Py_DECREF(formatted);
if (res < 0) {
Py_CLEAR(captured);
goto finally;
}
finally:
_PyXI_FreeExcInfo(info);
if (exc != exc_arg) {
if (PyErr_Occurred()) {
PyErr_SetRaisedException(exc);
}
else {
_PyErr_ChainExceptions1(exc);
}
}
return captured;
}
static PyMethodDef module_functions[] = {
{"new_config", _PyCFunction_CAST(interp_new_config),
METH_VARARGS | METH_KEYWORDS, new_config_doc},
_INTERPRETERS_CREATE_METHODDEF
_INTERPRETERS_DESTROY_METHODDEF
_INTERPRETERS_LIST_ALL_METHODDEF
_INTERPRETERS_GET_CURRENT_METHODDEF
_INTERPRETERS_GET_MAIN_METHODDEF
_INTERPRETERS_IS_RUNNING_METHODDEF
_INTERPRETERS_GET_CONFIG_METHODDEF
_INTERPRETERS_WHENCE_METHODDEF
_INTERPRETERS_EXEC_METHODDEF
_INTERPRETERS_CALL_METHODDEF
_INTERPRETERS_RUN_STRING_METHODDEF
_INTERPRETERS_RUN_FUNC_METHODDEF
_INTERPRETERS_SET___MAIN___ATTRS_METHODDEF
_INTERPRETERS_INCREF_METHODDEF
_INTERPRETERS_DECREF_METHODDEF
_INTERPRETERS_IS_SHAREABLE_METHODDEF
_INTERPRETERS_CAPTURE_EXCEPTION_METHODDEF
{NULL, NULL} /* sentinel */
};
/* initialization function */
PyDoc_STRVAR(module_doc,
"This module provides primitive operations to manage Python interpreters.\n\
The 'interpreters' module provides a more convenient interface.");
static int
module_exec(PyObject *mod)
{
PyThreadState *tstate = _PyThreadState_GET();
module_state *state = get_module_state(mod);
#define ADD_WHENCE(NAME) \
if (PyModule_AddIntConstant(mod, "WHENCE_" #NAME, \
_PyInterpreterState_WHENCE_##NAME) < 0) \
{ \
goto error; \
}
ADD_WHENCE(UNKNOWN)
ADD_WHENCE(RUNTIME)
ADD_WHENCE(LEGACY_CAPI)
ADD_WHENCE(CAPI)
ADD_WHENCE(XI)
ADD_WHENCE(STDLIB)
#undef ADD_WHENCE
// exceptions
if (PyModule_AddType(mod, (PyTypeObject *)PyExc_InterpreterError) < 0) {
goto error;
}
if (PyModule_AddType(mod, (PyTypeObject *)PyExc_InterpreterNotFoundError) < 0) {
goto error;
}
PyObject *exctype = _PyXIData_GetNotShareableErrorType(tstate);
if (PyModule_AddType(mod, (PyTypeObject *)exctype) < 0) {
goto error;
}
if (register_memoryview_xid(mod, &state->XIBufferViewType) < 0) {
goto error;
}
return 0;
error:
return -1;
}
static struct PyModuleDef_Slot module_slots[] = {
{Py_mod_exec, module_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
{0, NULL},
};
static int
module_traverse(PyObject *mod, visitproc visit, void *arg)
{
module_state *state = get_module_state(mod);
assert(state != NULL);
return traverse_module_state(state, visit, arg);
}
static int
module_clear(PyObject *mod)
{
module_state *state = get_module_state(mod);
assert(state != NULL);
return clear_module_state(state);
}
static void
module_free(void *mod)
{
module_state *state = get_module_state((PyObject *)mod);
assert(state != NULL);
(void)clear_module_state(state);
}
static struct PyModuleDef moduledef = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = MODULE_NAME_STR,
.m_doc = module_doc,
.m_size = sizeof(module_state),
.m_methods = module_functions,
.m_slots = module_slots,
.m_traverse = module_traverse,
.m_clear = module_clear,
.m_free = module_free,
};
PyMODINIT_FUNC
MODINIT_FUNC_NAME(void)
{
return PyModuleDef_Init(&moduledef);
}