mirror of
https://github.com/python/cpython.git
synced 2025-10-28 17:13:08 +00:00
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.)
This commit is contained in:
parent
67c19e57b5
commit
e80abd57a8
11 changed files with 622 additions and 155 deletions
|
|
@ -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,
|
||||
|
|
@ -1499,6 +1523,33 @@ PyDoc_STRVAR(queuesmod_get_maxsize_doc,
|
|||
\n\
|
||||
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)
|
||||
{
|
||||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -902,6 +902,56 @@ The code/function must not take any arguments or be a closure\n\
|
|||
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)
|
||||
{
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue