summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2024-02-28 23:08:08 (GMT)
committerGitHub <noreply@github.com>2024-02-28 23:08:08 (GMT)
commite80abd57a82ea1beae0a82423d45c6eb8c5c5c74 (patch)
tree3fd81507ec511caa0a98f2141ce8af6953359fb0 /Modules
parent67c19e57b5c928278ebd191a545979ce786f06b3 (diff)
downloadcpython-e80abd57a82ea1beae0a82423d45c6eb8c5c5c74.zip
cpython-e80abd57a82ea1beae0a82423d45c6eb8c5c5c74.tar.gz
cpython-e80abd57a82ea1beae0a82423d45c6eb8c5c5c74.tar.bz2
gh-76785: Update test.support.interpreters to Align With PEP 734 (gh-115566)
This brings the code under test.support.interpreters, and the corresponding extension modules, in line with recent updates to PEP 734. (Note: PEP 734 has not been accepted at this time. However, we are using an internal copy of the implementation in the test suite to exercise the existing subinterpreters feature.)
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_xxinterpqueuesmodule.c125
-rw-r--r--Modules/_xxsubinterpretersmodule.c58
2 files changed, 147 insertions, 36 deletions
diff --git a/Modules/_xxinterpqueuesmodule.c b/Modules/_xxinterpqueuesmodule.c
index 7d8c67f..715bb76 100644
--- a/Modules/_xxinterpqueuesmodule.c
+++ b/Modules/_xxinterpqueuesmodule.c
@@ -294,6 +294,8 @@ handle_queue_error(int err, PyObject *mod, int64_t qid)
case ERR_QUEUES_ALLOC:
PyErr_NoMemory();
break;
+ case -1:
+ return -1;
default:
state = get_module_state(mod);
assert(state->QueueError != NULL);
@@ -320,14 +322,17 @@ struct _queueitem;
typedef struct _queueitem {
_PyCrossInterpreterData *data;
+ int fmt;
struct _queueitem *next;
} _queueitem;
static void
-_queueitem_init(_queueitem *item, _PyCrossInterpreterData *data)
+_queueitem_init(_queueitem *item,
+ _PyCrossInterpreterData *data, int fmt)
{
*item = (_queueitem){
.data = data,
+ .fmt = fmt,
};
}
@@ -344,14 +349,14 @@ _queueitem_clear(_queueitem *item)
}
static _queueitem *
-_queueitem_new(_PyCrossInterpreterData *data)
+_queueitem_new(_PyCrossInterpreterData *data, int fmt)
{
_queueitem *item = GLOBAL_MALLOC(_queueitem);
if (item == NULL) {
PyErr_NoMemory();
return NULL;
}
- _queueitem_init(item, data);
+ _queueitem_init(item, data, fmt);
return item;
}
@@ -373,9 +378,11 @@ _queueitem_free_all(_queueitem *item)
}
static void
-_queueitem_popped(_queueitem *item, _PyCrossInterpreterData **p_data)
+_queueitem_popped(_queueitem *item,
+ _PyCrossInterpreterData **p_data, int *p_fmt)
{
*p_data = item->data;
+ *p_fmt = item->fmt;
// We clear them here, so they won't be released in _queueitem_clear().
item->data = NULL;
_queueitem_free(item);
@@ -393,10 +400,11 @@ typedef struct _queue {
_queueitem *first;
_queueitem *last;
} items;
+ int fmt;
} _queue;
static int
-_queue_init(_queue *queue, Py_ssize_t maxsize)
+_queue_init(_queue *queue, Py_ssize_t maxsize, int fmt)
{
PyThread_type_lock mutex = PyThread_allocate_lock();
if (mutex == NULL) {
@@ -408,6 +416,7 @@ _queue_init(_queue *queue, Py_ssize_t maxsize)
.items = {
.maxsize = maxsize,
},
+ .fmt = fmt,
};
return 0;
}
@@ -486,7 +495,7 @@ _queue_unlock(_queue *queue)
}
static int
-_queue_add(_queue *queue, _PyCrossInterpreterData *data)
+_queue_add(_queue *queue, _PyCrossInterpreterData *data, int fmt)
{
int err = _queue_lock(queue);
if (err < 0) {
@@ -502,7 +511,7 @@ _queue_add(_queue *queue, _PyCrossInterpreterData *data)
return ERR_QUEUE_FULL;
}
- _queueitem *item = _queueitem_new(data);
+ _queueitem *item = _queueitem_new(data, fmt);
if (item == NULL) {
_queue_unlock(queue);
return -1;
@@ -522,7 +531,8 @@ _queue_add(_queue *queue, _PyCrossInterpreterData *data)
}
static int
-_queue_next(_queue *queue, _PyCrossInterpreterData **p_data)
+_queue_next(_queue *queue,
+ _PyCrossInterpreterData **p_data, int *p_fmt)
{
int err = _queue_lock(queue);
if (err < 0) {
@@ -541,7 +551,7 @@ _queue_next(_queue *queue, _PyCrossInterpreterData **p_data)
}
queue->items.count -= 1;
- _queueitem_popped(item, p_data);
+ _queueitem_popped(item, p_data, p_fmt);
_queue_unlock(queue);
return 0;
@@ -843,18 +853,26 @@ finally:
PyThread_release_lock(queues->mutex);
}
-static int64_t *
+struct queue_id_and_fmt {
+ int64_t id;
+ int fmt;
+};
+
+static struct queue_id_and_fmt *
_queues_list_all(_queues *queues, int64_t *count)
{
- int64_t *qids = NULL;
+ struct queue_id_and_fmt *qids = NULL;
PyThread_acquire_lock(queues->mutex, WAIT_LOCK);
- int64_t *ids = PyMem_NEW(int64_t, (Py_ssize_t)(queues->count));
+ struct queue_id_and_fmt *ids = PyMem_NEW(struct queue_id_and_fmt,
+ (Py_ssize_t)(queues->count));
if (ids == NULL) {
goto done;
}
_queueref *ref = queues->head;
for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
- ids[i] = ref->qid;
+ ids[i].id = ref->qid;
+ assert(ref->queue != NULL);
+ ids[i].fmt = ref->queue->fmt;
}
*count = queues->count;
@@ -890,13 +908,13 @@ _queue_free(_queue *queue)
// Create a new queue.
static int64_t
-queue_create(_queues *queues, Py_ssize_t maxsize)
+queue_create(_queues *queues, Py_ssize_t maxsize, int fmt)
{
_queue *queue = GLOBAL_MALLOC(_queue);
if (queue == NULL) {
return ERR_QUEUE_ALLOC;
}
- int err = _queue_init(queue, maxsize);
+ int err = _queue_init(queue, maxsize, fmt);
if (err < 0) {
GLOBAL_FREE(queue);
return (int64_t)err;
@@ -925,7 +943,7 @@ queue_destroy(_queues *queues, int64_t qid)
// Push an object onto the queue.
static int
-queue_put(_queues *queues, int64_t qid, PyObject *obj)
+queue_put(_queues *queues, int64_t qid, PyObject *obj, int fmt)
{
// Look up the queue.
_queue *queue = NULL;
@@ -948,7 +966,7 @@ queue_put(_queues *queues, int64_t qid, PyObject *obj)
}
// Add the data to the queue.
- int res = _queue_add(queue, data);
+ int res = _queue_add(queue, data, fmt);
_queue_unmark_waiter(queue, queues->mutex);
if (res != 0) {
// We may chain an exception here:
@@ -963,7 +981,7 @@ queue_put(_queues *queues, int64_t qid, PyObject *obj)
// Pop the next object off the queue. Fail if empty.
// XXX Support a "wait" mutex?
static int
-queue_get(_queues *queues, int64_t qid, PyObject **res)
+queue_get(_queues *queues, int64_t qid, PyObject **res, int *p_fmt)
{
int err;
*res = NULL;
@@ -979,7 +997,7 @@ queue_get(_queues *queues, int64_t qid, PyObject **res)
// Pop off the next item from the queue.
_PyCrossInterpreterData *data = NULL;
- err = _queue_next(queue, &data);
+ err = _queue_next(queue, &data, p_fmt);
_queue_unmark_waiter(queue, queues->mutex);
if (err != 0) {
return err;
@@ -1267,14 +1285,15 @@ qidarg_converter(PyObject *arg, void *ptr)
static PyObject *
queuesmod_create(PyObject *self, PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = {"maxsize", NULL};
- Py_ssize_t maxsize = -1;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|n:create", kwlist,
- &maxsize)) {
+ static char *kwlist[] = {"maxsize", "fmt", NULL};
+ Py_ssize_t maxsize;
+ int fmt;
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ni:create", kwlist,
+ &maxsize, &fmt)) {
return NULL;
}
- int64_t qid = queue_create(&_globals.queues, maxsize);
+ int64_t qid = queue_create(&_globals.queues, maxsize, fmt);
if (qid < 0) {
(void)handle_queue_error((int)qid, self, qid);
return NULL;
@@ -1329,7 +1348,7 @@ static PyObject *
queuesmod_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
{
int64_t count = 0;
- int64_t *qids = _queues_list_all(&_globals.queues, &count);
+ struct queue_id_and_fmt *qids = _queues_list_all(&_globals.queues, &count);
if (qids == NULL) {
if (count == 0) {
return PyList_New(0);
@@ -1340,14 +1359,14 @@ queuesmod_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
if (ids == NULL) {
goto finally;
}
- int64_t *cur = qids;
+ struct queue_id_and_fmt *cur = qids;
for (int64_t i=0; i < count; cur++, i++) {
- PyObject *qidobj = PyLong_FromLongLong(*cur);
- if (qidobj == NULL) {
+ PyObject *item = Py_BuildValue("Li", cur->id, cur->fmt);
+ if (item == NULL) {
Py_SETREF(ids, NULL);
break;
}
- PyList_SET_ITEM(ids, (Py_ssize_t)i, qidobj);
+ PyList_SET_ITEM(ids, (Py_ssize_t)i, item);
}
finally:
@@ -1363,17 +1382,18 @@ Return the list of IDs for all queues.");
static PyObject *
queuesmod_put(PyObject *self, PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = {"qid", "obj", NULL};
+ static char *kwlist[] = {"qid", "obj", "fmt", NULL};
qidarg_converter_data qidarg;
PyObject *obj;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O:put", kwlist,
- qidarg_converter, &qidarg, &obj)) {
+ int fmt;
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&Oi:put", kwlist,
+ qidarg_converter, &qidarg, &obj, &fmt)) {
return NULL;
}
int64_t qid = qidarg.id;
/* Queue up the object. */
- int err = queue_put(&_globals.queues, qid, obj);
+ int err = queue_put(&_globals.queues, qid, obj, fmt);
if (handle_queue_error(err, self, qid)) {
return NULL;
}
@@ -1382,7 +1402,7 @@ queuesmod_put(PyObject *self, PyObject *args, PyObject *kwds)
}
PyDoc_STRVAR(queuesmod_put_doc,
-"put(qid, obj)\n\
+"put(qid, obj, sharedonly=False)\n\
\n\
Add the object's data to the queue.");
@@ -1399,7 +1419,8 @@ queuesmod_get(PyObject *self, PyObject *args, PyObject *kwds)
int64_t qid = qidarg.id;
PyObject *obj = NULL;
- int err = queue_get(&_globals.queues, qid, &obj);
+ int fmt;
+ int err = queue_get(&_globals.queues, qid, &obj, &fmt);
if (err == ERR_QUEUE_EMPTY && dflt != NULL) {
assert(obj == NULL);
obj = Py_NewRef(dflt);
@@ -1407,7 +1428,10 @@ queuesmod_get(PyObject *self, PyObject *args, PyObject *kwds)
else if (handle_queue_error(err, self, qid)) {
return NULL;
}
- return obj;
+
+ PyObject *res = Py_BuildValue("Oi", obj, fmt);
+ Py_DECREF(obj);
+ return res;
}
PyDoc_STRVAR(queuesmod_get_doc,
@@ -1500,6 +1524,33 @@ PyDoc_STRVAR(queuesmod_get_maxsize_doc,
Return the maximum number of items in the queue.");
static PyObject *
+queuesmod_get_default_fmt(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"qid", NULL};
+ qidarg_converter_data qidarg;
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ "O&:get_default_fmt", kwlist,
+ qidarg_converter, &qidarg)) {
+ return NULL;
+ }
+ int64_t qid = qidarg.id;
+
+ _queue *queue = NULL;
+ int err = _queues_lookup(&_globals.queues, qid, &queue);
+ if (handle_queue_error(err, self, qid)) {
+ return NULL;
+ }
+ int fmt = queue->fmt;
+ _queue_unmark_waiter(queue, _globals.queues.mutex);
+ return PyLong_FromLong(fmt);
+}
+
+PyDoc_STRVAR(queuesmod_get_default_fmt_doc,
+"get_default_fmt(qid)\n\
+\n\
+Return the default format to use for the queue.");
+
+static PyObject *
queuesmod_is_full(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"qid", NULL};
@@ -1593,6 +1644,8 @@ static PyMethodDef module_functions[] = {
METH_VARARGS | METH_KEYWORDS, queuesmod_release_doc},
{"get_maxsize", _PyCFunction_CAST(queuesmod_get_maxsize),
METH_VARARGS | METH_KEYWORDS, queuesmod_get_maxsize_doc},
+ {"get_default_fmt", _PyCFunction_CAST(queuesmod_get_default_fmt),
+ METH_VARARGS | METH_KEYWORDS, queuesmod_get_default_fmt_doc},
{"is_full", _PyCFunction_CAST(queuesmod_is_full),
METH_VARARGS | METH_KEYWORDS, queuesmod_is_full_doc},
{"get_count", _PyCFunction_CAST(queuesmod_get_count),
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index b4004d1..28c2f9c 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -903,6 +903,56 @@ If a function is provided, its code object is used and all its state\n\
is ignored, including its __globals__ dict.");
static PyObject *
+interp_call(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"id", "callable", "args", "kwargs", NULL};
+ PyObject *id, *callable;
+ PyObject *args_obj = NULL;
+ PyObject *kwargs_obj = NULL;
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ "OO|OO:" MODULE_NAME_STR ".call", kwlist,
+ &id, &callable, &args_obj, &kwargs_obj)) {
+ return NULL;
+ }
+
+ if (args_obj != NULL) {
+ PyErr_SetString(PyExc_ValueError, "got unexpected args");
+ return NULL;
+ }
+ if (kwargs_obj != NULL) {
+ PyErr_SetString(PyExc_ValueError, "got unexpected kwargs");
+ return NULL;
+ }
+
+ PyObject *code = (PyObject *)convert_code_arg(callable, MODULE_NAME_STR ".call",
+ "argument 2", "a function");
+ if (code == NULL) {
+ return NULL;
+ }
+
+ PyObject *excinfo = NULL;
+ int res = _interp_exec(self, id, code, NULL, &excinfo);
+ Py_DECREF(code);
+ if (res < 0) {
+ assert((excinfo == NULL) != (PyErr_Occurred() == NULL));
+ return excinfo;
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(call_doc,
+"call(id, callable, args=None, kwargs=None)\n\
+\n\
+Call the provided object in the identified interpreter.\n\
+Pass the given args and kwargs, if possible.\n\
+\n\
+\"callable\" may be a plain function with no free vars that takes\n\
+no arguments.\n\
+\n\
+The function's code object is used and all its state\n\
+is ignored, including its __globals__ dict.");
+
+static PyObject *
interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"id", "script", "shared", NULL};
@@ -1085,6 +1135,8 @@ static PyMethodDef module_functions[] = {
METH_VARARGS | METH_KEYWORDS, is_running_doc},
{"exec", _PyCFunction_CAST(interp_exec),
METH_VARARGS | METH_KEYWORDS, exec_doc},
+ {"call", _PyCFunction_CAST(interp_call),
+ METH_VARARGS | METH_KEYWORDS, call_doc},
{"run_string", _PyCFunction_CAST(interp_run_string),
METH_VARARGS | METH_KEYWORDS, run_string_doc},
{"run_func", _PyCFunction_CAST(interp_run_func),
@@ -1113,6 +1165,7 @@ The 'interpreters' module provides a more convenient interface.");
static int
module_exec(PyObject *mod)
{
+ PyInterpreterState *interp = PyInterpreterState_Get();
module_state *state = get_module_state(mod);
// exceptions
@@ -1122,6 +1175,11 @@ module_exec(PyObject *mod)
if (PyModule_AddType(mod, (PyTypeObject *)PyExc_InterpreterNotFoundError) < 0) {
goto error;
}
+ PyObject *PyExc_NotShareableError = \
+ _PyInterpreterState_GetXIState(interp)->PyExc_NotShareableError;
+ if (PyModule_AddType(mod, (PyTypeObject *)PyExc_NotShareableError) < 0) {
+ goto error;
+ }
if (register_memoryview_xid(mod, &state->XIBufferViewType) < 0) {
goto error;