2020-05-14 18:46:24 +02:00
|
|
|
/* interpreters module */
|
2018-01-29 18:23:44 -07:00
|
|
|
/* low-level access to interpreter primitives */
|
|
|
|
|
2023-08-31 13:53:19 +02:00
|
|
|
#ifndef Py_BUILD_CORE_BUILTIN
|
|
|
|
# define Py_BUILD_CORE_MODULE 1
|
|
|
|
#endif
|
|
|
|
|
2018-01-29 18:23:44 -07:00
|
|
|
#include "Python.h"
|
2025-03-20 12:35:23 +01:00
|
|
|
#include "pycore_code.h" // _PyCode_HAS_EXECUTORS()
|
2024-11-07 09:32:42 -07:00
|
|
|
#include "pycore_crossinterp.h" // _PyXIData_t
|
2025-05-21 14:16:55 -06:00
|
|
|
#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
|
2023-12-12 08:24:31 -07:00
|
|
|
#include "pycore_interp.h" // _PyInterpreterState_IDIncref()
|
2023-10-17 14:30:31 +02:00
|
|
|
#include "pycore_modsupport.h" // _PyArg_BadArgument()
|
2024-04-02 17:16:50 -06:00
|
|
|
#include "pycore_namespace.h" // _PyNamespace_New()
|
2023-12-12 08:24:31 -07:00
|
|
|
#include "pycore_pybuffer.h" // _PyBuffer_ReleaseInInterpreterAndRawFree()
|
2024-04-02 17:16:50 -06:00
|
|
|
#include "pycore_pylifecycle.h" // _PyInterpreterConfig_AsDict()
|
2025-03-20 12:35:23 +01:00
|
|
|
#include "pycore_pystate.h" // _PyInterpreterState_IsRunningMain()
|
2023-10-17 14:30:31 +02:00
|
|
|
|
2023-10-06 17:52:22 -06:00
|
|
|
#include "marshal.h" // PyMarshal_ReadObjectFromString()
|
2018-01-29 18:23:44 -07:00
|
|
|
|
2024-02-13 14:56:49 -07:00
|
|
|
#include "_interpreters_common.h"
|
2018-01-29 18:23:44 -07:00
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
#include "clinic/_interpretersmodule.c.h"
|
2024-02-13 14:56:49 -07:00
|
|
|
|
2024-04-24 10:18:24 -06:00
|
|
|
#define MODULE_NAME _interpreters
|
2024-02-13 14:56:49 -07:00
|
|
|
#define MODULE_NAME_STR Py_STRINGIFY(MODULE_NAME)
|
|
|
|
#define MODINIT_FUNC_NAME RESOLVE_MODINIT_FUNC_NAME(MODULE_NAME)
|
2022-12-02 11:36:57 -07:00
|
|
|
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[clinic input]
|
|
|
|
module _interpreters
|
|
|
|
[clinic start generated code]*/
|
|
|
|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=bfd967980a0de892]*/
|
|
|
|
|
2020-05-14 18:46:24 +02:00
|
|
|
static PyInterpreterState *
|
2022-12-02 11:36:57 -07:00
|
|
|
_get_current_interp(void)
|
2020-05-07 08:56:01 -06:00
|
|
|
{
|
2020-05-14 18:46:24 +02:00
|
|
|
// PyInterpreterState_Get() aborts if lookup fails, so don't need
|
|
|
|
// to check the result for NULL.
|
|
|
|
return PyInterpreterState_Get();
|
2018-01-29 18:23:44 -07:00
|
|
|
}
|
|
|
|
|
2024-03-21 09:56:12 -06:00
|
|
|
#define look_up_interp _PyInterpreterState_LookUpIDObject
|
2023-12-12 08:24:31 -07:00
|
|
|
|
|
|
|
|
2025-04-25 10:43:50 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-03-21 18:20:20 -06:00
|
|
|
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
|
2025-05-01 06:36:59 +03:00
|
|
|
// to call _PyInterpreterState_SetRunningMain().
|
2024-03-21 18:20:20 -06:00
|
|
|
if (_Py_IsMainInterpreter(interp)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-05-30 09:15:00 -06:00
|
|
|
static inline int
|
|
|
|
is_notshareable_raised(PyThreadState *tstate)
|
|
|
|
{
|
|
|
|
PyObject *exctype = _PyXIData_GetNotShareableErrorType(tstate);
|
|
|
|
return _PyErr_ExceptionMatches(tstate, exctype);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2025-06-13 16:45:21 -06:00
|
|
|
unwrap_not_shareable(PyThreadState *tstate, _PyXI_failure *failure)
|
2025-05-30 09:15:00 -06:00
|
|
|
{
|
2025-06-13 16:45:21 -06:00
|
|
|
if (_PyXI_UnwrapNotShareableError(tstate, failure) < 0) {
|
|
|
|
_PyErr_Clear(tstate);
|
2025-05-30 09:15:00 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-04-25 10:43:50 -06:00
|
|
|
/* 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.
|
2025-05-21 07:23:48 -06:00
|
|
|
if (ensure_xid_class(&PyMemoryView_Type, GETDATA(_pybuffer_shared)) < 0) {
|
2025-04-25 10:43:50 -06:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
// We don't ever bother un-registering memoryview.
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-12-05 13:40:20 -07:00
|
|
|
/* module state *************************************************************/
|
|
|
|
|
|
|
|
typedef struct {
|
2023-11-22 17:55:00 -07:00
|
|
|
int _notused;
|
2025-04-25 10:43:50 -06:00
|
|
|
|
|
|
|
/* heap types */
|
|
|
|
PyTypeObject *XIBufferViewType;
|
2022-12-05 13:40:20 -07:00
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
|
2025-04-25 10:43:50 -06:00
|
|
|
static module_state *
|
|
|
|
_get_current_module_state(void)
|
|
|
|
{
|
|
|
|
PyObject *mod = _get_current_module();
|
|
|
|
if (mod == NULL) {
|
2025-05-30 09:15:00 -06:00
|
|
|
mod = PyImport_ImportModule(MODULE_NAME_STR);
|
|
|
|
if (mod == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2025-04-25 10:43:50 -06:00
|
|
|
}
|
|
|
|
module_state *state = get_module_state(mod);
|
|
|
|
Py_DECREF(mod);
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2022-12-05 13:40:20 -07:00
|
|
|
static int
|
|
|
|
traverse_module_state(module_state *state, visitproc visit, void *arg)
|
|
|
|
{
|
2025-04-25 10:43:50 -06:00
|
|
|
/* heap types */
|
|
|
|
Py_VISIT(state->XIBufferViewType);
|
|
|
|
|
2022-12-05 13:40:20 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
clear_module_state(module_state *state)
|
|
|
|
{
|
2025-04-25 10:43:50 -06:00
|
|
|
/* heap types */
|
|
|
|
Py_CLEAR(state->XIBufferViewType);
|
|
|
|
|
2022-12-05 13:40:20 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-04-25 10:43:50 -06:00
|
|
|
static PyTypeObject *
|
|
|
|
_get_current_xibufferview_type(void)
|
|
|
|
{
|
|
|
|
module_state *state = _get_current_module_state();
|
|
|
|
if (state == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return state->XIBufferViewType;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-12-05 13:40:20 -07:00
|
|
|
/* interpreter-specific code ************************************************/
|
2018-02-02 21:49:49 -07:00
|
|
|
|
2024-04-02 17:16:50 -06:00
|
|
|
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)) {
|
2024-10-31 10:14:37 -04:00
|
|
|
const char *utf8name = PyUnicode_AsUTF8(configobj);
|
|
|
|
if (utf8name == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (init_named_config(config, utf8name) < 0) {
|
2024-04-02 17:16:50 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-05-30 09:15:00 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2025-06-13 16:45:21 -06:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2025-05-30 09:15:00 -06:00
|
|
|
static int
|
|
|
|
_interp_call_unpack(struct interp_call *call,
|
|
|
|
PyObject **p_func, PyObject **p_args, PyObject **p_kwargs)
|
|
|
|
{
|
2025-06-13 16:45:21 -06:00
|
|
|
PyThreadState *tstate = PyThreadState_Get();
|
|
|
|
|
2025-05-30 09:15:00 -06:00
|
|
|
// Unpack the func.
|
|
|
|
PyObject *func = _PyXIData_NewObject(call->func);
|
|
|
|
if (func == NULL) {
|
2025-06-13 16:45:21 -06:00
|
|
|
wrap_notshareable(tstate, "func");
|
2025-05-30 09:15:00 -06:00
|
|
|
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) {
|
2025-06-13 16:45:21 -06:00
|
|
|
wrap_notshareable(tstate, "args");
|
2025-05-30 09:15:00 -06:00
|
|
|
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) {
|
2025-06-13 16:45:21 -06:00
|
|
|
wrap_notshareable(tstate, "kwargs");
|
2025-05-30 09:15:00 -06:00
|
|
|
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,
|
2025-06-13 16:45:21 -06:00
|
|
|
PyObject **p_result, _PyXI_failure *failure)
|
2025-05-30 09:15:00 -06:00
|
|
|
{
|
|
|
|
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);
|
2025-06-13 16:45:21 -06:00
|
|
|
_PyXI_InitFailure(failure, _PyXI_ERR_OTHER, NULL);
|
|
|
|
unwrap_not_shareable(tstate, failure);
|
2025-05-30 09:15:00 -06:00
|
|
|
return -1;
|
|
|
|
}
|
2025-06-17 13:16:59 -06:00
|
|
|
assert(!_PyErr_Occurred(tstate));
|
2025-05-30 09:15:00 -06:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2018-01-29 18:23:44 -07:00
|
|
|
static int
|
2025-06-13 16:45:21 -06:00
|
|
|
_run_script(_PyXIData_t *script, PyObject *ns, _PyXI_failure *failure)
|
2018-01-29 18:23:44 -07:00
|
|
|
{
|
2025-05-26 11:50:10 -06:00
|
|
|
PyObject *code = _PyXIData_NewObject(script);
|
|
|
|
if (code == NULL) {
|
2025-06-13 16:45:21 -06:00
|
|
|
_PyXI_InitFailure(failure, _PyXI_ERR_NOT_SHAREABLE, NULL);
|
2025-05-26 11:50:10 -06:00
|
|
|
return -1;
|
2023-10-06 17:52:22 -06:00
|
|
|
}
|
2025-05-26 11:50:10 -06:00
|
|
|
PyObject *result = PyEval_EvalCode(code, ns, ns);
|
|
|
|
Py_DECREF(code);
|
2018-01-29 18:23:44 -07:00
|
|
|
if (result == NULL) {
|
2025-06-13 16:45:21 -06:00
|
|
|
_PyXI_InitFailure(failure, _PyXI_ERR_UNCAUGHT_EXCEPTION, NULL);
|
2023-11-01 17:36:40 -06:00
|
|
|
return -1;
|
2018-01-29 18:23:44 -07:00
|
|
|
}
|
2025-05-30 09:15:00 -06:00
|
|
|
assert(result == Py_None);
|
2023-11-01 17:36:40 -06:00
|
|
|
Py_DECREF(result); // We throw away the result.
|
2018-01-29 18:23:44 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2025-05-30 09:15:00 -06:00
|
|
|
struct run_result {
|
|
|
|
PyObject *result;
|
|
|
|
PyObject *excinfo;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
_run_result_clear(struct run_result *runres)
|
|
|
|
{
|
|
|
|
Py_CLEAR(runres->result);
|
|
|
|
Py_CLEAR(runres->excinfo);
|
|
|
|
}
|
|
|
|
|
2018-01-29 18:23:44 -07:00
|
|
|
static int
|
2025-05-30 09:15:00 -06:00
|
|
|
_run_in_interpreter(PyThreadState *tstate, PyInterpreterState *interp,
|
|
|
|
_PyXIData_t *script, struct interp_call *call,
|
|
|
|
PyObject *shareables, struct run_result *runres)
|
2018-01-29 18:23:44 -07:00
|
|
|
{
|
2025-05-26 11:50:10 -06:00
|
|
|
assert(!_PyErr_Occurred(tstate));
|
2025-06-13 16:45:21 -06:00
|
|
|
int res = -1;
|
|
|
|
_PyXI_failure *failure = _PyXI_NewFailure();
|
|
|
|
if (failure == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
2025-05-22 10:14:04 -06:00
|
|
|
_PyXI_session *session = _PyXI_NewSession();
|
|
|
|
if (session == NULL) {
|
2025-06-13 16:45:21 -06:00
|
|
|
_PyXI_FreeFailure(failure);
|
2025-05-22 10:14:04 -06:00
|
|
|
return -1;
|
|
|
|
}
|
2025-05-30 09:15:00 -06:00
|
|
|
_PyXI_session_result result = {0};
|
2018-01-29 18:23:44 -07:00
|
|
|
|
2023-11-01 17:36:40 -06:00
|
|
|
// Prep and switch interpreters.
|
2025-05-30 09:15:00 -06:00
|
|
|
if (_PyXI_Enter(session, interp, shareables, &result) < 0) {
|
2025-07-19 09:48:04 +01:00
|
|
|
// If an error occurred at this step, it means that interp
|
2025-05-30 09:15:00 -06:00
|
|
|
// was not prepared and switched.
|
2025-05-22 10:14:04 -06:00
|
|
|
_PyXI_FreeSession(session);
|
2025-06-13 16:45:21 -06:00
|
|
|
_PyXI_FreeFailure(failure);
|
2025-05-30 09:15:00 -06:00
|
|
|
assert(result.excinfo == NULL);
|
2018-01-29 18:23:44 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2025-05-30 09:15:00 -06:00
|
|
|
// Run in the interpreter.
|
|
|
|
if (script != NULL) {
|
|
|
|
assert(call == NULL);
|
2025-06-13 16:45:21 -06:00
|
|
|
PyObject *mainns = _PyXI_GetMainNamespace(session, failure);
|
2025-05-30 09:15:00 -06:00
|
|
|
if (mainns == NULL) {
|
|
|
|
goto finally;
|
|
|
|
}
|
2025-06-13 16:45:21 -06:00
|
|
|
res = _run_script(script, mainns, failure);
|
2025-05-22 10:14:04 -06:00
|
|
|
}
|
2025-05-30 09:15:00 -06:00
|
|
|
else {
|
|
|
|
assert(call != NULL);
|
|
|
|
PyObject *resobj;
|
2025-06-13 16:45:21 -06:00
|
|
|
res = _make_call(call, &resobj, failure);
|
2025-05-30 09:15:00 -06:00
|
|
|
if (res == 0) {
|
2025-06-13 16:45:21 -06:00
|
|
|
res = _PyXI_Preserve(session, "resobj", resobj, failure);
|
2025-05-30 09:15:00 -06:00
|
|
|
Py_DECREF(resobj);
|
|
|
|
if (res < 0) {
|
|
|
|
goto finally;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-01-29 18:23:44 -07:00
|
|
|
|
2025-05-22 10:14:04 -06:00
|
|
|
finally:
|
2023-11-01 17:36:40 -06:00
|
|
|
// Clean up and switch back.
|
2025-06-13 16:45:21 -06:00
|
|
|
(void)res;
|
|
|
|
int exitres = _PyXI_Exit(session, failure, &result);
|
2025-05-30 09:15:00 -06:00
|
|
|
assert(res == 0 || exitres != 0);
|
|
|
|
_PyXI_FreeSession(session);
|
2025-06-13 16:45:21 -06:00
|
|
|
_PyXI_FreeFailure(failure);
|
2018-01-29 18:23:44 -07:00
|
|
|
|
2025-05-30 09:15:00 -06:00
|
|
|
res = exitres;
|
|
|
|
if (_PyErr_Occurred(tstate)) {
|
2025-06-13 16:45:21 -06:00
|
|
|
// It's a directly propagated exception.
|
2025-05-30 09:15:00 -06:00
|
|
|
assert(res < 0);
|
|
|
|
}
|
|
|
|
else if (res < 0) {
|
|
|
|
assert(result.excinfo != NULL);
|
|
|
|
runres->excinfo = Py_NewRef(result.excinfo);
|
|
|
|
res = -1;
|
2018-01-29 18:23:44 -07:00
|
|
|
}
|
2023-11-01 17:36:40 -06:00
|
|
|
else {
|
2025-05-30 09:15:00 -06:00
|
|
|
assert(result.excinfo == NULL);
|
|
|
|
runres->result = _PyXI_GetPreserved(&result, "resobj");
|
|
|
|
if (_PyErr_Occurred(tstate)) {
|
|
|
|
res = -1;
|
|
|
|
}
|
2018-01-29 18:23:44 -07:00
|
|
|
}
|
2025-05-30 09:15:00 -06:00
|
|
|
_PyXI_ClearResult(&result);
|
2023-11-01 17:36:40 -06:00
|
|
|
return res;
|
2018-01-29 18:23:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* module level code ********************************************************/
|
|
|
|
|
2024-04-11 17:23:25 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-10 18:37:01 -06:00
|
|
|
static PyObject *
|
|
|
|
get_summary(PyInterpreterState *interp)
|
|
|
|
{
|
|
|
|
PyObject *idobj = _PyInterpreterState_GetIDObject(interp);
|
|
|
|
if (idobj == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2024-04-11 17:23:25 -06:00
|
|
|
PyObject *whenceobj = PyLong_FromLong(
|
|
|
|
get_whence(interp));
|
|
|
|
if (whenceobj == NULL) {
|
|
|
|
Py_DECREF(idobj);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
PyObject *res = PyTuple_Pack(2, idobj, whenceobj);
|
2024-04-10 18:37:01 -06:00
|
|
|
Py_DECREF(idobj);
|
2024-04-11 17:23:25 -06:00
|
|
|
Py_DECREF(whenceobj);
|
2024-04-10 18:37:01 -06:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
// Not converted to Argument Clinic because the function uses ``**kwargs``.
|
2018-01-29 18:23:44 -07:00
|
|
|
static PyObject *
|
2024-04-02 17:16:50 -06:00
|
|
|
interp_new_config(PyObject *self, PyObject *args, PyObject *kwds)
|
2018-01-29 18:23:44 -07:00
|
|
|
{
|
2024-04-02 17:16:50 -06:00
|
|
|
const char *name = NULL;
|
2025-08-12 16:23:13 +01:00
|
|
|
if (!PyArg_ParseTuple(args, "|s:" MODULE_NAME_STR ".new_config", &name))
|
2024-04-02 17:16:50 -06:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
PyObject *overrides = kwds;
|
2020-05-01 11:33:44 +02:00
|
|
|
|
2024-04-02 17:16:50 -06:00
|
|
|
PyInterpreterConfig config;
|
|
|
|
if (init_named_config(&config, name) < 0) {
|
2018-01-29 18:23:44 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-04-02 17:16:50 -06:00
|
|
|
if (overrides != NULL && PyDict_GET_SIZE(overrides) > 0) {
|
|
|
|
if (_PyInterpreterConfig_UpdateFromDict(&config, overrides) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2023-10-03 09:20:48 -06:00
|
|
|
|
2024-04-02 17:16:50 -06:00
|
|
|
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,
|
2025-08-12 16:23:13 +01:00
|
|
|
"new_config($module, name='isolated', /, **overrides)\n\
|
|
|
|
--\n\
|
2024-04-02 17:16:50 -06:00
|
|
|
\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.");
|
|
|
|
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[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]*/
|
|
|
|
|
2024-04-02 17:16:50 -06:00
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_create_impl(PyObject *module, PyObject *configobj, int reqrefs)
|
|
|
|
/*[clinic end generated code: output=c1cc6835b1277c16 input=235ce396a23624d5]*/
|
2024-04-02 17:16:50 -06:00
|
|
|
{
|
|
|
|
PyInterpreterConfig config;
|
|
|
|
if (config_from_object(configobj, &config) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-04-11 17:23:25 -06:00
|
|
|
long whence = _PyInterpreterState_WHENCE_STDLIB;
|
|
|
|
PyInterpreterState *interp = \
|
|
|
|
_PyXI_NewInterpreter(&config, &whence, NULL, NULL);
|
2024-04-02 17:16:50 -06:00
|
|
|
if (interp == NULL) {
|
|
|
|
// XXX Move the chained exception to interpreters.create()?
|
2023-03-21 10:49:12 -06:00
|
|
|
PyObject *exc = PyErr_GetRaisedException();
|
2024-04-02 17:16:50 -06:00
|
|
|
assert(exc != NULL);
|
2024-04-03 10:58:39 -06:00
|
|
|
PyErr_SetString(PyExc_InterpreterError, "interpreter creation failed");
|
2023-03-21 10:49:12 -06:00
|
|
|
_PyErr_ChainExceptions1(exc);
|
2018-01-29 18:23:44 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
2024-04-11 17:23:25 -06:00
|
|
|
assert(_PyInterpreterState_IsReady(interp));
|
2023-10-03 09:20:48 -06:00
|
|
|
|
2024-04-10 18:37:01 -06:00
|
|
|
PyObject *idobj = _PyInterpreterState_GetIDObject(interp);
|
|
|
|
if (idobj == NULL) {
|
|
|
|
_PyXI_EndInterpreter(interp, NULL, NULL);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-04-02 17:16:50 -06:00
|
|
|
if (reqrefs) {
|
|
|
|
// Decref to 0 will destroy the interpreter.
|
|
|
|
_PyInterpreterState_RequireIDRef(interp, 1);
|
2019-03-15 16:35:46 -06:00
|
|
|
}
|
2023-10-03 09:20:48 -06:00
|
|
|
|
2019-03-15 16:35:46 -06:00
|
|
|
return idobj;
|
2018-01-29 18:23:44 -07:00
|
|
|
}
|
|
|
|
|
2024-04-02 17:16:50 -06:00
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[clinic input]
|
|
|
|
_interpreters.destroy
|
|
|
|
id: object
|
|
|
|
*
|
|
|
|
restrict as restricted: bool = False
|
|
|
|
|
|
|
|
Destroy the identified interpreter.
|
2018-01-29 18:23:44 -07:00
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
Attempting to destroy the current interpreter raises InterpreterError.
|
|
|
|
So does an unrecognized ID.
|
|
|
|
[clinic start generated code]*/
|
2018-01-29 18:23:44 -07:00
|
|
|
|
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_destroy_impl(PyObject *module, PyObject *id, int restricted)
|
|
|
|
/*[clinic end generated code: output=0bc20da8700ab4dd input=561bdd6537639d40]*/
|
2018-01-29 18:23:44 -07:00
|
|
|
{
|
|
|
|
// Look up the interpreter.
|
2024-04-11 17:23:25 -06:00
|
|
|
int reqready = 0;
|
|
|
|
PyInterpreterState *interp = \
|
|
|
|
resolve_interp(id, restricted, reqready, "destroy");
|
2018-01-29 18:23:44 -07:00
|
|
|
if (interp == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure we don't try to destroy the current interpreter.
|
2022-12-02 11:36:57 -07:00
|
|
|
PyInterpreterState *current = _get_current_interp();
|
2018-01-29 18:23:44 -07:00
|
|
|
if (current == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (interp == current) {
|
2024-04-03 10:58:39 -06:00
|
|
|
PyErr_SetString(PyExc_InterpreterError,
|
2018-01-29 18:23:44 -07:00
|
|
|
"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. */
|
2024-03-21 18:20:20 -06:00
|
|
|
if (is_running_main(interp)) {
|
2024-04-03 10:58:39 -06:00
|
|
|
PyErr_Format(PyExc_InterpreterError, "interpreter running");
|
2018-01-29 18:23:44 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Destroy the interpreter.
|
2024-04-10 18:37:01 -06:00
|
|
|
_PyXI_EndInterpreter(interp, NULL, NULL);
|
2018-01-29 18:23:44 -07:00
|
|
|
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[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]*/
|
2018-01-29 18:23:44 -07:00
|
|
|
|
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_list_all_impl(PyObject *module, int reqready)
|
|
|
|
/*[clinic end generated code: output=3f21c1a7c78043c0 input=35bae91c381a2cf9]*/
|
2018-01-29 18:23:44 -07:00
|
|
|
{
|
2024-04-11 17:23:25 -06:00
|
|
|
PyObject *ids = PyList_New(0);
|
2018-01-29 18:23:44 -07:00
|
|
|
if (ids == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-04-11 17:23:25 -06:00
|
|
|
PyInterpreterState *interp = PyInterpreterState_Head();
|
2018-01-29 18:23:44 -07:00
|
|
|
while (interp != NULL) {
|
2024-04-11 17:23:25 -06:00
|
|
|
if (!reqready || _PyInterpreterState_IsReady(interp)) {
|
|
|
|
PyObject *item = get_summary(interp);
|
|
|
|
if (item == NULL) {
|
|
|
|
Py_DECREF(ids);
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-01-29 18:23:44 -07:00
|
|
|
|
2024-04-11 17:23:25 -06:00
|
|
|
// insert at front of list
|
|
|
|
int res = PyList_Insert(ids, 0, item);
|
|
|
|
Py_DECREF(item);
|
|
|
|
if (res < 0) {
|
|
|
|
Py_DECREF(ids);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2018-01-29 18:23:44 -07:00
|
|
|
interp = PyInterpreterState_Next(interp);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ids;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[clinic input]
|
|
|
|
_interpreters.get_current
|
|
|
|
|
|
|
|
Return (ID, whence) of the current interpreter.
|
|
|
|
[clinic start generated code]*/
|
2018-01-29 18:23:44 -07:00
|
|
|
|
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_get_current_impl(PyObject *module)
|
|
|
|
/*[clinic end generated code: output=03161c8fcc0136eb input=37fb2c067c14d543]*/
|
2018-01-29 18:23:44 -07:00
|
|
|
{
|
2022-12-02 11:36:57 -07:00
|
|
|
PyInterpreterState *interp =_get_current_interp();
|
2018-01-29 18:23:44 -07:00
|
|
|
if (interp == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2024-04-11 17:23:25 -06:00
|
|
|
assert(_PyInterpreterState_IsReady(interp));
|
2024-04-10 18:37:01 -06:00
|
|
|
return get_summary(interp);
|
2018-01-29 18:23:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[clinic input]
|
|
|
|
_interpreters.get_main
|
|
|
|
|
|
|
|
Return (ID, whence) of the main interpreter.
|
|
|
|
[clinic start generated code]*/
|
2018-01-29 18:23:44 -07:00
|
|
|
|
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_get_main_impl(PyObject *module)
|
|
|
|
/*[clinic end generated code: output=9647288aff735557 input=b4ace23ca562146f]*/
|
2018-01-29 18:23:44 -07:00
|
|
|
{
|
2024-04-10 18:37:01 -06:00
|
|
|
PyInterpreterState *interp = _PyInterpreterState_Main();
|
2024-04-11 17:23:25 -06:00
|
|
|
assert(_PyInterpreterState_IsReady(interp));
|
2024-04-10 18:37:01 -06:00
|
|
|
return get_summary(interp);
|
2018-01-29 18:23:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[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]*/
|
2024-04-11 17:23:25 -06:00
|
|
|
|
2023-12-12 11:06:06 -07:00
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_set___main___attrs_impl(PyObject *module, PyObject *id,
|
|
|
|
PyObject *updates, int restricted)
|
|
|
|
/*[clinic end generated code: output=f3803010cb452bf0 input=d16ab8d81371f86a]*/
|
2023-12-12 11:06:06 -07:00
|
|
|
{
|
|
|
|
// Look up the interpreter.
|
2024-04-11 17:23:25 -06:00
|
|
|
int reqready = 1;
|
|
|
|
PyInterpreterState *interp = \
|
|
|
|
resolve_interp(id, restricted, reqready, "update __main__ for");
|
2023-12-12 11:06:06 -07:00
|
|
|
if (interp == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the updates.
|
2025-06-24 14:53:14 -04:00
|
|
|
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;
|
2023-12-12 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
2025-05-22 10:14:04 -06:00
|
|
|
_PyXI_session *session = _PyXI_NewSession();
|
|
|
|
if (session == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2023-12-12 11:06:06 -07:00
|
|
|
|
|
|
|
// Prep and switch interpreters, including apply the updates.
|
2025-05-30 09:15:00 -06:00
|
|
|
if (_PyXI_Enter(session, interp, updates, NULL) < 0) {
|
2025-05-22 10:14:04 -06:00
|
|
|
_PyXI_FreeSession(session);
|
2023-12-12 11:06:06 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clean up and switch back.
|
2025-05-30 09:15:00 -06:00
|
|
|
assert(!PyErr_Occurred());
|
2025-06-13 16:45:21 -06:00
|
|
|
int res = _PyXI_Exit(session, NULL, NULL);
|
2025-05-22 10:14:04 -06:00
|
|
|
_PyXI_FreeSession(session);
|
2025-05-30 09:15:00 -06:00
|
|
|
assert(res == 0);
|
|
|
|
if (res < 0) {
|
|
|
|
// unreachable
|
|
|
|
if (!PyErr_Occurred()) {
|
|
|
|
PyErr_SetString(PyExc_RuntimeError, "unresolved error");
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2023-12-12 11:06:06 -07:00
|
|
|
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
|
2024-04-11 17:23:25 -06:00
|
|
|
|
2025-05-30 09:15:00 -06:00
|
|
|
static PyObject *
|
|
|
|
_handle_script_error(struct run_result *runres)
|
2025-05-23 14:04:20 -06:00
|
|
|
{
|
2025-05-30 09:15:00 -06:00
|
|
|
assert(runres->result == NULL);
|
|
|
|
if (runres->excinfo == NULL) {
|
|
|
|
assert(PyErr_Occurred());
|
|
|
|
return NULL;
|
2025-05-23 14:04:20 -06:00
|
|
|
}
|
2025-05-30 09:15:00 -06:00
|
|
|
assert(!PyErr_Occurred());
|
|
|
|
return runres->excinfo;
|
2023-10-06 17:52:22 -06:00
|
|
|
}
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[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]*/
|
|
|
|
|
2018-01-29 18:23:44 -07:00
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_exec_impl(PyObject *module, PyObject *id, PyObject *code,
|
|
|
|
PyObject *shared, int restricted)
|
|
|
|
/*[clinic end generated code: output=492057c4f10dc304 input=5a22c1ed0c5dbcf3]*/
|
2018-01-29 18:23:44 -07:00
|
|
|
{
|
2025-05-21 14:16:55 -06:00
|
|
|
PyThreadState *tstate = _PyThreadState_GET();
|
2024-04-11 17:23:25 -06:00
|
|
|
int reqready = 1;
|
|
|
|
PyInterpreterState *interp = \
|
|
|
|
resolve_interp(id, restricted, reqready, "exec code for");
|
|
|
|
if (interp == NULL) {
|
2018-01-29 18:23:44 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2025-05-26 11:50:10 -06:00
|
|
|
// 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) {
|
2025-06-13 16:45:21 -06:00
|
|
|
unwrap_not_shareable(tstate, NULL);
|
2018-01-29 18:23:44 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2025-05-30 09:15:00 -06:00
|
|
|
struct run_result runres = {0};
|
|
|
|
int res = _run_in_interpreter(
|
|
|
|
tstate, interp, &xidata, NULL, shared, &runres);
|
2025-05-26 11:50:10 -06:00
|
|
|
_PyXIData_Release(&xidata);
|
2023-10-06 17:52:22 -06:00
|
|
|
if (res < 0) {
|
2025-05-30 09:15:00 -06:00
|
|
|
return _handle_script_error(&runres);
|
2023-10-06 17:52:22 -06:00
|
|
|
}
|
2025-05-30 09:15:00 -06:00
|
|
|
assert(runres.result == NULL);
|
2023-10-06 17:52:22 -06:00
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[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]*/
|
2023-10-06 17:52:22 -06:00
|
|
|
|
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_run_string_impl(PyObject *module, PyObject *id,
|
|
|
|
PyObject *script, PyObject *shared,
|
|
|
|
int restricted)
|
|
|
|
/*[clinic end generated code: output=a30a64fb9ad396a2 input=51ce549b9a8dbe21]*/
|
2023-10-06 17:52:22 -06:00
|
|
|
{
|
2025-05-21 14:16:55 -06:00
|
|
|
#define FUNCNAME MODULE_NAME_STR ".run_string"
|
|
|
|
PyThreadState *tstate = _PyThreadState_GET();
|
2024-04-11 17:23:25 -06:00
|
|
|
int reqready = 1;
|
|
|
|
PyInterpreterState *interp = \
|
|
|
|
resolve_interp(id, restricted, reqready, "run a string in");
|
|
|
|
if (interp == NULL) {
|
2018-01-29 18:23:44 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
2023-10-06 17:52:22 -06:00
|
|
|
|
2025-05-26 11:50:10 -06:00
|
|
|
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) {
|
2025-06-13 16:45:21 -06:00
|
|
|
unwrap_not_shareable(tstate, NULL);
|
2018-01-29 18:23:44 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2025-05-30 09:15:00 -06:00
|
|
|
struct run_result runres = {0};
|
|
|
|
int res = _run_in_interpreter(
|
|
|
|
tstate, interp, &xidata, NULL, shared, &runres);
|
2025-05-26 11:50:10 -06:00
|
|
|
_PyXIData_Release(&xidata);
|
2023-10-06 17:52:22 -06:00
|
|
|
if (res < 0) {
|
2025-05-30 09:15:00 -06:00
|
|
|
return _handle_script_error(&runres);
|
2018-01-29 18:23:44 -07:00
|
|
|
}
|
2025-05-30 09:15:00 -06:00
|
|
|
assert(runres.result == NULL);
|
2018-01-29 18:23:44 -07:00
|
|
|
Py_RETURN_NONE;
|
2025-05-21 14:16:55 -06:00
|
|
|
#undef FUNCNAME
|
2018-01-29 18:23:44 -07:00
|
|
|
}
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[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]*/
|
2023-10-06 17:52:22 -06:00
|
|
|
|
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_run_func_impl(PyObject *module, PyObject *id, PyObject *func,
|
|
|
|
PyObject *shared, int restricted)
|
|
|
|
/*[clinic end generated code: output=131f7202ca4a0c5e input=2d62bb9b9eaf4948]*/
|
2023-10-06 17:52:22 -06:00
|
|
|
{
|
2025-05-21 14:16:55 -06:00
|
|
|
#define FUNCNAME MODULE_NAME_STR ".run_func"
|
|
|
|
PyThreadState *tstate = _PyThreadState_GET();
|
2024-04-11 17:23:25 -06:00
|
|
|
int reqready = 1;
|
|
|
|
PyInterpreterState *interp = \
|
|
|
|
resolve_interp(id, restricted, reqready, "run a function in");
|
|
|
|
if (interp == NULL) {
|
2023-10-06 17:52:22 -06:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2025-05-26 11:50:10 -06:00
|
|
|
// 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) {
|
2025-06-13 16:45:21 -06:00
|
|
|
unwrap_not_shareable(tstate, NULL);
|
2023-10-06 17:52:22 -06:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2025-05-30 09:15:00 -06:00
|
|
|
struct run_result runres = {0};
|
|
|
|
int res = _run_in_interpreter(
|
|
|
|
tstate, interp, &xidata, NULL, shared, &runres);
|
2025-05-26 11:50:10 -06:00
|
|
|
_PyXIData_Release(&xidata);
|
2023-10-06 17:52:22 -06:00
|
|
|
if (res < 0) {
|
2025-05-30 09:15:00 -06:00
|
|
|
return _handle_script_error(&runres);
|
2023-10-06 17:52:22 -06:00
|
|
|
}
|
2025-05-30 09:15:00 -06:00
|
|
|
assert(runres.result == NULL);
|
2023-10-06 17:52:22 -06:00
|
|
|
Py_RETURN_NONE;
|
2025-05-21 14:16:55 -06:00
|
|
|
#undef FUNCNAME
|
2023-10-06 17:52:22 -06:00
|
|
|
}
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[clinic input]
|
|
|
|
_interpreters.call
|
|
|
|
id: object
|
|
|
|
callable: object
|
2025-08-12 23:28:38 +01:00
|
|
|
args: object(subclass_of='&PyTuple_Type', c_default='NULL') = ()
|
|
|
|
kwargs: object(subclass_of='&PyDict_Type', c_default='NULL') = {}
|
2025-08-12 16:23:13 +01:00
|
|
|
*
|
|
|
|
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]*/
|
2018-01-29 18:23:44 -07:00
|
|
|
|
2025-04-28 11:55:15 -06:00
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_call_impl(PyObject *module, PyObject *id, PyObject *callable,
|
2025-08-12 23:28:38 +01:00
|
|
|
PyObject *args, PyObject *kwargs, int preserve_exc,
|
|
|
|
int restricted)
|
|
|
|
/*[clinic end generated code: output=b7a4a27d72df3ebc input=b026d0b212a575e6]*/
|
2025-04-28 11:55:15 -06:00
|
|
|
{
|
2025-05-21 14:16:55 -06:00
|
|
|
PyThreadState *tstate = _PyThreadState_GET();
|
2025-04-28 11:55:15 -06:00
|
|
|
int reqready = 1;
|
|
|
|
PyInterpreterState *interp = \
|
|
|
|
resolve_interp(id, restricted, reqready, "make a call in");
|
|
|
|
if (interp == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2025-05-30 09:15:00 -06:00
|
|
|
struct interp_call call = {0};
|
2025-08-12 23:28:38 +01:00
|
|
|
if (_interp_call_pack(tstate, &call, callable, args, kwargs) < 0) {
|
2025-04-28 11:55:15 -06:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2025-05-30 09:15:00 -06:00
|
|
|
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));
|
2025-04-28 11:55:15 -06:00
|
|
|
}
|
2025-05-30 09:15:00 -06:00
|
|
|
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));
|
2025-04-28 11:55:15 -06:00
|
|
|
|
2025-05-30 09:15:00 -06:00
|
|
|
finally:
|
|
|
|
_interp_call_clear(&call);
|
|
|
|
_run_result_clear(&runres);
|
|
|
|
return res_and_exc;
|
2025-04-28 11:55:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[clinic input]
|
2025-08-18 18:29:00 +01:00
|
|
|
@permit_long_summary
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters.is_shareable
|
|
|
|
obj: object
|
|
|
|
|
|
|
|
Return True if the object's data may be shared between interpreters and False otherwise.
|
|
|
|
[clinic start generated code]*/
|
2018-01-29 18:23:44 -07:00
|
|
|
|
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_is_shareable_impl(PyObject *module, PyObject *obj)
|
2025-08-18 18:29:00 +01:00
|
|
|
/*[clinic end generated code: output=227856926a22940b input=95f888d35a6d4bb3]*/
|
2018-01-29 18:23:44 -07:00
|
|
|
{
|
2025-04-25 14:43:38 -06:00
|
|
|
PyThreadState *tstate = _PyThreadState_GET();
|
|
|
|
if (_PyObject_CheckXIData(tstate, obj) == 0) {
|
2018-01-29 18:23:44 -07:00
|
|
|
Py_RETURN_TRUE;
|
|
|
|
}
|
|
|
|
PyErr_Clear();
|
|
|
|
Py_RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[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]*/
|
2018-01-29 18:23:44 -07:00
|
|
|
|
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_is_running_impl(PyObject *module, PyObject *id, int restricted)
|
|
|
|
/*[clinic end generated code: output=32a6225d5ded9bdb input=3291578d04231125]*/
|
2018-01-29 18:23:44 -07:00
|
|
|
{
|
2024-04-11 17:23:25 -06:00
|
|
|
int reqready = 1;
|
|
|
|
PyInterpreterState *interp = \
|
|
|
|
resolve_interp(id, restricted, reqready, "check if running for");
|
2018-01-29 18:23:44 -07:00
|
|
|
if (interp == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2024-04-11 17:23:25 -06:00
|
|
|
|
2024-03-21 18:20:20 -06:00
|
|
|
if (is_running_main(interp)) {
|
2018-01-29 18:23:44 -07:00
|
|
|
Py_RETURN_TRUE;
|
|
|
|
}
|
|
|
|
Py_RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[clinic input]
|
|
|
|
_interpreters.get_config
|
2025-08-12 23:28:38 +01:00
|
|
|
id: object
|
2025-08-12 16:23:13 +01:00
|
|
|
*
|
|
|
|
restrict as restricted: bool = False
|
|
|
|
|
|
|
|
Return a representation of the config used to initialize the interpreter.
|
|
|
|
[clinic start generated code]*/
|
2023-10-02 14:12:12 -06:00
|
|
|
|
2023-12-12 08:24:31 -07:00
|
|
|
static PyObject *
|
2025-08-12 23:28:38 +01:00
|
|
|
_interpreters_get_config_impl(PyObject *module, PyObject *id, int restricted)
|
|
|
|
/*[clinic end generated code: output=56773353b9b7224a input=59519a01c22d96d1]*/
|
2023-12-12 08:24:31 -07:00
|
|
|
{
|
2025-08-12 23:28:38 +01:00
|
|
|
if (id == Py_None) {
|
|
|
|
id = NULL;
|
2025-07-22 16:39:50 +03:00
|
|
|
}
|
2024-04-11 17:23:25 -06:00
|
|
|
|
|
|
|
int reqready = 0;
|
|
|
|
PyInterpreterState *interp = \
|
2025-08-12 23:28:38 +01:00
|
|
|
resolve_interp(id, restricted, reqready, "get the config of");
|
2024-04-11 17:23:25 -06:00
|
|
|
if (interp == NULL) {
|
|
|
|
return NULL;
|
2024-04-02 17:16:50 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[clinic input]
|
|
|
|
_interpreters.whence
|
|
|
|
id: object
|
|
|
|
|
|
|
|
Return an identifier for where the interpreter was created.
|
|
|
|
[clinic start generated code]*/
|
2024-04-02 17:16:50 -06:00
|
|
|
|
2024-04-10 18:37:01 -06:00
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_whence_impl(PyObject *module, PyObject *id)
|
|
|
|
/*[clinic end generated code: output=ef2c21ab106c2c20 input=eeede0a2fbfa2968]*/
|
2024-04-10 18:37:01 -06:00
|
|
|
{
|
|
|
|
PyInterpreterState *interp = look_up_interp(id);
|
|
|
|
if (interp == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-04-11 17:23:25 -06:00
|
|
|
long whence = get_whence(interp);
|
2024-04-10 18:37:01 -06:00
|
|
|
return PyLong_FromLong(whence);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[clinic input]
|
|
|
|
_interpreters.incref
|
|
|
|
id: object
|
|
|
|
*
|
|
|
|
implieslink: bool = False
|
|
|
|
restrict as restricted: bool = False
|
|
|
|
|
|
|
|
[clinic start generated code]*/
|
2024-04-10 18:37:01 -06:00
|
|
|
|
2024-04-02 17:16:50 -06:00
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_incref_impl(PyObject *module, PyObject *id, int implieslink,
|
|
|
|
int restricted)
|
|
|
|
/*[clinic end generated code: output=eccaa4e03fbe8ee2 input=a0a614748f2e348c]*/
|
2024-04-02 17:16:50 -06:00
|
|
|
{
|
2024-04-11 17:23:25 -06:00
|
|
|
int reqready = 1;
|
|
|
|
PyInterpreterState *interp = \
|
|
|
|
resolve_interp(id, restricted, reqready, "incref");
|
2023-12-12 08:24:31 -07:00
|
|
|
if (interp == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2024-04-02 17:16:50 -06:00
|
|
|
|
|
|
|
if (implieslink) {
|
|
|
|
// Decref to 0 will destroy the interpreter.
|
|
|
|
_PyInterpreterState_RequireIDRef(interp, 1);
|
2023-12-12 08:24:31 -07:00
|
|
|
}
|
|
|
|
_PyInterpreterState_IDIncref(interp);
|
|
|
|
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[clinic input]
|
|
|
|
_interpreters.decref
|
|
|
|
id: object
|
|
|
|
*
|
|
|
|
restrict as restricted: bool = False
|
|
|
|
|
|
|
|
[clinic start generated code]*/
|
|
|
|
|
2023-12-12 08:24:31 -07:00
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_decref_impl(PyObject *module, PyObject *id, int restricted)
|
|
|
|
/*[clinic end generated code: output=5c54db4b22086171 input=c4aa34f09c44e62a]*/
|
2023-12-12 08:24:31 -07:00
|
|
|
{
|
2024-04-11 17:23:25 -06:00
|
|
|
int reqready = 1;
|
|
|
|
PyInterpreterState *interp = \
|
|
|
|
resolve_interp(id, restricted, reqready, "decref");
|
2023-12-12 08:24:31 -07:00
|
|
|
if (interp == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2024-04-11 17:23:25 -06:00
|
|
|
|
2023-12-12 08:24:31 -07:00
|
|
|
_PyInterpreterState_IDDecref(interp);
|
|
|
|
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
/*[clinic input]
|
2025-08-18 18:29:00 +01:00
|
|
|
@permit_long_docstring_body
|
2025-08-12 16:23:13 +01:00
|
|
|
_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]*/
|
|
|
|
|
2024-04-10 18:37:01 -06:00
|
|
|
static PyObject *
|
2025-08-12 16:23:13 +01:00
|
|
|
_interpreters_capture_exception_impl(PyObject *module, PyObject *exc_arg)
|
2025-08-18 18:29:00 +01:00
|
|
|
/*[clinic end generated code: output=ef3f5393ef9c88a6 input=6c4dcb78fb722217]*/
|
2024-04-10 18:37:01 -06:00
|
|
|
{
|
|
|
|
PyObject *exc = exc_arg;
|
2025-07-22 16:39:50 +03:00
|
|
|
if (exc == NULL || exc == Py_None) {
|
2024-04-10 18:37:01 -06:00
|
|
|
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;
|
|
|
|
|
2025-06-13 16:45:21 -06:00
|
|
|
_PyXI_excinfo *info = _PyXI_NewExcInfo(exc);
|
|
|
|
if (info == NULL) {
|
2024-04-10 18:37:01 -06:00
|
|
|
goto finally;
|
|
|
|
}
|
2025-06-13 16:45:21 -06:00
|
|
|
captured = _PyXI_ExcInfoAsObject(info);
|
2024-04-10 18:37:01 -06:00
|
|
|
if (captured == NULL) {
|
|
|
|
goto finally;
|
|
|
|
}
|
|
|
|
|
2025-06-13 16:45:21 -06:00
|
|
|
PyObject *formatted = _PyXI_FormatExcInfo(info);
|
2024-04-10 18:37:01 -06:00
|
|
|
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:
|
2025-06-13 16:45:21 -06:00
|
|
|
_PyXI_FreeExcInfo(info);
|
2024-04-10 18:37:01 -06:00
|
|
|
if (exc != exc_arg) {
|
|
|
|
if (PyErr_Occurred()) {
|
|
|
|
PyErr_SetRaisedException(exc);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
_PyErr_ChainExceptions1(exc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return captured;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-29 18:23:44 -07:00
|
|
|
static PyMethodDef module_functions[] = {
|
2024-04-02 17:16:50 -06:00
|
|
|
{"new_config", _PyCFunction_CAST(interp_new_config),
|
|
|
|
METH_VARARGS | METH_KEYWORDS, new_config_doc},
|
2024-04-10 18:37:01 -06:00
|
|
|
|
2025-08-12 16:23:13 +01:00
|
|
|
_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
|
2024-04-10 18:37:01 -06:00
|
|
|
|
2018-01-29 18:23:44 -07:00
|
|
|
{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.");
|
|
|
|
|
2022-12-02 11:36:57 -07:00
|
|
|
static int
|
|
|
|
module_exec(PyObject *mod)
|
2018-01-29 18:23:44 -07:00
|
|
|
{
|
2025-04-25 14:43:38 -06:00
|
|
|
PyThreadState *tstate = _PyThreadState_GET();
|
2023-12-12 08:24:31 -07:00
|
|
|
module_state *state = get_module_state(mod);
|
|
|
|
|
2024-04-10 18:37:01 -06:00
|
|
|
#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)
|
2024-04-11 17:23:25 -06:00
|
|
|
ADD_WHENCE(STDLIB)
|
2024-04-10 18:37:01 -06:00
|
|
|
#undef ADD_WHENCE
|
|
|
|
|
2023-12-12 08:24:31 -07:00
|
|
|
// exceptions
|
|
|
|
if (PyModule_AddType(mod, (PyTypeObject *)PyExc_InterpreterError) < 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (PyModule_AddType(mod, (PyTypeObject *)PyExc_InterpreterNotFoundError) < 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
2025-04-25 14:43:38 -06:00
|
|
|
PyObject *exctype = _PyXIData_GetNotShareableErrorType(tstate);
|
|
|
|
if (PyModule_AddType(mod, (PyTypeObject *)exctype) < 0) {
|
2024-02-28 16:08:08 -07:00
|
|
|
goto error;
|
|
|
|
}
|
2023-12-12 08:24:31 -07:00
|
|
|
|
2025-04-25 10:43:50 -06:00
|
|
|
if (register_memoryview_xid(mod, &state->XIBufferViewType) < 0) {
|
2022-12-02 11:36:57 -07:00
|
|
|
goto error;
|
2018-02-16 18:53:40 -07:00
|
|
|
}
|
2018-01-29 18:23:44 -07:00
|
|
|
|
2022-12-02 11:36:57 -07:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-12-05 13:40:20 -07:00
|
|
|
static struct PyModuleDef_Slot module_slots[] = {
|
|
|
|
{Py_mod_exec, module_exec},
|
2023-05-05 15:11:27 -06:00
|
|
|
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
|
2024-05-03 08:30:55 -07:00
|
|
|
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
2022-12-05 13:40:20 -07:00
|
|
|
{0, NULL},
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
module_traverse(PyObject *mod, visitproc visit, void *arg)
|
|
|
|
{
|
|
|
|
module_state *state = get_module_state(mod);
|
|
|
|
assert(state != NULL);
|
2025-06-25 17:17:02 +03:00
|
|
|
return traverse_module_state(state, visit, arg);
|
2022-12-05 13:40:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
module_clear(PyObject *mod)
|
|
|
|
{
|
|
|
|
module_state *state = get_module_state(mod);
|
|
|
|
assert(state != NULL);
|
2025-06-25 17:17:02 +03:00
|
|
|
return clear_module_state(state);
|
2022-12-05 13:40:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
module_free(void *mod)
|
|
|
|
{
|
2025-02-17 11:34:14 +01:00
|
|
|
module_state *state = get_module_state((PyObject *)mod);
|
2022-12-05 13:40:20 -07:00
|
|
|
assert(state != NULL);
|
2025-02-17 11:34:14 +01:00
|
|
|
(void)clear_module_state(state);
|
2022-12-05 13:40:20 -07:00
|
|
|
}
|
|
|
|
|
2022-12-02 11:36:57 -07:00
|
|
|
static struct PyModuleDef moduledef = {
|
|
|
|
.m_base = PyModuleDef_HEAD_INIT,
|
2024-02-13 14:56:49 -07:00
|
|
|
.m_name = MODULE_NAME_STR,
|
2022-12-02 11:36:57 -07:00
|
|
|
.m_doc = module_doc,
|
2022-12-05 13:40:20 -07:00
|
|
|
.m_size = sizeof(module_state),
|
2022-12-02 11:36:57 -07:00
|
|
|
.m_methods = module_functions,
|
2022-12-05 13:40:20 -07:00
|
|
|
.m_slots = module_slots,
|
|
|
|
.m_traverse = module_traverse,
|
|
|
|
.m_clear = module_clear,
|
2025-02-17 11:34:14 +01:00
|
|
|
.m_free = module_free,
|
2022-12-02 11:36:57 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
PyMODINIT_FUNC
|
2024-02-13 14:56:49 -07:00
|
|
|
MODINIT_FUNC_NAME(void)
|
2022-12-02 11:36:57 -07:00
|
|
|
{
|
2022-12-05 13:40:20 -07:00
|
|
|
return PyModuleDef_Init(&moduledef);
|
2018-01-29 18:23:44 -07:00
|
|
|
}
|