summaryrefslogtreecommitdiff
path: root/Modules/_xxsubinterpretersmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_xxsubinterpretersmodule.c')
-rw-r--r--Modules/_xxsubinterpretersmodule.c89
1 files changed, 83 insertions, 6 deletions
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 2ee8d07d06..e618930e09 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -538,7 +538,7 @@ _channelend_find(_channelend *first, int64_t interp, _channelend **pprev)
typedef struct _channelassociations {
// Note that the list entries are never removed for interpreter
- // for which the channel is closed. This should be a problem in
+ // for which the channel is closed. This should not be a problem in
// practice. Also, a channel isn't automatically closed when an
// interpreter is destroyed.
int64_t numsendopen;
@@ -1179,11 +1179,6 @@ _channels_list_all(_channels *channels, int64_t *count)
{
int64_t *cids = NULL;
PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
- int64_t numopen = channels->numopen;
- if (numopen >= PY_SSIZE_T_MAX) {
- PyErr_SetString(PyExc_RuntimeError, "too many channels open");
- goto done;
- }
int64_t *ids = PyMem_NEW(int64_t, (Py_ssize_t)(channels->numopen));
if (ids == NULL) {
goto done;
@@ -1392,6 +1387,24 @@ _channel_close(_channels *channels, int64_t id, int end, int force)
return _channels_close(channels, id, NULL, end, force);
}
+static int
+_channel_is_associated(_channels *channels, int64_t cid, int64_t interp,
+ int send)
+{
+ _PyChannelState *chan = _channels_lookup(channels, cid, NULL);
+ if (chan == NULL) {
+ return -1;
+ } else if (send && chan->closing != NULL) {
+ PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
+ return -1;
+ }
+
+ _channelend *end = _channelend_find(send ? chan->ends->send : chan->ends->recv,
+ interp, NULL);
+
+ return (end != NULL && end->open);
+}
+
/* ChannelID class */
static PyTypeObject ChannelIDtype;
@@ -2324,6 +2337,68 @@ PyDoc_STRVAR(channel_list_all_doc,
Return the list of all IDs for active channels.");
static PyObject *
+channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"cid", "send", NULL};
+ int64_t cid; /* Channel ID */
+ int send = 0; /* Send or receive end? */
+ int64_t id;
+ PyObject *ids, *id_obj;
+ PyInterpreterState *interp;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds, "O&$p:channel_list_interpreters",
+ kwlist, channel_id_converter, &cid, &send)) {
+ return NULL;
+ }
+
+ ids = PyList_New(0);
+ if (ids == NULL) {
+ goto except;
+ }
+
+ interp = PyInterpreterState_Head();
+ while (interp != NULL) {
+ id = PyInterpreterState_GetID(interp);
+ assert(id >= 0);
+ int res = _channel_is_associated(&_globals.channels, cid, id, send);
+ if (res < 0) {
+ goto except;
+ }
+ if (res) {
+ id_obj = _PyInterpreterState_GetIDObject(interp);
+ if (id_obj == NULL) {
+ goto except;
+ }
+ res = PyList_Insert(ids, 0, id_obj);
+ Py_DECREF(id_obj);
+ if (res < 0) {
+ goto except;
+ }
+ }
+ interp = PyInterpreterState_Next(interp);
+ }
+
+ goto finally;
+
+except:
+ Py_XDECREF(ids);
+ ids = NULL;
+
+finally:
+ return ids;
+}
+
+PyDoc_STRVAR(channel_list_interpreters_doc,
+"channel_list_interpreters(cid, *, send) -> [id]\n\
+\n\
+Return the list of all interpreter IDs associated with an end of the channel.\n\
+\n\
+The 'send' argument should be a boolean indicating whether to use the send or\n\
+receive end.");
+
+
+static PyObject *
channel_send(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"cid", "obj", NULL};
@@ -2493,6 +2568,8 @@ static PyMethodDef module_functions[] = {
METH_VARARGS | METH_KEYWORDS, channel_destroy_doc},
{"channel_list_all", channel_list_all,
METH_NOARGS, channel_list_all_doc},
+ {"channel_list_interpreters", (PyCFunction)(void(*)(void))channel_list_interpreters,
+ METH_VARARGS | METH_KEYWORDS, channel_list_interpreters_doc},
{"channel_send", (PyCFunction)(void(*)(void))channel_send,
METH_VARARGS | METH_KEYWORDS, channel_send_doc},
{"channel_recv", (PyCFunction)(void(*)(void))channel_recv,