2020-05-14 13:46:24 -03:00
|
|
|
|
|
|
|
/* interpreters module */
|
2018-01-29 21:23:44 -04:00
|
|
|
/* low-level access to interpreter primitives */
|
2021-10-22 10:36:28 -03:00
|
|
|
#ifndef Py_BUILD_CORE_BUILTIN
|
|
|
|
# define Py_BUILD_CORE_MODULE 1
|
|
|
|
#endif
|
2018-01-29 21:23:44 -04:00
|
|
|
|
|
|
|
#include "Python.h"
|
2022-12-02 14:36:57 -04:00
|
|
|
// XXX This module should not rely on internal API.
|
2021-07-26 07:22:16 -03:00
|
|
|
#include "pycore_frame.h"
|
2021-10-13 09:09:13 -03:00
|
|
|
#include "pycore_pystate.h" // _PyThreadState_GET()
|
2021-10-15 06:56:34 -03:00
|
|
|
#include "pycore_interpreteridobject.h"
|
2018-01-29 21:23:44 -04:00
|
|
|
|
|
|
|
|
2022-12-02 14:36:57 -04:00
|
|
|
#define MODULE_NAME "_xxsubinterpreters"
|
|
|
|
|
|
|
|
|
2023-03-13 19:01:44 -03:00
|
|
|
static const char *
|
2020-05-14 13:46:24 -03:00
|
|
|
_copy_raw_string(PyObject *strobj)
|
2020-05-07 11:56:01 -03:00
|
|
|
{
|
2020-05-14 13:46:24 -03:00
|
|
|
const char *str = PyUnicode_AsUTF8(strobj);
|
2020-05-07 11:56:01 -03:00
|
|
|
if (str == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2023-03-13 19:01:44 -03:00
|
|
|
char *copied = PyMem_RawMalloc(strlen(str)+1);
|
2020-05-14 13:46:24 -03:00
|
|
|
if (copied == NULL) {
|
2020-05-07 11:56:01 -03:00
|
|
|
PyErr_NoMemory();
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-05-14 13:46:24 -03:00
|
|
|
strcpy(copied, str);
|
|
|
|
return copied;
|
2020-05-07 11:56:01 -03:00
|
|
|
}
|
|
|
|
|
2020-05-14 13:46:24 -03:00
|
|
|
static PyInterpreterState *
|
2022-12-02 14:36:57 -04:00
|
|
|
_get_current_interp(void)
|
2020-05-07 11:56:01 -03:00
|
|
|
{
|
2020-05-14 13:46:24 -03:00
|
|
|
// PyInterpreterState_Get() aborts if lookup fails, so don't need
|
|
|
|
// to check the result for NULL.
|
|
|
|
return PyInterpreterState_Get();
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
|
|
|
|
2022-12-02 14:36:57 -04:00
|
|
|
static PyObject *
|
|
|
|
add_new_exception(PyObject *mod, const char *name, PyObject *base)
|
|
|
|
{
|
|
|
|
assert(!PyObject_HasAttrString(mod, name));
|
|
|
|
PyObject *exctype = PyErr_NewException(name, base, NULL);
|
|
|
|
if (exctype == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
int res = PyModule_AddType(mod, (PyTypeObject *)exctype);
|
|
|
|
if (res < 0) {
|
|
|
|
Py_DECREF(exctype);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return exctype;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ADD_NEW_EXCEPTION(MOD, NAME, BASE) \
|
|
|
|
add_new_exception(MOD, MODULE_NAME "." Py_STRINGIFY(NAME), BASE)
|
|
|
|
|
|
|
|
static int
|
|
|
|
_release_xid_data(_PyCrossInterpreterData *data, int ignoreexc)
|
|
|
|
{
|
2023-03-06 13:49:31 -04:00
|
|
|
PyObject *exc;
|
2022-12-02 14:36:57 -04:00
|
|
|
if (ignoreexc) {
|
2023-03-06 13:49:31 -04:00
|
|
|
exc = PyErr_GetRaisedException();
|
2022-12-02 14:36:57 -04:00
|
|
|
}
|
|
|
|
int res = _PyCrossInterpreterData_Release(data);
|
|
|
|
if (res < 0) {
|
2023-04-05 21:42:02 -03:00
|
|
|
/* The owning interpreter is already destroyed. */
|
2022-12-05 16:40:20 -04:00
|
|
|
_PyCrossInterpreterData_Clear(NULL, data);
|
2022-12-02 14:36:57 -04:00
|
|
|
if (ignoreexc) {
|
|
|
|
// XXX Emit a warning?
|
|
|
|
PyErr_Clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ignoreexc) {
|
2023-03-06 13:49:31 -04:00
|
|
|
PyErr_SetRaisedException(exc);
|
2022-12-02 14:36:57 -04:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2018-02-03 00:49:49 -04:00
|
|
|
|
2022-12-05 16:40:20 -04:00
|
|
|
/* module state *************************************************************/
|
|
|
|
|
|
|
|
typedef struct {
|
2023-02-03 21:14:43 -04:00
|
|
|
/* exceptions */
|
2022-12-05 16:40:20 -04:00
|
|
|
PyObject *RunFailedError;
|
|
|
|
} 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 int
|
|
|
|
traverse_module_state(module_state *state, visitproc visit, void *arg)
|
|
|
|
{
|
2023-02-03 21:14:43 -04:00
|
|
|
/* exceptions */
|
2022-12-05 16:40:20 -04:00
|
|
|
Py_VISIT(state->RunFailedError);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
clear_module_state(module_state *state)
|
|
|
|
{
|
2023-02-03 21:14:43 -04:00
|
|
|
/* exceptions */
|
2022-12-05 16:40:20 -04:00
|
|
|
Py_CLEAR(state->RunFailedError);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-29 21:23:44 -04:00
|
|
|
/* data-sharing-specific code ***********************************************/
|
|
|
|
|
2018-02-03 00:49:49 -04:00
|
|
|
struct _sharednsitem {
|
2023-03-13 19:01:44 -03:00
|
|
|
const char *name;
|
2018-01-29 21:23:44 -04:00
|
|
|
_PyCrossInterpreterData data;
|
2018-02-03 00:49:49 -04:00
|
|
|
};
|
|
|
|
|
2019-03-15 19:35:46 -03:00
|
|
|
static void _sharednsitem_clear(struct _sharednsitem *); // forward
|
|
|
|
|
2018-02-03 00:49:49 -04:00
|
|
|
static int
|
|
|
|
_sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value)
|
|
|
|
{
|
2020-05-14 13:46:24 -03:00
|
|
|
item->name = _copy_raw_string(key);
|
|
|
|
if (item->name == NULL) {
|
2018-02-03 00:49:49 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) {
|
2019-03-15 19:35:46 -03:00
|
|
|
_sharednsitem_clear(item);
|
2018-02-03 00:49:49 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_sharednsitem_clear(struct _sharednsitem *item)
|
|
|
|
{
|
2020-05-14 13:46:24 -03:00
|
|
|
if (item->name != NULL) {
|
2023-03-13 19:01:44 -03:00
|
|
|
PyMem_RawFree((void *)item->name);
|
2020-05-14 13:46:24 -03:00
|
|
|
item->name = NULL;
|
|
|
|
}
|
2022-12-02 14:36:57 -04:00
|
|
|
(void)_release_xid_data(&item->data, 1);
|
2018-02-03 00:49:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
_sharednsitem_apply(struct _sharednsitem *item, PyObject *ns)
|
|
|
|
{
|
2020-05-14 13:46:24 -03:00
|
|
|
PyObject *name = PyUnicode_FromString(item->name);
|
2018-02-03 00:49:49 -04:00
|
|
|
if (name == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
PyObject *value = _PyCrossInterpreterData_NewObject(&item->data);
|
|
|
|
if (value == NULL) {
|
|
|
|
Py_DECREF(name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
int res = PyDict_SetItem(ns, name, value);
|
|
|
|
Py_DECREF(name);
|
|
|
|
Py_DECREF(value);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct _sharedns {
|
|
|
|
Py_ssize_t len;
|
|
|
|
struct _sharednsitem* items;
|
|
|
|
} _sharedns;
|
|
|
|
|
|
|
|
static _sharedns *
|
|
|
|
_sharedns_new(Py_ssize_t len)
|
|
|
|
{
|
|
|
|
_sharedns *shared = PyMem_NEW(_sharedns, 1);
|
|
|
|
if (shared == NULL) {
|
|
|
|
PyErr_NoMemory();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
shared->len = len;
|
|
|
|
shared->items = PyMem_NEW(struct _sharednsitem, len);
|
|
|
|
if (shared->items == NULL) {
|
|
|
|
PyErr_NoMemory();
|
|
|
|
PyMem_Free(shared);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return shared;
|
|
|
|
}
|
2018-01-29 21:23:44 -04:00
|
|
|
|
2018-02-03 00:49:49 -04:00
|
|
|
static void
|
|
|
|
_sharedns_free(_sharedns *shared)
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
2018-02-03 00:49:49 -04:00
|
|
|
for (Py_ssize_t i=0; i < shared->len; i++) {
|
|
|
|
_sharednsitem_clear(&shared->items[i]);
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
2018-02-03 00:49:49 -04:00
|
|
|
PyMem_Free(shared->items);
|
|
|
|
PyMem_Free(shared);
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
|
|
|
|
2018-02-03 00:49:49 -04:00
|
|
|
static _sharedns *
|
2023-02-03 21:14:43 -04:00
|
|
|
_get_shared_ns(PyObject *shareable)
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
|
|
|
if (shareable == NULL || shareable == Py_None) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Py_ssize_t len = PyDict_Size(shareable);
|
|
|
|
if (len == 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-02-03 00:49:49 -04:00
|
|
|
_sharedns *shared = _sharedns_new(len);
|
2018-01-29 21:23:44 -04:00
|
|
|
if (shared == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Py_ssize_t pos = 0;
|
|
|
|
for (Py_ssize_t i=0; i < len; i++) {
|
|
|
|
PyObject *key, *value;
|
|
|
|
if (PyDict_Next(shareable, &pos, &key, &value) == 0) {
|
|
|
|
break;
|
|
|
|
}
|
2018-02-03 00:49:49 -04:00
|
|
|
if (_sharednsitem_init(&shared->items[i], key, value) != 0) {
|
2018-01-29 21:23:44 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (PyErr_Occurred()) {
|
2018-02-03 00:49:49 -04:00
|
|
|
_sharedns_free(shared);
|
2018-01-29 21:23:44 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return shared;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2018-02-03 00:49:49 -04:00
|
|
|
_sharedns_apply(_sharedns *shared, PyObject *ns)
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
2018-02-03 00:49:49 -04:00
|
|
|
for (Py_ssize_t i=0; i < shared->len; i++) {
|
|
|
|
if (_sharednsitem_apply(&shared->items[i], ns) != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
2018-02-03 00:49:49 -04:00
|
|
|
return 0;
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ultimately we'd like to preserve enough information about the
|
|
|
|
// exception and traceback that we could re-constitute (or at least
|
|
|
|
// simulate, a la traceback.TracebackException), and even chain, a copy
|
|
|
|
// of the exception in the calling interpreter.
|
|
|
|
|
|
|
|
typedef struct _sharedexception {
|
2023-03-13 19:01:44 -03:00
|
|
|
const char *name;
|
|
|
|
const char *msg;
|
2018-01-29 21:23:44 -04:00
|
|
|
} _sharedexception;
|
|
|
|
|
2023-03-13 19:01:44 -03:00
|
|
|
static const struct _sharedexception no_exception = {
|
|
|
|
.name = NULL,
|
|
|
|
.msg = NULL,
|
|
|
|
};
|
2018-02-03 00:49:49 -04:00
|
|
|
|
|
|
|
static void
|
2020-05-14 13:46:24 -03:00
|
|
|
_sharedexception_clear(_sharedexception *exc)
|
2018-02-03 00:49:49 -04:00
|
|
|
{
|
2020-05-14 13:46:24 -03:00
|
|
|
if (exc->name != NULL) {
|
2023-03-13 19:01:44 -03:00
|
|
|
PyMem_RawFree((void *)exc->name);
|
2020-05-14 13:46:24 -03:00
|
|
|
}
|
|
|
|
if (exc->msg != NULL) {
|
2023-03-13 19:01:44 -03:00
|
|
|
PyMem_RawFree((void *)exc->msg);
|
2020-05-14 13:46:24 -03:00
|
|
|
}
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
|
|
|
|
2023-03-13 19:01:44 -03:00
|
|
|
static const char *
|
|
|
|
_sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
2023-03-06 13:49:31 -04:00
|
|
|
assert(exc != NULL);
|
2023-03-13 19:01:44 -03:00
|
|
|
const char *failure = NULL;
|
2022-12-02 14:36:57 -04:00
|
|
|
|
2023-03-13 19:01:44 -03:00
|
|
|
PyObject *nameobj = PyUnicode_FromFormat("%S", Py_TYPE(exc));
|
|
|
|
if (nameobj == NULL) {
|
2023-02-03 21:14:43 -04:00
|
|
|
failure = "unable to format exception type name";
|
2023-03-13 19:01:44 -03:00
|
|
|
goto error;
|
2018-05-16 16:04:57 -03:00
|
|
|
}
|
2023-03-13 19:01:44 -03:00
|
|
|
sharedexc->name = _copy_raw_string(nameobj);
|
|
|
|
Py_DECREF(nameobj);
|
|
|
|
if (sharedexc->name == NULL) {
|
2023-02-03 21:14:43 -04:00
|
|
|
if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
|
|
|
|
failure = "out of memory copying exception type name";
|
|
|
|
} else {
|
|
|
|
failure = "unable to encode and copy exception type name";
|
|
|
|
}
|
2023-03-13 19:01:44 -03:00
|
|
|
goto error;
|
2018-05-16 16:04:57 -03:00
|
|
|
}
|
|
|
|
|
2023-02-03 21:14:43 -04:00
|
|
|
if (exc != NULL) {
|
2023-03-13 19:01:44 -03:00
|
|
|
PyObject *msgobj = PyUnicode_FromFormat("%S", exc);
|
|
|
|
if (msgobj == NULL) {
|
2023-02-03 21:14:43 -04:00
|
|
|
failure = "unable to format exception message";
|
2023-03-13 19:01:44 -03:00
|
|
|
goto error;
|
2023-02-03 21:14:43 -04:00
|
|
|
}
|
2023-03-13 19:01:44 -03:00
|
|
|
sharedexc->msg = _copy_raw_string(msgobj);
|
|
|
|
Py_DECREF(msgobj);
|
|
|
|
if (sharedexc->msg == NULL) {
|
2023-02-03 21:14:43 -04:00
|
|
|
if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
|
|
|
|
failure = "out of memory copying exception message";
|
|
|
|
} else {
|
|
|
|
failure = "unable to encode and copy exception message";
|
|
|
|
}
|
2023-03-13 19:01:44 -03:00
|
|
|
goto error;
|
2023-02-03 21:14:43 -04:00
|
|
|
}
|
2018-05-16 16:04:57 -03:00
|
|
|
}
|
2022-12-02 14:36:57 -04:00
|
|
|
|
2023-03-13 19:01:44 -03:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
error:
|
|
|
|
assert(failure != NULL);
|
|
|
|
PyErr_Clear();
|
|
|
|
_sharedexception_clear(sharedexc);
|
|
|
|
*sharedexc = no_exception;
|
|
|
|
return failure;
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
|
|
|
|
2023-02-03 21:14:43 -04:00
|
|
|
static void
|
|
|
|
_sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
2023-02-03 21:14:43 -04:00
|
|
|
if (exc->name != NULL) {
|
|
|
|
if (exc->msg != NULL) {
|
|
|
|
PyErr_Format(wrapperclass, "%s: %s", exc->name, exc->msg);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PyErr_SetString(wrapperclass, exc->name);
|
2022-12-02 14:36:57 -04:00
|
|
|
}
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
2023-02-03 21:14:43 -04:00
|
|
|
else if (exc->msg != NULL) {
|
|
|
|
PyErr_SetString(wrapperclass, exc->msg);
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
2023-02-03 21:14:43 -04:00
|
|
|
else {
|
|
|
|
PyErr_SetNone(wrapperclass);
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-03 00:49:49 -04:00
|
|
|
|
2022-12-05 16:40:20 -04:00
|
|
|
/* interpreter-specific code ************************************************/
|
2018-02-03 00:49:49 -04:00
|
|
|
|
|
|
|
static int
|
2023-02-03 21:14:43 -04:00
|
|
|
exceptions_init(PyObject *mod)
|
2018-02-03 00:49:49 -04:00
|
|
|
{
|
2022-12-05 16:40:20 -04:00
|
|
|
module_state *state = get_module_state(mod);
|
|
|
|
if (state == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
2018-02-03 00:49:49 -04:00
|
|
|
|
2022-12-02 14:36:57 -04:00
|
|
|
#define ADD(NAME, BASE) \
|
|
|
|
do { \
|
2022-12-05 16:40:20 -04:00
|
|
|
assert(state->NAME == NULL); \
|
|
|
|
state->NAME = ADD_NEW_EXCEPTION(mod, NAME, BASE); \
|
|
|
|
if (state->NAME == NULL) { \
|
|
|
|
return -1; \
|
2022-12-02 14:36:57 -04:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
// An uncaught exception came out of interp_run_string().
|
|
|
|
ADD(RunFailedError, PyExc_RuntimeError);
|
|
|
|
#undef ADD
|
2018-02-03 00:49:49 -04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2018-01-29 21:23:44 -04:00
|
|
|
|
|
|
|
static int
|
|
|
|
_is_running(PyInterpreterState *interp)
|
|
|
|
{
|
|
|
|
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
|
|
|
|
if (PyThreadState_Next(tstate) != NULL) {
|
|
|
|
PyErr_SetString(PyExc_RuntimeError,
|
|
|
|
"interpreter has more than one thread");
|
|
|
|
return -1;
|
|
|
|
}
|
2020-04-28 22:01:43 -03:00
|
|
|
|
|
|
|
assert(!PyErr_Occurred());
|
2022-02-25 11:22:00 -04:00
|
|
|
_PyInterpreterFrame *frame = tstate->cframe->current_frame;
|
2018-01-29 21:23:44 -04:00
|
|
|
if (frame == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
2022-03-22 09:57:19 -03:00
|
|
|
return 1;
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
_ensure_not_running(PyInterpreterState *interp)
|
|
|
|
{
|
|
|
|
int is_running = _is_running(interp);
|
|
|
|
if (is_running < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (is_running) {
|
|
|
|
PyErr_Format(PyExc_RuntimeError, "interpreter already running");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
_run_script(PyInterpreterState *interp, const char *codestr,
|
2023-03-13 19:01:44 -03:00
|
|
|
_sharedns *shared, _sharedexception *sharedexc)
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
2020-05-14 13:46:24 -03:00
|
|
|
PyObject *excval = NULL;
|
2019-03-15 19:35:46 -03:00
|
|
|
PyObject *main_mod = _PyInterpreterState_GetMainModule(interp);
|
2018-01-29 21:23:44 -04:00
|
|
|
if (main_mod == NULL) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
PyObject *ns = PyModule_GetDict(main_mod); // borrowed
|
|
|
|
Py_DECREF(main_mod);
|
|
|
|
if (ns == NULL) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
Py_INCREF(ns);
|
|
|
|
|
|
|
|
// Apply the cross-interpreter data.
|
|
|
|
if (shared != NULL) {
|
2018-02-03 00:49:49 -04:00
|
|
|
if (_sharedns_apply(shared, ns) != 0) {
|
|
|
|
Py_DECREF(ns);
|
|
|
|
goto error;
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run the string (see PyRun_SimpleStringFlags).
|
|
|
|
PyObject *result = PyRun_StringFlags(codestr, Py_file_input, ns, ns, NULL);
|
|
|
|
Py_DECREF(ns);
|
|
|
|
if (result == NULL) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Py_DECREF(result); // We throw away the result.
|
|
|
|
}
|
|
|
|
|
2023-03-13 19:01:44 -03:00
|
|
|
*sharedexc = no_exception;
|
2018-01-29 21:23:44 -04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
2023-03-06 13:49:31 -04:00
|
|
|
excval = PyErr_GetRaisedException();
|
2023-03-13 19:01:44 -03:00
|
|
|
const char *failure = _sharedexception_bind(excval, sharedexc);
|
|
|
|
if (failure != NULL) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"RunFailedError: script raised an uncaught exception (%s)",
|
|
|
|
failure);
|
2020-05-14 13:46:24 -03:00
|
|
|
PyErr_Clear();
|
2018-02-03 00:49:49 -04:00
|
|
|
}
|
2023-03-13 19:01:44 -03:00
|
|
|
Py_XDECREF(excval);
|
|
|
|
assert(!PyErr_Occurred());
|
2018-01-29 21:23:44 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2022-12-02 14:36:57 -04:00
|
|
|
_run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
|
|
|
|
const char *codestr, PyObject *shareables)
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
|
|
|
if (_ensure_not_running(interp) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2022-12-05 16:40:20 -04:00
|
|
|
module_state *state = get_module_state(mod);
|
2018-01-29 21:23:44 -04:00
|
|
|
|
2023-02-03 21:14:43 -04:00
|
|
|
_sharedns *shared = _get_shared_ns(shareables);
|
2018-01-29 21:23:44 -04:00
|
|
|
if (shared == NULL && PyErr_Occurred()) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Switch to interpreter.
|
2018-02-20 19:30:17 -04:00
|
|
|
PyThreadState *save_tstate = NULL;
|
2020-03-13 14:15:33 -03:00
|
|
|
if (interp != PyInterpreterState_Get()) {
|
2018-02-20 19:30:17 -04:00
|
|
|
// XXX Using the "head" thread isn't strictly correct.
|
|
|
|
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
|
|
|
|
// XXX Possible GILState issues?
|
|
|
|
save_tstate = PyThreadState_Swap(tstate);
|
|
|
|
}
|
2018-01-29 21:23:44 -04:00
|
|
|
|
|
|
|
// Run the script.
|
2023-04-04 11:51:30 -03:00
|
|
|
_sharedexception exc = {NULL, NULL};
|
2023-02-03 21:14:43 -04:00
|
|
|
int result = _run_script(interp, codestr, shared, &exc);
|
2018-01-29 21:23:44 -04:00
|
|
|
|
|
|
|
// Switch back.
|
|
|
|
if (save_tstate != NULL) {
|
|
|
|
PyThreadState_Swap(save_tstate);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Propagate any exception out to the caller.
|
2023-03-13 19:01:44 -03:00
|
|
|
if (exc.name != NULL) {
|
2022-12-05 16:40:20 -04:00
|
|
|
assert(state != NULL);
|
2023-03-13 19:01:44 -03:00
|
|
|
_sharedexception_apply(&exc, state->RunFailedError);
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
|
|
|
else if (result != 0) {
|
|
|
|
// We were unable to allocate a shared exception.
|
|
|
|
PyErr_NoMemory();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shared != NULL) {
|
2018-02-03 00:49:49 -04:00
|
|
|
_sharedns_free(shared);
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* module level code ********************************************************/
|
|
|
|
|
|
|
|
static PyObject *
|
2020-05-01 06:33:44 -03:00
|
|
|
interp_create(PyObject *self, PyObject *args, PyObject *kwds)
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
2020-05-01 06:33:44 -03:00
|
|
|
|
|
|
|
static char *kwlist[] = {"isolated", NULL};
|
|
|
|
int isolated = 1;
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$i:create", kwlist,
|
|
|
|
&isolated)) {
|
2018-01-29 21:23:44 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create and initialize the new interpreter.
|
2021-10-13 09:09:13 -03:00
|
|
|
PyThreadState *save_tstate = _PyThreadState_GET();
|
gh-98610: Adjust the Optional Restrictions on Subinterpreters (GH-98618)
Previously, the optional restrictions on subinterpreters were: disallow fork, subprocess, and threads. By default, we were disallowing all three for "isolated" interpreters. We always allowed all three for the main interpreter and those created through the legacy `Py_NewInterpreter()` API.
Those settings were a bit conservative, so here we've adjusted the optional restrictions to: fork, exec, threads, and daemon threads. The default for "isolated" interpreters disables fork, exec, and daemon threads. Regular threads are allowed by default. We continue always allowing everything For the main interpreter and the legacy API.
In the code, we add `_PyInterpreterConfig.allow_exec` and `_PyInterpreterConfig.allow_daemon_threads`. We also add `Py_RTFLAGS_DAEMON_THREADS` and `Py_RTFLAGS_EXEC`.
2022-10-31 16:35:54 -03:00
|
|
|
const _PyInterpreterConfig config = isolated
|
|
|
|
? (_PyInterpreterConfig)_PyInterpreterConfig_INIT
|
|
|
|
: (_PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT;
|
2018-02-20 19:30:17 -04:00
|
|
|
// XXX Possible GILState issues?
|
2023-03-21 13:49:12 -03:00
|
|
|
PyThreadState *tstate = NULL;
|
|
|
|
PyStatus status = _Py_NewInterpreterFromConfig(&tstate, &config);
|
2018-01-29 21:23:44 -04:00
|
|
|
PyThreadState_Swap(save_tstate);
|
2023-03-21 13:49:12 -03:00
|
|
|
if (PyStatus_Exception(status)) {
|
2018-01-29 21:23:44 -04:00
|
|
|
/* Since no new thread state was created, there is no exception to
|
|
|
|
propagate; raise a fresh one after swapping in the old thread
|
|
|
|
state. */
|
2023-03-21 13:49:12 -03:00
|
|
|
_PyErr_SetFromPyStatus(status);
|
|
|
|
PyObject *exc = PyErr_GetRaisedException();
|
2018-01-29 21:23:44 -04:00
|
|
|
PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
|
2023-03-21 13:49:12 -03:00
|
|
|
_PyErr_ChainExceptions1(exc);
|
2018-01-29 21:23:44 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
2023-03-21 13:49:12 -03:00
|
|
|
assert(tstate != NULL);
|
2020-03-25 15:52:02 -03:00
|
|
|
PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate);
|
|
|
|
PyObject *idobj = _PyInterpreterState_GetIDObject(interp);
|
2019-03-15 19:35:46 -03:00
|
|
|
if (idobj == NULL) {
|
|
|
|
// XXX Possible GILState issues?
|
|
|
|
save_tstate = PyThreadState_Swap(tstate);
|
|
|
|
Py_EndInterpreter(tstate);
|
|
|
|
PyThreadState_Swap(save_tstate);
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-03-25 15:52:02 -03:00
|
|
|
_PyInterpreterState_RequireIDRef(interp, 1);
|
2019-03-15 19:35:46 -03:00
|
|
|
return idobj;
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
PyDoc_STRVAR(create_doc,
|
|
|
|
"create() -> ID\n\
|
|
|
|
\n\
|
|
|
|
Create a new interpreter and return a unique generated ID.");
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
2018-05-16 16:04:57 -03:00
|
|
|
interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
2018-05-16 16:04:57 -03:00
|
|
|
static char *kwlist[] = {"id", NULL};
|
2018-01-29 21:23:44 -04:00
|
|
|
PyObject *id;
|
2018-05-16 16:04:57 -03:00
|
|
|
// XXX Use "L" for id?
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds,
|
|
|
|
"O:destroy", kwlist, &id)) {
|
2018-01-29 21:23:44 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Look up the interpreter.
|
2019-03-15 19:35:46 -03:00
|
|
|
PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
|
2018-01-29 21:23:44 -04:00
|
|
|
if (interp == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure we don't try to destroy the current interpreter.
|
2022-12-02 14:36:57 -04:00
|
|
|
PyInterpreterState *current = _get_current_interp();
|
2018-01-29 21:23:44 -04:00
|
|
|
if (current == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (interp == current) {
|
|
|
|
PyErr_SetString(PyExc_RuntimeError,
|
|
|
|
"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 (_ensure_not_running(interp) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Destroy the interpreter.
|
2018-02-20 19:30:17 -04:00
|
|
|
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
|
|
|
|
// XXX Possible GILState issues?
|
|
|
|
PyThreadState *save_tstate = PyThreadState_Swap(tstate);
|
2018-01-29 21:23:44 -04:00
|
|
|
Py_EndInterpreter(tstate);
|
|
|
|
PyThreadState_Swap(save_tstate);
|
|
|
|
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyDoc_STRVAR(destroy_doc,
|
2018-05-16 16:04:57 -03:00
|
|
|
"destroy(id)\n\
|
2018-01-29 21:23:44 -04:00
|
|
|
\n\
|
|
|
|
Destroy the identified interpreter.\n\
|
|
|
|
\n\
|
|
|
|
Attempting to destroy the current interpreter results in a RuntimeError.\n\
|
|
|
|
So does an unrecognized ID.");
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
2018-04-29 15:59:33 -03:00
|
|
|
interp_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
|
|
|
PyObject *ids, *id;
|
|
|
|
PyInterpreterState *interp;
|
|
|
|
|
|
|
|
ids = PyList_New(0);
|
|
|
|
if (ids == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
interp = PyInterpreterState_Head();
|
|
|
|
while (interp != NULL) {
|
2019-03-15 19:35:46 -03:00
|
|
|
id = _PyInterpreterState_GetIDObject(interp);
|
2018-01-29 21:23:44 -04:00
|
|
|
if (id == NULL) {
|
|
|
|
Py_DECREF(ids);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
// insert at front of list
|
2018-02-03 00:49:49 -04:00
|
|
|
int res = PyList_Insert(ids, 0, id);
|
|
|
|
Py_DECREF(id);
|
|
|
|
if (res < 0) {
|
2018-01-29 21:23:44 -04:00
|
|
|
Py_DECREF(ids);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
interp = PyInterpreterState_Next(interp);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ids;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyDoc_STRVAR(list_all_doc,
|
|
|
|
"list_all() -> [ID]\n\
|
|
|
|
\n\
|
|
|
|
Return a list containing the ID of every existing interpreter.");
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
2018-04-29 15:59:33 -03:00
|
|
|
interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
2022-12-02 14:36:57 -04:00
|
|
|
PyInterpreterState *interp =_get_current_interp();
|
2018-01-29 21:23:44 -04:00
|
|
|
if (interp == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-03-15 19:35:46 -03:00
|
|
|
return _PyInterpreterState_GetIDObject(interp);
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
PyDoc_STRVAR(get_current_doc,
|
|
|
|
"get_current() -> ID\n\
|
|
|
|
\n\
|
|
|
|
Return the ID of current interpreter.");
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
2018-04-29 15:59:33 -03:00
|
|
|
interp_get_main(PyObject *self, PyObject *Py_UNUSED(ignored))
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
|
|
|
// Currently, 0 is always the main interpreter.
|
2020-04-17 14:13:06 -03:00
|
|
|
int64_t id = 0;
|
2019-03-15 19:35:46 -03:00
|
|
|
return _PyInterpreterID_New(id);
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
PyDoc_STRVAR(get_main_doc,
|
|
|
|
"get_main() -> ID\n\
|
|
|
|
\n\
|
|
|
|
Return the ID of main interpreter.");
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
2018-05-16 16:04:57 -03:00
|
|
|
interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
2018-05-16 16:04:57 -03:00
|
|
|
static char *kwlist[] = {"id", "script", "shared", NULL};
|
2018-01-29 21:23:44 -04:00
|
|
|
PyObject *id, *code;
|
|
|
|
PyObject *shared = NULL;
|
2018-05-16 16:04:57 -03:00
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds,
|
|
|
|
"OU|O:run_string", kwlist,
|
|
|
|
&id, &code, &shared)) {
|
2018-01-29 21:23:44 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Look up the interpreter.
|
2019-03-15 19:35:46 -03:00
|
|
|
PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
|
2018-01-29 21:23:44 -04:00
|
|
|
if (interp == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extract code.
|
|
|
|
Py_ssize_t size;
|
|
|
|
const char *codestr = PyUnicode_AsUTF8AndSize(code, &size);
|
|
|
|
if (codestr == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (strlen(codestr) != (size_t)size) {
|
|
|
|
PyErr_SetString(PyExc_ValueError,
|
|
|
|
"source code string cannot contain null bytes");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run the code in the interpreter.
|
2022-12-02 14:36:57 -04:00
|
|
|
if (_run_script_in_interpreter(self, interp, codestr, shared) != 0) {
|
2018-01-29 21:23:44 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyDoc_STRVAR(run_string_doc,
|
2018-05-16 16:04:57 -03:00
|
|
|
"run_string(id, script, shared)\n\
|
2018-01-29 21:23:44 -04:00
|
|
|
\n\
|
|
|
|
Execute the provided string in the identified interpreter.\n\
|
|
|
|
\n\
|
|
|
|
See PyRun_SimpleStrings.");
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
2018-05-16 16:04:57 -03:00
|
|
|
object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
2018-05-16 16:04:57 -03:00
|
|
|
static char *kwlist[] = {"obj", NULL};
|
2018-01-29 21:23:44 -04:00
|
|
|
PyObject *obj;
|
2018-05-16 16:04:57 -03:00
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds,
|
|
|
|
"O:is_shareable", kwlist, &obj)) {
|
2018-01-29 21:23:44 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
2018-05-16 16:04:57 -03:00
|
|
|
|
2018-01-29 21:23:44 -04:00
|
|
|
if (_PyObject_CheckCrossInterpreterData(obj) == 0) {
|
|
|
|
Py_RETURN_TRUE;
|
|
|
|
}
|
|
|
|
PyErr_Clear();
|
|
|
|
Py_RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyDoc_STRVAR(is_shareable_doc,
|
|
|
|
"is_shareable(obj) -> bool\n\
|
|
|
|
\n\
|
|
|
|
Return True if the object's data may be shared between interpreters and\n\
|
|
|
|
False otherwise.");
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
2018-05-16 16:04:57 -03:00
|
|
|
interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
2018-05-16 16:04:57 -03:00
|
|
|
static char *kwlist[] = {"id", NULL};
|
2018-01-29 21:23:44 -04:00
|
|
|
PyObject *id;
|
2018-05-16 16:04:57 -03:00
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds,
|
|
|
|
"O:is_running", kwlist, &id)) {
|
2018-01-29 21:23:44 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-03-15 19:35:46 -03:00
|
|
|
PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
|
2018-01-29 21:23:44 -04:00
|
|
|
if (interp == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
int is_running = _is_running(interp);
|
|
|
|
if (is_running < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (is_running) {
|
|
|
|
Py_RETURN_TRUE;
|
|
|
|
}
|
|
|
|
Py_RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyDoc_STRVAR(is_running_doc,
|
|
|
|
"is_running(id) -> bool\n\
|
|
|
|
\n\
|
|
|
|
Return whether or not the identified interpreter is running.");
|
|
|
|
|
|
|
|
static PyMethodDef module_functions[] = {
|
2022-05-03 16:42:14 -03:00
|
|
|
{"create", _PyCFunction_CAST(interp_create),
|
2020-05-01 06:33:44 -03:00
|
|
|
METH_VARARGS | METH_KEYWORDS, create_doc},
|
2022-05-03 16:42:14 -03:00
|
|
|
{"destroy", _PyCFunction_CAST(interp_destroy),
|
2018-05-16 16:04:57 -03:00
|
|
|
METH_VARARGS | METH_KEYWORDS, destroy_doc},
|
2018-04-29 15:59:33 -03:00
|
|
|
{"list_all", interp_list_all,
|
2018-01-29 21:23:44 -04:00
|
|
|
METH_NOARGS, list_all_doc},
|
2018-04-29 15:59:33 -03:00
|
|
|
{"get_current", interp_get_current,
|
2018-01-29 21:23:44 -04:00
|
|
|
METH_NOARGS, get_current_doc},
|
2018-04-29 15:59:33 -03:00
|
|
|
{"get_main", interp_get_main,
|
2018-01-29 21:23:44 -04:00
|
|
|
METH_NOARGS, get_main_doc},
|
2023-02-03 21:14:43 -04:00
|
|
|
|
2022-05-03 16:42:14 -03:00
|
|
|
{"is_running", _PyCFunction_CAST(interp_is_running),
|
2018-05-16 16:04:57 -03:00
|
|
|
METH_VARARGS | METH_KEYWORDS, is_running_doc},
|
2022-05-03 16:42:14 -03:00
|
|
|
{"run_string", _PyCFunction_CAST(interp_run_string),
|
2018-05-16 16:04:57 -03:00
|
|
|
METH_VARARGS | METH_KEYWORDS, run_string_doc},
|
2018-01-29 21:23:44 -04:00
|
|
|
|
2022-05-03 16:42:14 -03:00
|
|
|
{"is_shareable", _PyCFunction_CAST(object_is_shareable),
|
2018-05-16 16:04:57 -03:00
|
|
|
METH_VARARGS | METH_KEYWORDS, is_shareable_doc},
|
2018-01-29 21:23:44 -04: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 14:36:57 -04:00
|
|
|
static int
|
|
|
|
module_exec(PyObject *mod)
|
2018-01-29 21:23:44 -04:00
|
|
|
{
|
|
|
|
/* Add exception types */
|
2023-02-03 21:14:43 -04:00
|
|
|
if (exceptions_init(mod) != 0) {
|
2022-12-02 14:36:57 -04:00
|
|
|
goto error;
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|
2022-12-05 16:40:20 -04:00
|
|
|
|
|
|
|
// PyInterpreterID
|
2022-12-02 14:36:57 -04:00
|
|
|
if (PyModule_AddType(mod, &_PyInterpreterID_Type) < 0) {
|
|
|
|
goto error;
|
2018-02-16 21:53:40 -04:00
|
|
|
}
|
2018-01-29 21:23:44 -04:00
|
|
|
|
2022-12-02 14:36:57 -04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-12-05 16:40:20 -04:00
|
|
|
static struct PyModuleDef_Slot module_slots[] = {
|
|
|
|
{Py_mod_exec, module_exec},
|
|
|
|
{0, NULL},
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
module_traverse(PyObject *mod, visitproc visit, void *arg)
|
|
|
|
{
|
|
|
|
module_state *state = get_module_state(mod);
|
|
|
|
assert(state != NULL);
|
|
|
|
traverse_module_state(state, visit, arg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
module_clear(PyObject *mod)
|
|
|
|
{
|
|
|
|
module_state *state = get_module_state(mod);
|
|
|
|
assert(state != NULL);
|
|
|
|
clear_module_state(state);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
module_free(void *mod)
|
|
|
|
{
|
|
|
|
module_state *state = get_module_state(mod);
|
|
|
|
assert(state != NULL);
|
|
|
|
clear_module_state(state);
|
|
|
|
}
|
|
|
|
|
2022-12-02 14:36:57 -04:00
|
|
|
static struct PyModuleDef moduledef = {
|
|
|
|
.m_base = PyModuleDef_HEAD_INIT,
|
|
|
|
.m_name = MODULE_NAME,
|
|
|
|
.m_doc = module_doc,
|
2022-12-05 16:40:20 -04:00
|
|
|
.m_size = sizeof(module_state),
|
2022-12-02 14:36:57 -04:00
|
|
|
.m_methods = module_functions,
|
2022-12-05 16:40:20 -04:00
|
|
|
.m_slots = module_slots,
|
|
|
|
.m_traverse = module_traverse,
|
|
|
|
.m_clear = module_clear,
|
|
|
|
.m_free = (freefunc)module_free,
|
2022-12-02 14:36:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
PyMODINIT_FUNC
|
|
|
|
PyInit__xxsubinterpreters(void)
|
|
|
|
{
|
2022-12-05 16:40:20 -04:00
|
|
|
return PyModuleDef_Init(&moduledef);
|
2018-01-29 21:23:44 -04:00
|
|
|
}
|